Exemple #1
0
    def _OH_session_trickle(self, data):
        transaction = data.get('transaction', None)
        if transaction is None:
            log.warn('Transaction not specified!')
            return

        try:
            try:
                session = data['session']
                candidates = data['candidates']
            except KeyError:
                raise APIError('Invalid parameters: "session" and "candidates" must be specified')

            try:
                session_info = self.sessions_map[session]
            except KeyError:
                raise APIError('Unknown session specified: %s' % session)
            if session_info.state == 'terminated':
                raise APIError('Session is terminated')

            block_on(self.backend.janus_trickle(self.janus_session_id, session_info.janus_handle_id, candidates))
            data = dict(sylkrtc='ack', transaction=transaction)
            self._send_data(json.dumps(data))
            log.msg('Trickled ICE candidate(s) for session %s' % session)
        except APIError, e:
            log.error('session-trickle: %s' % e)
            data = dict(sylkrtc='error', transaction=transaction, error=str(e))
            self._send_data(json.dumps(data))
 def delete_messages(self, local_uri=None, remote_uri=None, date=None, after_date=None, before_date=None, media_type=None):
     block_on(self.chat_history.delete_messages(local_uri=local_uri, remote_uri=remote_uri, date=date, after_date=after_date, before_date=before_date, media_type=media_type))
     block_on(self.session_history.delete_entries(local_uri=local_uri, remote_uri=remote_uri, after_date=after_date, before_date=before_date))
     self.search_text = None
     self.search_uris = None
     self.search_local = None
     self.refreshViewer()
Exemple #3
0
    def _OH_session_terminate(self, data):
        transaction = data.get('transaction', None)
        if transaction is None:
            log.warn('Transaction not specified!')
            return

        try:
            try:
                session = data['session']
            except KeyError:
                raise APIError('Invalid parameters: "session" must be specified')

            try:
                session_info = self.sessions_map[session]
            except KeyError:
                raise APIError('Unknown session specified: %s' % session)
            if session_info.state not in ('connecting', 'progress', 'accepted', 'established'):
                raise APIError('Invalid state for session terminate: \"%s\"' % session_info.state)

            if session_info.direction == 'incoming' and session_info.state == 'connecting':
                data = {'request': 'decline', 'code': 486}
            else:
                data = {'request': 'hangup'}
            block_on(self.backend.janus_message(self.janus_session_id, session_info.janus_handle_id, data))
            data = dict(sylkrtc='ack', transaction=transaction)
            self._send_data(json.dumps(data))
            log.msg('%s terminated session %s' % (session_info.account_id, session))
        except APIError, e:
            log.error('session-terminate: %s' % e)
            data = dict(sylkrtc='error', transaction=transaction, error=str(e))
            self._send_data(json.dumps(data))
 def test_block_on_success(self):
     from twisted.internet import reactor
     d = reactor.resolver.getHostByName('www.google.com')
     ip = block_on(d)
     assert len(ip.split('.')) == 4, ip
     ip2 = block_on(d)
     assert ip == ip2, (ip, ip2)
Exemple #5
0
    def _OH_session_answer(self, data):
        transaction = data.get('transaction', None)
        if transaction is None:
            log.warn('Transaction not specified!')
            return

        try:
            try:
                session = data['session']
                sdp = data['sdp']
            except KeyError:
                raise APIError('Invalid parameters: "session" and "sdp" must be specified')

            try:
                session_info = self.sessions_map[session]
            except KeyError:
                raise APIError('Unknown session specified: %s' % session)

            if session_info.direction != 'incoming':
                raise APIError('Cannot answer outgoing session')
            if session_info.state != 'connecting':
                raise APIError('Invalid state for session answer')

            data = {'request': 'accept'}
            jsep = {'type': 'answer', 'sdp': sdp}
            block_on(self.backend.janus_message(self.janus_session_id, session_info.janus_handle_id, data, jsep))
            data = dict(sylkrtc='ack', transaction=transaction)
            self._send_data(json.dumps(data))
            log.msg('%s answered session %s' % (session_info.account_id, session))
        except APIError, e:
            log.error('session-answer: %s' % e)
            data = dict(sylkrtc='error', transaction=transaction, error=str(e))
            self._send_data(json.dumps(data))
Exemple #6
0
    def _OH_account_unregister(self, data):
        transaction = data.get('transaction', None)
        if transaction is None:
            log.warn('Transaction not specified!')
            return

        try:
            try:
                account = data['account']
            except KeyError:
                raise APIError('Invalid parameters: "account" must be specified')

            try:
                account_info = self.accounts_map[account]
            except KeyError:
                raise APIError('Unknown account specified: %s' % account)

            handle_id = account_info.janus_handle_id
            if handle_id is not None:
                block_on(self.backend.janus_detach(self.janus_session_id, handle_id))
                self.backend.janus_set_event_handler(handle_id, None)
                account_info.janus_handle_id = None
                self.account_handles_map.pop(handle_id)

            data = dict(sylkrtc='ack', transaction=transaction)
            self._send_data(json.dumps(data))
            log.msg('Account %s will unregister' % account)
        except APIError, e:
            log.error('account-unregister: %s' % e)
            data = dict(sylkrtc='error', transaction=transaction, error=str(e))
            self._send_data(json.dumps(data))
Exemple #7
0
 def do_cleanup():
     if self.janus_session_id is None:
         # The connection was closed, there is noting to do here
         return
     self.sessions_map.pop(session.id)
     if session.direction == 'outgoing':
         # Destroy plugin handle for outgoing sessions. For incoming ones it's the
         # same as the account handle, so don't
         block_on(self.backend.janus_detach(self.janus_session_id, session.janus_handle_id))
         self.backend.janus_set_event_handler(session.janus_handle_id, None)
     self.session_handles_map.pop(session.janus_handle_id)
Exemple #8
0
    def _start_outgoing_jingle_session(self, streams):
        if self.xmpp_identity.uri.resource is not None:
            self.sip_session.reject()
            return
        xmpp_manager = XMPPManager()
        local_jid = self.sip_identity.uri.as_xmpp_jid()
        remote_jid = self.xmpp_identity.uri.as_xmpp_jid()

        # If this was an invitation to a conference, use the information in the Referred-By header
        if self.sip_identity.uri.host in xmpp_manager.muc_domains and self.sip_session.transfer_info and self.sip_session.transfer_info.referred_by:
            try:
                referred_by_uri = SIPURI.parse(self.sip_session.transfer_info.referred_by)
            except SIPCoreError:
                self.sip_session.reject(488)
                return
            else:
                inviter_uri = FrozenURI(referred_by_uri.user, referred_by_uri.host)
                local_jid = inviter_uri.as_xmpp_jid()

        # Use disco to gather potential JIDs to call
        d = xmpp_manager.disco_client_protocol.requestItems(remote_jid, sender=local_jid)
        try:
            items = block_on(d)
        except Exception:
            items = []
        if not items:
            self.sip_session.reject(480)
            return

        # Check which items support Jingle
        valid = []
        for item in items:
            d = xmpp_manager.disco_client_protocol.requestInfo(item.entity, nodeIdentifier=item.nodeIdentifier, sender=local_jid)
            try:
                info = block_on(d)
            except Exception:
                continue
            if jingle.NS_JINGLE in info.features and jingle.NS_JINGLE_APPS_RTP in info.features:
                valid.append(item.entity)
        if not valid:
            self.sip_session.reject(480)
            return

        # TODO: start multiple sessions?
        self._xmpp_identity = Identity(FrozenURI.parse(valid[0]))

        notification_center = NotificationCenter()
        if self.sip_identity.uri.host in xmpp_manager.muc_domains:
            self.jingle_session = JingleSession(xmpp_manager.jingle_coin_protocol)
        else:
            self.jingle_session = JingleSession(xmpp_manager.jingle_protocol)
        notification_center.add_observer(self, sender=self.jingle_session)
        self.jingle_session.connect(self.sip_identity, self.xmpp_identity, streams, is_focus=self.sip_session.remote_focus)
Exemple #9
0
    def _start_outgoing_jingle_session(self, streams):
        if self.xmpp_identity.uri.resource is not None:
            self.sip_session.reject()
            return
        xmpp_manager = XMPPManager()
        local_jid = self.sip_identity.uri.as_xmpp_jid()
        remote_jid = self.xmpp_identity.uri.as_xmpp_jid()

        # If this was an invitation to a conference, use the information in the Referred-By header
        if self.sip_identity.uri.host in xmpp_manager.muc_domains and self.sip_session.transfer_info and self.sip_session.transfer_info.referred_by:
            try:
                referred_by_uri = SIPURI.parse(self.sip_session.transfer_info.referred_by)
            except SIPCoreError:
                self.sip_session.reject(488)
                return
            else:
                inviter_uri = FrozenURI(referred_by_uri.user, referred_by_uri.host)
                local_jid = inviter_uri.as_xmpp_jid()

        # Use disco to gather potential JIDs to call
        d = xmpp_manager.disco_client_protocol.requestItems(remote_jid, sender=local_jid)
        try:
            items = block_on(d)
        except Exception:
            items = []
        if not items:
            self.sip_session.reject(480)
            return

        # Check which items support Jingle
        valid = []
        for item in items:
            d = xmpp_manager.disco_client_protocol.requestInfo(item.entity, nodeIdentifier=item.nodeIdentifier, sender=local_jid)
            try:
                info = block_on(d)
            except Exception:
                continue
            if jingle.NS_JINGLE in info.features and jingle.NS_JINGLE_APPS_RTP in info.features:
                valid.append(item.entity)
        if not valid:
            self.sip_session.reject(480)
            return

        # TODO: start multiple sessions?
        self._xmpp_identity = Identity(FrozenURI.parse(valid[0]))

        notification_center = NotificationCenter()
        if self.sip_identity.uri.host in xmpp_manager.muc_domains:
            self.jingle_session = JingleSession(xmpp_manager.jingle_coin_protocol)
        else:
            self.jingle_session = JingleSession(xmpp_manager.jingle_protocol)
        notification_center.add_observer(self, sender=self.jingle_session)
        self.jingle_session.connect(self.sip_identity, self.xmpp_identity, streams, is_focus=self.sip_session.remote_focus)
Exemple #10
0
 def _shutdown(self):
     if self.disconnecting:
         return
     self.disconnecting = True
     self.dns_monitor.cancel()
     if self.advertiser:
         self.advertiser.cancel()
     if self.shutdown_message:
         self._publish(self.shutdown_message)
     requests = [conn.protocol.unsubscribe(*self.topics) for conn in self.connections]
     d = defer.DeferredList([request.deferred for request in requests])
     block_on(d)
     self._disconnect_all()
Exemple #11
0
 def _shutdown(self):
     if self.disconnecting:
         return
     self.disconnecting = True
     self.dns_monitor.cancel()
     if self.advertiser:
         self.advertiser.cancel()
     if self.shutdown_message:
         self._publish(self.shutdown_message)
     requests = [conn.protocol.unsubscribe(*self.topics) for conn in self.connections]
     d = defer.DeferredList([request.deferred for request in requests])
     block_on(d)
     self._disconnect_all()
Exemple #12
0
class JanusPluginHandle(object):
    backend = JanusBackend()
    plugin = None

    def __init__(self, session, event_handler):
        if self.plugin is None:
            raise TypeError(
                'Cannot instantiate {0.__class__.__name__} with no associated plugin'
                .format(self))
        response = block_on(self.backend.attach_plugin(
            session.id, self.plugin))  # type: janus.SuccessResponse
        self.id = response.data.id
        self.session = session
        self.backend.set_event_handler(self.id, event_handler)

    def __enter__(self):
        return self

    def __exit__(self, exception_type, exception_value, traceback):
        self.detach()

    def detach(self):
        try:
            block_on(self.backend.detach_plugin(self.session.id, self.id))
        except JanusError as e:
            log.warning('could not detach Janus plugin: %s', e)
        self.backend.set_event_handler(self.id, None)

    def message(self, body, jsep=None, async=False):
        deferred = self.backend.message(self.session.id, self.id, body, jsep)
        return deferred if async else block_on(deferred)
Exemple #13
0
    def _OH_account_register(self, data):
        transaction = data.get('transaction', None)
        if transaction is None:
            log.warn('Transaction not specified!')
            return

        try:
            try:
                account = data['account']
            except KeyError:
                raise APIError('Invalid parameters: "account" must be specified')

            try:
                account_info = self.accounts_map[account]
            except KeyError:
                raise APIError('Unknown account specified: %s' % account)

            proxy = self._lookup_sip_proxy(account)

            handle_id = account_info.janus_handle_id
            if handle_id is not None:
                # Destroy the existing plugin handle
                block_on(self.backend.janus_detach(self.janus_session_id, handle_id))
                self.backend.janus_set_event_handler(handle_id, None)
                self.account_handles_map.pop(handle_id)
                account_info.janus_handle_id = None

            # Create a plugin handle
            handle_id = block_on(self.backend.janus_attach(self.janus_session_id, 'janus.plugin.sip'))
            self.backend.janus_set_event_handler(handle_id, self._handle_janus_event)
            account_info.janus_handle_id = handle_id
            self.account_handles_map[handle_id] = account_info

            data = {'request': 'register',
                    'username': account_info.uri,
                    'ha1_secret': account_info.password,
                    'proxy': proxy}
            block_on(self.backend.janus_message(self.janus_session_id, handle_id, data))

            data = dict(sylkrtc='ack', transaction=transaction)
            self._send_data(json.dumps(data))
            log.msg('Account %s will register' % account)
        except APIError, e:
            log.error('account-register: %s' % e)
            data = dict(sylkrtc='error', transaction=transaction, error=str(e))
            self._send_data(json.dumps(data))
Exemple #14
0
 def __init__(self, session, event_handler):
     if self.plugin is None:
         raise TypeError(
             'Cannot instantiate {0.__class__.__name__} with no associated plugin'
             .format(self))
     response = block_on(self.backend.attach_plugin(
         session.id, self.plugin))  # type: janus.SuccessResponse
     self.id = response.data.id
     self.session = session
     self.backend.set_event_handler(self.id, event_handler)
Exemple #15
0
 def _create_janus_session(self):
     if self.ready_event.is_set():
         data = dict(sylkrtc='event', event='ready')
         self._send_data(json.dumps(data))
         return
     try:
         self.janus_session_id = block_on(self.backend.janus_create_session())
         self.backend.janus_start_keepalive(self.janus_session_id)
     except Exception, e:
         log.warn('Error creating session, disconnecting: %s' % e)
         self.disconnect(3000, unicode(e))
         return
Exemple #16
0
    def _OH_session_create(self, data):
        transaction = data.get('transaction', None)
        if transaction is None:
            log.warn('Transaction not specified!')
            return

        try:
            try:
                account = data['account']
                session = data['session']
                uri = data['uri']
                sdp = data['sdp']
            except KeyError:
                raise APIError('Invalid parameters: "account", "session", "uri" and "sdp" must be specified')

            try:
                account_info = self.accounts_map[account]
            except KeyError:
                raise APIError('Unknown account specified: %s' % account)

            if session in self.sessions_map:
                raise APIError('Session ID (%s) already in use' % session)

            # Create a new plugin handle and 'register' it, without actually doing so
            handle_id = block_on(self.backend.janus_attach(self.janus_session_id, 'janus.plugin.sip'))
            self.backend.janus_set_event_handler(handle_id, self._handle_janus_event)
            try:
                proxy = self._lookup_sip_proxy(account_info.id)
            except DNSLookupError:
                block_on(self.backend.janus_detach(self.janus_session_id, handle_id))
                self.backend.janus_set_event_handler(handle_id, None)
                raise APIError('DNS lookup error')
            account_uri = 'sip:%s' % account_info.id
            data = {'request': 'register', 'username': account_uri, 'ha1_secret': account_info.password, 'proxy': proxy, 'send_register': False}
            block_on(self.backend.janus_message(self.janus_session_id, handle_id, data))

            session_info = JanusSessionInfo(session)
            session_info.janus_handle_id = handle_id
            session_info.init_outgoing(account, uri)
            self.sessions_map[session_info.id] = session_info
            self.session_handles_map[handle_id] = session_info

            data = {'request': 'call', 'uri': 'sip:%s' % SIP_PREFIX_RE.sub('', uri)}
            jsep = {'type': 'offer', 'sdp': sdp}
            block_on(self.backend.janus_message(self.janus_session_id, handle_id, data, jsep))
            data = dict(sylkrtc='ack', transaction=transaction)
            self._send_data(json.dumps(data))
            log.msg('Outgoing session %s from %s to %s created' % (session, account, uri))
        except APIError, e:
            log.error('session-create: %s' % e)
            data = dict(sylkrtc='error', transaction=transaction, error=str(e))
            self._send_data(json.dumps(data))
Exemple #17
0
 def detach(self):
     try:
         block_on(self.backend.detach_plugin(self.session.id, self.id))
     except JanusError as e:
         log.warning('could not detach Janus plugin: %s', e)
     self.backend.set_event_handler(self.id, None)
 def test_block_on_already_succeed(self):
     d = defer.succeed('hey corotwine')
     res = block_on(d)
     assert res == 'hey corotwine', ` res `
Exemple #19
0
 def __init__(self):
     response = block_on(
         self.backend.create_session())  # type: janus.SuccessResponse
     self.id = response.data.id
Exemple #20
0
        self.detach()

    def detach(self):
        try:
            block_on(self.backend.detach_plugin(self.session.id, self.id))
        except JanusError as e:
            log.warning('could not detach Janus plugin: %s', e)
        self.backend.set_event_handler(self.id, None)

    def message(self, body, jsep=None, async=False):
        deferred = self.backend.message(self.session.id, self.id, body, jsep)
        return deferred if async else block_on(deferred)

    def trickle(self, candidates, async=False):
        deferred = self.backend.trickle(self.session.id, self.id, candidates)
        return deferred if async else block_on(deferred)


class GenericPluginHandle(JanusPluginHandle):
    def __init__(self, plugin, session, event_handler):
        self.plugin = plugin
        super(GenericPluginHandle, self).__init__(session, event_handler)


class SIPPluginHandle(JanusPluginHandle):
    plugin = 'janus.plugin.sip'

    def register(self, account, proxy=None):
        self.message(janus.SIPRegister(proxy=proxy, **account.user_data))

    def unregister(self):
Exemple #21
0
    def _OH_AcceptOperation(self, operation):
        if self.state != 'incoming':
            return

        notification_center = NotificationCenter()
        settings = SIPSimpleSettings()
        streams = operation.streams

        for stream in self.proposed_streams:
            if stream in streams:
                notification_center.add_observer(self, sender=stream)
                stream.initialize(self, direction='incoming')

        try:
            wait_count = len(self.proposed_streams)
            while wait_count > 0:
                notification = operation.channel.wait()
                if notification.name == 'MediaStreamDidInitialize':
                    wait_count -= 1

            remote_sdp = self._sdp_negotiator.current_remote
            local_ip = SIPConfig.local_ip.normalized
            local_sdp = SDPSession(local_ip, connection=SDPConnection(local_ip), name=settings.user_agent)
            stream_map = dict((stream.index, stream) for stream in self.proposed_streams)
            for index, media in enumerate(remote_sdp.media):
                stream = stream_map.get(index, None)
                if stream is not None:
                    media = stream.get_local_media(remote_sdp=remote_sdp, index=index)
                else:
                    media = SDPMediaStream.new(media)
                    media.port = 0
                    media.attributes = []
                local_sdp.media.append(media)
            try:
                self._sdp_negotiator.set_local_answer(local_sdp)
                self._sdp_negotiator.negotiate()
            except SIPCoreError, e:
                self._fail(originator='local', reason='incompatible-parameters', description=str(e))
                return

            self.local_focus = operation.is_focus

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

            # Get active SDPs (negotiator may make changes)
            local_sdp = self._sdp_negotiator.active_local
            remote_sdp = self._sdp_negotiator.active_remote

            # Build the payload and send it over
            payload = sdp_to_jingle(local_sdp)
            payload.sid = self._id
            if self.local_focus:
                payload.conference_info = jingle.ConferenceInfo(True)
            stanza = self._protocol.sessionAccept(self._local_jid, self._remote_jid, payload)
            d = self._send_stanza(stanza)
            block_on(d)

            wait_count = 0
            stream_map = dict((stream.index, stream) for stream in self.proposed_streams)
            for index, local_media in enumerate(local_sdp.media):
                remote_media = remote_sdp.media[index]
                stream = stream_map.get(index, None)
                if stream is not None:
                    if remote_media.port:
                        wait_count += 1
                        stream.start(local_sdp, remote_sdp, index)
                    else:
                        notification_center.remove_observer(self, sender=stream)
                        self.proposed_streams.remove(stream)
                        del stream_map[stream.index]
                        stream.deactivate()
                        stream.end()
            removed_streams = [stream for stream in self.proposed_streams if stream.index >= len(local_sdp.media)]
            for stream in removed_streams:
                notification_center.remove_observer(self, sender=stream)
                self.proposed_streams.remove(stream)
                del stream_map[stream.index]
                stream.deactivate()
                stream.end()
            with api.timeout(self.media_stream_timeout):
                while wait_count > 0:
                    notification = operation.channel.wait()
                    if notification.name == 'MediaStreamDidStart':
                        wait_count -= 1
Exemple #22
0
    def _OH_ConnectOperation(self, operation):
        if self.state is not None:
            return

        settings = SIPSimpleSettings()
        notification_center = NotificationCenter()

        self.direction = 'outgoing'
        self.state = 'connecting'
        self.proposed_streams = operation.streams
        self.local_focus = operation.is_focus
        self._id = random_id()
        self._local_identity = operation.sender
        self._remote_identity = operation.recipient
        self._local_jid = self._local_identity.uri.as_xmpp_jid()
        self._remote_jid = self._remote_identity.uri.as_xmpp_jid()

        notification_center.post_notification(
            'JingleSessionNewOutgoing', self,
            NotificationData(streams=operation.streams))

        for stream in self.proposed_streams:
            notification_center.add_observer(self, sender=stream)
            stream.initialize(self, direction='outgoing')

        try:
            wait_count = len(self.proposed_streams)
            while wait_count > 0:
                notification = operation.channel.wait()
                if notification.name == 'MediaStreamDidInitialize':
                    wait_count -= 1
            # Build local SDP and negotiator
            local_ip = SIPConfig.local_ip.normalized
            local_sdp = SDPSession(local_ip,
                                   connection=SDPConnection(local_ip),
                                   name=settings.user_agent)
            for index, stream in enumerate(self.proposed_streams):
                stream.index = index
                media = stream.get_local_media(remote_sdp=None, index=index)
                local_sdp.media.append(media)
            self._sdp_negotiator = SDPNegotiator.create_with_local_offer(
                local_sdp)
            # Build the payload and send it over
            payload = sdp_to_jingle(local_sdp)
            payload.sid = self._id
            if self.local_focus:
                payload.conference_info = jingle.ConferenceInfo(True)
            stanza = self._protocol.sessionInitiate(self._local_jid,
                                                    self._remote_jid, payload)
            d = self._send_stanza(stanza)
            block_on(d)
        except (MediaStreamDidNotInitializeError, MediaStreamDidFailError,
                IqTimeoutError, StanzaError, SIPCoreError) as e:
            for stream in self.proposed_streams:
                notification_center.remove_observer(self, sender=stream)
                stream.deactivate()
                stream.end()
            if isinstance(e, IqTimeoutError):
                error = 'timeout sending IQ stanza'
            elif isinstance(e, StanzaError):
                error = str(e.condition)
            elif isinstance(e, SIPCoreError):
                error = str(e)
            else:
                error = 'media stream failed: %s' % e.data.reason
            self.state = 'terminated'
            NotificationCenter().post_notification('JingleSessionDidFail',
                                                   sender=self,
                                                   data=NotificationData(
                                                       originator='local',
                                                       reason=error))
            self._channel.send_exception(proc.ProcExit)
        else:
            self._timer = reactor.callLater(settings.sip.invite_timeout,
                                            self.end)
Exemple #23
0
    def _OH_ConnectOperation(self, operation):
        if self.state is not None:
            return

        settings = SIPSimpleSettings()
        notification_center = NotificationCenter()

        self.direction = 'outgoing'
        self.state = 'connecting'
        self.proposed_streams = operation.streams
        self.local_focus = operation.is_focus
        self._id = random_id()
        self._local_identity = operation.sender
        self._remote_identity = operation.recipient
        self._local_jid = self._local_identity.uri.as_xmpp_jid()
        self._remote_jid = self._remote_identity.uri.as_xmpp_jid()

        notification_center.post_notification('JingleSessionNewOutgoing', self, NotificationData(streams=operation.streams))

        for stream in self.proposed_streams:
            notification_center.add_observer(self, sender=stream)
            stream.initialize(self, direction='outgoing')

        try:
            wait_count = len(self.proposed_streams)
            while wait_count > 0:
                notification = operation.channel.wait()
                if notification.name == 'MediaStreamDidInitialize':
                    wait_count -= 1
            # Build local SDP and negotiator
            local_ip = SIPConfig.local_ip.normalized
            local_sdp = SDPSession(local_ip, connection=SDPConnection(local_ip), name=settings.user_agent)
            for index, stream in enumerate(self.proposed_streams):
                stream.index = index
                media = stream.get_local_media(remote_sdp=None, index=index)
                local_sdp.media.append(media)
            self._sdp_negotiator = SDPNegotiator.create_with_local_offer(local_sdp)
            # Build the payload and send it over
            payload = sdp_to_jingle(local_sdp)
            payload.sid = self._id
            if self.local_focus:
                payload.conference_info = jingle.ConferenceInfo(True)
            stanza = self._protocol.sessionInitiate(self._local_jid, self._remote_jid, payload)
            d = self._send_stanza(stanza)
            block_on(d)
        except (MediaStreamDidNotInitializeError, MediaStreamDidFailError, IqTimeoutError, StanzaError, SIPCoreError), e:
            for stream in self.proposed_streams:
                notification_center.remove_observer(self, sender=stream)
                stream.deactivate()
                stream.end()
            if isinstance(e, IqTimeoutError):
                error = 'timeout sending IQ stanza'
            elif isinstance(e, StanzaError):
                error = str(e.condition)
            elif isinstance(e, SIPCoreError):
                error = str(e)
            else:
                error = 'media stream failed: %s' % e.data.reason
            self.state = 'terminated'
            NotificationCenter().post_notification('JingleSessionDidFail', sender=self, data=NotificationData(originator='local', reason=error))
            self._channel.send_exception(proc.ProcExit)
Exemple #24
0
    def _OH_AcceptOperation(self, operation):
        if self.state != 'incoming':
            return

        notification_center = NotificationCenter()
        settings = SIPSimpleSettings()
        streams = operation.streams

        for stream in self.proposed_streams:
            if stream in streams:
                notification_center.add_observer(self, sender=stream)
                stream.initialize(self, direction='incoming')

        try:
            wait_count = len(self.proposed_streams)
            while wait_count > 0:
                notification = operation.channel.wait()
                if notification.name == 'MediaStreamDidInitialize':
                    wait_count -= 1

            remote_sdp = self._sdp_negotiator.current_remote
            local_ip = SIPConfig.local_ip.normalized
            local_sdp = SDPSession(local_ip,
                                   connection=SDPConnection(local_ip),
                                   name=settings.user_agent)
            stream_map = dict(
                (stream.index, stream) for stream in self.proposed_streams)
            for index, media in enumerate(remote_sdp.media):
                stream = stream_map.get(index, None)
                if stream is not None:
                    media = stream.get_local_media(remote_sdp=remote_sdp,
                                                   index=index)
                else:
                    media = SDPMediaStream.new(media)
                    media.port = 0
                    media.attributes = []
                local_sdp.media.append(media)
            try:
                self._sdp_negotiator.set_local_answer(local_sdp)
                self._sdp_negotiator.negotiate()
            except SIPCoreError as e:
                self._fail(originator='local',
                           reason='incompatible-parameters',
                           description=str(e))
                return

            self.local_focus = operation.is_focus

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

            # Get active SDPs (negotiator may make changes)
            local_sdp = self._sdp_negotiator.active_local
            remote_sdp = self._sdp_negotiator.active_remote

            # Build the payload and send it over
            payload = sdp_to_jingle(local_sdp)
            payload.sid = self._id
            if self.local_focus:
                payload.conference_info = jingle.ConferenceInfo(True)
            stanza = self._protocol.sessionAccept(self._local_jid,
                                                  self._remote_jid, payload)
            d = self._send_stanza(stanza)
            block_on(d)

            wait_count = 0
            stream_map = dict(
                (stream.index, stream) for stream in self.proposed_streams)
            for index, local_media in enumerate(local_sdp.media):
                remote_media = remote_sdp.media[index]
                stream = stream_map.get(index, None)
                if stream is not None:
                    if remote_media.port:
                        wait_count += 1
                        stream.start(local_sdp, remote_sdp, index)
                    else:
                        notification_center.remove_observer(self,
                                                            sender=stream)
                        self.proposed_streams.remove(stream)
                        del stream_map[stream.index]
                        stream.deactivate()
                        stream.end()
            removed_streams = [
                stream for stream in self.proposed_streams
                if stream.index >= len(local_sdp.media)
            ]
            for stream in removed_streams:
                notification_center.remove_observer(self, sender=stream)
                self.proposed_streams.remove(stream)
                del stream_map[stream.index]
                stream.deactivate()
                stream.end()
            with api.timeout(self.media_stream_timeout):
                while wait_count > 0:
                    notification = operation.channel.wait()
                    if notification.name == 'MediaStreamDidStart':
                        wait_count -= 1
        except (MediaStreamDidNotInitializeError, MediaStreamDidFailError,
                api.TimeoutError, IqTimeoutError, StanzaError) as e:
            for stream in self.proposed_streams:
                notification_center.remove_observer(self, sender=stream)
                stream.deactivate()
                stream.end()
            if isinstance(e, api.TimeoutError):
                error = 'media stream timed out while starting'
            elif isinstance(e, IqTimeoutError):
                error = 'timeout sending IQ stanza'
            elif isinstance(e, StanzaError):
                error = str(e.condition)
            else:
                error = 'media stream failed: %s' % e.data.reason
            self._fail(originator='local',
                       reason='failed-application',
                       description=error)
        else:
            self.state = 'connected'
            self.streams = self.proposed_streams
            self.proposed_streams = None
            self.start_time = datetime.now()
            notification_center.post_notification(
                'JingleSessionDidStart', self,
                NotificationData(streams=self.streams))