def update(self, message=None): current = self.player.getState() self.debug("update current %r", current) connection_manager = self.server.connection_manager_server av_transport = self.server.av_transport_server conn_id = connection_manager.lookup_avt_id(self.current_connection_id) if current in (self.STATE_PLAYING, self.STATE_PAUSED): self._update_transport_state(current) elif self.playcontainer != None and message == self.MESSAGE_EOF and \ self.playcontainer[0] + 1 < len(self.playcontainer[2]): self._transition() next_track = () item = self.playcontainer[2][self.playcontainer[0] + 1] infos = connection_manager.get_variable('SinkProtocolInfo') local_protocol_infos = infos.value.split(',') res = item.res.get_matching(local_protocol_infos) if len(res) > 0: res = res[0] infos = res.protocolInfo.split(':') remote_protocol, remote_network, remote_content_format, _ = infos didl = DIDLLite.DIDLElement() didl.addItem(item) next_track = (res.data, didl.toString(), remote_content_format) self.playcontainer[0] = self.playcontainer[0] + 1 self.info("update: next=%s" % next_track) if len(next_track) == 3: av_transport.set_variable(conn_id, 'CurrentTrack', self.playcontainer[0] + 1) self.load(next_track[0], next_track[1], next_track[2]) self.play() else: self._update_transport_state(self.STATE_IDLE) elif message == self.MESSAGE_EOF and \ len(av_transport.get_variable('NextAVTransportURI').value) > 0: self._transition() CurrentURI = av_transport.get_variable('NextAVTransportURI').value metadata = av_transport.get_variable('NextAVTransportURIMetaData') CurrentURIMetaData = metadata.value av_transport.set_variable(conn_id, 'NextAVTransportURI', '') av_transport.set_variable(conn_id, 'NextAVTransportURIMetaData', '') r = self.upnp_SetAVTransportURI( self, InstanceID=0, CurrentURI=CurrentURI, CurrentURIMetaData=CurrentURIMetaData) self.info("update: r=%s" % r) if r == {}: self.play() else: self._update_transport_state(self.STATE_IDLE) else: self._update_transport_state(self.STATE_IDLE) self._update_transport_position()
def upnp_Seek(self, *args, **kwargs): InstanceID = int(kwargs['InstanceID']) Unit = kwargs['Unit'] Target = kwargs['Target'] if InstanceID != 0: return failure.Failure(errorCode(718)) if Unit in ['TRACK_NR']: if self.playcontainer == None: NextURI = self.server.av_transport_server.get_variable( 'NextAVTransportURI').value if NextURI != '': self.server.av_transport_server.set_variable( InstanceID, 'TransportState', 'TRANSITIONING') NextURIMetaData = self.server.av_transport_server.get_variable( 'NextAVTransportURIMetaData').value self.server.av_transport_server.set_variable( InstanceID, 'NextAVTransportURI', '') self.server.av_transport_server.set_variable( InstanceID, 'NextAVTransportURIMetaData', '') r = self.upnp_SetAVTransportURI( self, InstanceID=InstanceID, CurrentURI=NextURI, CurrentURIMetaData=NextURIMetaData) return r else: Target = int(Target) if 0 < Target <= len(self.playcontainer[2]): self.server.av_transport_server.set_variable( InstanceID, 'TransportState', 'TRANSITIONING') next_track = () item = self.playcontainer[2][Target - 1] local_protocol_infos = self.server.connection_manager_server.get_variable( 'SinkProtocolInfo').value.split(',') res = item.res.get_matching(local_protocol_infos, protocol_type='internal') if len(res) == 0: res = item.res.get_matching(local_protocol_infos) if len(res) > 0: res = res[0] remote_protocol, remote_network, remote_content_format, _ = res.protocolInfo.split( ':') didl = DIDLLite.DIDLElement() didl.addItem(item) next_track = (res.data, didl.toString(), remote_content_format) self.playcontainer[0] = Target - 1 if len(next_track) == 3: self.server.av_transport_server.set_variable( self.server.connection_manager_server. lookup_avt_id(self.current_connection_id), 'CurrentTrack', Target) self.load(next_track[0], next_track[1], next_track[2]) self.play() return {} return failure.Failure(errorCode(711)) return failure.Failure(errorCode(710))
def create_object(self, container_id, elements): if isinstance(elements, dict): elements = self.dict2item(elements) if isinstance(elements, DIDLLite.Object): didl = DIDLLite.DIDLElement() didl.addItem(elements) elements = didl.toString() if elements is None: elements = '' action = self.service.get_action('CreateObject') if action: # optional return action.call(ContainerID=container_id, Elements=elements) return None
def upnp_Search(self, *args, **kwargs): self.init_cover_root() Log.d("%s" % (kwargs, )) ContainerID = kwargs['ContainerID'] Filter = kwargs['Filter'] StartingIndex = int(kwargs['StartingIndex']) RequestedCount = int(kwargs['RequestedCount']) SortCriteria = kwargs['SortCriteria'] SearchCriteria = kwargs['SearchCriteria'] total = 0 root_id = 0 item = None items = [] parent_container = None SearchCriteria = SearchCriteria.split(" ") if "derivedfrom" in SearchCriteria: if SearchCriteria[0] == "upnp:class": Log.d("Searching by class! %s" % (SearchCriteria, )) if SearchCriteria[2].find(DIDLLite.AudioItem.upnp_class) >= 0: parent_container = str(self._audio_all_id) elif SearchCriteria[2].find( DIDLLite.VideoItem.upnp_class) >= 0: parent_container = str(self._video_all_id) Log.d(parent_container) if not parent_container: parent_container = str(ContainerID) didl = DIDLLite.DIDLElement( upnp_client=kwargs.get('X_UPnPClient', ''), parent_container=parent_container, transcoding=self.server.content_directory_server.transcoding) def build_response(tm): r = { 'Result': didl.toString(), 'TotalMatches': tm, 'NumberReturned': didl.numItems() } if hasattr(item, 'update_id'): r['UpdateID'] = item.update_id elif hasattr(self, 'update_id'): r['UpdateID'] = self.update_id # FIXME else: r['UpdateID'] = 0 return r def got_error(r): return r def process_result(result, total=None, found_item=None): if result == None: result = [] l = [] def process_items(result, tm): if result == None: result = [] for i in result: if i[0] == True: didl.addItem(i[1]) return build_response(tm) for i in result: d = defer.maybeDeferred(i.get_item) l.append(d) if found_item != None: def got_child_count(count): dl = defer.DeferredList(l) dl.addCallback(process_items, count) return dl d = defer.maybeDeferred(found_item.get_child_count) d.addCallback(got_child_count) return d elif total == None: total = item.get_child_count() dl = defer.DeferredList(l) dl.addCallback(process_items, total) return dl def proceed(result): if kwargs.get('X_UPnPClient', '') == 'XBox' and hasattr( result, 'get_artist_all_tracks'): d = defer.maybeDeferred(result.get_artist_all_tracks, StartingIndex, StartingIndex + RequestedCount) else: d = defer.maybeDeferred(result.get_children, StartingIndex, StartingIndex + RequestedCount) d.addCallback(process_result, found_item=result) d.addErrback(got_error) return d try: root_id = parent_container except: pass wmc_mapping = getattr(self, "wmc_mapping", None) if kwargs.get('X_UPnPClient', '') == 'XBox': if wmc_mapping and wmc_mapping.has_key(parent_container): """ fake a Windows Media Connect Server """ root_id = wmc_mapping[parent_container] if callable(root_id): item = root_id() if item is not None: if isinstance(item, list): total = len(item) if int(RequestedCount) == 0: items = item[StartingIndex:] else: items = item[StartingIndex:StartingIndex + RequestedCount] return process_result(items, total=total) else: if isinstance(item, defer.Deferred): item.addCallback(proceed) return item else: return proceed(item) item = self.get_by_id(root_id) if item == None: return process_result([], total=0) if isinstance(item, defer.Deferred): item.addCallback(proceed) return item else: return proceed(item) item = self.get_by_id(root_id) Log.w(item) if item == None: Log.w(701) return failure.Failure(errorCode(701)) if isinstance(item, defer.Deferred): item.addCallback(proceed) return item else: return proceed(item)
def upnp_XBrowse(self, *args, **kwargs): try: ObjectID = kwargs['ObjectID'] except: self.debug( "hmm, a Browse action and no ObjectID argument? An XBox maybe?" ) try: ObjectID = kwargs['ContainerID'] except: ObjectID = 0 BrowseFlag = kwargs['BrowseFlag'] Filter = kwargs['Filter'] StartingIndex = int(kwargs['StartingIndex']) RequestedCount = int(kwargs['RequestedCount']) SortCriteria = kwargs['SortCriteria'] parent_container = None requested_id = None if BrowseFlag == 'BrowseDirectChildren': parent_container = str(ObjectID) else: requested_id = str(ObjectID) self.info("upnp_Browse request %r %r %r %r", ObjectID, BrowseFlag, StartingIndex, RequestedCount) didl = DIDLLite.DIDLElement(upnp_client=kwargs.get('X_UPnPClient', ''), requested_id=requested_id, parent_container=parent_container) def build_response(tm): num_ret = didl.numItems() #if int(kwargs['RequestedCount']) != 0 and num_ret != int(kwargs['RequestedCount']): # num_ret = 0 #if RequestedCount == 0 and tm-StartingIndex != num_ret: # num_ret = 0 r = { 'Result': didl.toString(), 'TotalMatches': tm, 'NumberReturned': num_ret } self.info("upnp_Browse response %r %r", num_ret, tm) if hasattr(item, 'update_id'): r['UpdateID'] = item.update_id elif hasattr(self, 'update_id'): r['UpdateID'] = self.update_id # FIXME else: r['UpdateID'] = 0 return r total = 0 items = [] wmc_mapping = getattr(self, "wmc_mapping", None) if (kwargs.get('X_UPnPClient', '') == 'XBox' and wmc_mapping != None and ObjectID in wmc_mapping): """ fake a Windows Media Connect Server """ root_id = wmc_mapping[ObjectID] if isinstance(root_id, collections.Callable): item = root_id() if item is not None: if isinstance(item, list): total = len(item) if int(RequestedCount) == 0: items = item[StartingIndex:] else: items = item[StartingIndex:StartingIndex + RequestedCount] else: d = defer.maybeDeferred(item.get_children, StartingIndex, StartingIndex + RequestedCount) d.addCallback(process_result) d.addErrback(got_error) return d for i in items: didl.addItem(i.get_item()) return build_response(total) root_id = ObjectID item = self.get_by_id(root_id) if item is None: return failure.Failure(errorCode(701)) def got_error(r): return r def process_result(result, found_item): if result is None: result = [] if BrowseFlag == 'BrowseDirectChildren': l = [] def process_items(result, tm): if result == None: result = [] for i in result: if i[0] == True: didl.addItem(i[1]) return build_response(tm) for i in result: d = defer.maybeDeferred(i.get_item) l.append(d) def got_child_count(count): dl = defer.DeferredList(l) dl.addCallback(process_items, count) return dl d = defer.maybeDeferred(found_item.get_child_count) d.addCallback(got_child_count) return d else: didl.addItem(result) total = 1 return build_response(total) def proceed(result): if BrowseFlag == 'BrowseDirectChildren': d = defer.maybeDeferred(result.get_children, StartingIndex, StartingIndex + RequestedCount) else: d = defer.maybeDeferred(result.get_item) d.addCallback(process_result, result) d.addErrback(got_error) return d if isinstance(item, defer.Deferred): item.addCallback(proceed) return item else: return proceed(item)
def handle_reply(r, uri, action, kw): try: next_track = () elt = DIDLLite.DIDLElement.fromString(r['Result']) item = elt.getItems()[0] local_protocol_infos = self.server.connection_manager_server.get_variable('SinkProtocolInfo').value.split(',') res = item.res.get_matching(local_protocol_infos, protocol_type='internal') if len(res) == 0: res = item.res.get_matching(local_protocol_infos) if len(res) > 0: res = res[0] remote_protocol, remote_network, remote_content_format, _ = res.protocolInfo.split(':') didl = DIDLLite.DIDLElement() didl.addItem(item) next_track = (res.data, didl.toString(), remote_content_format) """ a list with these elements: the current track index - will change during playback of the container items the initial complete playcontainer-uri a list of all the items in the playcontainer the action methods to do the Browse call on the device the kwargs for the Browse call - kwargs['StartingIndex'] will be modified during further Browse requests """ self.playcontainer = [int(kw['StartingIndex']), uri, elt.getItems()[:], action, kw] def browse_more(starting_index, number_returned, total_matches): self.info("browse_more", starting_index, number_returned, total_matches) try: def handle_error(r): pass def handle_reply(r, starting_index): elt = DIDLLite.DIDLElement.fromString(r['Result']) self.playcontainer[2] += elt.getItems()[:] browse_more(starting_index, int(r['NumberReturned']), int(r['TotalMatches'])) if((number_returned != 5 or number_returned < (total_matches - starting_index)) and (total_matches - number_returned) != starting_index): self.info("seems we have been returned only a part of the result") self.info("requested %d, starting at %d" % (5, starting_index)) self.info("got %d out of %d" % (number_returned, total_matches)) self.info("requesting more starting now at %d" % (starting_index + number_returned)) self.playcontainer[4]['StartingIndex'] = str(starting_index + number_returned) d = self.playcontainer[3].call(**self.playcontainer[4]) d.addCallback(handle_reply, starting_index + number_returned) d.addErrback(handle_error) except: import traceback traceback.print_exc() browse_more(int(kw['StartingIndex']), int(r['NumberReturned']), int(r['TotalMatches'])) if len(next_track) == 3: return next_track except: import traceback traceback.print_exc() return failure.Failure(errorCode(714))
def update(self, message=None): _, current, _ = self.player.get_state() self.debug("update current %r", current) connection_manager = self.server.connection_manager_server av_transport = self.server.av_transport_server conn_id = connection_manager.lookup_avt_id(self.current_connection_id) if current == gst.STATE_PLAYING: state = 'playing' av_transport.set_variable(conn_id, 'TransportState', 'PLAYING') elif current == gst.STATE_PAUSED: state = 'paused' av_transport.set_variable(conn_id, 'TransportState', 'PAUSED_PLAYBACK') elif self.playcontainer != None and message == gst.MESSAGE_EOS and \ self.playcontainer[0]+1 < len(self.playcontainer[2]): state = 'transitioning' av_transport.set_variable(conn_id, 'TransportState', 'TRANSITIONING') next_track = () item = self.playcontainer[2][self.playcontainer[0] + 1] infos = connection_manager.get_variable('SinkProtocolInfo') local_protocol_infos = infos.value.split(',') res = item.res.get_matching(local_protocol_infos, protocol_type='internal') if len(res) == 0: res = item.res.get_matching(local_protocol_infos) if len(res) > 0: res = res[0] infos = res.protocolInfo.split(':') remote_protocol, remote_network, remote_content_format, _ = infos didl = DIDLLite.DIDLElement() didl.addItem(item) next_track = (res.data, didl.toString(), remote_content_format) self.playcontainer[0] = self.playcontainer[0] + 1 if len(next_track) == 3: av_transport.set_variable(conn_id, 'CurrentTrack', self.playcontainer[0] + 1) self.load(next_track[0], next_track[1], next_track[2]) self.play() else: state = 'idle' av_transport.set_variable(conn_id, 'TransportState', 'STOPPED') elif message == gst.MESSAGE_EOS and \ len(av_transport.get_variable('NextAVTransportURI').value) > 0: state = 'transitioning' av_transport.set_variable(conn_id, 'TransportState', 'TRANSITIONING') CurrentURI = av_transport.get_variable('NextAVTransportURI').value metadata = av_transport.get_variable('NextAVTransportURIMetaData') CurrentURIMetaData = metadata.value av_transport.set_variable(conn_id, 'NextAVTransportURI', '') av_transport.set_variable(conn_id, 'NextAVTransportURIMetaData', '') r = self.upnp_SetAVTransportURI( self, InstanceID=0, CurrentURI=CurrentURI, CurrentURIMetaData=CurrentURIMetaData) if r == {}: self.play() else: state = 'idle' av_transport.set_variable(conn_id, 'TransportState', 'STOPPED') else: state = 'idle' av_transport.set_variable(conn_id, 'TransportState', 'STOPPED') self.info("update %r" % state) self._update_transport_position(state)
def playing_song_changed(self, player, entry): self.info("playing_song_changed %r", entry) if self.server != None: connection_id = self.server.connection_manager_server.lookup_avt_id( self.current_connection_id) if entry == None: self.update('STOPPED') self.playing = False #self.entry = None self.metadata = None self.duration = None else: id = self.shell.props.db.entry_get(entry, rhythmdb.PROP_ENTRY_ID) bitrate = self.shell.props.db.entry_get( entry, rhythmdb.PROP_BITRATE) * 1024 / 8 # Duration is in HH:MM:SS format seconds = self.shell.props.db.entry_get(entry, rhythmdb.PROP_DURATION) hours = seconds / 3600 seconds = seconds - hours * 3600 minutes = seconds / 60 seconds = seconds - minutes * 60 self.duration = "%02d:%02d:%02d" % (hours, minutes, seconds) mimetype = self.shell.props.db.entry_get(entry, rhythmdb.PROP_MIMETYPE) # This isn't a real mime-type if mimetype == "application/x-id3": mimetype = "audio/mpeg" size = self.shell.props.db.entry_get(entry, rhythmdb.PROP_FILE_SIZE) # create item item = DIDLLite.MusicTrack(id + TRACK_COUNT, '101') item.album = self.shell.props.db.entry_get(entry, rhythmdb.PROP_ALBUM) item.artist = self.shell.props.db.entry_get( entry, rhythmdb.PROP_ARTIST) item.genre = self.shell.props.db.entry_get(entry, rhythmdb.PROP_GENRE) item.originalTrackNumber = str( self.shell.props.db.entry_get(entry, rhythmdb.PROP_TRACK_NUMBER)) item.title = self.shell.props.db.entry_get( entry, rhythmdb.PROP_TITLE) # much nicer if it was entry.title cover = self.shell.props.db.entry_request_extra_metadata( entry, "rb:coverArt-uri") if cover != None: _, ext = os.path.splitext(cover) item.albumArtURI = ''.join( (self.server.coherence.urlbase + str(self.dmr_uuid)[5:] + '/' + str(int(id) + TRACK_COUNT), '?cover', ext)) item.res = [] location = self.shell.props.db.entry_get(entry, rhythmdb.PROP_LOCATION) if location.startswith("file://"): location = unicode(urllib.unquote(location[len("file://"):])) uri = ''.join( (self.server.coherence.urlbase + str(self.dmr_uuid)[5:] + '/' + str(int(id) + TRACK_COUNT))) res = DIDLLite.Resource(uri, 'http-get:*:%s:*' % mimetype) if size > 0: res.size = size if self.duration > 0: res.duration = self.duration if bitrate > 0: res.bitrate = str(bitrate) item.res.append(res) # add internal resource res = DIDLLite.Resource( 'track-%d' % id, 'rhythmbox:%s:%s:*' % (self.server.coherence.hostname, mimetype)) if size > 0: res.size = size if self.duration > 0: res.duration = str(self.duration) if bitrate > 0: res.bitrate = str(bitrate) item.res.append(res) elt = DIDLLite.DIDLElement() elt.addItem(item) self.metadata = elt.toString() self.entry = entry if self.server != None: self.server.av_transport_server.set_variable( connection_id, 'CurrentTrackURI', uri) self.server.av_transport_server.set_variable( connection_id, 'AVTransportURI', uri) self.server.av_transport_server.set_variable( connection_id, 'AVTransportURIMetaData', self.metadata) self.server.av_transport_server.set_variable( connection_id, 'CurrentTrackMetaData', self.metadata) self.info("playing_song_changed %r", self.metadata) if self.server != None: self.server.av_transport_server.set_variable( connection_id, 'CurrentTransportActions', 'PLAY,STOP,PAUSE,SEEK,NEXT,PREVIOUS') self.server.av_transport_server.set_variable( connection_id, 'RelativeTimePosition', '00:00:00') self.server.av_transport_server.set_variable( connection_id, 'AbsoluteTimePosition', '00:00:00')
def reply(r): #print "browse_reply - %s of %s returned" % (r['NumberReturned'],r['TotalMatches']) from coherence.upnp.core import DIDLLite child = self.store.iter_children(iter) if child: upnp_class, = self.store.get(child,UPNP_CLASS_COLUMN) if upnp_class == 'placeholder': self.store.remove(child) title, = self.store.get(iter,NAME_COLUMN) try: title = title[:title.rindex('(')] self.store.set_value(iter,NAME_COLUMN, "%s(%d)" % (title,int(r['TotalMatches']))) except ValueError: pass didl = DIDLLite.DIDLElement.fromString(r['Result']) for item in didl.getItems(): #print item.title, item.id, item.upnp_class if item.upnp_class.startswith('object.container'): icon = self.folder_icon service, = self.store.get(iter,SERVICE_COLUMN) child_count = item.childCount try: title = "%s (%d)" % (item.title,item.childCount) except TypeError: title = "%s (n/a)" % item.title child_count = -1 else: icon=None service = '' if callable(self.cb_resource_chooser): service = self.cb_resource_chooser(item.res) else: res = item.res.get_matching(['*:%s:*:*' % self.hostname], protocol_type='internal') if len(res) == 0: res = item.res.get_matching(['*:*:*:*'], protocol_type='http-get') if len(res) > 0: res = res[0] remote_protocol,remote_network,remote_content_format,_ = res.protocolInfo.split(':') service = res.data child_count = -1 title = item.title if item.upnp_class.startswith('object.item.audioItem'): icon = self.audio_icon elif item.upnp_class.startswith('object.item.videoItem'): icon = self.video_icon elif item.upnp_class.startswith('object.item.imageItem'): icon = self.image_icon stored_didl = DIDLLite.DIDLElement() stored_didl.addItem(item) new_iter = self.store.append(iter, (title,item.id,item.upnp_class,child_count,'',service,icon,stored_didl.toString(),None)) if item.upnp_class.startswith('object.container'): self.store.append(new_iter, ('...loading...','','placeholder',-1,'','',None,'',None)) if((int(r['TotalMatches']) > 0 and force==False) or expand==True): view.expand_row(row_path, False) if(requested_count != int(r['NumberReturned']) and int(r['NumberReturned']) < (int(r['TotalMatches'])-starting_index)): print "seems we have been returned only a part of the result" print "requested %d, starting at %d" % (requested_count,starting_index) print "got %d out of %d" % (int(r['NumberReturned']), int(r['TotalMatches'])) print "requesting more starting now at %d" % (starting_index+int(r['NumberReturned'])) self.browse(view,row_path,column, starting_index=starting_index+int(r['NumberReturned']), force=True)
def setMediaUri(self, uri, item): elt = DIDLLite.DIDLElement() elt.addItem(item) metadata = elt.toString() self.__transport.set_av_transport_uri(current_uri=uri, current_uri_metadata=metadata)