def _receive_datagram(self, sock, cond): """ Implements the UDPListener listening actions. """ # print "@@@@@@@@ UDP datagram: " + str(sock) if not self.is_listening(): return try: (data, addr) = self.socket.recvfrom(self.BUFFER_SIZE) # if 'Coherence' in data: # print "@@@@@@@@ addr: " + str(addr) # print "@@@@@@@@ data before: " + str(data) # HACK: WMP sometimes returns 0.0.0.0 as the IP in its location field - fix it here if 'http://0.0.0.0:2869' in data: # print "@@@@@@@@ addr: " + str(addr) # print "@@@@@@@@ data before: " + str(data) ip, port = addr newaddr = 'http://' + ip + ':2869' data = data.replace('http://0.0.0.0:2869', newaddr) # print "@@@@@@@@ data after: " + str(data) self.forward_data(data, addr) except Exception, e: log.debug('Error when reading on UDP socket: %s', e)
def _event_subscribe_callback(self, cargo, subscription_id, timeout): log.debug('Event subscribe done cargo=%s sid=%s timeout=%s', cargo, subscription_id, timeout) udn, servicetype, service, name = cargo uuid = udn[5:] if servicetype == 'AVTransport': self.at_lookup[uuid] = subscription_id self.at_subscription_ids[subscription_id] = udn self.at_service[subscription_id] = service self.current_track_scrobbled[subscription_id] = False self.current_play_state[subscription_id] = None self.current_position_info[subscription_id] = None self.current_track_duration[subscription_id] = None self.current_track_relative_time_position[subscription_id] = None self.current_track_absolute_time_position[subscription_id] = None self.current_track_URI[subscription_id] = None self.current_track_start[subscription_id] = None self.previous_track_URI[subscription_id] = None self.previous_play_state[subscription_id] = None self.zone_grouped[subscription_id] = False self.current_track_metadata[subscription_id] = None self.current_transport_metadata[subscription_id] = None self.avt_track_URI[subscription_id] = None self.transport_error[subscription_id] = False self.zone_groups[subscription_id] = None self.zone_group_coordinators_lookup[subscription_id] = None if servicetype == 'ContentDirectory': self.cd_subscription_ids[subscription_id] = udn self.cd_service[subscription_id] = service if servicetype == 'ZoneGroupTopology': self.zt_lookup[uuid] = subscription_id self.zt_subscription_ids[subscription_id] = udn self.zt_service[subscription_id] = service self.subscription_ids[subscription_id] = '%s, %s' % (servicetype, name) self.process_event_queue(subscription_id)
def __init__(self, server_name, xml_description_filename, max_age=1800, receive_notify=True, udp_listener=""): """ Constructor for the SSDPServer class. @param server_name: server name @param xml_description_filename: XML description filename @param max_age: max age parameter, default 1800. @param receive_notify: if False, ignores notify messages @type server_name: string @type xml_description_filename: @type max_age: integer @type receive_notify: boolean """ self.server_name = server_name self.xml_description_filename = xml_description_filename self.max_age = max_age log.debug("max_age: %s", max_age) self.receive_notify = receive_notify self.running = False self.known_device = {} self.advertised = {} self._callbacks = {} self.udp_transport = UDPTransport() if udp_listener == "": self.udp_listener = UDPListener(SSDP_ADDR, SSDP_PORT, data_callback=self._datagram_received) else: self.udp_listener = None udp_listener.subscribe(self) self.renew_loop = LoopingCall(self._renew_notifications) self.renew_loop.start(0.8 * self.max_age, now=True)
def response(self, http_response, cargo): """ Callback for receiving the HTTP response on a successful HTTP call. @param http_response: response object @param cargo: callback parameters passed at construction @type http_response: HTTPResponse @rtype: boolean """ log.debug("response") compressed_headers = {} for k, v in dict(http_response.getheaders()).items(): if not v: v = "" compressed_headers[k.lower()] = v.strip() if 'sid' in compressed_headers: sid = compressed_headers['sid'] timeout = 300 if 'timeout' in compressed_headers: stimeout = compressed_headers['timeout'] if stimeout[0:7] == "Second-": try: timeout = int(stimeout[7:]) except ValueError: log.error( "value convert of timeout failed using default 300 seconds" ) self.service.event_sid = sid self.service.event_timeout = timeout if self.callback and sid: self.callback(self.cargo, sid, timeout) return True
def _main_select(self): """ Selects and process events. @return: True if no exception was raised. False if an exception was raised, meaning that we recommend another _main_select() @rtype: boolean """ try: revt, wevt, eevt = select.select(list(self._read_fds.keys()), list(self._write_fds.keys()), list(self._excpt_fds.keys()), self._get_min_timeout()) if not self._main_process_events(revt, wevt, eevt): return False # Fix problems with problematic file descriptors except ValueError as v: log.debug('Main loop ValueError: %s' % str(v)) self._main_cleanup_fds() except TypeError as t: log.debug('Main loop TypeError %s' % str(t)) self._main_cleanup_fds() except (select.error, IOError) as s: if s.args[0] in (0, 2): if not ((not self._read_fds) and (not self._write_fds)): raise elif s.args[0] == EINTR: pass elif s.args[0] == EBADF: self._main_cleanup_fds() except socket.error as s: if s.args[0] == EBADF: self._main_cleanup_fds() except KeyboardInterrupt: return False return True
def soap_SelectPreset(self, *args, **kwargs): """ Select Present state variables. This action restores (a subset) of the state variables to the values associated with the specified preset. """ log.debug('Action on RenderingControlController: SelectPreset()') return {}
def __init__(self, service, event_host, callback, cargo): """ Constructor for the SubscribeRequest class. @param service: service that is subscribing @param event_host: 2-tuple (host, port) of the event listener server @param callback: callback @param cargo: callback parameters @type service: Service @type event_host: tuple @type callback: callable """ log.debug("subscribe") self.callback = callback self.cargo = cargo self.service = service addr = "%s%s" % (service.url_base, service.event_sub_url) Paddr = parse_url(addr) headers = {} headers["User-agent"] = 'BRisa UPnP Framework' headers["TIMEOUT"] = 'Second-300' headers["NT"] = 'upnp:event' headers["CALLBACK"] = "<http://%s:%d/eventSub>" % event_host headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port) run_async_call(http_call, success_callback=self.response, error_callback=self.error, delay=0, method='SUBSCRIBE', url=addr, headers=headers)
def _do_notify(self, usn): """ Do a notification for the usn specified. @param usn: st @type usn: string """ log.debug('Sending alive notification for %s', usn) response = [ 'NOTIFY * HTTP/%s' % self.http_version, 'HOST: %s:%d' % (SSDP_ADDR, SSDP_PORT), 'NTS: ssdp:alive', ] stcpy = dict(self.advertised[usn].iteritems()) stcpy['NT'] = stcpy['ST'] del stcpy['EXT'] del stcpy['ST'] response.extend(map(lambda x: ': '.join(x), stcpy.iteritems())) append = response.append [append('%s: %s' % (k, v)) for k, v in self.additional_headers.items()] response.extend(('', '')) log.debug('Sending notify message with content %s' % response) try: self.udp_transport.send_data('\r\n'.join(response), SSDP_ADDR, SSDP_PORT) self.udp_transport.send_data('\r\n'.join(response), SSDP_ADDR, SSDP_PORT) except Exception, e: log.info("Failure sending notify with message %s" % str(e))
def response(self, http_response, cargo): """ Callback for receiving the HTTP response on a successful HTTP call. @param http_response: response object @param cargo: callback parameters passed at construction @type http_response: HTTPResponse @rtype: boolean """ log.debug("response") compressed_headers = {} for k, v in dict(http_response.getheaders()).items(): if not v: v = "" # compressed_headers[k.lower()] = v.lower().strip() compressed_headers[k.lower()] = v.strip() if "sid" in compressed_headers: sid = compressed_headers["sid"] timeout = 1800 if "timeout" in compressed_headers: stimeout = compressed_headers["timeout"] if stimeout[0:7] == "second-": try: timeout = int(stimeout[7:]) except ValueError: pass self.service.event_sid = sid self.service.event_timeout = timeout if self.callback and sid: self.callback(self.cargo, sid, timeout) return True
def getAlbumArt(service, AlbumArtURI): #TODO: display a "getting album art" graphic until art is updated # log.debug('#### GETALBUMART service: %s' % service) # log.debug('#### GETALBUMART AlbumArtURI: %s' % AlbumArtURI) if AlbumArtURI == '' or AlbumArtURI == None: return (None, "No albumart to display") else: url_info = parse_url(service.url_base) # log.debug('#### GETALBUMART url_info: %s' % str(url_info)) aa_url = "%s://%s%s" % (url_info[0], url_info[1], AlbumArtURI) # log.debug('#### GETALBUMART control_url: %s' % aa_url) try: fd = url_fetch(aa_url) # except HTTPError as detail: except HTTPError: return (None, HTTPError) try: data = fd.read() except: log.debug("#### GETALBUMART fd is invalid") return (None, "Error getting albumArt") pbl = gtk.gdk.PixbufLoader() pbl.write(data) pbuf = pbl.get_pixbuf() # print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" # print pbl.get_format() # print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" pbl.close() return (pbuf, '')
def _renew_notifications(self): """ Renew notifications (sends a notify """ own_temp = self.advertised.copy() for usn in own_temp: log.debug('Renew notification for %s ', own_temp[usn]['USN']) self._do_notify(own_temp[usn]['USN'])
def _parse_description(self, fd): """ Parses the actions and state variables of a service given a file descriptor containing the SCPD XML. File descriptor must be open. @param fd: file descriptor @type fd: file @return: True if service parser succeeded, otherwise False. @rtype: bool """ # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>BaseServiceBuilder._parse_description" try: data = fd.read() # print "data: " + str(data) data = data[data.find("<"):data.rfind(">") + 1] tree = ElementTree.XML(data) # print "tree: " + str(tree) if tree: self._parse_actions(tree) self._parse_variables(tree) # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>BaseServiceBuilder._parse_description success" return True except Exception, e: log.debug('Could not build service SCPD XML. %s' % str(e))
def read_notify_message_body(body_data): changed_vars = {} try: tree = ElementTree.XML(body_data) except: log.debug("Event XML invalid: %s", body_data) tree = None if tree: for prop1 in tree.findall("{%s}property" % "urn:schemas-upnp-org:event-1-0"): # prop1 = <e:property> <Ble> cont </Ble> </e:property> for prop2 in prop1: # <Ble>cont</Ble> # PS: IMERGE do not adhere to UPnP standard # the following is a get out of jail card if "}" in prop2.tag: # Then you have something that is not UPnP compliant log.debug("Imerge do not adhere to UPnP and they ought to be shot!") crudly_madeup_tag = prop2.tag.split("}")[1] changed_vars[crudly_madeup_tag] = prop2.text else: changed_vars[prop2.tag] = prop2.text # Never to be submitted to Brisa, since non UPnP fix return changed_vars
def start(self, interval=DEFAULT_SEARCH_TIME, search_type=DEFAULT_SEARCH_TYPE, http_version="1.1", man='"ssdp:discover"', mx=1, additionals={}): """ Starts the search. @param interval: interval between searchs. Default is 600.0 seconds @param search_type: type of the search, default is "ssdp:all" @param http_version: http version for m-search (default is 1.1) @param man: man field for m-search (default is ssdp:discover) @param mx: mx field for m-search (default is 1) @param additionals: dict containing additional field to be appended in the end of the m-search message (default is a empty dictionary) @type interval: float @type search_type: string @type http_version: string @type man: string @type mx: int @type additionals: dict """ if not self.is_running(): self.ssdp.search_type = search_type self.listen_udp.start() self.loopcall._args = (search_type, http_version, man, mx, additionals, ) self.loopcall.start(interval, now=True) log.debug('MSearch started') else: log.warning(self.msg_already_started)
def make_third_party_mediaserver_service(self, mediaserver): """ Mmanually create Sonos Third Party Media Server service """ ''' mediaserver['CURL'] = "http://192.168.0.10:56043/ContentDirectory/50565062-8a5b-7f33-c3de-168e9401eaee/control.xml" mediaserver['EURL'] = "http://192.168.0.10:56043/ContentDirectory/50565062-8a5b-7f33-c3de-168e9401eaee/event.xml" mediaserver['T'] = "1" mediaserver['EXT'] = "" mediaserver['Name'] = "Sonos: Asset UPnP: HENKELIS" mediaserver['UDN'] = "50565062-8a5b-7f33-c3de-168e9401eaee" mediaserver['Location'] = "http://192.168.0.10:56043/DeviceDescription.xml" ''' # For Third Party Media Servers in Sonos, the event and control urls are absolute and may be at different ip's # Sonos doesn't provide the Media Server SCPD address - so we get it from the location # As the urls can be at different ip's, when we build the service we send absolute ip's and a null base url log.debug("make_third_party_mediaserver_service: %s", mediaserver) scpd_url = self.getscpdurl(mediaserver['Location']) if scpd_url != None: # Sonos may hold out of date info, especially for proxies log.debug("create tpms_service: %s", mediaserver['Name']) self.tpms_service[unicode(mediaserver['Name'])] = Service('Browse', 'urn:schemas-upnp-org:service:ContentDirectory:1', #'http://www.sonos.com/Services/1.1', url_base = '', control_url = mediaserver['CURL'], event_url = mediaserver['EURL'], scpd_url = scpd_url, build = True)
def soap_GetProtocolInfo(self, *args, **kwargs): """Required: Returns the protocol-related info that this \ ConnectionManager supports in its current state """ log.debug('Action on ConnectionManager: GetProtocolInfo()') return {'Source': 'http-get:*:*:*', 'Sink': ''}
def forward_notification(self, received_headers, data): """ Forwards notifications to the observer registered. @param received_headers: headers received on the event notify @param data: XML data for the event @type received_headers: dictionary @type data: string """ log.debug('forward notification') headers = {} for k, v in received_headers.items(): headers[k.lower()] = v changed_vars = read_notify_message_body(data) log.debug('Event changed vars: %s', changed_vars) if self.observer and 'sid' in headers: self.observer._on_event(headers['sid'], changed_vars) for id, dev in self.observer._known_devices.items(): service = self._find_service(dev, headers['sid']) if service != None: service._on_event(changed_vars) return
def response(self, http_response, cargo): """ Callback for receiving the HTTP response on a successful HTTP call. @param http_response: response object @param cargo: callback parameters passed at construction @type http_response: HTTPResponse @rtype: boolean """ log.debug("response") compressed_headers = {} for k, v in dict(http_response.getheaders()).items(): if not v: v = "" compressed_headers[k.lower()] = v.strip() if 'sid' in compressed_headers: sid = compressed_headers['sid'] timeout = 300 if 'timeout' in compressed_headers: stimeout = compressed_headers['timeout'] if stimeout[0:7] == "Second-": try: timeout = int(stimeout[7:]) except ValueError: log.error("value convert of timeout failed using default 300 seconds") self.service.event_sid = sid self.service.event_timeout = timeout if self.callback and sid: self.callback(self.cargo, sid, timeout) return True
def add_device(self, device): """ Adds a device embedded inside this device. @param device: device to be added @type device: Device """ if device in self.devices.values(): log.debug('Device %s already contained by %s' % (device, self)) return False if device.friendly_name not in self.devices: self.devices[device.friendly_name] = device else: d = 0 name = None while not name: name = '%s%d' % (device.friendly_name, d) if name not in [d.friendly_name for d in self.devices if \ device.friendly_name in d.friendly_name]: break else: d += 1 name = None continue self.devices[name] = device return True
def soap_GetCurrentConnectionIDs(self, *args, **kwargs): """Required: Returns a comma-separated list of ConnectionIDs of currently ongoing Connections.""" log.debug('Action on ConnectionManager: GetCurrentConnectionIDs()') #If optional action PrepareForConnection is not implemented #this state variable should be set to 0. return {'ConnectionIDs': '0'}
def __init__(self, service, event_host, callback, cargo): """ Constructor for the RenewSubscribeRequest class. @param service: service that is renewing the subscribe @param event_host: 2-tuple (host, port) of the event listener server @param callback: callback @param cargo: callback parameters @type service: Service @type event_host: tuple @type callback: callable """ log.debug("renew subscribe") if not service.event_sid or service.event_sid == "": return self.callback = callback self.cargo = cargo self.service = service addr = "%s%s" % (service.url_base, service.event_sub_url) Paddr = parse_url(addr) headers = {} headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port) headers["SID"] = self.service.event_sid headers["TIMEOUT"] = 'Second-300' run_async_call(http_call, success_callback=self.response, error_callback=self.error, delay=0, method='SUBSCRIBE', url=addr, headers=headers)
def __init__(self, service, event_host, callback, cargo): """ Constructor for the SubscribeRequest class. @param service: service that is subscribing @param event_host: 2-tuple (host, port) of the event listener server @param callback: callback @param cargo: callback parameters @type service: Service @type event_host: tuple @type callback: callable """ log.debug("subscribe") self.callback = callback self.cargo = cargo self.service = service addr = "%s%s" % (service.url_base, service.event_sub_url) Paddr = parse_url(addr) headers = {} # headers["Host"] = Paddr.hostname headers["User-agent"] = 'BRisa UPnP Framework' headers["TIMEOUT"] = 'Second-1800' headers["NT"] = 'upnp:event' headers["CALLBACK"] = "<http://%s:%d/eventSub>" % event_host headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port) run_async_call(http_call, success_callback=self.response, error_callback=self.error, delay=0, method='SUBSCRIBE', url=addr, headers=headers)
def _parse_description(self, fd): """ Parses the actions and state variables of a service given a file descriptor containing the SCPD XML. File descriptor must be open. @param fd: file descriptor @type fd: file @return: True if service parser succeeded, otherwise False. @rtype: bool """ # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>BaseServiceBuilder._parse_description" try: data = fd.read() # print "data: " + str(data) data = data[data.find("<"):data.rfind(">")+1] tree = ElementTree.XML(data) # print "tree: " + str(tree) if tree: self._parse_actions(tree) self._parse_variables(tree) return True except Exception, e: log.debug('Could not build service SCPD XML. %s' % str(e))
def __init__(self, service, subscription_duration, delivery_url, http_version, event_reload_time, force_event_reload): self.service = service self.subscription_id = uuid.uuid4() self.delivery_url = delivery_url url = parse_url(delivery_url) self.host = '%s:%d' % (url.hostname, url.port) self.event_key = 0 self.subscription_duration = subscription_duration self.http_version = http_version self.timestamp = datetime.now() self.eventing_variables = {} for name, state_var in self.service.get_variables().items(): state_var.subscribe_for_update(self._update_variable) self.force_event_reload = force_event_reload if not force_event_reload: self.looping_call = LoopingCall(self._send_variables) reactor.add_after_stop_func(self.looping_call.stop) self.looping_call.start(event_reload_time, False) sid = str(self.subscription_id) log.debug('Creating subscriber with subscription id: %s' % sid)
def soap_Browse(self, *args, **kwargs): """ Implements the Browse action for the ContentDirectory. @param args: list of arguments for the Browse UPnP\ function @param kwargs: dict of arguments for the Browse UPnP\ function @type args: list @type kwargs: dict @return: the results of the browsing @rtype: dict """ log.debug('Action on ContentDirectory: Browse%s', args) # Formats the parameters for the real soap browse args = (kwargs['ObjectID'], kwargs['BrowseFlag'], kwargs['Filter'], kwargs['StartingIndex'], kwargs['RequestedCount'], kwargs['SortCriteria']) l = {} l['query'] = 'Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' \ 'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % \ tuple(map(repr, args)) try: ret = self._soap_Browse(*args) except Exception as e: log.error('Action Browse on ContentDirectory: %s', e.message) l['response'] = ret return ret
def render_unsubscribe(self, request, response, compressed_headers): """ Renders the unsubscribe message for an event. @param request: request object (Cherrypy) @param response: response object (Cherrypy) @note: see Cherrypy documentation for further info about request and response attributes and methods. """ # print "EventController.render_unsubscribe" # print "request: " + str(request) # print "compressed_headers: " + str(compressed_headers) log.debug('Receiving unsubscribe request') request_status, subs = self._validate_unsubscribe_request(request, compressed_headers) if request_status == 200: self._remove_subscriber(subs) response.status = 200 response.body = [""] return response.body else: return self._build_error(request_status, request, response)
def _parse_services(self): for xml_service_element in self.tree.\ findall('.//{%s}service' % self.ns): service_type = xml_service_element.\ findtext('{%s}serviceType' % self.ns) service_id = xml_service_element.\ findtext('{%s}serviceId' % self.ns) control_url = xml_service_element.\ findtext('{%s}controlURL' % self.ns) if control_url and not control_url.startswith('/'): control_url = '/' + control_url event_sub_url = xml_service_element.\ findtext('{%s}eventSubURL' % self.ns) if event_sub_url and not event_sub_url.startswith('/'): event_sub_url = '/' + event_sub_url presentation_url = xml_service_element.\ findtext('{%s}presentationURL' % self.ns) if presentation_url and not presentation_url.startswith('/'): presentation_url = '/' + presentation_url scpd_url = xml_service_element.\ findtext('{%s}SCPDURL' % self.ns) if scpd_url and not scpd_url.startswith('/'): scpd_url = '/' + scpd_url log.debug('control_url: %s, event_sub_url: %s, presentation_url: %s, scpd_url: %s', control_url, event_sub_url, presentation_url, scpd_url) service = Service(service_id, service_type, self.location, scpd_url, control_url, event_sub_url, presentation_url) self.device.add_service(service)
def soap_GetProtocolInfo(self, *args, **kwargs): """Required: Returns the protocol-related info that this ConnectionManager supports in its current state - Specific for MediaRenderer Devices""" log.debug('Action on ConnectionManager: GetProtocolInfo()') return {'Source': '', 'Sink': 'http-get:*:audio/mpeg:*'}
def _get_call_response(self, request, response_obj, method_name, function, *args, **kwargs): """ Performs the soap call, builds and returns a response. """ try: result = function(*args, **kwargs) force_use_header = False if "__header__" in result: header_args = result.pop("__header__", {}) force_use_header = True except Exception as e: # TODO: Create a soap exception to return to the remote requester log.debug(str(e)) print((str(e))) ns = self.service_type try: method = list(result.keys())[0] result = result[method] except AttributeError as IndexError: result = {} method = '' if not force_use_header: header_args = self.service.call_headers response = soap.build_soap_call("{%s}%s" % (ns, method), result, encoding=None, header_args=header_args) return self._build_response(request, response, response_obj)
def _parse_services(self): for xml_service_element in self.tree.\ findall('.//{%s}service' % self.ns): service_type = xml_service_element.\ findtext('{%s}serviceType' % self.ns) service_id = xml_service_element.\ findtext('{%s}serviceId' % self.ns) control_url = xml_service_element.\ findtext('{%s}controlURL' % self.ns) if control_url and not control_url.startswith('/'): control_url = '/' + control_url event_sub_url = xml_service_element.\ findtext('{%s}eventSubURL' % self.ns) if event_sub_url and not event_sub_url.startswith('/'): event_sub_url = '/' + event_sub_url presentation_url = xml_service_element.\ findtext('{%s}presentationURL' % self.ns) if presentation_url and not presentation_url.startswith('/'): presentation_url = '/' + presentation_url scpd_url = xml_service_element.\ findtext('{%s}SCPDURL' % self.ns) if scpd_url and not scpd_url.startswith('/'): scpd_url = '/' + scpd_url log.debug( 'control_url: %s, event_sub_url: %s, presentation_url: %s, scpd_url: %s', control_url, event_sub_url, presentation_url, scpd_url) service = Service(service_id, service_type, self.location, scpd_url, control_url, event_sub_url, presentation_url) self.device.add_service(service)
def forward_notification(self, received_headers, data): """ Forwards notifications to the observer registered. @param received_headers: headers received on the event notify @param data: XML data for the event @type received_headers: dictionary @type data: string """ log.debug('forward notification') headers = {} for k, v in list(received_headers.items()): headers[k.lower()] = v changed_vars = read_notify_message_body(data) log.debug('Event changed vars: %s', changed_vars) if self.observer and 'sid' in headers: self.observer._on_event(headers['sid'], changed_vars) for id, dev in list(self.observer._known_devices.items()): service = self._find_service(dev, headers['sid']) if service != None: service._on_event(changed_vars) return
def soap_Browse(self, *args, **kwargs): """ Implements the Browse action for the ContentDirectory. @param args: list of arguments for the Browse UPnP\ function @param kwargs: dict of arguments for the Browse UPnP\ function @type args: list @type kwargs: dict @return: the results of the browsing @rtype: dict """ log.debug('Action on ContentDirectory: Browse%s', args) # Formats the parameters for the real soap browse args = (kwargs['ObjectID'], kwargs['BrowseFlag'], kwargs['Filter'], kwargs['StartingIndex'], kwargs['RequestedCount'], kwargs['SortCriteria']) l = {} l['query'] = 'Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' \ 'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % \ tuple(map(repr, args)) try: ret = self._soap_Browse(*args) except Exception, e: log.error('Action Browse on ContentDirectory: %s', e.message)
def listener_start(self): """ Starts the listener. """ if not self.listener_is_running(): self.listen_udp.start() log.debug('Multicast event listener started') else: log.warning(self.msg_already_started)
def listener_stop(self): """ Stops the search. """ if self.listener_is_running(): log.debug('Multicast event listener stopped') self.listen_udp.stop() else: log.warning(self.msg_already_stopped)
def _call(self): if not self.running: log.debug('LoopingCall on function %s cancelled' % str(self._function)) return False self._function(*self._args, **self._kwargs) return True
def mount_device_async_gotdata(self, fd, cargo=None): try: log.debug('to object async got data getting tree') tree = ElementTree(file=fd).getroot() except Exception, e: log.error("Bad device XML %s" % e.message) self.callback(self.cargo, None) return
def _guess_content_type(self): """ Guesses content type for this file based on the filename. Copyright (c) 2002-2008, CherryPy Team ([email protected]) """ self._content_type = mimetypes.types_map.get( '.%s' % self.path.split('.')[-1], 'text/plain') log.debug('File %s type %s' % (self.path, self._content_type))
def seek(self, unit, target): ''' <InstanceID>0</InstanceID> <Unit>TRACK_NR</Unit> <Target>57</Target> ''' ssresult = self.get_at_service().Seek(InstanceID=0, Unit=unit, Target=target) log.debug('seek result: %s', ssresult)
def soap_GetVolume(self, *args, **kwargs): """ Return the current volume state. This action retrieves the current value of the Volume state variable of the specified channel for the specified instance of this service """ log.debug('Action on RenderingControlController: GetVolume()') (instance_id, channel) = args volume = int(self.gst_player.get_volume()) return {'CurrentVolume': volume}
def soap_SetVolume(self, *args, **kwargs): """Set volume of instance and chanel. This action sets the Volume state variable of the specified instance and channel to the specified value.""" log.debug('Action on RenderingControlController: SetVolume%s', args) (instance_id, channel, desired_volume) = args self.gst_player.set_volume(int(desired_volume)) return {}
def stop(self): """ Stops the search. """ if self.is_running(): log.debug('MSearch stopped') self.listen_udp.stop() self.loopcall.stop() else: log.warning(self.msg_already_stopped)
def _guess_content_type(self): """ Guesses content type for this file based on the filename. Copyright (c) 2002-2008, CherryPy Team ([email protected]) """ self._content_type = mimetypes.types_map.get('.%s' % self.path.split('.')[-1], 'text/plain') log.debug('File %s type %s' % (self.path, self._content_type))
def render(self, uri, request, response): """ Event renderer method. @param uri: URI of the request @param request: request object (Cherrypy) @param response: response object (Cherrypy) @type uri: string @note: see Cherrypy documentation for further info about request and response attributes and methods. """ ''' print "EventController.render" print "uri: " + str(uri) print "request: " + str(request) if request.env: print " request.env: " + str(request.env) if request.body: print " request.body: " + str(request.body) if request.headers: print " request.headers: " + str(request.headers) if request.method: print " request.method: " + str(request.method) if request.server_protocol: print " request.server_protocol: " + str(request.server_protocol) if request.query: print " request.query: " + str(request.query) if request.uri: print " request.uri: " + str(request.uri) if request.params: print " request.params: " + str(request.params) ''' compressed_headers = {} for k, v in request.headers.items(): if not v: v = "" compressed_headers[k.lower()] = v.strip() if request.method.lower() == "subscribe": log.debug("uri: %s, headers: %s", uri, compressed_headers) log.debug("subscribers: %s", self.subscribers) if not 'sid' in compressed_headers: return self.render_subscriber(request, response, compressed_headers) else: return self.render_renew(request, response, compressed_headers) elif request.method.lower() == "unsubscribe": return self.render_unsubscribe(request, response, compressed_headers) return response.body
def _unregister(self, usn): log.debug("Unregistering %s", usn) try: self._callback("removed_device_event", self.known_device[usn]) if usn in self.known_device: del self.known_device[usn] except: pass
def __add__(self, obj): if issubclass(obj.__class__, Device): log.debug("Adding device %s as embedded for %s", obj, self) self.add_device(obj) elif issubclass(obj.__class__, BaseService): log.debug("Adding service %s as service for %s", obj, self) self.add_service(obj) else: log.warning("Ignored invalid addition: %s + %s", self, obj) return self
def on_new_zone_player(self, device_object): self.known_zone_players[device_object.udn] = device_object self.zoneattributes[device_object.udn] = self.get_zone_details(device_object) self.musicservices[device_object.udn] = self.get_music_services(device_object) log.debug('new zone player - %s' % self.zoneattributes[device_object.udn]['CurrentZoneName']) self.known_zone_names[device_object.udn] = self.zoneattributes[device_object.udn]['CurrentZoneName'] self.subscribe_to_device(self.control_point.get_zt_service(device_object), device_object.udn, "ZoneGroupTopology", self.known_zone_names[device_object.udn]) self.subscribe_to_device(self.control_point.get_ms_service(device_object), device_object.udn, "MusicServices", self.known_zone_names[device_object.udn]) self.subscribe_to_device(self.control_point.get_dp_service(device_object), device_object.udn, "DeviceProperties", self.known_zone_names[device_object.udn]) self.subscribe_to_device(self.control_point.get_sp_service(device_object), device_object.udn, "SystemProperties", self.known_zone_names[device_object.udn]) self.subscribe_to_device(self.control_point.get_gm_service(device_object), device_object.udn, "GroupManagement", self.known_zone_names[device_object.udn])
def _receive_datagram(self, sock, cond): """ Implements the UDPListener listening actions. """ if not self.is_listening(): return try: (data, addr) = self.socket.recvfrom(self.BUFFER_SIZE) self.forward_data(data, addr) except Exception, e: log.debug('Error when reading on UDP socket: %s', e)
def force_discovery(self, search_type="ssdp:all"): """ Forces a multicast MSearch bypassing the time interval. This method force msearch to send discovery message, bypassing the initial time interval passed to start_search function. Note this method doesn't cause any effect if the start_search call was never called. @param search_type: UPnP type search @type search_type: string """ log.debug('force_discovery, search_type: %s', search_type) self._msearch.double_discover(search_type)
def service_has_been_built(self, built_ok): log.debug("Service fetched, %d left, result %s", \ self.pending_services - 1, built_ok) if not built_ok and not brisa.__tolerate_service_parse_failure__: log.warning("Device killed") self.device = None self.pending_services -= 1 if self.pending_services <= 0: log.debug("All services fetched, sending device forward") self.callback(self.cargo, self.device)