Moode Forum

Full Version: CamillaDSP offline state possible to avoid?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi here all Smile 

While mocking up an bluetooth (ESP32) transmitter/reciever for my moOde player, i need some way of toggling play&pause from within a Python script.
(The bluetooth remote uses CamillaDSP's volume control for volume)

Snip of cdsp .yml config ::



Code:
filters:
 Gain_L:
   parameters:
     gain: -3
     inverted: false
     mute: false
   type: Gain
 Gain_R:
   parameters:
     gain: -3
     inverted: false
     mute: false
   type: Gain
 Vol_L:
   parameters:
     ramp_time: 200
   type: Volume
 Vol_R:
   parameters:
     ramp_time: 200
   type: Volume
pipeline:
- channel: 0
 names:
 - Gain_L
 - Vol_L
 type: Filter
- channel: 1
 names:
 - Gain_R
 - Vol_R
 type: Filter
...


I found that mpc toggle can do the trick very easily, so thats good. But camillaDSP goes offline every time i pause the player causing the python script to crash.
Well maybe (i guess) i could let the when done systemctl script restart the Python, but i don't like it this way.

Soo quistion is: Is there a way to avoid CamillaDSP to go offline when pausing the player ?

Rgds; Jesper
I will btw. post additional info about my project later on in the process.
So i tried different.

The bluetooth remote don't like restart's and script are getting lacky when running - So my own idea to restart at crash is a nogo Shy

So, i could maybe use mpc commands to control volume this way, but the hole idea is to use Camilladsp's, so nogo too  Rolleyes


My python3 script (Reciever end - connected with usb to RaspberryPi)
Only ekstra lib installed for this is ::
Quote:sudo -H pip3 install pyserial


Code:
#!/usr/bin/python3

#################################################
#                                               #
# SuperPlayer Bluetooth (BLE) remote controller #
#                                               #
# Build with help from different sources (www)  #
#                                               #
# Jesper Lykke [user :: Lykkedk @ diyaudio.com] #
#                                               #
#################################################

from camilladsp import CamillaConnection
import io
import os
import stat
import subprocess
import sys
from subprocess import call
import time
import serial

cdsp = CamillaConnection("127.0.0.1", 1234)

GO = int(1)            # Go through loop = (1)
MUTE = int(0)          # Mute = (1) / Unmute = (0)

# CamillaDSP '--gain <gain>': Must be a number between -120 and +20

volume = int(-0)       # We start with volume at -0dB
MIN_volume = int(-110) # Lower limit with some proof
MAX_volume = int(-0)   # Upper limit without 'clipping'
CN = int(-0)           # Set volume default for Unmute / Mute

OLD_value = int(100000)                  # The same value as encoder is given at start
LONG_press = int(25000)                  # 25000 = long pressed
DOUBLE_press = int(50000)                # 50000 = double pressed
SLEEP_trigger = int(125000)              # Value recieved here, just before SuperPlayer-Controller goes to sleep

newline = "\r\n"                         # To send "newline" serial signal

def SEGMENT_TRIGGER():
   CNN=abs(CN)                          # Convert CN [Volume from CamillaDSP / cdsp.get_volume()]
   CNNN = (CNN/10)                      # Divide to fit segment display
   CN_STRING = (str(CNNN))              # Convert to string
   ser.write(CN_STRING.encode('utf-8')) # Encode to utf-8 (Arduino) and send through serial
   ser.write(newline.encode('utf-8'))   # Encode to utf-8 (Arduino) and send this "newline"

ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=.1) # Setup serial connection

while 1:

   serialdata = ser.readline()[:-2]

   if serialdata:

       data = (serialdata.decode('utf-8'))
       raw = int(data)

       if (MUTE == 0):
           if (raw < OLD_value):

               volume = (volume -1)
               cdsp.connect()
               CN=cdsp.get_volume()

               if (CN <= MIN_volume):
                   volume = int(MIN_volume)
                   cdsp.connect()
                   cdsp.set_volume(volume)
                   CN=cdsp.get_volume()

               cdsp.connect()
               cdsp.set_volume(volume)
               CN=cdsp.get_volume()
               print ("Volume DOWN :", CN)
               SEGMENT_TRIGGER()
               OLD_value = raw

       if (MUTE == 0):
           if (raw > OLD_value):

               volume = (volume +1)
               cdsp.connect()
               CN=cdsp.get_volume()
               if (CN >= MAX_volume):
                   volume = int(MAX_volume)
                   cdsp.connect()
                   cdsp.set_volume(volume)
                   CN=cdsp.get_volume()

               cdsp.connect()
               cdsp.set_volume(volume)
               CN=cdsp.get_volume()
               print ("Volume UP   :", CN)
               SEGMENT_TRIGGER()
               OLD_value = raw

       if (raw == LONG_press):
           # Option : Trigger play / pause
           print ("Pause / Play")
           subprocess.call(['mpc', 'toggle' ])
           raw = OLD_value
           time.sleep(1.00)

       if (raw == DOUBLE_press):
           print ("Double press")
           MUTE = (MUTE + 1) % 2
           if (MUTE == 0):
               print ("<> Unmute system <>")
               cdsp.connect()
               cdsp.set_volume(CN)
               time.sleep(1.00)
           if (MUTE == 1):
               print ("<> Mute system <>")
               cdsp.connect()
               CN=cdsp.get_volume()
               cdsp.set_volume(MIN_volume)
               time.sleep(1.00)

       if (raw == SLEEP_trigger):
           print ("ESP32 Controller sleep state detected")
           Sleep = int(250)                            # Value tells ESP32 reciever to display sleep state
           Sleep_String = (str(Sleep))                 # Convert to string
           ser.write(Sleep_String.encode('utf-8'))     # Encode to utf-8 (Arduino) and send through serial
           ser.write(newline.encode('utf-8'))          # Encode to utf-8 (Arduino) and send this "newline"
           time.sleep(2.00)

   time.sleep(0.1)

I see that duo to ressources, sighup is send to Camilla everytime mpd is paused, stopped etc... good idea offcause, but not so good for my project through Big Grin 



I really hope there is a way to avoid this ? - I sure miss my remotecontroller listning to music with my beautifull MoOdeAudio player Cool 

Rgds; Jesper.
@lykkedk nope you can not prevent camilladsp going offlin and it will  also happen when the audio format changes.

But that shouldn't be issue to handle for you code.  Just accept that it camilladsp can be offline (there can always happing some unexpected) and handle it that by making your script a little bit more robust by adding try/except exception handling (see the pycamilladsp example on the pycamilladsp site).

Below is an example of main loop that automatic tries to reconnect in case of problems:

Code:
while 1:
   connected = cdsp.is_connected()
   if not connected:
       print('trying connect')
       try:
           cdsp.connect()
           connected = cdsp.is_connected()
           print('connected')
       except ConnectionRefusedError as e:
           connected = False
           time.sleep(2.00)

   if connected:
       try:
           print( cdsp.get_volume())
           time.sleep(2.00)
       except IOError as e:
           print('lost connection')
           pass

Only now you have another issue when camilladsp is restart volume will be on the 0db until your script updates the volume after a reconnect.
You can prevent this by adding -m or -g option to camilladsp startups command of alsa_cdsp.

And keep also in mind that not all moOde audio source can use camilladsp, an overview f what suppports what can be found here https://www.bitlab.nl/page_id=872 .
Bitlab; thank's a lot for putting me in the right direction Cool

I haven't thought of the try: / except: solution.

I still need some polish to get there, and a systemctl or some daemon which restart's my script if it by any chance will crash.
I still need to dig into how you suggested the try: / except: as i normally use it more "plain"
Also i need to preserve my volume level and restore it when reconnected as you also explained...

My script is working very OK now, so it's a good start.

Rgds; Jesper.


Code:
#!/usr/bin/python3

#################################################
#                                               #
# SuperPlayer Bluetooth (BLE) remote controller #
#                                               #
# Build with help from different sources (www)  #
#                                               #
# Jesper Lykke [user :: Lykkedk @ diyaudio.com] #
#                                               #
#################################################

from camilladsp import CamillaConnection
import io
import os
import stat
import subprocess
import sys
from subprocess import call
import time
import serial

cdsp = CamillaConnection("127.0.0.1", 1234)

MUTE = int(0)          # Mute = (1) / Unmute = (0)

# CamillaDSP '--gain <gain>': Must be a number between -120 and +20

volume = int(-0)       # We start with volume at -0dB
MIN_volume = int(-110) # Lower limit with some proof
MAX_volume = int(-0)   # Upper limit without 'clipping'
CN = int(-0)           # Set volume default for Unmute / Mute

OLD_value = int(100000)                  # The same value as encoder is given at start
LONG_press = int(25000)                  # 25000 = long pressed
DOUBLE_press = int(50000)                # 50000 = double pressed
SLEEP_trigger = int(125000)              # Value recieved here, just before SuperPlayer-Controller goes to sleep

newline = "\r\n"                         # To send "newline" serial signal

connected = True

def SEGMENT_TRIGGER():
   CNN=abs(CN)                          # Convert CN [Volume from CamillaDSP / cdsp.get_volume()]
   CNNN = (CNN/10)                      # Divide to fit segment display
   CN_STRING = (str(CNNN))              # Convert to string
   ser.write(CN_STRING.encode('utf-8')) # Encode to utf-8 (Arduino) and send through serial
   ser.write(newline.encode('utf-8'))   # Encode to utf-8 (Arduino) and send this "newline"

ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=.1) # Setup serial connection

while 1:

   connected = cdsp.is_connected()
   if not connected:
       print("Trying to connect")
   try:
       cdsp.connect()
       connected = cdsp.is_connected()
       #print("CamillaDSP is connected")

       serialdata = ser.readline()[:-2]
       if serialdata:
           data = (serialdata.decode('utf-8'))
           raw = int(data)

           if (MUTE == 0):
               if (raw < OLD_value):
                   volume = (volume -1)
                   cdsp.connect()
                   CN=cdsp.get_volume()

                   if (CN <= MIN_volume):
                       volume = int(MIN_volume)
                       cdsp.connect()
                       cdsp.set_volume(volume)
                       CN=cdsp.get_volume()

                   cdsp.connect()
                   cdsp.set_volume(volume)
                   CN=cdsp.get_volume()
                   print ("Volume DOWN :", CN)
                   SEGMENT_TRIGGER()
                   OLD_value = raw

           if (MUTE == 0):
               if (raw > OLD_value):
                   volume = (volume +1)
                   cdsp.connect()
                   CN=cdsp.get_volume()
                   if (CN >= MAX_volume):
                       volume = int(MAX_volume)
                       cdsp.connect()
                       cdsp.set_volume(volume)
                       CN=cdsp.get_volume()

                   cdsp.connect()
                   cdsp.set_volume(volume)
                   CN=cdsp.get_volume()
                   print ("Volume UP   :", CN)
                   SEGMENT_TRIGGER()
                   OLD_value = raw

           if (raw == LONG_press):
               subprocess.call(['mpc', 'pause' ])
               raw = OLD_value

           if (raw == DOUBLE_press):
               print ("Double press")
               MUTE = (MUTE + 1) % 2
               if (MUTE == 0):
                   print ("<> Unmute system <>")
                   cdsp.connect()
                   cdsp.set_volume(CN)
               if (MUTE == 1):
                   print ("<> Mute system <>")
                   cdsp.connect()
                   CN=cdsp.get_volume()
                   cdsp.set_volume(MIN_volume)

           if (raw == SLEEP_trigger):
               print ("ESP32 Controller sleep state detected")
               Sleep = int(250)                            # Value tells ESP32 reciever to display sleep state
               Sleep_String = (str(Sleep))                 # Convert to string
               ser.write(Sleep_String.encode('utf-8'))     # Encode to utf-8 (Arduino) and send through serial
               ser.write(newline.encode('utf-8'))          # Encode to utf-8 (Arduino) and send this "newline"


   except:
       connected = False
       serialdata = ser.readline()[:-2]
       if serialdata:
           data = (serialdata.decode('utf-8'))
           raw = int(data)
           if (raw == LONG_press):
               subprocess.call(['mpc', 'play' ])
               raw = OLD_value
       time.sleep(2.00)

       time.sleep(0.1)