|
40 | 40 | from math import log10, exp, log |
41 | 41 | from mpd import MPDClient, ConnectionError |
42 | 42 |
|
43 | | -try: |
44 | | - from camilladsp import CamillaClient |
45 | | -except: |
46 | | - from camilladsp import CamillaConnection as CamillaClient |
| 43 | +import camilladsp |
47 | 44 |
|
48 | | -VERSION = "0.4.0" |
| 45 | +VERSION = "1.0.0" |
49 | 46 |
|
50 | 47 | def lin_vol_curve(perc: int, dynamic_range: float= 60.0) -> float: |
51 | 48 | ''' |
@@ -147,92 +144,79 @@ class CamillaDSPVolumeUpdater: |
147 | 144 | """Updates CamillaDSP volume |
148 | 145 | When cdsp isn't running and a volume state file for alsa_cdsp is provided that one is updated |
149 | 146 | """ |
| 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 | + |
150 | 155 | def __init__(self, volume_state_file: Optional[Path] = None, host: str='127.0.0.1', port:int=1234): |
151 | 156 | self._volume_state_file: Optional[Path]= volume_state_file |
152 | | - self._cdsp = CamillaClient(host, port) |
| 157 | + self._cdsp = camilladsp.CamillaClient(host, port) |
153 | 158 | if volume_state_file: |
154 | 159 | logging.info('volume state file: "%s"', volume_state_file ) |
155 | 160 |
|
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 |
166 | 180 |
|
167 | 181 | def update_cdsp_volume(self, volume_db: float): |
168 | 182 | try: |
169 | 183 | if self._cdsp.is_connected() is False: |
170 | 184 | self._cdsp.connect() |
171 | 185 |
|
| 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) |
172 | 190 |
|
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 !') |
174 | 194 | 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) |
185 | 195 | return True |
186 | 196 | except (ConnectionRefusedError, IOError) as e: |
187 | 197 | 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) |
192 | 199 | return False |
193 | 200 |
|
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 | | - |
217 | 201 | def update_cdsp_statefile(self, main_volume: float=-6.0, main_mute:bool = False): |
218 | 202 | """ Update statefile from camilladsp. Used for CamillaDSP 2.x and higher.""" |
219 | 203 | 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) |
225 | 205 | if self._volume_state_file: |
226 | 206 | try: |
227 | 207 | 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') |
229 | 213 | else: |
230 | 214 | logging.info('no state file present, create one') |
231 | 215 |
|
232 | 216 | cdsp_state['volume'][0] = main_volume |
233 | 217 | cdsp_state['mute'][0] = main_mute |
234 | 218 |
|
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)) |
236 | 220 | except FileNotFoundError as e: |
237 | 221 | logging.error('Couldn\'t create state file "%s", prob basedir doesn\'t exists.', self._volume_state_file) |
238 | 222 | except PermissionError as e: |
@@ -285,6 +269,10 @@ def get_config(config_file: Path): |
285 | 269 | if args.verbose: |
286 | 270 | logging.basicConfig(level=logging.INFO) |
287 | 271 |
|
| 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 | + |
288 | 276 | logging.info('start-up mpd2cdspvolume') |
289 | 277 |
|
290 | 278 | dynamic_range : Optional[int]= None |
@@ -313,24 +301,13 @@ def get_config(config_file: Path): |
313 | 301 |
|
314 | 302 |
|
315 | 303 | 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 | | - |
328 | 304 | cdsp = CamillaDSPVolumeUpdater(state_file, host = args.cdsp_host, port = args.cdsp_port) |
| 305 | + if cdsp.check_cdsp_statefile() is False: |
| 306 | + exit(1) |
329 | 307 | monitor = MPDMixerMonitor(host = args.mpd_host, port = args.mpd_port, callback = cdsp.update_cdsp_volume, dynamic_range=dynamic_range, volume_offset=volume_offset) |
330 | 308 |
|
331 | 309 | signal.signal(signal.SIGINT, monitor.exit_gracefully) |
332 | 310 | signal.signal(signal.SIGTERM, monitor.exit_gracefully) |
333 | | - signal.signal(signal.SIGHUP, cdsp.sig_hup) |
334 | 311 |
|
335 | 312 | monitor.run_monitor() |
336 | 313 |
|
|
0 commit comments