def speak(room): global sonosPlayerList, _myIp for place, player in sonosPlayerList.iteritems(): if (room.lower() == 'default' and place == _CORE_PLACEMENT.lower()) or room.lower() == place.lower(): # Taking a snapshot of the current state allows use to easily pause the currently playing track on the device before speaking on it and restore the music later snapshot = Snapshot(player) snapshot.snapshot() if isPlaying(player): player.pause() time.sleep(0.5) player.volume = 50 player.play_uri( 'x-file-cifs://{}/share/snipsTalk.wav'.format(_myIp), title='Snips') # Sonos can be sleeping. We have to loop until detecting a playing state or sometimes it might fail speaking, ending before it even started while player.get_current_transport_info( )['current_transport_state'] != 'PLAYING': time.sleep(0.1) # Once we started playing the sound, loop until it's finished while player.get_current_transport_info( )['current_transport_state'] == 'PLAYING': time.sleep(0.1) # Restore the state we were before speaking on the player snapshot.restore()
def __init__(self, hass, player): """Initialize the Sonos device.""" from soco.snapshot import Snapshot self.hass = hass self.volume_increment = 5 self._unique_id = player.uid self._player = player self._player_volume = None self._player_volume_muted = None self._speaker_info = None self._name = None self._status = None self._coordinator = None self._media_content_id = None self._media_duration = None self._media_image_url = None self._media_artist = None self._media_album_name = None self._media_title = None self._media_radio_show = None self._media_next_title = None self._support_previous_track = False self._support_next_track = False self._support_pause = False self._current_track_uri = None self._current_track_is_radio_stream = False self._queue = None self._last_avtransport_event = None self._is_playing_line_in = None self._is_playing_tv = None self.soco_snapshot = Snapshot(self._player)
def play_alert(zones, alert_uri, alert_volume=60, alert_duration=0, fade_back=True): # Use soco.snapshot to capture current state of each zone to allow restore for zone in zones: zone.snap = Snapshot(zone) zone.snap.snapshot() print('snapshot of zone: {}'.format(zone.player_name)) # prepare all zones for playing the alert for zone in zones: # Each Sonos group has one coordinator only these can play, pause, etc. if zone.is_coordinator: if not zone.is_playing_tv: # can't pause TV - so don't try! # pause music for each coordinators if playing trans_state = zone.get_current_transport_info() if trans_state['current_transport_state'] == 'PLAYING': zone.pause() # For every Sonos player set volume and mute for every zone zone.volume = alert_volume zone.mute = False # play the sound (uri) on each sonos coordinator print('will play: {} on all coordinators'.format(alert_uri)) for zone in zones: if zone.is_coordinator: zone.play_uri(uri=alert_uri, title='Sonos Alert') # wait for alert_duration time.sleep(alert_duration) # restore each zone to previous state for zone in zones: print('restoring {}'.format(zone.player_name)) zone.snap.restore(fade=fade_back)
def save_snapshot(self, speaker: Speaker): """Saves the current playback state of the passed speaker :param models.speaker.Speaker speaker: Speaker which playback state should be saved """ soco_instance = self.get_coordinator_instance(speaker) soco_instance.snapshot = Snapshot(soco_instance) soco_instance.snapshot.snapshot()
def __init__(self, hass, player): """Initialize the Sonos device.""" self.hass = hass self.volume_increment = 5 super(SonosDevice, self).__init__() self._player = player self.update() from soco.snapshot import Snapshot self.soco_snapshot = Snapshot(self._player)
def __init__(self, hass, player): """Initialize the Sonos device.""" from soco.snapshot import Snapshot self.hass = hass self.volume_increment = 5 self._player = player self._name = None self.update() self.soco_snapshot = Snapshot(self._player)
def snapshot(self, with_group=True): """Snapshot the player.""" from soco.snapshot import Snapshot self._soco_snapshot = Snapshot(self.soco) self._soco_snapshot.snapshot() if with_group: self._snapshot_group = self.soco.group if self._coordinator: self._coordinator.snapshot(False) else: self._snapshot_group = None
def play_snippet(self, uri, volume=-1, group_command=False, fade_in=False): """ Plays a audio snippet. This will pause the current audio track , plays the snippet and after that, the previous track will be continued. :param uri: uri to be played :param volume: Snippet volume [-1-100]. After the snippet was played, the previous/original volume is set. If volume is '-1', the current volume is used. Default: -1 :param group_command: Only affects the volume. If True, the snippet volume is set to all zone members. Default: False :raise err: """ self._fade_in = fade_in if not self.is_coordinator: logger.debug( "forwarding play_snippet command to coordinator with uid {uid}" .format(uid=self.zone_coordinator.uid)) self._zone_coordinator.play_snippet(uri, volume) else: with self._snippet_queue_lock: try: was_empty = False ''' Check if event queue is empty. if yes, then add the currently played track to the end of the queue ''' if self._snippet_queue.empty(): # if there is now music item in the current playlist, an exception is thrown # uncritical try: self._saved_music_item = Snapshot( device=self.soco, snapshot_queue=True) self._saved_music_item.snapshot() was_empty = True except: pass # snippet is priority 1, save_music_track is 2 self._snippet_queue.put((1, uri, volume)) if was_empty: self._snippet_queue.put((2, self._saved_music_item)) except KeyError as err: # The key have been deleted in another thread del self._snippet_queue.queue[:] raise err except Exception as err: del self._snippet_queue.queue[:] raise err
def play(): file = 'http://192.168.1.52/sounds/' + random.choice(sounds) try: sonos = by_name("Lekrum") if sonos.group: sonos = sonos.group.coordinator snap = Snapshot(sonos) snap.snapshot() sonos.play_uri(file) time.sleep(5) snap.restore(fade=True) except: print("Failed to play on " + str(sonos))
def play_alert(zones, alert_uri, alert_volume=20, alert_duration=0, fade_back=False): """ Demo function using soco.snapshot across multiple Sonos players. Args: zones (set): a set of SoCo objects alert_uri (str): uri that Sonos can play as an alert alert_volume (int): volume level for playing alert (0 tp 100) alert_duration (int): length of alert (if zero then length of track) fade_back (bool): on reinstating the zones fade up the sound? """ # Use soco.snapshot to capture current state of each zone to allow restore for zone in zones: zone.snap = Snapshot(zone) zone.snap.snapshot() print('snapshot of zone: {}'.format(zone.player_name)) # prepare all zones for playing the alert for zone in zones: # Each Sonos group has one coordinator only these can play, pause, etc. if zone.is_coordinator: if not zone.is_playing_tv: # can't pause TV - so don't try! # pause music for each coordinators if playing trans_state = zone.get_current_transport_info() if trans_state['current_transport_state'] == 'PLAYING': zone.pause() # For every Sonos player set volume and mute for every zone zone.volume = alert_volume zone.mute = False # play the sound (uri) on each sonos coordinator print('will play: {} on all coordinators'.format(alert_uri)) for zone in zones: if zone.is_coordinator: zone.play_uri(uri=alert_uri, title='Sonos Alert') # wait for alert_duration time.sleep(alert_duration) # restore each zone to previous state for zone in zones: print('restoring {}'.format(zone.player_name)) zone.snap.restore(fade=fade_back)
def get_playlist(self): try: snapshot = Snapshot(device=self.soco, snapshot_queue=True) snapshot.snapshot() f = io.BytesIO() pickle.dump(snapshot.queue, f, pickle.HIGHEST_PROTOCOL) f.seek(0) return definitions.MB_PLAYLIST + base64.b64encode( f.read()).decode('ascii') except Exception as err: raise Exception( "Unable to get playlist! Error: {err}".format(err=err)) finally: f.close()
def test_sonos_restore(self, restoreMock, *args): """Ensuring soco methods called for sonos_restor service.""" from soco.snapshot import Snapshot sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1') device = self.hass.data[sonos.DATA_SONOS][-1] device.hass = self.hass restoreMock.return_value = True device._snapshot_coordinator = mock.MagicMock() device._snapshot_coordinator.soco_device = SoCoMock('192.0.2.17') device._soco_snapshot = Snapshot(device._player) device.restore() self.assertEqual(restoreMock.call_count, 1) self.assertEqual(restoreMock.call_args, mock.call(False))
def doorbell(self): for zone in self.zones: zone.snap = Snapshot(zone) zone.snap.snapshot() # print('found zone') # print(zone.snap.volume, zone.is_coordinator, zone.is_playing_tv, zone.player_name.encode('latin-1')) coordinators = [ zone for zone in self.zones if zone.is_coordinator and not zone.is_playing_tv ] # print (coordinators) for zone_c in coordinators: trans_state = zone_c.get_current_transport_info() #print(zone_c.player_name.encode('latin-1'), trans_state) if trans_state['current_transport_state'] == 'PLAYING': zone_c.pause() for zone in self.zones: if zone.is_playing_tv: zone.volume = 0 else: zone.volume = 1 waitTime = 0 for zone_c in coordinators: # print('Play doorbell', zone_c.player_name.encode('latin-1')) zone_c.play_uri( 'x-file-cifs://raspberrypi/PiShare/Sounds/doorbell.mp3') if (waitTime == 0): waitTime = int( zone_c.get_current_track_info()['duration'][-2:]) time.sleep(waitTime) for zone in self.zones: if zone.is_playing_tv: pass else: print('restoring {}'.format( zone.player_name.encode('latin-1'))) zone.snap.restore(fade=True)
def __init__(self, name, init, messager): self.name = name self.pref_zone = init['children']['1'] sonos_list = soco.discover() zones = {} self.prev_snapshot = {} while (len(sonos_list) > 0): player = sonos_list.pop() zones[player.player_name] = player snap = Snapshot(player) self.prev_snapshot[player.player_name] = snap self.prev_snapshot[player.player_name].snapshot() if (player.player_name == self.pref_zone): self.sonos = player self.zones = zones self.state = {} #self.children = init['children'] self.messager = messager self.polling = 60 self.last_check = time.time()
def set_playlist(self, playlist, play_on_insert): try: snapshot = Snapshot(device=self.soco, snapshot_queue=False) snapshot.device.stop() snapshot.snapshot() # check magic bytes if not playlist.startswith("#so_pl#"): raise Exception("This is not a valid playlist file.") # remove magic bytes playlist = playlist.lstrip(definitions.MB_PLAYLIST) with tempfile.TemporaryFile() as f: f.write(base64.b64decode(playlist)) f.seek(0) snapshot.queue = pickle.load(f) snapshot.restore() if play_on_insert: self.set_play(1, True) except Exception as err: print(err) pass
def on_doorbell(root_path, audio_file, volume, zone): global doorbell_playing http_path = root_path + "/" + audio_file.url print('on_doorbell {} {} {}'.format(audio_file.name, volume, zone)) if is_doorbell_busy(): print('Doorbell already playing...suppressing') return doorbell_playing = True snap = Snapshot(zone) snap.snapshot() # Zone does not support snapshort restore properly for soundbar should_ring = zone.is_coordinator and not zone.is_playing_tv if should_ring: trans_state = zone.get_current_transport_info() if trans_state['current_transport_state'] == 'PLAYING': zone.pause() zone.volume = volume print('Play doorbell on ', zone.player_name) zone.play_uri(uri=http_path, title="Doorbell") time.sleep(audio_file.length) print('Restoring {}'.format(zone.player_name)) if snap.is_playing_cloud_queue: print( "Unlikely to resume playback. Cloud restore doesn't really work" ) snap.restore(fade=False) else: print('Cannot play doorbell on the provided zone') doorbell_playing = False
# -*- coding: utf-8 -*- """ Test for #224 """ import time import soco from soco.snapshot import Snapshot # alert = "x-file-cifs://DoorPi/DoorPiPublic/doorbell/sounds/Tinkle5sec.mp3" alert = 'http://archive.org/download/TenD2005-07-16.flac16/TenD2005-07-16t10Wonderboy_64kb.mp3' device = soco.SoCo('192.168.1.73') #take snapshot of current state snap = Snapshot(device) is_coord = snap.snapshot # print 'playlist_pos:', snap.playlist_position # print 'track_pos:', snap.track_position # #print 'stream_uri:', snap.stream_uri # #print 'meta:', snap.metadata # print 'media uri:', snap.media_uri # #print 'media meta:', snap.media_metadata # print 'Transport state:', snap.transport_state # Do something here that changes what's playing etc. device.volume = 20 if is_coord: device.play_uri(uri=alert) time.sleep(4)
def take_snapshot(): print("Taking snapshot for backup purposes...") snap = Snapshot(speaker) return snap.snapshot()
def say(self, message): # Need to subscribe to transport events, this is so that we know # when a given track has finished, and so we can stop it, if # we do not stop it, then it will repeat the text for a second time sub = self.device.avTransport.subscribe() # fade out #prefade_volume = self.device.volume #for v in range(prefade_volume): # self.device.volume -= 1 # time.sleep(0.25) # Take a snapshot of the current sonos device state, we will want # to roll back to this when we are done snap = Snapshot(self.device) snap.snapshot() msg = cgi.escape(message) payload = { 'ie': 'UTF-8', 'q': message, 'tl': 'en', 'total': 1, 'idx': 0, 'client': 't', 'textlen': len(message), 'tk': Token().calculate_token(message) } #trans_URL = "x-rincon-mp3radio://translate.google.com/translate_tts?tl=en&q=%s" % msg trans_URL = "x-rincon-mp3radio://translate.google.com/translate_tts?" + urlencode( payload) print trans_URL #from IPython import embed #embed() self.device.play_uri(trans_URL, title="Speech") #self.device.volume = prefade_volume impatience = time.time() patience = time.time() + 20 while patience > impatience: try: event = sub.events.get(timeout=0.5) print event.variables if 'restart_pending' not in event.variables: continue restart_pending = event.variables['restart_pending'] # About to try and restart, so stop looping and stop the # track before it starts again if restart_pending == '1': break except Empty: pass # Wait another second for the speech to stop playing time.sleep(1) impatience = time.time() time.sleep(0) # Stop the stream playing self.device.stop() # Restore the sonos device back to it's previous state snap.restore() # fade back in #for v in range(prefade_volume): # self.device.volume += 1 # time.sleep(0.25) # We no longer want to receive messages sub.unsubscribe() event_listener.stop()
def say(self, message): log("Speech: Message to say is: %s" % message) # Start by checking to see if the message is valid if not self.checkIfValidMessage(message): return xbmc.executebuiltin("ActivateWindow(busydialog)") try: # Need to subscribe to transport events, this is so that we know # when a given track has finished, and so we can stop it, if # we do not stop it, then it will repeat the text for a second time sub = self.device.avTransport.subscribe() # Take a snapshot of the current sonos device state, we will want # to roll back to this when we are done log("Speech: Taking snapshot") snap = Snapshot(self.device) snap.snapshot() # Get the URI and play it trans_URI = self._get_uri(message) log("Speech: Playing URI %s" % trans_URI) self.device.play_uri(trans_URI, title=ADDON.getLocalizedString(32105)) # The maximum number of seconds that we will wait for the message to # complete playing duration = 200 while duration > 0: # Check to see if the system is shutting down if xbmc.abortRequested: break try: eventItem = sub.events.get(timeout=0.1) # Now get the details of an event if there is one there if eventItem is not None: # Check to see if there is a message saying that it is waiting # to restart the audio stream. This happens because it is # being treated like a radio stream, so Sonos things when the # end of the mp3 file playing is reached that there has been # a connection error and needs to reconnect. If left to itself # it would play the mp3 file again if hasattr(eventItem, 'restart_pending') and ( eventItem.restart_pending is not None): # About to try and restart, so stop looping and stop the # track before it starts again if eventItem.restart_pending == '1': log("Speech: Detected restart attempt") break except Empty: pass # Wait another 10th of a second for the speech to stop playing duration = duration - 1 xbmc.sleep(100) log("Speech: Stopping speech") # Stop the stream playing self.device.stop() log("Speech: Restoring snapshot") try: # We no longer want to receive messages sub.unsubscribe() except: log( "Sonos: Failed to unsubscribe: %s" % traceback.format_exc(), xbmc.LOGERROR) try: # Make sure the thread is stopped even if unsubscribe failed event_listener.stop() except: log( "Sonos: Failed to stop event listener: %s" % traceback.format_exc(), xbmc.LOGERROR) del sub # Restore the sonos device back to it's previous state snap.restore() del snap except: log("Speech: %s" % traceback.format_exc(), xbmc.LOGERROR) xbmc.executebuiltin("Dialog.Close(busydialog)") raise xbmc.executebuiltin("Dialog.Close(busydialog)")
def _snap(self): for zone in self.zones: zone.snap = Snapshot(zone) zone.snap.snapshot()
import soco from soco.snapshot import Snapshot # something to play on a Sonos player to start (a radio station) start_uri = "x-sonosapi-stream:s2846?sid=254&flags=32" # alert sound to interrupt the above (a poem) - use amy file Sonos can play alert_uri = "https://ia800504.us.archive.org/21/items/PoemsInEnglish/tygerblake.mp3" # choose device device = soco.SoCo("192.168.1.68") # <--change IP to one of your Sonos devices # start playing something on this device(a radio station) print("playing a radio station") device.play_uri(start_uri, title="test radio station") time.sleep(10) # pause to ensure radio station playing # take snapshot of current state snap = Snapshot(device) # 1) create a Snapshot class for this device snap.snapshot() # 2) take a snapshot of this device's status # Do something that changes what's playing on this device print("playing alert") device.volume += 10 # increase volume device.play_uri(alert_uri, title="my alert") # play an alert sound time.sleep(10) # wait for a bit ! # Restore previous state of Sonos (with slow fade up) print("reinstating how it was before....") snap.restore(fade=True)