Skip to content

Commit 2b1b636

Browse files
authored
Merge pull request #2 from bitkeeper/v1.x
Merge v1.x develop to main
2 parents 8550b81 + 1951d61 commit 2b1b636

File tree

5 files changed

+73
-139
lines changed

5 files changed

+73
-139
lines changed

README.MD

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ MPD2CamillaDSPVolume<!-- omit in toc -->
22
=============================================
33
bitkeeper @ github 2022
44

5+
Starting from mpd2cdspvolume version `1.0.0` support for camilladsp 1.x is dropped. With that also the command `cdspstorevolume` is dropped.
6+
57
# Introduction
68

79
[MPD2CamillaDSPVolume](https://github.com/bitkeeper/mpd2cdspvolume) makes it possible to control the volume of CamillaDSP with the volume of MPD.
@@ -16,26 +18,19 @@ Features:
1618

1719
How it works:
1820
* It listens to MPD Mixer changes.
19-
* When CamillaDSP is running, the changed volume is send to CamillaDSP else to the state file.
21+
* When CamillaDSP is running, the changed volume is send to CamillaDSP else to the statefile.
2022

2123
Requires:
22-
* Using for MPD volume control the mixer type `null`
23-
* Use in the alsa_cdsp config the `camilla_exit_cmd` to make sure the volume is writen on exit.
24-
```
25-
camilla_exit_cmd "/usr/local/bin/cdspstorevolume"
26-
```
27-
* The camilla_exit_cmd requires that the process of alsa_cdsp can send signals to MPD2CamillaDSPVolume (most easy to run both as the same user)
24+
* Add in alsa_cdsp config for the `cargs` the argument to the correct statefile ` -s <path_t_your_statefile>` to start camilladsp with the correct statefile.
25+
* Use the same statefile with mpd2cdspvolume.
2826

2927

30-
When using MPD with CamillaDSP the volume of MPD isn't coupled to CamillaDSP.
31-
3228
# Files
3329
## From source
3430

3531
| File | Description | Packed as |
3632
|---------- |-----------------|---------------|
3733
| mpd2cdspvolume.py | mpd volume to camilladsp syncer | /usr/local/bin/mpd2cdspvolume |
38-
| cdspstorevolume.sh | store the current cdsp volume in to the volume state file | /usr/local/bin/cdspstorevolume.sh |
3934
| etc/mpd2cdspvolume.conf | tmpfs files to created | /usr/lib/tmpfiles.d/mpd2cdspvolume.conf |
4035
| etc/mpd2cdspvolume.service | systemd service file | /lib/systemd/system/mpd2cdspvolume.service |
4136
| etc/mpd2cdspvolume.config | mpd2cdspvolume config file* | /etc/mpd2cdspvolume.config
@@ -48,7 +43,8 @@ When using MPD with CamillaDSP the volume of MPD isn't coupled to CamillaDSP.
4843
| File | Description |
4944
|---------- |-----------------|
5045
| /var/run/mpd2cdspvol/mpd2cdspvol.pid | Contains PID of mpd2cdspvolume. Path is in a temp.fs and is created on boot by `usr/lib/tmpfiles.d/mpd2cdspvolume.conf` |
51-
| /var/lib/cdsp/camilladsp_volume_state| Contains the volume_state as required by alsa_cdsp. Path is postinstall.sh (typical runned on deb install time)|
46+
| /var/lib/cdsp/statefile.yml | Contains the volume_state as required by camilladsp. Path is postinstall.sh (typical runned on deb install time)|
47+
5248
# Install
5349

5450

@@ -68,7 +64,6 @@ Copy the scripts to a convient location like:
6864
```bash
6965
sudo cp mpd2cdspvolume.py /usr/local/bin/mpd2cdspvolume
7066
sudo chmod a+x /usr/local/bin/mpd2cdspvolume
71-
sudo cp cdspstorevolume.sh /usr/local/bin/cdspstorevolume
7267
sudo chmod a+x /usr/local/bin/cdspstorevolume
7368
sudo cp etc/mpd2cdspvolume.conf usr/lib/tmpfiles.d/
7469
```
@@ -105,12 +100,6 @@ optional arguments:
105100
106101
example:
107102
108-
with camilladsp 1.x
109-
```bash
110-
sudo -H -u mpd bash -c "/usr/local/bin/mpd2cdspvolume --verbose --pid_file /var/run/mpd2cdspvol/mpd2cdspvol.pid --volume_state_file /var/lib/cdsp/camilladsp_volume_state --config /etc/mpd2cdspvolume.config"
111-
```
112-
113-
with camilladsp 2.x
114103
```bash
115104
sudo -H -u mpd bash -c "/usr/local/bin/mpd2cdspvolume --verbose --pid_file /var/run/mpd2cdspvol/mpd2cdspvol.pid --volume_state_file /var/lib/cdsp/statefile.yml --config /etc/mpd2cdspvolume.config"
116105
```
@@ -120,22 +109,20 @@ This will run the program as user `mpd` and with `--verbose` show output of the
120109
When also [alsa_cdsp](https://github.com/scripple/alsa_cdsp) is used, alsa_cdsp start and stop camilladsp on source change like samplerate. Also when music is pauzed camilladsp is stopped. [moOde](https://www.moode.org) is an example that uses alsa_cdsp
121110
122111
To preserve the volume settings of camilladsp alsa_cdsp a way of using a volume state file:
123-
- Before camilladsp is started, the state file is read and volume is supplied as argument to camilladsp
124-
- Just before shutting down camilladsp an 'exit' command can be executed to store the volume.
125-
126-
127-
When a SIGHUP signal is send to mpd2cdspvolume it read the current volume setting of camilladsp and write it to file.
112+
- camilladsp gets and argument at startup with the used statefile
128113
129-
Md2cdspvolume provides and script `cdspstorevolume` that can be use as 'exit' command, that send the SIGHUP to `mpd2cdspvolume` script.
130114
131115
When MPD volume changes are made, while the music isn't playing or camilladsp isn't active, the volume setting is writen to the state file instead.
132116
133117
To use the state file with alsa_cdsp edit the config and add the `vol_file` and `camilla_exit_cmd` arguments.
134118
135119
For example with moOde add following lines to `/etc/alsa/conf.d/camilladsp.conf`:
136120
```bash
137-
vol_file "/var/lib/cdsp/camilladsp_volume_state"
138-
camilla_exit_cmd "/usr/local/bin/cdspstorevolume"
121+
cargs [
122+
-p "1234"
123+
-a "0.0.0.0"
124+
-s "/var/lib/cdsp/statefile.yml"
125+
]
139126
```
140127
141128
To make this work the user of the process who is running should have the rights to send a signal to mpd2cdspvolume.

builddep.sh

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fi
1616

1717
if [ -z "$PKGVERSION" ]
1818
then
19-
PKGVERSION="0.4.0"
19+
PKGVERSION="1.0.0"
2020
fi
2121

2222
if [ -z "$DEBVER" ]
@@ -33,14 +33,12 @@ fi
3333
# Prep root to pack
3434
mkdir -p root/usr/local/bin
3535
cp mpd2cdspvolume.py root/usr/local/bin/mpd2cdspvolume
36-
cp cdspstorevolume.sh root/usr/local/bin/cdspstorevolume
3736
mkdir -p root/usr/lib/tmpfiles.d
3837
cp etc/mpd2cdspvolume.conf root/usr/lib/tmpfiles.d/
3938
mkdir -p root/etc
4039
cp etc/mpd2cdspvolume.config root/etc
4140

4241
chmod a+x root/usr/local/bin/mpd2cdspvolume
43-
chmod a+x root/usr/local/bin/cdspstorevolume
4442

4543
# build the package
4644
fpm -s dir -t deb -n $PKGNAME -v $PKGVERSION \
@@ -56,7 +54,7 @@ fpm -s dir -t deb -n $PKGNAME -v $PKGVERSION \
5654
--description "Service for synchronizing MPD volume to CamillaDSP." \
5755
--deb-systemd etc/mpd2cdspvolume.service \
5856
--depends python3-mpd2 \
59-
--depends python3-camilladsp \
57+
--depends 'python3-camilladsp >= 2.0.0' \
6058
--after-install etc/postinstall.sh \
6159
root/usr/=/usr/. \
6260
root/etc/=/etc/.

cdspstorevolume.sh

Lines changed: 0 additions & 35 deletions
This file was deleted.

changelog.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
1.0.0
2+
* [refactor!] Drop support Camilladsp 1.x
3+
* [fix] Correct initial statefile generation
4+
* [feat] Create correct statefile if format is not valid
5+
* [feat] Detect if correct camilladsp python pacakge is installed
6+
* [refactor] Don't store volume on sighup (not required any more with CamillaDSP)
7+
18
0.4.0
29
* Support for Camilladsp 2.0
310

mpd2cdspvolume.py

Lines changed: 51 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,9 @@
4040
from math import log10, exp, log
4141
from mpd import MPDClient, ConnectionError
4242

43-
try:
44-
from camilladsp import CamillaClient
45-
except:
46-
from camilladsp import CamillaConnection as CamillaClient
43+
import camilladsp
4744

48-
VERSION = "0.4.0"
45+
VERSION = "1.0.0"
4946

5047
def lin_vol_curve(perc: int, dynamic_range: float= 60.0) -> float:
5148
'''
@@ -147,92 +144,79 @@ class CamillaDSPVolumeUpdater:
147144
"""Updates CamillaDSP volume
148145
When cdsp isn't running and a volume state file for alsa_cdsp is provided that one is updated
149146
"""
147+
148+
CDSP_STATE_TEMPLATE = {
149+
'config_path': '/usr/share/camilladsp/working_config.yml',
150+
'mute': [ False,False, False,False,False],
151+
'volume': [ -6.0, -6.0, -6.0, -6.0, -6.0]
152+
}
153+
""" Used as default statefile value, when not present or invalid"""
154+
150155
def __init__(self, volume_state_file: Optional[Path] = None, host: str='127.0.0.1', port:int=1234):
151156
self._volume_state_file: Optional[Path]= volume_state_file
152-
self._cdsp = CamillaClient(host, port)
157+
self._cdsp = camilladsp.CamillaClient(host, port)
153158
if volume_state_file:
154159
logging.info('volume state file: "%s"', volume_state_file )
155160

156-
def update_alsa_cdsp_volume_file(self, volume_db: float, mute: int=0):
157-
""" Store state in own mpd2cdspvolume statefile. Required for CamillaDSP < 2.x"""
158-
if self._volume_state_file and self._volume_state_file.exists():
159-
logging.info('update volume state file : %.2f dB, mute: %d', volume_db,mute)
160-
try:
161-
self._volume_state_file.write_text('{} {}'.format(volume_db, mute))
162-
except FileNotFoundError as e:
163-
logging.error('Couldn\'t create state file "%s", prob basedir doesn\'t exists.', self._volume_state_file)
164-
except PermissionError as e:
165-
logging.error('Couldn\'t write state to "%s", prob incorrect owner rights of dir.', self._volume_state_file)
161+
def check_cdsp_statefile(self) -> bool:
162+
""" check if it exists and is valid. If not create a valid one"""
163+
try:
164+
if self._volume_state_file and self._volume_state_file.is_file() is False:
165+
logging.info('Create statefile %s',self._volume_state_file)
166+
cdsp.update_cdsp_statefile(0, False)
167+
elif self._volume_state_file.is_file() is True:
168+
cdsp_state = yaml.load(self._volume_state_file.read_text(), Loader=yaml.Loader)
169+
if isinstance(cdsp_state, dict) is False:
170+
logging.info('Statefile %s content not valid recreate it',self._volume_state_file)
171+
cdsp.update_cdsp_statefile(0, False)
172+
except FileNotFoundError as e:
173+
logging.error('Couldn\'t create state file "%s", prob basedir doesn\'t exists.', self._volume_state_file)
174+
return False
175+
except PermissionError as e:
176+
logging.error('Couldn\'t write state to "%s", prob incorrect owner rights of dir.', self._volume_state_file)
177+
return False
178+
179+
return True
166180

167181
def update_cdsp_volume(self, volume_db: float):
168182
try:
169183
if self._cdsp.is_connected() is False:
170184
self._cdsp.connect()
171185

186+
self._cdsp.volume.set_main(volume_db)
187+
time.sleep(0.2)
188+
cdsp_actual_volume = self._cdsp.volume.main()
189+
logging.info('volume set to %.2f [readback = %.2f] dB', volume_db, cdsp_actual_volume)
172190

173-
if hasattr(self._cdsp, "volume"):
191+
# correct issue when volume is not the required one (issue with cdsp 2.0)
192+
if abs(cdsp_actual_volume-volume_db) > .2:
193+
# logging.info('volume incorrect !')
174194
self._cdsp.volume.set_main(volume_db)
175-
time.sleep(0.2)
176-
cdsp_actual_volume = self._cdsp.volume.main()
177-
logging.info('volume set to %.2f [readback = %.2f] dB', volume_db, cdsp_actual_volume)
178-
179-
# correct issue when volume is not the required one (issue with cdsp 2.0)
180-
if abs(cdsp_actual_volume-volume_db) > .2:
181-
# logging.info('volume incorrect !')
182-
self._cdsp.volume.set_main(volume_db)
183-
else:
184-
self._cdsp.set_volume(volume_db)
185195
return True
186196
except (ConnectionRefusedError, IOError) as e:
187197
logging.info('no cdsp')
188-
if hasattr(self._cdsp, "volume"):
189-
self.update_alsa_cdsp_volume_file(volume_db)
190-
else:
191-
self.update_cdsp_statefile(volume_db)
198+
self.update_cdsp_statefile(volume_db)
192199
return False
193200

194-
def store_volume(self):
195-
try:
196-
if self._cdsp.is_connected() is False:
197-
self._cdsp.connect()
198-
199-
if hasattr(self._cdsp, "volume"):
200-
volume_db = float(self._cdsp.volume.main())
201-
mute = 1 if self._cdsp.mute.main() else 0
202-
else:
203-
volume_db = float(self._cdsp.get_volume())
204-
mute = 1 if self._cdsp.get_mute() else 0
205-
self.update_alsa_cdsp_volume_file(volume_db, mute)
206-
207-
except (ConnectionRefusedError, IOError) as e:
208-
logging.warning('store volume: no cdsp')
209-
210-
def sig_hup(self, signum, frame):
211-
if hasattr(self._cdsp, "volume") is False:
212-
self.store_volume()
213-
# force disconnect to prevent a 'hanging' socket during close down of cdsp
214-
if self._cdsp.is_connected():
215-
self._cdsp.disconnect()
216-
217201
def update_cdsp_statefile(self, main_volume: float=-6.0, main_mute:bool = False):
218202
""" Update statefile from camilladsp. Used for CamillaDSP 2.x and higher."""
219203
logging.info('update volume state file : %.2f dB, mute: %d', main_volume ,main_mute)
220-
cdsp_state = {
221-
'config_path': '/usr/share/camilladsp/working_config.yml',
222-
'mute': [ False,False, False,False,False],
223-
'volume': [ -6.0, -6.0, -6.0, -6.0, -6.0]
224-
}
204+
cdsp_state = dict(CamillaDSPVolumeUpdater.CDSP_STATE_TEMPLATE)
225205
if self._volume_state_file:
226206
try:
227207
if self._volume_state_file.exists():
228-
cdsp_state = yaml.load(self._volume_state_file.read_text(), Loader=yaml.Loader)
208+
data = yaml.load(self._volume_state_file.read_text(), Loader=yaml.Loader)
209+
if isinstance(data, dict):
210+
cdsp_state = data
211+
else:
212+
logging.warning('no valid state file content, overwrite it')
229213
else:
230214
logging.info('no state file present, create one')
231215

232216
cdsp_state['volume'][0] = main_volume
233217
cdsp_state['mute'][0] = main_mute
234218

235-
self._volume_state_file.write_text(yaml.dump(data, indent=8, explicit_start=True))
219+
self._volume_state_file.write_text(yaml.dump(cdsp_state, indent=8, explicit_start=True))
236220
except FileNotFoundError as e:
237221
logging.error('Couldn\'t create state file "%s", prob basedir doesn\'t exists.', self._volume_state_file)
238222
except PermissionError as e:
@@ -285,6 +269,10 @@ def get_config(config_file: Path):
285269
if args.verbose:
286270
logging.basicConfig(level=logging.INFO)
287271

272+
if not hasattr(camilladsp, 'CamillaClient'):
273+
logging.error('No or wrong version of Python package camilladsp installed, requires version 2 or higher.')
274+
exit(1)
275+
288276
logging.info('start-up mpd2cdspvolume')
289277

290278
dynamic_range : Optional[int]= None
@@ -313,24 +301,13 @@ def get_config(config_file: Path):
313301

314302

315303
state_file = args.volume_state_file
316-
if state_file and state_file.is_file() is False:
317-
logging.info('Create statefile %s',state_file)
318-
try:
319-
state_file.write_text('0 0')
320-
except FileNotFoundError as e:
321-
logging.error('Couldn\'t create state file "%s", prob basedir doesn\'t exists.', state_file)
322-
exit(1)
323-
except PermissionError as e:
324-
logging.error('Couldn\'t write state to "%s", prob incorrect owner rights of dir.', state_file)
325-
exit(1)
326-
327-
328304
cdsp = CamillaDSPVolumeUpdater(state_file, host = args.cdsp_host, port = args.cdsp_port)
305+
if cdsp.check_cdsp_statefile() is False:
306+
exit(1)
329307
monitor = MPDMixerMonitor(host = args.mpd_host, port = args.mpd_port, callback = cdsp.update_cdsp_volume, dynamic_range=dynamic_range, volume_offset=volume_offset)
330308

331309
signal.signal(signal.SIGINT, monitor.exit_gracefully)
332310
signal.signal(signal.SIGTERM, monitor.exit_gracefully)
333-
signal.signal(signal.SIGHUP, cdsp.sig_hup)
334311

335312
monitor.run_monitor()
336313

0 commit comments

Comments
 (0)