def stop(self):
     if self.stopped:
         return
     engine = Engine()
     engine.stop()
     self.reactor_thread.join()
     self.stop_event.set()
Exemple #2
0
def refresh_audio_devices():
    engine = Engine()
    engine.refresh_sound_devices()
    devices = {'input': ['system_default', None], 'output': ['system_default', None]}
    devices['input'].extend(engine.input_devices)
    devices['output'].extend(engine.output_devices)
    return jsonify({'devices': devices})
Exemple #3
0
 def stop(self):
     if self.stopped:
         return
     engine = Engine()
     engine.stop()
     self.reactor_thread.join()
     self.stop_event.set()
Exemple #4
0
 def __init__(self):
     self.provisioning = XCAPProvisioning()
     self.engine = Engine()
     self.engine.start(
         ip_address=None
         if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
         user_agent="OpenXCAP %s" % xcap.__version__,
     )
Exemple #5
0
class SIPNotifier(object):
    __metaclass__ = Singleton

    implements(IObserver)

    def __init__(self):
        self.engine = Engine()
        self.engine.start(
            ip_address=None
            if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
            user_agent="OpenXCAP %s" % xcap.__version__,
        )
        self.sip_prefix_re = re.compile('^sips?:')
        try:
            self.outbound_proxy = SIPProxyAddress.from_description(
                Config.outbound_sip_proxy)
        except ValueError:
            log.warning('Invalid SIP proxy address specified: %s' %
                        Config.outbound_sip_proxy)
            self.outbound_proxy = None

    def send_publish(self, uri, body):
        if self.outbound_proxy is None:
            return
        uri = self.sip_prefix_re.sub('', uri)
        publication = Publication(
            FromHeader(SIPURI(uri)),
            "xcap-diff",
            "application/xcap-diff+xml",
            duration=0,
            extra_headers=[Header('Thor-Scope', 'publish-xcap')])
        NotificationCenter().add_observer(self, sender=publication)
        route_header = RouteHeader(
            SIPURI(host=self.outbound_proxy.host,
                   port=self.outbound_proxy.port,
                   parameters=dict(transport=self.outbound_proxy.transport)))
        publication.publish(body, route_header, timeout=5)

    @run_in_twisted_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPPublicationDidSucceed(self, notification):
        log.info('PUBLISH for xcap-diff event successfully sent to %s for %s' %
                 (notification.data.route_header.uri,
                  notification.sender.from_header.uri))

    def _NH_SIPPublicationDidEnd(self, notification):
        log.info('PUBLISH for xcap-diff event ended for %s' %
                 notification.sender.from_header.uri)
        notification.center.remove_observer(self, sender=notification.sender)

    def _NH_SIPPublicationDidFail(self, notification):
        log.info('PUBLISH for xcap-diff event failed to %s for %s' %
                 (notification.data.route_header.uri,
                  notification.sender.from_header.uri))
        notification.center.remove_observer(self, sender=notification.sender)
Exemple #6
0
 def stop(self):
     self.stopping = True
     for subscription in self.subscriptions:
         if subscription is not None and subscription.state.lower() in (
                 'accepted', 'pending', 'active'):
             subscription.end(timeout=1)
         else:
             engine = Engine()
             engine.stop()
Exemple #7
0
 def _start_engine(self):
     engine = Engine()
     NotificationCenter().add_observer(self, sender=engine)
     engine.start(ip_address=None,
                  udp_port=GeneralConfig.sip_udp_port,
                  tcp_port=GeneralConfig.sip_tcp_port,
                  tls_port=None,
                  user_agent='SIPwPinger %s' % __version__,
                  log_level=0)
 def _start_engine(self):
     engine = Engine()
     NotificationCenter().add_observer(self, sender=engine)
     engine.start(
         ip_address=None,
         udp_port=GeneralConfig.sip_udp_port,
         tcp_port=GeneralConfig.sip_tcp_port,
         tls_port=None,
         user_agent='SIPwPinger %s' % __version__,
         log_level=0
     )
Exemple #9
0
class SIPNotifier(object):
    __metaclass__ = Singleton

    implements(IObserver)

    def __init__(self):
        self.provisioning = XCAPProvisioning()
        self.engine = Engine()
        self.engine.start(
            ip_address=None
            if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
            user_agent="OpenXCAP %s" % xcap.__version__,
        )

    def send_publish(self, uri, body):
        uri = re.sub("^(sip:|sips:)", "", uri)
        destination_node = self.provisioning.lookup(uri)
        if destination_node is not None:
            # TODO: add configuration settings for SIP transport. -Saul
            publication = Publication(
                FromHeader(SIPURI(uri)),
                "xcap-diff",
                "application/xcap-diff+xml",
                duration=0,
                extra_headers=[Header('Thor-Scope', 'publish-xcap')])
            NotificationCenter().add_observer(self, sender=publication)
            route_header = RouteHeader(
                SIPURI(host=str(destination_node),
                       port='5060',
                       parameters=dict(transport='udp')))
            publication.publish(body, route_header, timeout=5)

    @run_in_twisted_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPPublicationDidSucceed(self, notification):
        log.info('PUBLISH for xcap-diff event successfully sent to %s for %s' %
                 (notification.data.route_header.uri,
                  notification.sender.from_header.uri))

    def _NH_SIPPublicationDidEnd(self, notification):
        log.info('PUBLISH for xcap-diff event ended for %s' %
                 notification.sender.from_header.uri)
        NotificationCenter().remove_observer(self, sender=notification.sender)

    def _NH_SIPPublicationDidFail(self, notification):
        log.info('PUBLISH for xcap-diff event failed to %s for %s' %
                 (notification.data.route_header.uri,
                  notification.sender.from_header.uri))
        NotificationCenter().remove_observer(self, sender=notification.sender)
Exemple #10
0
 def __init__(self):
     self.engine = Engine()
     self.engine.start(
         ip_address=None
         if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
         user_agent="OpenXCAP %s" % xcap.__version__,
     )
     self.sip_prefix_re = re.compile('^sips?:')
     try:
         self.outbound_proxy = SIPProxyAddress.from_description(
             Config.outbound_sip_proxy)
     except ValueError:
         log.warning('Invalid SIP proxy address specified: %s' %
                     Config.outbound_sip_proxy)
         self.outbound_proxy = None
Exemple #11
0
 def __init__(self):
     self.provisioning = XCAPProvisioning()
     self.engine = Engine()
     self.engine.start(
        ip_address=None if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
        user_agent="OpenXCAP %s" % xcap.__version__,
     )
    def rightMouseDown_(self, event):
        point = self.window().convertScreenToBase_(NSEvent.mouseLocation())
        event = NSEvent.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure_(
                  NSRightMouseUp, point, 0, NSDate.timeIntervalSinceReferenceDate(), self.window().windowNumber(),
                  self.window().graphicsContext(), 0, 1, 0)

        videoDevicesMenu = NSMenu.alloc().init()
        lastItem = videoDevicesMenu.addItemWithTitle_action_keyEquivalent_(NSLocalizedString("Select Video Camera", "Menu item"), "", "")
        lastItem.setEnabled_(False)
        videoDevicesMenu.addItem_(NSMenuItem.separatorItem())

        i = 0
        for item in Engine().video_devices:
            if item not in (None, 'system_default'):
                i += 1

            lastItem = videoDevicesMenu.addItemWithTitle_action_keyEquivalent_(item, "changeVideoDevice:", "")
            lastItem.setRepresentedObject_(item)
            if SIPApplication.video_device.real_name == item:
                lastItem.setState_(NSOnState)

        if i > 1:
              videoDevicesMenu.addItem_(NSMenuItem.separatorItem())
              settings = SIPSimpleSettings()
              lastItem = videoDevicesMenu.addItemWithTitle_action_keyEquivalent_(NSLocalizedString("Auto Rotate Cameras", "Menu item"), "toggleAutoRotate:", "")
              lastItem.setState_(NSOnState if settings.video.auto_rotate_cameras else NSOffState)

        NSMenu.popUpContextMenu_withEvent_forView_(videoDevicesMenu, event, self.window().contentView())
Exemple #13
0
class SIPNotifier(object):
    __metaclass__ = Singleton

    implements(IObserver)

    def __init__(self):
        self.engine = Engine()
        self.engine.start(
           ip_address=None if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
           user_agent="OpenXCAP %s" % xcap.__version__,
        )
        self.sip_prefix_re = re.compile('^sips?:')
        try:
            self.outbound_proxy = SIPProxyAddress.from_description(Config.outbound_sip_proxy)
        except ValueError:
            log.warning('Invalid SIP proxy address specified: %s' % Config.outbound_sip_proxy)
            self.outbound_proxy = None

    def send_publish(self, uri, body):
        if self.outbound_proxy is None:
            return
        uri = self.sip_prefix_re.sub('', uri)
        publication = Publication(FromHeader(SIPURI(uri)),
                                  "xcap-diff",
                                  "application/xcap-diff+xml",
                                  duration=0,
                                  extra_headers=[Header('Thor-Scope', 'publish-xcap')])
        NotificationCenter().add_observer(self, sender=publication)
        route_header = RouteHeader(SIPURI(host=self.outbound_proxy.host, port=self.outbound_proxy.port, parameters=dict(transport=self.outbound_proxy.transport)))
        publication.publish(body, route_header, timeout=5)

    @run_in_twisted_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPPublicationDidSucceed(self, notification):
        log.msg("PUBLISH for xcap-diff event successfully sent to %s for %s" % (notification.data.route_header.uri, notification.sender.from_header.uri))

    def _NH_SIPPublicationDidEnd(self, notification):
        log.msg("PUBLISH for xcap-diff event ended for %s" % notification.sender.from_header.uri)
        notification.center.remove_observer(self, sender=notification.sender)

    def _NH_SIPPublicationDidFail(self, notification):
        log.msg("PUBLISH for xcap-diff event failed to %s for %s" % (notification.data.route_header.uri, notification.sender.from_header.uri))
        notification.center.remove_observer(self, sender=notification.sender)
    def video_devices(self):
        devices = set()
        for item in Engine().video_devices:
            if 'colorbar' in item.lower():
                continue
            if 'null' in item.lower():
                continue

            devices.add(item)
        return list(devices)
Exemple #15
0
 def _refresh(self):
     account = DefaultAccount()
     transport = self.route.transport
     parameters = {} if transport == 'udp' else {'transport': transport}
     contact_uri = SIPURI(user=account.contact.username,
                          host=SIPConfig.local_ip.normalized,
                          port=getattr(Engine(), '%s_port' % transport),
                          parameters=parameters)
     contact_header = ContactHeader(contact_uri)
     self._referral.refresh(contact_header=contact_header, timeout=2)
Exemple #16
0
class SIPNotifier(object):
    __metaclass__ = Singleton

    implements(IObserver)

    def __init__(self):
        self.provisioning = XCAPProvisioning()
        self.engine = Engine()
        self.engine.start(
           ip_address=None if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
           user_agent="OpenXCAP %s" % xcap.__version__,
        )

    def send_publish(self, uri, body):
        uri = re.sub("^(sip:|sips:)", "", uri)
        destination_node = self.provisioning.lookup(uri)
        if destination_node is not None:
            # TODO: add configuration settings for SIP transport. -Saul
            publication = Publication(FromHeader(SIPURI(uri)),
                                      "xcap-diff",
                                      "application/xcap-diff+xml",
                                      duration=0,
                                      extra_headers=[Header('Thor-Scope', 'publish-xcap')])
            NotificationCenter().add_observer(self, sender=publication)
            route_header = RouteHeader(SIPURI(host=str(destination_node), port='5060', parameters=dict(transport='udp')))
            publication.publish(body, route_header, timeout=5)

    @run_in_twisted_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPPublicationDidSucceed(self, notification):
        log.msg("PUBLISH for xcap-diff event successfully sent to %s for %s" % (notification.data.route_header.uri, notification.sender.from_header.uri))

    def _NH_SIPPublicationDidEnd(self, notification):
        log.msg("PUBLISH for xcap-diff event ended for %s" % notification.sender.from_header.uri)
        NotificationCenter().remove_observer(self, sender=notification.sender)

    def _NH_SIPPublicationDidFail(self, notification):
        log.msg("PUBLISH for xcap-diff event failed to %s for %s" % (notification.data.route_header.uri, notification.sender.from_header.uri))
        NotificationCenter().remove_observer(self, sender=notification.sender)
Exemple #17
0
 def _NH_SIPEngineDidStart(self, notification):
     self.state = 'started'
     engine = Engine()
     for transport in ('udp', 'tcp', 'tls'):
         if getattr(engine, '%s_port' % transport) is not None:
             self.supported_transports.append(transport)
     self.http_listener = HTTPListener()
     self.http_listener.start()
     log.msg('SIP Engine started')
     log.msg('Enabled SIP transports: %s' %
             ', '.join(transport.upper()
                       for transport in self.supported_transports))
Exemple #18
0
 def __init__(self):
     self.engine = Engine()
     self.engine.start(
        ip_address=None if ServerConfig.address == '0.0.0.0' else ServerConfig.address,
        user_agent="OpenXCAP %s" % xcap.__version__,
     )
     self.sip_prefix_re = re.compile('^sips?:')
     try:
         self.outbound_proxy = SIPProxyAddress.from_description(Config.outbound_sip_proxy)
     except ValueError:
         log.warning('Invalid SIP proxy address specified: %s' % Config.outbound_sip_proxy)
         self.outbound_proxy = None
    def start(self, storage):
        if not ISIPSimpleStorage.providedBy(storage):
            raise TypeError(
                "storage must implement the ISIPSimpleStorage interface")

        with self._lock:
            if self.state is not None:
                raise RuntimeError(
                    "SIPApplication cannot be started from '%s' state" %
                    self.state)
            self.state = 'starting'

        self.engine = Engine()
        self.storage = storage

        thread_manager = ThreadManager()
        thread_manager.start()

        configuration_manager = ConfigurationManager()
        addressbook_manager = AddressbookManager()
        account_manager = AccountManager()

        # load configuration and initialize core
        try:
            configuration_manager.start()
            SIPSimpleSettings()
            account_manager.load()
            addressbook_manager.load()
        except:
            self.engine = None
            self.state = None
            self.storage = None
            raise

        # run the reactor thread
        self.thread = Thread(name='Reactor Thread', target=self._run_reactor)
        self.thread.start()
Exemple #20
0
    def start(self):
        notification_center = NotificationCenter()
        self.greenlet = api.getcurrent()
        settings = SIPSimpleSettings()
        account = AccountManager().sylkserver_account
        if account.sip.outbound_proxy is not None:
            uri = SIPURI(
                host=account.sip.outbound_proxy.host,
                port=account.sip.outbound_proxy.port,
                parameters={'transport': account.sip.outbound_proxy.transport})
        else:
            uri = self.destination_uri
        lookup = DNSLookup()
        try:
            routes = lookup.lookup_sip_proxy(
                uri, settings.sip.transport_list).wait()
        except DNSLookupError:
            notification_center.post_notification(
                'OutgoingFileTransferHandlerDidFail', sender=self)
            return

        self.session = Session(account)
        self.stream = FileTransferStream(self.file_selector, 'sendonly')
        notification_center.add_observer(self, sender=self.session)
        notification_center.add_observer(self, sender=self.stream)
        from_header = FromHeader(self.sender_uri, u'SIPStache File Transfer')
        to_header = ToHeader(self.destination_uri)
        transport = routes[0].transport
        parameters = {} if transport == 'udp' else {'transport': transport}
        contact_header = ContactHeader(
            SIPURI(user=self.sender_uri.user,
                   host=SIPConfig.local_ip.normalized,
                   port=getattr(Engine(), '%s_port' % transport),
                   parameters=parameters))
        extra_headers = []
        if ThorNodeConfig.enabled:
            extra_headers.append(Header('Thor-Scope', 'sipstache-file'))
        extra_headers.append(
            Header('X-Originator-From', str(self.destination_uri)))
        self.session.connect(from_header,
                             to_header,
                             contact_header=contact_header,
                             routes=routes,
                             streams=[self.stream],
                             is_focus=False,
                             extra_headers=extra_headers)
        notification_center.post_notification(
            'OutgoingFileTransferHandlerDidStart', sender=self)
Exemple #21
0
    def run(self):
        account_manager = AccountManager()
        configuration = ConfigurationManager()
        engine = Engine()

        # start output thread
        self.output.start()

        # startup configuration
        Account.register_extension(AccountExtension)
        SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension)
        SIPApplication.storage = FileStorage(config_directory)
        try:
            configuration.start()
        except ConfigurationError, e:
            raise RuntimeError(
                "failed to load sipclient's configuration: %s\nIf an old configuration file is in place, delete it or move it and recreate the configuration using the sip_settings script."
                % str(e))
Exemple #22
0
    def __getitem__(self, key):
        if isinstance(key, tuple):
            # The first part of the key might be PublicGRUU and so on, but we don't care about
            # those here, so ignore them
            _, key = key
        if not isinstance(key, (basestring, Route)):
            raise KeyError("key must be a transport name or Route instance")

        transport = key if isinstance(key, basestring) else key.transport
        parameters = {} if transport=='udp' else {'transport': transport}
        if SIPConfig.local_ip not in (None, '0.0.0.0'):
            ip = SIPConfig.local_ip.normalized
        elif isinstance(key, basestring):
            ip = host.default_ip
        else:
            ip = host.outgoing_ip_for(key.address)
        if ip is None:
            raise KeyError("could not get outgoing IP address")
        port = getattr(Engine(), '%s_port' % transport, None)
        if port is None:
            raise KeyError("unsupported transport: %s" % transport)
        uri = SIPURI(user=self.username, host=ip, port=port)
        uri.parameters.update(parameters)
        return uri
Exemple #23
0
    def __init__(self):
        # Loads the config file
        config = configparser.ConfigParser()
        try:
            config.read('config.ini')
        except Exception as e:
            print("ERROR: " + e)
            return
        self.account_name = config["SIPCONFIG"]["account_name"]
        self.target = None
        self.input = InputThread(self)
        self.output = EventQueue(self._write)
        self.logger = Logger(sip_to_stdout=False,
                             pjsip_to_stdout=False,
                             notifications_to_stdout=False)
        self.account = None
        self.subscriptions = []
        self.subscriptionqueue = []
        self.statusdict = {}
        self.stopping = False
        self.lastmessage = None
        self.commandsystemenabled = bool(config['SIPCONFIG']['commands'])

        self._subscription_routes = None
        self._subscription_timeout = 0.0
        self._subscription_wait = 0.5

        account_manager = AccountManager()
        engine = Engine()
        notification_center = NotificationCenter()
        notification_center.add_observer(self, sender=account_manager)
        notification_center.add_observer(self, sender=engine)
        notification_center.add_observer(self, sender=self.input)
        notification_center.add_observer(self, name='SIPEngineGotMessage')

        log.level.current = log.level.WARNING
Exemple #24
0
    def _sip_subscription_handler(self, command):
        notification_center = NotificationCenter()
        settings = SIPSimpleSettings()

        account = DefaultAccount()
        refresh_interval = getattr(command, 'refresh_interval',
                                   None) or account.sip.subscribe_interval

        try:
            # Lookup routes
            if account.sip.outbound_proxy is not None:
                uri = SIPURI(host=account.sip.outbound_proxy.host,
                             port=account.sip.outbound_proxy.port,
                             parameters={
                                 'transport':
                                 account.sip.outbound_proxy.transport
                             })
            else:
                uri = SIPURI(host=self.sip_identity.uri.as_sip_uri().host)
            lookup = DNSLookup()
            try:
                routes = lookup.lookup_sip_proxy(
                    uri, settings.sip.transport_list).wait()
            except DNSLookupError as e:
                timeout = random.uniform(15, 30)
                raise SubscriptionError(error='DNS lookup failed: %s' % e,
                                        timeout=timeout)

            timeout = time() + 30
            for route in routes:
                remaining_time = timeout - time()
                if remaining_time > 0:
                    transport = route.transport
                    parameters = {} if transport == 'udp' else {
                        'transport': transport
                    }
                    contact_uri = SIPURI(user=account.contact.username,
                                         host=SIPConfig.local_ip.normalized,
                                         port=getattr(Engine(),
                                                      '%s_port' % transport),
                                         parameters=parameters)
                    subscription_uri = self.sip_identity.uri.as_sip_uri()
                    subscription = Subscription(
                        subscription_uri,
                        FromHeader(self.xmpp_identity.uri.as_sip_uri()),
                        ToHeader(subscription_uri),
                        ContactHeader(contact_uri),
                        'presence',
                        RouteHeader(route.uri),
                        refresh=refresh_interval)
                    notification_center.add_observer(self, sender=subscription)
                    try:
                        subscription.subscribe(
                            timeout=limit(remaining_time, min=1, max=5))
                    except SIPCoreError:
                        notification_center.remove_observer(
                            self, sender=subscription)
                        raise SubscriptionError(error='Internal error',
                                                timeout=5)
                    self._sip_subscription = subscription
                    try:
                        while True:
                            notification = self._data_channel.wait()
                            if notification.sender is subscription and notification.name == 'SIPSubscriptionDidStart':
                                break
                    except SIPSubscriptionDidFail as e:
                        notification_center.remove_observer(
                            self, sender=subscription)
                        self._sip_subscription = None
                        if e.data.code == 407:
                            # Authentication failed, so retry the subscription in some time
                            raise SubscriptionError(
                                error='Authentication failed',
                                timeout=random.uniform(60, 120))
                        elif e.data.code == 403:
                            # Forbidden
                            raise SubscriptionError(error='Forbidden',
                                                    timeout=None,
                                                    fatal=True)
                        elif e.data.code == 423:
                            # Get the value of the Min-Expires header
                            if e.data.min_expires is not None and e.data.min_expires > refresh_interval:
                                interval = e.data.min_expires
                            else:
                                interval = None
                            raise SubscriptionError(error='Interval too short',
                                                    timeout=random.uniform(
                                                        60, 120),
                                                    refresh_interval=interval)
                        elif e.data.code in (405, 406, 489):
                            raise SubscriptionError(
                                error='Method or event not supported',
                                timeout=None,
                                fatal=True)
                        elif e.data.code == 1400:
                            raise SubscriptionError(error=e.data.reason,
                                                    timeout=None,
                                                    fatal=True)
                        else:
                            # Otherwise just try the next route
                            continue
                    else:
                        self.subscribed = True
                        command.signal()
                        break
            else:
                # There are no more routes to try, give up
                raise SubscriptionError(error='No more routes to try',
                                        timeout=None,
                                        fatal=True)
            # At this point it is subscribed. Handle notifications and ending/failures.
            try:
                while True:
                    notification = self._data_channel.wait()
                    if notification.sender is not self._sip_subscription:
                        continue
                    if self._xmpp_subscription is None:
                        continue
                    if notification.name == 'SIPSubscriptionGotNotify':
                        if notification.data.event == 'presence':
                            subscription_state = notification.data.headers.get(
                                'Subscription-State').state
                            if subscription_state == 'active' and self._xmpp_subscription.state != 'active':
                                self._xmpp_subscription.accept()
                            elif subscription_state == 'pending' and self._xmpp_subscription.state == 'active':
                                # The state went from active to pending, hide the presence state?
                                pass
                            if notification.data.body:
                                if XMPPGatewayConfig.log_presence:
                                    log.info(
                                        'SIP NOTIFY from %s to %s' %
                                        (format_uri(self.sip_identity.uri,
                                                    'sip'),
                                         format_uri(self.xmpp_identity.uri,
                                                    'xmpp')))
                                self._process_pidf(notification.data.body)
                    elif notification.name == 'SIPSubscriptionDidEnd':
                        break
            except SIPSubscriptionDidFail as e:
                if e.data.code == 0 and e.data.reason == 'rejected':
                    self._xmpp_subscription.reject()
                else:
                    self._command_channel.send(Command('subscribe'))
            notification_center.remove_observer(self,
                                                sender=self._sip_subscription)
        except InterruptSubscription as e:
            if not self.subscribed:
                command.signal(e)
            if self._sip_subscription is not None:
                notification_center.remove_observer(
                    self, sender=self._sip_subscription)
                try:
                    self._sip_subscription.end(timeout=2)
                except SIPCoreError:
                    pass
        except TerminateSubscription as e:
            if not self.subscribed:
                command.signal(e)
            if self._sip_subscription is not None:
                try:
                    self._sip_subscription.end(timeout=2)
                except SIPCoreError:
                    pass
                else:
                    try:
                        while True:
                            notification = self._data_channel.wait()
                            if notification.sender is self._sip_subscription and notification.name == 'SIPSubscriptionDidEnd':
                                break
                    except SIPSubscriptionDidFail:
                        pass
                finally:
                    notification_center.remove_observer(
                        self, sender=self._sip_subscription)
        except SubscriptionError as e:
            if not e.fatal:
                self._sip_subscription_timer = reactor.callLater(
                    e.timeout, self._command_channel.send,
                    Command('subscribe',
                            command.event,
                            refresh_interval=e.refresh_interval))
        finally:
            self.subscribed = False
            self._sip_subscription = None
            self._sip_subscription_proc = None
            reactor.callLater(0, self.end)
Exemple #25
0
    def _run(self):
        notification_center = NotificationCenter()
        settings = SIPSimpleSettings()

        sender_uri = self.sender.uri.as_sip_uri()
        recipient_uri = self.recipient.uri.as_sip_uri()
        participant_uri = self.participant.uri.as_sip_uri()

        try:
            # Lookup routes
            account = DefaultAccount()
            if account.sip.outbound_proxy is not None and account.sip.outbound_proxy.transport in settings.sip.transport_list:
                uri = SIPURI(host=account.sip.outbound_proxy.host,
                             port=account.sip.outbound_proxy.port,
                             parameters={
                                 'transport':
                                 account.sip.outbound_proxy.transport
                             })
            elif account.sip.always_use_my_proxy:
                uri = SIPURI(host=account.id.domain)
            else:
                uri = SIPURI.new(recipient_uri)
            lookup = DNSLookup()
            try:
                routes = lookup.lookup_sip_proxy(
                    uri, settings.sip.transport_list).wait()
            except DNSLookupError as e:
                raise ReferralError(error='DNS lookup failed: %s' % e)

            timeout = time() + 30
            for route in routes:
                self.route = route
                remaining_time = timeout - time()
                if remaining_time > 0:
                    transport = route.transport
                    parameters = {} if transport == 'udp' else {
                        'transport': transport
                    }
                    contact_uri = SIPURI(user=account.contact.username,
                                         host=SIPConfig.local_ip.normalized,
                                         port=getattr(Engine(),
                                                      '%s_port' % transport),
                                         parameters=parameters)
                    refer_to_header = ReferToHeader(str(participant_uri))
                    refer_to_header.parameters['method'] = 'INVITE'
                    referral = Referral(recipient_uri, FromHeader(sender_uri),
                                        ToHeader(recipient_uri),
                                        refer_to_header,
                                        ContactHeader(contact_uri),
                                        RouteHeader(route.uri),
                                        account.credentials)
                    notification_center.add_observer(self, sender=referral)
                    try:
                        referral.send_refer(
                            timeout=limit(remaining_time, min=1, max=5))
                    except SIPCoreError:
                        notification_center.remove_observer(self,
                                                            sender=referral)
                        timeout = 5
                        raise ReferralError(error='Internal error')
                    self._referral = referral
                    try:
                        while True:
                            notification = self._channel.wait()
                            if notification.name == 'SIPReferralDidStart':
                                break
                    except SIPReferralDidFail as e:
                        notification_center.remove_observer(self,
                                                            sender=referral)
                        self._referral = None
                        if e.data.code in (403, 405):
                            raise ReferralError(
                                error=sip_status_messages[e.data.code],
                                code=e.data.code)
                        else:
                            # Otherwise just try the next route
                            continue
                    else:
                        break
            else:
                self.route = None
                raise ReferralError(error='No more routes to try')
            # At this point it is subscribed. Handle notifications and ending/failures.
            try:
                self.active = True
                while True:
                    notification = self._channel.wait()
                    if notification.name == 'SIPReferralDidEnd':
                        break
            except SIPReferralDidFail as e:
                notification_center.remove_observer(self,
                                                    sender=self._referral)
                raise ReferralError(error=e.data.reason, code=e.data.code)
            else:
                notification_center.remove_observer(self,
                                                    sender=self._referral)
            finally:
                self.active = False
        except ReferralError as e:
            self._failure = MucInvitationFailure(e.code, e.error)
        finally:
            notification_center.remove_observer(
                self, name='NetworkConditionsDidChange')
            self._referral = None
            if self._failure is not None:
                notification_center.post_notification(
                    'X2SMucInvitationHandlerDidFail',
                    sender=self,
                    data=NotificationData(failure=self._failure))
            else:
                notification_center.post_notification(
                    'X2SMucInvitationHandlerDidEnd', sender=self)
class SIPApplication(object, metaclass=Singleton):

    default_ip = None
    storage = ApplicationAttribute(value=None)
    engine = ApplicationAttribute(value=None)
    thread = ApplicationAttribute(value=None)

    state = ApplicationAttribute(value=None)

    alert_audio_device = ApplicationAttribute(value=None)
    alert_audio_bridge = ApplicationAttribute(value=None)
    voice_audio_device = ApplicationAttribute(value=None)
    voice_audio_bridge = ApplicationAttribute(value=None)

    video_device = ApplicationAttribute(value=None)

    _lock = ApplicationAttribute(value=RLock())
    _timer = ApplicationAttribute(value=None)
    _stop_pending = ApplicationAttribute(value=False)

    running = classproperty(lambda cls: cls.state == 'started')
    alert_audio_mixer = classproperty(lambda cls: cls.alert_audio_bridge.mixer
                                      if cls.alert_audio_bridge else None)
    voice_audio_mixer = classproperty(lambda cls: cls.voice_audio_bridge.mixer
                                      if cls.voice_audio_bridge else None)

    def start(self, storage):
        if not ISIPSimpleStorage.providedBy(storage):
            raise TypeError(
                "storage must implement the ISIPSimpleStorage interface")

        with self._lock:
            if self.state is not None:
                raise RuntimeError(
                    "SIPApplication cannot be started from '%s' state" %
                    self.state)
            self.state = 'starting'

        self.engine = Engine()
        self.storage = storage

        thread_manager = ThreadManager()
        thread_manager.start()

        configuration_manager = ConfigurationManager()
        addressbook_manager = AddressbookManager()
        account_manager = AccountManager()

        # load configuration and initialize core
        try:
            configuration_manager.start()
            SIPSimpleSettings()
            account_manager.load()
            addressbook_manager.load()
        except:
            self.engine = None
            self.state = None
            self.storage = None
            raise

        # run the reactor thread
        self.thread = Thread(name='Reactor Thread', target=self._run_reactor)
        self.thread.start()

    def stop(self):
        with self._lock:
            if self.state in (None, 'stopping', 'stopped'):
                return
            elif self.state == 'starting':
                self._stop_pending = True
                return
            self.state = 'stopping'
        notification_center = NotificationCenter()
        notification_center.post_notification('SIPApplicationWillEnd',
                                              sender=self)
        self._shutdown_subsystems()

    def _run_reactor(self):
        from eventlib.twistedutil import join_reactor
        del join_reactor  # imported for the side effect of making the twisted reactor green

        notification_center = NotificationCenter()

        notification_center.post_notification('SIPApplicationWillStart',
                                              sender=self)
        with self._lock:
            stop_pending = self._stop_pending
            if stop_pending:
                self.state = 'stopping'
        if stop_pending:
            notification_center.post_notification('SIPApplicationWillEnd',
                                                  sender=self)
        else:
            self._initialize_core()
            reactor.run(installSignalHandlers=False)
        with self._lock:
            self.state = 'stopped'
        notification_center.post_notification('SIPApplicationDidEnd',
                                              sender=self)

    def _initialize_core(self):
        notification_center = NotificationCenter()
        settings = SIPSimpleSettings()

        # initialize core
        options = dict(  # general
            user_agent=settings.user_agent,
            # SIP
            detect_sip_loops=True,
            udp_port=settings.sip.udp_port
            if 'udp' in settings.sip.transport_list else None,
            tcp_port=settings.sip.tcp_port
            if 'tcp' in settings.sip.transport_list else None,
            tls_port=None,
            # TLS
            tls_verify_server=False,
            tls_ca_file=None,
            tls_cert_file=None,
            tls_privkey_file=None,
            # rtp
            rtp_port_range=(settings.rtp.port_range.start,
                            settings.rtp.port_range.end),
            # audio
            codecs=list(settings.rtp.audio_codec_list),
            # video
            video_codecs=list(settings.rtp.video_codec_list),
            # logging
            log_level=settings.logs.pjsip_level
            if settings.logs.trace_pjsip else 0,
            trace_sip=settings.logs.trace_sip)
        notification_center.add_observer(self, sender=self.engine)
        self.engine.start(**options)

    def _initialize_tls(self):
        settings = SIPSimpleSettings()
        account_manager = AccountManager()
        account = account_manager.default_account
        if account is not None:
            try:
                self.engine.set_tls_options(
                    port=settings.sip.tls_port,
                    verify_server=account.tls.verify_server,
                    ca_file=settings.tls.ca_list.normalized
                    if settings.tls.ca_list else None,
                    cert_file=account.tls.certificate.normalized
                    if account.tls.certificate else None,
                    privkey_file=account.tls.certificate.normalized
                    if account.tls.certificate else None)
            except Exception as e:
                notification_center = NotificationCenter()
                notification_center.post_notification(
                    'SIPApplicationFailedToStartTLS',
                    sender=self,
                    data=NotificationData(error=e))

    @run_in_green_thread
    def _initialize_subsystems(self):
        notification_center = NotificationCenter()

        with self._lock:
            stop_pending = self._stop_pending
            if stop_pending:
                self.state = 'stopping'
        if stop_pending:
            notification_center.post_notification('SIPApplicationWillEnd',
                                                  sender=self)
            # stop the subsystems we already started: threads, engine and reactor
            self.engine.stop()
            self.engine.join(timeout=5)
            thread_manager = ThreadManager()
            thread_manager.stop()
            reactor.stop()
            return

        account_manager = AccountManager()
        addressbook_manager = AddressbookManager()
        dns_manager = DNSManager()
        session_manager = SessionManager()
        settings = SIPSimpleSettings()

        xcap_client.DEFAULT_HEADERS = {'User-Agent': settings.user_agent}

        # initialize TLS
        self._initialize_tls()

        # initialize PJSIP internal resolver
        self.engine.set_nameservers(dns_manager.nameservers)

        # initialize audio objects
        alert_device = settings.audio.alert_device
        if alert_device not in (
                None, 'system_default'
        ) and alert_device not in self.engine.output_devices:
            alert_device = 'system_default'
        input_device = settings.audio.input_device
        if input_device not in (
                None, 'system_default'
        ) and input_device not in self.engine.input_devices:
            input_device = 'system_default'
        output_device = settings.audio.output_device
        if output_device not in (
                None, 'system_default'
        ) and output_device not in self.engine.output_devices:
            output_device = 'system_default'
        tail_length = settings.audio.echo_canceller.tail_length if settings.audio.echo_canceller.enabled else 0
        voice_mixer = AudioMixer(input_device, output_device,
                                 settings.audio.sample_rate, tail_length)
        voice_mixer.muted = settings.audio.muted
        self.voice_audio_device = AudioDevice(voice_mixer)
        self.voice_audio_bridge = RootAudioBridge(voice_mixer)
        self.voice_audio_bridge.add(self.voice_audio_device)
        alert_mixer = AudioMixer(None, alert_device,
                                 settings.audio.sample_rate, 0)
        if settings.audio.silent:
            alert_mixer.output_volume = 0
        self.alert_audio_device = AudioDevice(alert_mixer)
        self.alert_audio_bridge = RootAudioBridge(alert_mixer)
        self.alert_audio_bridge.add(self.alert_audio_device)

        settings.audio.input_device = voice_mixer.input_device
        settings.audio.output_device = voice_mixer.output_device
        settings.audio.alert_device = alert_mixer.output_device

        # initialize video
        self.video_device = VideoDevice(settings.video.device,
                                        settings.video.resolution,
                                        settings.video.framerate)
        self.video_device.muted = settings.video.muted
        settings.video.device = self.video_device.name
        self.engine.set_video_options(settings.video.resolution,
                                      settings.video.framerate,
                                      settings.video.max_bitrate)
        self.engine.set_h264_options(settings.video.h264.profile,
                                     settings.video.h264.level)

        # initialize instance id
        if not settings.instance_id:
            settings.instance_id = uuid4().urn

        # initialize path for ZRTP cache file
        if ISIPSimpleApplicationDataStorage.providedBy(self.storage):
            self.engine.zrtp_cache = os.path.join(self.storage.directory,
                                                  'zrtp.db')

        # save settings in case something was modified during startup
        settings.save()

        # initialize middleware components
        dns_manager.start()
        account_manager.start()
        addressbook_manager.start()
        session_manager.start()

        notification_center.add_observer(self,
                                         name='CFGSettingsObjectDidChange')
        notification_center.add_observer(self, name='DNSNameserversDidChange')
        notification_center.add_observer(self, name='SystemIPAddressDidChange')
        notification_center.add_observer(self, name='SystemDidWakeUpFromSleep')

        with self._lock:
            self.state = 'started'
            stop_pending = self._stop_pending

        notification_center.post_notification('SIPApplicationDidStart',
                                              sender=self)

        if stop_pending:
            self.stop()

    @run_in_green_thread
    def _shutdown_subsystems(self):
        # cleanup internals
        if self._timer is not None and self._timer.active():
            self._timer.cancel()
        self._timer = None

        # shutdown middleware components
        dns_manager = DNSManager()
        account_manager = AccountManager()
        addressbook_manager = AddressbookManager()
        session_manager = SessionManager()
        procs = [
            proc.spawn(dns_manager.stop),
            proc.spawn(account_manager.stop),
            proc.spawn(addressbook_manager.stop),
            proc.spawn(session_manager.stop)
        ]
        proc.waitall(procs)

        # stop video device
        self.video_device.producer.close()

        # shutdown engine
        self.engine.stop()
        self.engine.join(timeout=5)

        # stop threads
        thread_manager = ThreadManager()
        thread_manager.stop()

        # stop the reactor
        reactor.stop()

    def _network_conditions_changed(self):
        if self.running and self._timer is None:

            def notify():
                if self.running:
                    settings = SIPSimpleSettings()
                    if 'tcp' in settings.sip.transport_list:
                        self.engine.set_tcp_port(None)
                        self.engine.set_tcp_port(settings.sip.tcp_port)
                    if 'tls' in settings.sip.transport_list:
                        self._initialize_tls()
                    notification_center = NotificationCenter()
                    _changed = []
                    if self.default_ip != Host.default_ip:
                        _changed.append('ip')
                    data = NotificationData(changed=_changed)
                    notification_center.post_notification(
                        'NetworkConditionsDidChange', sender=self, data=data)
                    self.default_ip = Host.default_ip
                self._timer = None

            self._timer = reactor.callLater(5, notify)

    @run_in_twisted_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPEngineDidStart(self, notification):
        self._initialize_subsystems()

    def _NH_SIPEngineDidFail(self, notification):
        with self._lock:
            if self.state == 'stopping':
                return
            self.state = 'stopping'
        notification.center.post_notification('SIPApplicationWillEnd',
                                              sender=self)
        #
        # In theory we need to stop the subsystems here, based on what subsystems are already running according to our state,
        # but in practice the majority of those subsystems need the engine even to stop and the engine has failed.
        #
        # Even the ThreadManager might have threads that try to execute operations on the engine, which could block indefinitely
        # waiting for an answer that will no longer arrive, thus blocking the ThreadManager stop operation.
        #
        # As a result the safest thing to do is to just stop the engine thread and the reactor, which means in this case we
        # will not cleanup properly (the engine thread should already have ended as a result of the failure, so stopping it
        # is technically a no-op).
        #
        self.engine.stop()
        self.engine.join(timeout=5)
        reactor.stop()

    def _NH_SIPEngineGotException(self, notification):
        notification.center.post_notification('SIPApplicationGotFatalError',
                                              sender=self,
                                              data=notification.data)

    @run_in_thread('device-io')
    def _NH_CFGSettingsObjectDidChange(self, notification):
        settings = SIPSimpleSettings()
        account_manager = AccountManager()

        try:
            if notification.sender is settings:
                if 'audio.sample_rate' in notification.data.modified:
                    alert_device = settings.audio.alert_device
                    if alert_device not in (
                            None, 'system_default'
                    ) and alert_device not in self.engine.output_devices:
                        alert_device = 'system_default'
                    input_device = settings.audio.input_device
                    if input_device not in (
                            None, 'system_default'
                    ) and input_device not in self.engine.input_devices:
                        input_device = 'system_default'
                    output_device = settings.audio.output_device
                    if output_device not in (
                            None, 'system_default'
                    ) and output_device not in self.engine.output_devices:
                        output_device = 'system_default'
                    tail_length = settings.audio.echo_canceller.tail_length if settings.audio.echo_canceller.enabled else 0
                    voice_mixer = AudioMixer(input_device, output_device,
                                             settings.audio.sample_rate,
                                             tail_length)
                    voice_mixer.muted = settings.audio.muted
                    self.voice_audio_device = AudioDevice(voice_mixer)
                    self.voice_audio_bridge = RootAudioBridge(voice_mixer)
                    self.voice_audio_bridge.add(self.voice_audio_device)
                    alert_mixer = AudioMixer(None, alert_device,
                                             settings.audio.sample_rate, 0)
                    self.alert_audio_device = AudioDevice(alert_mixer)
                    self.alert_audio_bridge = RootAudioBridge(alert_mixer)
                    self.alert_audio_bridge.add(self.alert_audio_device)
                    if settings.audio.silent:
                        alert_mixer.output_volume = 0
                    settings.audio.input_device = voice_mixer.input_device
                    settings.audio.output_device = voice_mixer.output_device
                    settings.audio.alert_device = alert_mixer.output_device
                    settings.save()
                else:
                    if {
                            'audio.input_device', 'audio.output_device',
                            'audio.alert_device',
                            'audio.echo_canceller.enabled',
                            'audio.echo_canceller.tail_length'
                    }.intersection(notification.data.modified):
                        input_device = settings.audio.input_device
                        if input_device not in (
                                None, 'system_default'
                        ) and input_device not in self.engine.input_devices:
                            input_device = 'system_default'
                        output_device = settings.audio.output_device
                        if output_device not in (
                                None, 'system_default'
                        ) and output_device not in self.engine.output_devices:
                            output_device = 'system_default'
                        tail_length = settings.audio.echo_canceller.tail_length if settings.audio.echo_canceller.enabled else 0
                        if (input_device, output_device,
                                tail_length) != attrgetter(
                                    'input_device', 'output_device',
                                    'ec_tail_length')(
                                        self.voice_audio_bridge.mixer):
                            self.voice_audio_bridge.mixer.set_sound_devices(
                                input_device, output_device, tail_length)
                            settings.audio.input_device = self.voice_audio_bridge.mixer.input_device
                            settings.audio.output_device = self.voice_audio_bridge.mixer.output_device
                            settings.save()
                        alert_device = settings.audio.alert_device
                        if alert_device not in (
                                None, 'system_default'
                        ) and alert_device not in self.engine.output_devices:
                            alert_device = 'system_default'
                        if alert_device != self.alert_audio_bridge.mixer.output_device:
                            self.alert_audio_bridge.mixer.set_sound_devices(
                                None, alert_device, 0)
                            settings.audio.alert_device = self.alert_audio_bridge.mixer.output_device
                            settings.save()
                    if 'audio.muted' in notification.data.modified:
                        self.voice_audio_bridge.mixer.muted = settings.audio.muted
                    if 'audio.silent' in notification.data.modified:
                        if settings.audio.silent:
                            self.alert_audio_bridge.mixer.output_volume = 0
                        else:
                            self.alert_audio_bridge.mixer.output_volume = 100
                if 'video.muted' in notification.data.modified:
                    self.video_device.muted = settings.video.muted
                if {'video.h264.profile', 'video.h264.level'
                    }.intersection(notification.data.modified):
                    self.engine.set_h264_options(settings.video.h264.profile,
                                                 settings.video.h264.level)
                if {
                        'video.device', 'video.resolution', 'video.framerate',
                        'video.max_bitrate'
                }.intersection(notification.data.modified):
                    if {'video.device', 'video.resolution', 'video.framerate'
                        }.intersection(
                            notification.data.modified
                        ) or settings.video.device != self.video_device.name:
                        self.video_device.set_camera(settings.video.device,
                                                     settings.video.resolution,
                                                     settings.video.framerate)
                        settings.video.device = self.video_device.name
                        settings.save()
                    self.engine.set_video_options(settings.video.resolution,
                                                  settings.video.framerate,
                                                  settings.video.max_bitrate)
                if 'user_agent' in notification.data.modified:
                    self.engine.user_agent = settings.user_agent
                if 'sip.udp_port' in notification.data.modified:
                    self.engine.set_udp_port(settings.sip.udp_port)
                if 'sip.tcp_port' in notification.data.modified:
                    self.engine.set_tcp_port(settings.sip.tcp_port)
                if {'sip.tls_port', 'tls.ca_list', 'default_account'
                    }.intersection(notification.data.modified):
                    self._initialize_tls()
                if 'rtp.port_range' in notification.data.modified:
                    self.engine.rtp_port_range = (
                        settings.rtp.port_range.start,
                        settings.rtp.port_range.end)
                if 'rtp.audio_codec_list' in notification.data.modified:
                    print(settings.rtp.audio_codec_list)
                    self.engine.codecs = list(
                        codec.encode()
                        for codec in settings.rtp.audio_codec_list)
                if 'rtp.video_codec_list' in notification.data.modified:
                    print(settings.rtp.video_codec_list)
                    self.engine.video_codecs = list(
                        codec.encode()
                        for codec in settings.rtp.video_codec_list)
                if 'logs.trace_sip' in notification.data.modified:
                    self.engine.trace_sip = settings.logs.trace_sip
                if {'logs.trace_pjsip', 'logs.pjsip_level'
                    }.intersection(notification.data.modified):
                    self.engine.log_level = settings.logs.pjsip_level if settings.logs.trace_pjsip else 0
            elif notification.sender is account_manager.default_account:
                if {'tls.verify_server', 'tls.certificate'
                    }.intersection(notification.data.modified):
                    self._initialize_tls()
        except (SIPCoreError, PJSIPError) as e:
            print('Error setting core option: %s' % str(e))

    @run_in_thread('device-io')
    def _NH_DefaultAudioDeviceDidChange(self, notification):
        if None in (self.voice_audio_bridge, self.alert_audio_bridge):
            return
        settings = SIPSimpleSettings()
        current_input_device = self.voice_audio_bridge.mixer.input_device
        current_output_device = self.voice_audio_bridge.mixer.output_device
        current_alert_device = self.alert_audio_bridge.mixer.output_device
        ec_tail_length = self.voice_audio_bridge.mixer.ec_tail_length
        if notification.data.changed_input and 'system_default' in (
                current_input_device, settings.audio.input_device):
            self.voice_audio_bridge.mixer.set_sound_devices(
                'system_default', current_output_device, ec_tail_length)
        if notification.data.changed_output and 'system_default' in (
                current_output_device, settings.audio.output_device):
            self.voice_audio_bridge.mixer.set_sound_devices(
                current_input_device, 'system_default', ec_tail_length)
        if notification.data.changed_output and 'system_default' in (
                current_alert_device, settings.audio.alert_device):
            self.alert_audio_bridge.mixer.set_sound_devices(
                None, 'system_default', 0)

    @run_in_thread('device-io')
    def _NH_AudioDevicesDidChange(self, notification):
        old_devices = set(notification.data.old_devices)
        new_devices = set(notification.data.new_devices)
        removed_devices = old_devices - new_devices

        if not removed_devices:
            return

        input_device = self.voice_audio_bridge.mixer.input_device
        output_device = self.voice_audio_bridge.mixer.output_device
        alert_device = self.alert_audio_bridge.mixer.output_device
        if self.voice_audio_bridge.mixer.real_input_device in removed_devices:
            input_device = 'system_default' if new_devices else None
        if self.voice_audio_bridge.mixer.real_output_device in removed_devices:
            output_device = 'system_default' if new_devices else None
        if self.alert_audio_bridge.mixer.real_output_device in removed_devices:
            alert_device = 'system_default' if new_devices else None

        self.voice_audio_bridge.mixer.set_sound_devices(
            input_device, output_device,
            self.voice_audio_bridge.mixer.ec_tail_length)
        self.alert_audio_bridge.mixer.set_sound_devices(None, alert_device, 0)

        settings = SIPSimpleSettings()
        settings.audio.input_device = self.voice_audio_bridge.mixer.input_device
        settings.audio.output_device = self.voice_audio_bridge.mixer.output_device
        settings.audio.alert_device = self.alert_audio_bridge.mixer.output_device
        settings.save()

    @run_in_thread('device-io')
    def _NH_VideoDevicesDidChange(self, notification):
        old_devices = set(notification.data.old_devices)
        new_devices = set(notification.data.new_devices)
        removed_devices = old_devices - new_devices

        if not removed_devices:
            return

        device = self.video_device.name
        if self.video_device.real_name in removed_devices:
            device = 'system_default' if new_devices else None

        settings = SIPSimpleSettings()
        self.video_device.set_camera(device, settings.video.resolution,
                                     settings.video.framerate)
        settings.video.device = self.video_device.name
        settings.save()

    def _NH_DNSNameserversDidChange(self, notification):
        if self.running:
            self.engine.set_nameservers(notification.data.nameservers)
            notification_center = NotificationCenter()
            notification_center.post_notification(
                'NetworkConditionsDidChange',
                sender=self,
                data=NotificationData(changed=['dns']))

    def _NH_SystemIPAddressDidChange(self, notification):
        self._network_conditions_changed()

    def _NH_SystemDidWakeUpFromSleep(self, notification):
        self._network_conditions_changed()
Exemple #27
0
    def _sip_subscription_handler(self, command):
        notification_center = NotificationCenter()
        settings = SIPSimpleSettings()

        account = DefaultAccount()
        refresh_interval =  getattr(command, 'refresh_interval', None) or account.sip.subscribe_interval

        try:
            # Lookup routes
            if account.sip.outbound_proxy is not None:
                uri = SIPURI(host=account.sip.outbound_proxy.host,
                             port=account.sip.outbound_proxy.port,
                             parameters={'transport': account.sip.outbound_proxy.transport})
            else:
                uri = SIPURI(host=self.sip_identity.uri.as_sip_uri().host)
            lookup = DNSLookup()
            try:
                routes = lookup.lookup_sip_proxy(uri, settings.sip.transport_list).wait()
            except DNSLookupError, e:
                timeout = random.uniform(15, 30)
                raise SubscriptionError(error='DNS lookup failed: %s' % e, timeout=timeout)

            timeout = time() + 30
            for route in routes:
                remaining_time = timeout - time()
                if remaining_time > 0:
                    transport = route.transport
                    parameters = {} if transport=='udp' else {'transport': transport}
                    contact_uri = SIPURI(user=account.contact.username, host=SIPConfig.local_ip.normalized, port=getattr(Engine(), '%s_port' % transport), parameters=parameters)
                    subscription_uri = self.sip_identity.uri.as_sip_uri()
                    subscription = Subscription(subscription_uri, FromHeader(self.xmpp_identity.uri.as_sip_uri()),
                                                ToHeader(subscription_uri),
                                                ContactHeader(contact_uri),
                                                'presence',
                                                RouteHeader(route.uri),
                                                refresh=refresh_interval)
                    notification_center.add_observer(self, sender=subscription)
                    try:
                        subscription.subscribe(timeout=limit(remaining_time, min=1, max=5))
                    except SIPCoreError:
                        notification_center.remove_observer(self, sender=subscription)
                        raise SubscriptionError(error='Internal error', timeout=5)
                    self._sip_subscription = subscription
                    try:
                        while True:
                            notification = self._data_channel.wait()
                            if notification.sender is subscription and notification.name == 'SIPSubscriptionDidStart':
                                break
                    except SIPSubscriptionDidFail, e:
                        notification_center.remove_observer(self, sender=subscription)
                        self._sip_subscription = None
                        if e.data.code == 407:
                            # Authentication failed, so retry the subscription in some time
                            raise SubscriptionError(error='Authentication failed', timeout=random.uniform(60, 120))
                        elif e.data.code == 403:
                            # Forbidden
                            raise SubscriptionError(error='Forbidden', timeout=None, fatal=True)
                        elif e.data.code == 423:
                            # Get the value of the Min-Expires header
                            if e.data.min_expires is not None and e.data.min_expires > refresh_interval:
                                interval = e.data.min_expires
                            else:
                                interval = None
                            raise SubscriptionError(error='Interval too short', timeout=random.uniform(60, 120), refresh_interval=interval)
                        elif e.data.code in (405, 406, 489):
                            raise SubscriptionError(error='Method or event not supported', timeout=None, fatal=True)
                        elif e.data.code == 1400:
                            raise SubscriptionError(error=e.data.reason, timeout=None, fatal=True)
                        else:
                            # Otherwise just try the next route
                            continue
                    else:
                        self.subscribed = True
                        command.signal()
                        break