def connect(self, src): """ Connect a VLC output to a given audio source This will create a VLC process based on the given name """ print('connecting {} to {}...'.format(self.name, src)) if self.mock: print('{} connected to {}'.format(self.name, src)) self.state = 'connected' self.src = src return # Make all of the necessary dir(s) config_folder = '/home/pi/config/srcs/{}'.format(src) os.system('mkdir -p {}'.format(config_folder)) # Start audio via runvlc.py song_info_path = '/home/pi/config/srcs/{}/currentSong'.format(src) inetradio_args = [ 'python3', '/home/pi/config/runvlc.py', '{}'.format(self.url), '{}'.format(utils.output_device(src)), '--song-info', song_info_path ] self.proc = subprocess.Popen(args=inetradio_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setpgrp) print('{} (stream: {}) connected to {} via {}'.format( self.name, self.url, src, utils.output_device(src))) self.state = 'connected' self.src = src
def connect(self, src): """ Connect a VLC output to a given audio source This will create a VLC process based on the given name """ print(f'connecting {self.name} to {src}...') if self.mock: print(f'{self.name} connected to {src}') self.state = 'playing' self.src = src return # Make all of the necessary dir(s) src_config_folder = f"{utils.get_folder('config')}/srcs/{src}" os.system(f'mkdir -p {src_config_folder}') # Start audio via runvlc.py song_info_path = f'{src_config_folder}/currentSong' log_file_path = f'{src_config_folder}/log' inetradio_args = [ sys.executable, f"{utils.get_folder('streams')}/runvlc.py", self.url, utils.output_device(src), '--song-info', song_info_path, '--log', log_file_path ] print(f'running: {inetradio_args}') self.proc = subprocess.Popen(args=inetradio_args, preexec_fn=os.setpgrp) print( f'{self.name} (stream: {self.url}) connected to {src} via {utils.output_device(src)}' ) self.state = 'playing' self.src = src
def connect(self, src): """ Connect a fmradio.py output to a given audio source """ if self.mock: self._connect(src) return # Make all of the necessary dir(s) src_config_folder = f"{utils.get_folder('config')}/srcs/{src}" os.system('mkdir -p {}'.format(src_config_folder)) song_info_path = f'{src_config_folder}/currentSong' log_file_path = f'{src_config_folder}/log' fmradio_args = [ sys.executable, f"{utils.get_folder('streams')}/fmradio.py", self.freq, utils.output_device(src), '--song-info', song_info_path, '--log', log_file_path ] print(f'running: {fmradio_args}') self.proc = subprocess.Popen(args=fmradio_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setpgrp) self._connect(src)
def connect(self, src): """ Connect a DLNA device to a given audio source This creates a DLNA streaming option based on the configuration """ if self.mock: self._connect(src) return # Generate some of the DLNA_Args self.uuid = 0 self.uuid = uuid_gen() portnum = 49494 + int(src) src_config_folder = f'{utils.get_folder("config")}/srcs/{src}' meta_args = [ f'{utils.get_folder("streams")}/dlna_metadata.bash', f'{src_config_folder}' ] dlna_args = [ 'gmediarender', '--gstout-audiosink', 'alsasink', '--gstout-audiodevice', utils.output_device(src), '--gstout-initial-volume-db', '0.0', '-p', f'{portnum}', '-u', f'{self.uuid}', '-f', f'{self.name}', '--logfile', f'{src_config_folder}/metafifo' ] self.proc = subprocess.Popen(args=meta_args, preexec_fn=os.setpgrp, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.proc2 = subprocess.Popen(args=dlna_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._connect(src)
def connect(self, src): """ Connect pandora output to a given audio source This will start up pianobar with a configuration specific to @src """ if self.mock: self._connect(src) return # TODO: future work, make pandora and shairport use audio fifos that makes it simple to switch their sinks # make a special home/config to launch pianobar in (this allows us to have multiple pianobars) src_config_folder = f'{utils.get_folder("config")}/srcs/{src}' eventcmd_template = f'{utils.get_folder("streams")}/eventcmd.sh' pb_home = src_config_folder pb_config_folder = f'{pb_home}/.config/pianobar' pb_control_fifo = f'{pb_config_folder}/ctl' pb_status_fifo = f'{pb_config_folder}/stat' pb_config_file = f'{pb_config_folder}/config' pb_output_file = f'{pb_config_folder}/output' pb_error_file = f'{pb_config_folder}/error' pb_eventcmd_file = f'{pb_config_folder}/eventcmd.sh' pb_src_config_file = f'{pb_home}/.libao' # make all of the necessary dir(s) os.system(f'mkdir -p {pb_config_folder}') os.system(f'cp {eventcmd_template} {pb_eventcmd_file}' ) # Copy to retain executable status # write pianobar and libao config files write_config_file( pb_config_file, { 'user': self.user, 'password': self.password, 'autostart_station': self.station, 'fifo': pb_control_fifo, 'event_command': pb_eventcmd_file }) write_config_file(pb_src_config_file, { 'default_driver': 'alsa', 'dev': utils.output_device(src) }) # create fifos if needed if not os.path.exists(pb_control_fifo): os.system(f'mkfifo {pb_control_fifo}') if not os.path.exists(pb_status_fifo): os.system(f'mkfifo {pb_status_fifo}') # start pandora process in special home print(f'Pianobar config at {pb_config_folder}') try: self.proc = subprocess.Popen(args='pianobar', stdin=subprocess.PIPE, stdout=open(pb_output_file, 'w'), stderr=open(pb_error_file, 'w'), env={'HOME': pb_home}) time.sleep( 0.1) # Delay a bit before creating a control pipe to pianobar self.ctrl = pb_control_fifo self._connect(src) self.state = 'playing' except Exception as exc: print(f'error starting pianobar: {exc}')
def connect(self, src): """ Connect pandora output to a given audio source This will start up pianobar with a configuration specific to @src """ if self.mock: print('{} connected to {}'.format(self.name, src)) self.state = 'playing' # TODO: only play station based streams self.src = src return # TODO: future work, make pandora and shairport use audio fifos that makes it simple to switch their sinks # make a special home, with specific config to launch pianobar in (this allows us to have multiple pianobars) eventcmd_template = '/home/pi/config/eventcmd.sh' pb_home = '/home/pi/config/srcs/{}'.format(src) # the simulated HOME for an instance of pianobar pb_config_folder = '{}/.config/pianobar'.format(pb_home) pb_control_fifo = '{}/ctl'.format(pb_config_folder) pb_status_fifo = '{}/stat'.format(pb_config_folder) pb_config_file = '{}/config'.format(pb_config_folder) pb_output_file = '{}/output'.format(pb_config_folder) pb_error_file = '{}/error'.format(pb_config_folder) pb_eventcmd_file = '{}/eventcmd.sh'.format(pb_config_folder) pb_src_config_file = '{}/.libao'.format(pb_home) # make all of the necessary dir(s) os.system('mkdir -p {}'.format(pb_config_folder)) os.system('cp {} {}'.format(eventcmd_template, pb_eventcmd_file)) # Copy to retain executable status # write pianobar and libao config files write_config_file(pb_config_file, { 'user': self.user, 'password': self.password, 'autostart_station': self.station, 'fifo': pb_control_fifo, 'event_command': pb_eventcmd_file }) write_config_file(pb_src_config_file, {'default_driver': 'alsa', 'dev': utils.output_device(src)}) try: with open(pb_eventcmd_file) as ect: template = ect.read().replace('source_id', str(src)) with open(pb_eventcmd_file, 'w') as ec: ec.write(template) except Exception as e: print('error creating eventcmd: {}'.format(e)) # create fifos if needed if not os.path.exists(pb_control_fifo): os.system('mkfifo {}'.format(pb_control_fifo)) if not os.path.exists(pb_status_fifo): os.system('mkfifo {}'.format(pb_status_fifo)) # start pandora process in special home print('Pianobar config at {}'.format(pb_config_folder)) try: self.proc = subprocess.Popen(args='pianobar', stdin=subprocess.PIPE, stdout=open(pb_output_file, 'w'), stderr=open(pb_error_file, 'w'), env={'HOME' : pb_home}) time.sleep(0.1) # Delay a bit before creating a control pipe to pianobar self.ctrl = Pandora.Control(pb_control_fifo) self.src = src self.state = 'playing' print('{} connected to {}'.format(self.name, src)) except Exception as e: print('error starting pianobar: {}'.format(e))
def connect(self, src): """ Connect an Airplay device to a given audio source This creates an Airplay streaming option based on the configuration """ if self.mock: print('{} connected to {}'.format(self.name, src)) self.state = 'connected' self.src = src return config = { 'general': { 'name': self.name, 'port': 5100 + 100 * src, # Listen for service requests on this port 'udp_port_base': 6101 + 100 * src, # start allocating UDP ports from this port number when needed 'drift': 2000, # allow this number of frames of drift away from exact synchronisation before attempting to correct it 'resync_threshold': 0, # a synchronisation error greater than this will cause resynchronisation; 0 disables it 'log_verbosity': 0, # "0" means no debug verbosity, "3" is most verbose. }, 'metadata':{ 'enabled': 'yes', 'include_cover_art': 'yes', 'pipe_name': '/home/pi/config/srcs/{}/shairport-sync-metadata'.format(src), 'pipe_timeout': 5000, }, 'alsa': { 'output_device': utils.output_device(src), # alsa output device 'audio_backend_buffer_desired_length': 11025 # If set too small, buffer underflow occurs on low-powered machines. Too long and the response times with software mixer become annoying. }, } config_folder = '/home/pi/config/srcs/{}'.format(src) # make all of the necessary dir(s) os.system('mkdir -p {}'.format(config_folder)) config_file = '{}/shairport.conf'.format(config_folder) write_sp_config_file(config_file, config) shairport_args = 'shairport-sync -c {}'.format(config_file).split(' ') # TODO: figure out how to get status from shairport self.proc = subprocess.Popen(args=shairport_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print('{} connected to {}'.format(self.name, src)) self.state = 'connected' self.src = src
def connect(self, src): """ Connect an AirPlay device to a given audio source This creates an AirPlay streaming option based on the configuration """ if self.mock: self._connect(src) return config = { 'general': { 'name': self.name, 'port': 5100 + 100 * src, # Listen for service requests on this port 'udp_port_base': 6101 + 100 * src, # start allocating UDP ports from this port number when needed 'drift': 2000, # allow this number of frames of drift away from exact synchronisation before attempting to correct it 'resync_threshold': 0, # a synchronisation error greater than this will cause resynchronisation; 0 disables it 'log_verbosity': 0, # "0" means no debug verbosity, "3" is most verbose. }, 'metadata': { 'enabled': 'yes', 'include_cover_art': 'yes', 'pipe_name': f'{utils.get_folder("config")}/srcs/{src}/shairport-sync-metadata', 'pipe_timeout': 5000, }, 'alsa': { 'output_device': utils.output_device(src), # alsa output device 'audio_backend_buffer_desired_length': 11025 # If set too small, buffer underflow occurs on low-powered machines. Too long and the response times with software mixer become annoying. }, } src_config_folder = f'{utils.get_folder("config")}/srcs/{src}' os.system(f'rm -f {src_config_folder}/currentSong') web_dir = f"{utils.get_folder('web/generated')}/shairport/srcs/{src}" # make all of the necessary dir(s) os.system(f'rm -r -f {web_dir}') os.system(f'mkdir -p {web_dir}') os.system(f'mkdir -p {src_config_folder}') config_file = f'{src_config_folder}/shairport.conf' write_sp_config_file(config_file, config) shairport_args = f'shairport-sync -c {config_file}'.split(' ') meta_args = [ f"{utils.get_folder('streams')}/shairport_metadata.bash", src_config_folder, web_dir ] print(f'shairport_args: {shairport_args}') print(f'meta_args: {meta_args}') # TODO: figure out how to get status from shairport self.proc = subprocess.Popen(args=shairport_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.proc2 = subprocess.Popen(args=meta_args, preexec_fn=os.setpgrp, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._connect(src)