I am attempting to write a Gstreamer Python program that will control the Whole Home Audio system in my house. The basic premise is that I will have multiple different options for sources (Pandora, MP3, Google Music, etc.) and will be able to play them in different "Zones" throughout my house. I have gotten it to work for dynamically adding a zone to a currently playing pipeline, but when I attempt to remove a zone the audio stops playing in all zones. Here is the relevant code, I can post more if necessary:
Basic Setup:
def __init__(self, username, password, zones=[]):
# initialize the player
self.player = gst.element_factory_make('playbin2', 'pandora_player')
fakesink = gst.element_factory_make('fakesink', 'fakesink')
self.player.set_property('video-sink', fakesink)
# enable progressive download (GST_PLAY_FLAG_DOWNLOAD)
self.player.props.flags |= (1 << 7)
# create bin
teebin = gst.element_factory_make('bin', 'master')
tee = gst.element_factory_make('tee', 'tee')
teebin.add(tee)
ghost_pad = gst.GhostPad('sink', tee.get_pad('sink'))
teebin.add_pad(ghost_pad)
# set bin as audio sink
self.player.set_property('audio-sink', teebin)
# set volume
self.player.set_property('volume', 0.01)
bus = self.player.get_bus()
bus.add_signal_watch()
bus.connect('message', self.on_message)
# make everything accessible
self.tee = tee
self.teebin = teebin
def add_zone(self, zone_id):
# create out first audio output device
zone_name = 'zone_{0}'.format(zone_id)
device_name = 'mono{0}'.format(zone_id)
bin_name = 'bin_{0}'.format(zone_id)
queue_name = 'q_{0}'.format(zone_id)
# wrap everything in a convenient zone object
zone = gst.element_factory_make('bin', bin_name)
# handle sending to the proper sound device
zone_device = gst.element_factory_make('alsasink', zone_name)
zone_device.set_property('device', device_name)
# create a queue to handle asynchronous playback
zone_queue = gst.element_factory_make('queue', queue_name)
zone.add(zone_queue, zone_device)
zone_queue.link(zone_device)
# add sink into element
zone_ghost = gst.GhostPad('sink', zone_queue.get_pad('sink'))
zone.add_pad(zone_ghost)
self.zones[zone_id] = zone
self.teebin.add(zone)
zone.sync_state_with_parent()
self.tee.link(zone)
def remove_zone(self, zone_id):
# get zone
zone = self.zones[zone_id]
# get src pad that is sending audio
pad = zone.get_pad('sink').get_peer()
# block src pad
pad.set_blocked(True)
# set zone state null
zone.set_state(gst.STATE_NULL)
# unlink and remove zone
self.tee.unlink(zone)
self.teebin.remove(zone)
# remove zone reference
del self.zones[zone_id]