예제 #1
0
 def start(self, local_sdp, remote_sdp, stream_index):
     self.greenlet = api.getcurrent()
     notification_center = NotificationCenter()
     context = 'sdp_negotiation'
     try:
         remote_media = remote_sdp.media[stream_index]
         self.remote_media = remote_media
         self.remote_accept_types = remote_media.attributes.getfirst(
             b'accept-types', b'').decode().split()
         self.remote_accept_wrapped_types = remote_media.attributes.getfirst(
             b'accept-wrapped-types', b'').decode().split()
         self.cpim_enabled = contains_mime_type(
             self.accept_types, 'message/cpim') and contains_mime_type(
                 self.remote_accept_types, 'message/cpim')
         remote_uri_path = remote_media.attributes.getfirst(b'path')
         if remote_uri_path is None:
             raise AttributeError(
                 "remote SDP media does not have 'path' attribute")
         full_remote_path = [
             URI.parse(uri) for uri in remote_uri_path.decode().split()
         ]
         remote_transport = 'tls' if full_remote_path[0].use_tls else 'tcp'
         if self.transport != remote_transport:
             raise MSRPStreamError(
                 "remote transport ('%s') different from local transport ('%s')"
                 % (remote_transport, self.transport))
         if isinstance(self.session.account,
                       Account) and self.local_role == 'actpass':
             remote_setup = remote_media.attributes.getfirst(
                 'setup', 'passive')
             if remote_setup == 'passive':
                 # If actpass is offered connectors are always started as passive
                 # We need to switch to active if the remote answers with passive
                 if self.session.account.msrp.connection_model == 'relay':
                     self.msrp_connector.mode = 'active'
                 else:
                     local_uri = self.msrp_connector.local_uri
                     logger = self.msrp_connector.logger
                     self.msrp_connector = DirectConnector(
                         logger=logger, use_sessmatch=True)
                     self.msrp_connector.prepare(local_uri)
         context = 'start'
         self.msrp = self.msrp_connector.complete(full_remote_path)
         if self.msrp_session_class is not None:
             self.msrp_session = self.msrp_session_class(
                 self.msrp,
                 accept_types=self.accept_types,
                 on_incoming_cb=self._handle_incoming,
                 automatic_reports=False)
         self.msrp_connector = None
     except (CertificateAuthorityError, CertificateError,
             CertificateRevokedError) as e:
         peer = '%s:%s' % (full_remote_path[0].host,
                           full_remote_path[0].port)
         self._failure_reason = "%s - %s" % (peer, e.error)
         notification_center.post_notification(
             'MediaStreamDidFail',
             sender=self,
             data=NotificationData(
                 context=context,
                 reason=self._failure_reason,
                 transport=self.transport,
                 credentials=self.session.account.tls_credentials))
     except Exception as e:
         #traceback.print_exc()
         self._failure_reason = str(e)
         notification_center.post_notification(
             'MediaStreamDidFail',
             sender=self,
             data=NotificationData(
                 context=context,
                 reason=self._failure_reason,
                 transport=self.transport,
                 credentials=self.session.account.tls_credentials))
     else:
         notification_center.post_notification('MediaStreamDidStart',
                                               sender=self)
     finally:
         self.greenlet = None
예제 #2
0
    def __init__(self, parent=None):
        super(AddAccountDialog, self).__init__(parent)
        with Resources.directory:
            self.setupUi(self)
        self.background_frame.setStyleSheet("")
        self.button_group = QButtonGroup(self)
        self.button_group.setObjectName("button_group")
        self.button_group.addButton(
            self.add_account_button,
            self.panel_view.indexOf(self.add_account_panel))
        self.button_group.addButton(
            self.create_account_button,
            self.panel_view.indexOf(self.create_account_panel))
        default_font_size = self.info_label.fontInfo().pointSizeF()
        title_font_size = limit(default_font_size + 3, max=14)
        font = self.title_label.font()
        font.setPointSizeF(title_font_size)
        self.title_label.setFont(font)
        font_metrics = self.create_status_label.fontMetrics()
        self.create_status_label.setMinimumHeight(
            font_metrics.height() + 2 *
            (font_metrics.height() + font_metrics.leading())
        )  # reserve space for 3 lines
        font_metrics = self.email_note_label.fontMetrics()
        self.email_note_label.setMinimumWidth(
            font_metrics.width(
                u'The E-mail address is used when sending voicemail')
        )  # hack to make text justification look nice everywhere
        self.add_account_button.setChecked(True)
        self.panel_view.setCurrentWidget(self.add_account_panel)
        self.new_password_editor.textChanged.connect(
            self._SH_PasswordTextChanged)
        self.button_group.buttonClicked[int].connect(
            self._SH_PanelChangeRequest)
        self.accept_button.clicked.connect(self._SH_AcceptButtonClicked)
        self.display_name_editor.statusChanged.connect(
            self._SH_ValidityStatusChanged)
        self.name_editor.statusChanged.connect(self._SH_ValidityStatusChanged)
        self.username_editor.statusChanged.connect(
            self._SH_ValidityStatusChanged)
        self.sip_address_editor.statusChanged.connect(
            self._SH_ValidityStatusChanged)
        self.password_editor.statusChanged.connect(
            self._SH_ValidityStatusChanged)
        self.new_password_editor.statusChanged.connect(
            self._SH_ValidityStatusChanged)
        self.verify_password_editor.statusChanged.connect(
            self._SH_ValidityStatusChanged)
        self.email_address_editor.statusChanged.connect(
            self._SH_ValidityStatusChanged)
        self.display_name_editor.regexp = re.compile('^.*$')
        self.name_editor.regexp = re.compile('^.+$')
        self.username_editor.regexp = re.compile(
            '^\w(?<=[^0_])[\w.-]{4,31}(?<=[^_.-])$', re.IGNORECASE
        )  # in order to enable unicode characters add re.UNICODE to flags
        self.sip_address_editor.regexp = re.compile('^[^@\s]+@[^@\s]+$')
        self.password_editor.regexp = re.compile('^.*$')
        self.new_password_editor.regexp = re.compile('^.{8,}$')
        self.verify_password_editor.regexp = re.compile('^$')
        self.email_address_editor.regexp = re.compile('^[^@\s]+@[^@\s]+$')

        account_manager = AccountManager()
        notification_center = NotificationCenter()
        notification_center.add_observer(self, sender=account_manager)
예제 #3
0
 def stop(self):
     notification_center = NotificationCenter()
     notification_center.remove_observer(
         self, name='XMPPIncomingMucSessionDidStart')
     notification_center.remove_observer(
         self, name='XMPPIncomingMucSessionDidEnd')
예제 #4
0
    def __init__(self, sessionController):

        self.notification_center = NotificationCenter()

        self.sessionController = None
        self.audio_stream = None
        self.chat_stream = None

        self.add_session(sessionController)
        self.add_audio_stream()
        self.add_chat_stream()

        self.timer = NSTimer.timerWithTimeInterval_target_selector_userInfo_repeats_(
            1.0, self, "updateTimer:", None, True)
        NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer,
                                                     NSModalPanelRunLoopMode)
        NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer,
                                                     NSDefaultRunLoopMode)
        NSBundle.loadNibNamed_owner_("SessionInfoPanel", self)

        sessionBoxTitle = NSAttributedString.alloc(
        ).initWithString_attributes_(
            "SIP Session",
            NSDictionary.dictionaryWithObject_forKey_(
                NSColor.orangeColor(), NSForegroundColorAttributeName))
        self.sessionBox.setTitle_(sessionBoxTitle)

        audioBoxTitle = NSAttributedString.alloc().initWithString_attributes_(
            "Audio RTP Stream",
            NSDictionary.dictionaryWithObject_forKey_(
                NSColor.orangeColor(), NSForegroundColorAttributeName))
        self.audioBox.setTitle_(audioBoxTitle)

        chatBoxTitle = NSAttributedString.alloc().initWithString_attributes_(
            "Chat MSRP Stream",
            NSDictionary.dictionaryWithObject_forKey_(
                NSColor.orangeColor(), NSForegroundColorAttributeName))
        self.chatBox.setTitle_(chatBoxTitle)

        self.audio_rtt_graph.setLineWidth_(1.0)
        self.audio_rtt_graph.setLineSpacing_(1.0)
        self.audio_rtt_graph.setAboveLimit_(
            200)  # if higher than 200 ms show red color
        self.audio_rtt_graph.setMinimumHeigth_(200)

        self.audio_packet_loss_graph.setLineWidth_(1.0)
        self.audio_packet_loss_graph.setLineSpacing_(1.0)
        self.audio_packet_loss_graph.setAboveLimit_(
            3)  # if higher than 3% show red color
        self.audio_packet_loss_graph.setLineColor_(NSColor.greenColor())
        self.audio_packet_loss_graph.setMinimumHeigth_(5)

        self.audio_jitter_graph.setLineWidth_(1.0)
        self.audio_jitter_graph.setLineSpacing_(1.0)
        self.audio_jitter_graph.setAboveLimit_(
            50)  # if higher than 50 ms show red color
        self.audio_jitter_graph.setLineColor_(NSColor.yellowColor())
        self.audio_jitter_graph.setMinimumHeigth_(100)

        self.resetSession()
        self.updatePanelValues()
예제 #5
0
 def __init__(self):
     self.notifications = deque()
     NotificationCenter().add_observer(ObserverWeakrefProxy(self))
 def _NH_MediaStreamDidStart(self, sender, data):
     self.sessionController.log_info("Screen sharing started")
     self.changeStatus(STREAM_CONNECTED)
     NotificationCenter().add_observer(self, name="MSRPTransportTrace")
예제 #7
0
 def start(self):
     notification_center = NotificationCenter()
     notification_center.add_observer(self, name='JanusBackendConnected')
     notification_center.add_observer(self, name='JanusBackendDisconnected')
     self.connector = connectWS(self.factory)
예제 #8
0
 def smp_verify(self, secret, question=None):
     if self.encrypted:
         self.protocol.smp_verify(secret, question)
     else:
         notification_center = NotificationCenter()
         notification_center.post_notification('OTRSessionSMPVerificationDidNotStart', sender=self, data=NotificationData(reason='not encrypted'))
예제 #9
0
    def awakeFromNib(self):
        if not self.accountTable:
            return
        NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
            self, "userDefaultsDidChange:",
            "NSUserDefaultsDidChangeNotification",
            NSUserDefaults.standardUserDefaults())

        dotPath = NSBezierPath.bezierPathWithOvalInRect_(NSMakeRect(
            2, 2, 8, 8))
        self.dots = {}
        for i, color in [("red", NSColor.redColor()),
                         ("yellow", NSColor.yellowColor()),
                         ("green", NSColor.greenColor())]:
            dot = NSImage.alloc().initWithSize_(NSMakeSize(12, 12))
            dot.lockFocus()
            color.set()
            dotPath.fill()
            dot.unlockFocus()
            self.dots[i] = dot

        if self.advancedTabView is not None:
            self.tableViewSelectionDidChange_(None)

        if self.accountTable:
            self.accountTable.setDraggingSourceOperationMask_forLocal_(
                NSDragOperationGeneric, True)
            self.accountTable.registerForDraggedTypes_(
                NSArray.arrayWithObject_("dragged-account"))

        notification_center = NotificationCenter()
        notification_center.add_observer(self,
                                         name="CFGSettingsObjectDidChange")
        notification_center.add_observer(self, name="AudioDevicesDidChange")

        self.window().setTitle_("%s Preferences" %
                                NSApp.delegate().applicationName)

        self.toolbar.setSelectedItemIdentifier_('accounts')

        if NSApp.delegate().applicationName == 'Blink Lite':
            PreferenceOptionTypes['audio.pause_music'] = HiddenOption
            PreferenceOptionTypes['audio.directory'] = HiddenOption
            PreferenceOptionTypes['audio.auto_recording'] = HiddenOption
            PreferenceOptionTypes['logs.directory'] = HiddenOption
            PreferenceOptionTypes[
                'contacts.enable_favorites_group'] = HiddenOption
            PreferenceOptionTypes[
                'contacts.enable_incoming_calls_group'] = HiddenOption
            PreferenceOptionTypes[
                'contacts.enable_outgoing_calls_group'] = HiddenOption
            PreferenceOptionTypes[
                'contacts.enable_missed_calls_group'] = HiddenOption
            PreferenceOptionTypes['contacts.maximum_calls'] = HiddenOption

            for identifier in ('answering_machine', 'advanced'):
                try:
                    item = (item for item in self.toolbar.visibleItems()
                            if item.itemIdentifier() == identifier).next()
                    self.toolbar.removeItemAtIndex_(
                        self.toolbar.visibleItems().index(item))
                except StopIteration:
                    pass
            self.sync_with_icloud_checkbox.setHidden_(True)
        else:
            major, minor = platform.mac_ver()[0].split('.')[0:2]
            self.sync_with_icloud_checkbox.setHidden_(False if (
                (int(major) == 10 and int(minor) >= 7) or int(major) > 10
            ) else True)

        self.userDefaultsDidChange_(None)
예제 #10
0
 def _browse_cb(self, file, flags, interface_index, error_code,
                service_name, regtype, reply_domain):
     notification_center = NotificationCenter()
     file = BonjourDiscoveryFile.find_by_file(file)
     service_description = BonjourServiceDescription(
         service_name, regtype, reply_domain)
     if error_code != _bonjour.kDNSServiceErr_NoError:
         error = _bonjour.BonjourError(error_code)
         notification_center.post_notification(
             'BonjourAccountDiscoveryDidFail',
             sender=self.account,
             data=NotificationData(reason=str(error),
                                   transport=file.transport))
         removed_files = [file] + [
             f for f in self._files if isinstance(f, BonjourResolutionFile)
             and f.discovery_file == file
         ]
         for f in removed_files:
             self._files.remove(f)
         self._select_proc.kill(RestartSelect)
         for f in removed_files:
             f.close()
         if self._discover_timer is None:
             self._discover_timer = reactor.callLater(
                 1, self._command_channel.send, Command('discover'))
         return
     if reply_domain != 'local.':
         return
     if flags & _bonjour.kDNSServiceFlagsAdd:
         try:
             resolution_file = next(
                 (f for f in self._files
                  if isinstance(f, BonjourResolutionFile)
                  and f.discovery_file == file
                  and f.service_description == service_description))
         except StopIteration:
             try:
                 resolution_file = _bonjour.DNSServiceResolve(
                     0, interface_index, service_name, regtype,
                     reply_domain, self._resolve_cb)
             except _bonjour.BonjourError as e:
                 notification_center.post_notification(
                     'BonjourAccountDiscoveryFailure',
                     sender=self.account,
                     data=NotificationData(error=str(e),
                                           transport=file.transport))
             else:
                 resolution_file = BonjourResolutionFile(
                     resolution_file,
                     discovery_file=file,
                     service_description=service_description)
                 self._files.append(resolution_file)
                 self._select_proc.kill(RestartSelect)
     else:
         try:
             resolution_file = next(
                 (f for f in self._files
                  if isinstance(f, BonjourResolutionFile)
                  and f.discovery_file == file
                  and f.service_description == service_description))
         except StopIteration:
             pass
         else:
             self._files.remove(resolution_file)
             self._select_proc.kill(RestartSelect)
             resolution_file.close()
             service_description = resolution_file.service_description
             if service_description in self._neighbours:
                 record = self._neighbours.pop(service_description)
                 notification_center.post_notification(
                     'BonjourAccountDidRemoveNeighbour',
                     sender=self.account,
                     data=NotificationData(neighbour=service_description,
                                           record=record))
예제 #11
0
 def _CH_discover(self, command):
     notification_center = NotificationCenter()
     settings = SIPSimpleSettings()
     if self._discover_timer is not None and self._discover_timer.active():
         self._discover_timer.cancel()
     self._discover_timer = None
     supported_transports = set(
         transport for transport in settings.sip.transport_list
         if transport != 'tls' or self.account.tls.certificate is not None)
     discoverable_transports = set(
         'tcp' if transport == 'tls' else transport
         for transport in supported_transports)
     old_files = []
     for file in (
             f for f in self._files[:]
             if isinstance(f, (BonjourDiscoveryFile, BonjourResolutionFile))
             and f.transport not in discoverable_transports):
         old_files.append(file)
         self._files.remove(file)
     self._select_proc.kill(RestartSelect)
     for file in old_files:
         file.close()
     for service_description in [
             service for service, record in self._neighbours.items()
             if record.uri.transport not in supported_transports
     ]:
         record = self._neighbours.pop(service_description)
         notification_center.post_notification(
             'BonjourAccountDidRemoveNeighbour',
             sender=self.account,
             data=NotificationData(neighbour=service_description,
                                   record=record))
     discovered_transports = set(file.transport for file in self._files
                                 if isinstance(file, BonjourDiscoveryFile))
     missing_transports = discoverable_transports - discovered_transports
     added_transports = set()
     for transport in missing_transports:
         notification_center.post_notification(
             'BonjourAccountWillInitiateDiscovery',
             sender=self.account,
             data=NotificationData(transport=transport))
         try:
             file = _bonjour.DNSServiceBrowse(regtype="_sipuri._%s" %
                                              transport,
                                              callBack=self._browse_cb)
         except _bonjour.BonjourError as e:
             notification_center.post_notification(
                 'BonjourAccountDiscoveryDidFail',
                 sender=self.account,
                 data=NotificationData(reason=str(e), transport=transport))
         else:
             self._files.append(BonjourDiscoveryFile(file, transport))
             added_transports.add(transport)
     if added_transports:
         self._select_proc.kill(RestartSelect)
     if added_transports != missing_transports:
         self._discover_timer = reactor.callLater(
             1, self._command_channel.send,
             Command('discover', command.event))
     else:
         command.signal()
예제 #12
0
 def stop(self):
     notification_center = NotificationCenter()
     notification_center.remove_observer(self,
                                         name='NetworkConditionsDidChange')
     self._select_proc.kill()
     self._command_channel.send_exception(api.GreenletExit)
예제 #13
0
 def start(self):
     notification_center = NotificationCenter()
     notification_center.add_observer(self,
                                      name='NetworkConditionsDidChange')
     self._select_proc = proc.spawn(self._process_files)
     proc.spawn(self._handle_commands)
예제 #14
0
 def __init__(self):
     from application import log
     self.level = log.level
     self.notification_center = NotificationCenter()
     self.log_settings = SIPSimpleSettings().logs
예제 #15
0
 def stop(self):
     notification_center = NotificationCenter()
     notification_center.remove_observer(self)
예제 #16
0
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.saved_account_state = None

        notification_center = NotificationCenter()
        notification_center.add_observer(self, name='SIPApplicationWillStart')
        notification_center.add_observer(self, name='SIPApplicationDidStart')
        notification_center.add_observer(self, name='SIPAccountGotMessageSummary')
        notification_center.add_observer(self, name='SIPAccountGotPendingWatcher')
        notification_center.add_observer(self, name='BlinkSessionNewOutgoing')
        notification_center.add_observer(self, name='BlinkSessionDidReinitializeForOutgoing')
        notification_center.add_observer(self, name='BlinkFileTransferNewIncoming')
        notification_center.add_observer(self, name='BlinkFileTransferNewOutgoing')
        notification_center.add_observer(self, name='DocumentSharingFileTransferCompleted')
        notification_center.add_observer(self, sender=AccountManager())

        icon_manager = IconManager()

        self.pending_watcher_dialogs = []

        self.mwi_icons = [QIcon(Resources.get('icons/mwi-%d.png' % i)) for i in xrange(0, 11)]
        self.mwi_icons.append(QIcon(Resources.get('icons/mwi-many.png')))

        with Resources.directory:
            self.setupUi()

        self.setWindowTitle('Blink')
        self.setWindowIconText('Blink')

        geometry = QSettings().value("main_window/geometry")
        if geometry:
            self.restoreGeometry(geometry)

        self.default_icon_path = Resources.get('icons/default-avatar.png')
        self.default_icon = QIcon(self.default_icon_path)
        self.last_icon_directory = Path('~').normalized
        self.set_user_icon(icon_manager.get('avatar'))

        self.active_sessions_label.hide()
        self.enable_call_buttons(False)
        self.conference_button.setEnabled(False)
        self.hangup_all_button.setEnabled(False)
        self.sip_server_settings_action.setEnabled(False)
        self.search_for_people_action.setEnabled(False)
        self.history_on_server_action.setEnabled(False)
        self.main_view.setCurrentWidget(self.contacts_panel)
        self.contacts_view.setCurrentWidget(self.contact_list_panel)
        self.search_view.setCurrentWidget(self.search_list_panel)

        # System tray
        if QSystemTrayIcon.isSystemTrayAvailable():
            self.system_tray_icon = QSystemTrayIcon(QIcon(Resources.get('icons/blink.png')), self)
            self.system_tray_icon.activated.connect(self._SH_SystemTrayIconActivated)
            menu = QMenu(self)
            menu.addAction(QAction("Show", self, triggered=self._AH_SystemTrayShowWindow))
            menu.addAction(QAction(QIcon(Resources.get('icons/application-exit.png')), "Quit", self, triggered=self._AH_QuitActionTriggered))
            self.system_tray_icon.setContextMenu(menu)
            self.system_tray_icon.show()
        else:
            self.system_tray_icon = None

        # Accounts
        self.account_model = AccountModel(self)
        self.enabled_account_model = ActiveAccountModel(self.account_model, self)
        self.server_tools_account_model = ServerToolsAccountModel(self.account_model, self)
        self.identity.setModel(self.enabled_account_model)

        # Contacts
        self.contact_model = ContactModel(self)
        self.contact_search_model = ContactSearchModel(self.contact_model, self)
        self.contact_list.setModel(self.contact_model)
        self.search_list.setModel(self.contact_search_model)

        # Sessions (audio)
        self.session_model = AudioSessionModel(self)
        self.session_list.setModel(self.session_model)
        self.session_list.selectionModel().selectionChanged.connect(self._SH_SessionListSelectionChanged)

        # History
        self.history_manager = HistoryManager()

        # Windows, dialogs and panels
        self.about_panel = AboutPanel(self)
        self.conference_dialog = ConferenceDialog(self)
        self.contact_editor_dialog = ContactEditorDialog(self)
        self.google_contacts_dialog = GoogleContactsDialog(self)
        self.filetransfer_window = FileTransferWindow()
        self.preferences_window = PreferencesWindow(self.account_model, None)
        self.server_tools_window = ServerToolsWindow(self.server_tools_account_model, None)

        self.documents_window = DocumentsWindow()

        # Signals
        self.account_state.stateChanged.connect(self._SH_AccountStateChanged)
        self.account_state.clicked.connect(self._SH_AccountStateClicked)
        self.activity_note.editingFinished.connect(self._SH_ActivityNoteEditingFinished)
        self.add_contact_button.clicked.connect(self._SH_AddContactButtonClicked)
        self.add_search_contact_button.clicked.connect(self._SH_AddContactButtonClicked)
        self.audio_call_button.clicked.connect(self._SH_AudioCallButtonClicked)
        self.video_call_button.clicked.connect(self._SH_VideoCallButtonClicked)
        self.chat_session_button.clicked.connect(self._SH_ChatSessionButtonClicked)
        self.share_document_button.clicked.connect(self._SH_ShareDocumentButtonClicked)
        self.back_to_contacts_button.clicked.connect(self.search_box.clear) # this can be set in designer -Dan
        self.conference_button.makeConference.connect(self._SH_MakeConference)
        self.conference_button.breakConference.connect(self._SH_BreakConference)

        self.contact_list.selectionModel().selectionChanged.connect(self._SH_ContactListSelectionChanged)
        self.contact_model.itemsAdded.connect(self._SH_ContactModelAddedItems)
        self.contact_model.itemsRemoved.connect(self._SH_ContactModelRemovedItems)

        self.display_name.editingFinished.connect(self._SH_DisplayNameEditingFinished)
        self.hangup_all_button.clicked.connect(self._SH_HangupAllButtonClicked)

        self.identity.activated[int].connect(self._SH_IdentityChanged)
        self.identity.currentIndexChanged[int].connect(self._SH_IdentityCurrentIndexChanged)

        self.mute_button.clicked.connect(self._SH_MuteButtonClicked)

        self.search_box.textChanged.connect(self._SH_SearchBoxTextChanged)
        self.search_box.returnPressed.connect(self._SH_SearchBoxReturnPressed)
        self.search_box.shortcut.activated.connect(self.search_box.setFocus)

        self.search_list.selectionModel().selectionChanged.connect(self._SH_SearchListSelectionChanged)

        self.server_tools_account_model.rowsInserted.connect(self._SH_ServerToolsAccountModelChanged)
        self.server_tools_account_model.rowsRemoved.connect(self._SH_ServerToolsAccountModelChanged)

        self.session_model.sessionAdded.connect(self._SH_AudioSessionModelAddedSession)
        self.session_model.sessionRemoved.connect(self._SH_AudioSessionModelRemovedSession)
        self.session_model.structureChanged.connect(self._SH_AudioSessionModelChangedStructure)

        self.silent_button.clicked.connect(self._SH_SilentButtonClicked)
        self.switch_view_button.viewChanged.connect(self._SH_SwitchViewButtonChangedView)

        # Blink menu actions
        self.about_action.triggered.connect(self.about_panel.show)
        self.add_account_action.triggered.connect(self.preferences_window.show_add_account_dialog)
        self.manage_accounts_action.triggered.connect(self.preferences_window.show_for_accounts)
        self.help_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/help-qt.phtml')))
        self.preferences_action.triggered.connect(self.preferences_window.show)
        self.auto_accept_chat_action.triggered.connect(self._AH_AutoAcceptChatActionTriggered)
        self.received_messages_sound_action.triggered.connect(self._AH_ReceivedMessagesSoundActionTriggered)
        self.answering_machine_action.triggered.connect(self._AH_EnableAnsweringMachineActionTriggered)
        self.release_notes_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/changelog-qt.phtml')))
        self.quit_action.triggered.connect(self._AH_QuitActionTriggered)

        # Call menu actions
        self.redial_action.triggered.connect(self._AH_RedialActionTriggered)
        self.join_conference_action.triggered.connect(self.conference_dialog.show)
        self.history_menu.aboutToShow.connect(self._SH_HistoryMenuAboutToShow)
        self.history_menu.triggered.connect(self._AH_HistoryMenuTriggered)
        self.output_devices_group.triggered.connect(self._AH_AudioOutputDeviceChanged)
        self.input_devices_group.triggered.connect(self._AH_AudioInputDeviceChanged)
        self.alert_devices_group.triggered.connect(self._AH_AudioAlertDeviceChanged)
        self.video_devices_group.triggered.connect(self._AH_VideoDeviceChanged)
        self.mute_action.triggered.connect(self._SH_MuteButtonClicked)
        self.silent_action.triggered.connect(self._SH_SilentButtonClicked)

        # Tools menu actions
        self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings)
        self.search_for_people_action.triggered.connect(self._AH_SearchForPeople)
        self.history_on_server_action.triggered.connect(self._AH_HistoryOnServer)

        # Window menu actions
        self.chat_window_action.triggered.connect(self._AH_ChatWindowActionTriggered)
        self.transfers_window_action.triggered.connect(self._AH_TransfersWindowActionTriggered)
        self.logs_window_action.triggered.connect(self._AH_LogsWindowActionTriggered)
        self.received_files_window_action.triggered.connect(self._AH_ReceivedFilesWindowActionTriggered)
        self.screenshots_window_action.triggered.connect(self._AH_ScreenshotsWindowActionTriggered)
        self.documents_window_action.triggered.connect(self._AH_DocumentsWindowActionTriggered)
예제 #17
0
    def userDefaultsDidChange_(self, notification):
        userdef = NSUserDefaults.standardUserDefaults()
        notification_center = NotificationCenter()
        trace = userdef.integerForKey_("SIPTrace")
        if trace == Disabled:
            notification_center.discard_observer(self,
                                                 name="SIPEngineSIPTrace")
            notification_center.discard_observer(self, name="DNSLookupTrace")
            self.sipTraceType = None
        elif trace == Simplified:
            notification_center.add_observer(self, name="SIPEngineSIPTrace")
            notification_center.add_observer(self, name="DNSLookupTrace")
            self.sipTraceType = "simple"
        elif trace == Full:
            notification_center.add_observer(self, name="SIPEngineSIPTrace")
            notification_center.add_observer(self, name="DNSLookupTrace")
            self.sipTraceType = "full"

        trace = userdef.integerForKey_("MSRPTrace")
        if trace == Disabled:
            notification_center.discard_observer(self, name="MSRPLibraryLog")
            notification_center.discard_observer(self,
                                                 name="MSRPTransportTrace")
            self.msrpTraceType = None
        elif trace == Simplified:
            notification_center.add_observer(self, name="MSRPLibraryLog")
            notification_center.add_observer(self, name="MSRPTransportTrace")
            self.msrpTraceType = "simple"
        elif trace == Full:
            notification_center.add_observer(self, name="MSRPLibraryLog")
            notification_center.add_observer(self, name="MSRPTransportTrace")
            self.msrpTraceType = "full"

        trace = userdef.integerForKey_("XCAPTrace")
        if trace == Disabled:
            notification_center.discard_observer(
                self, name="XCAPManagerDidDiscoverServerCapabilities")
            notification_center.discard_observer(
                self, name="XCAPSubscriptionGotNotify")
            notification_center.discard_observer(
                self, name="XCAPManagerDidChangeState")
            self.xcapTraceType = None
        elif trace == Simplified:
            notification_center.add_observer(
                self, name="XCAPManagerDidDiscoverServerCapabilities")
            notification_center.add_observer(self,
                                             name="XCAPManagerDidChangeState")
            self.xcapTraceType = "simple"
        elif trace == Full:
            notification_center.add_observer(
                self, name="XCAPManagerDidDiscoverServerCapabilities")
            notification_center.add_observer(self,
                                             name="XCAPManagerDidChangeState")
            notification_center.add_observer(self,
                                             name="XCAPSubscriptionGotNotify")
            self.xcapTraceType = "full"

        trace = userdef.boolForKey_("EnablePJSIPTrace")
        if trace:
            notification_center.add_observer(self, name="SIPEngineLog")
        else:
            notification_center.discard_observer(self, name="SIPEngineLog")

        trace = userdef.boolForKey_("EnableNotificationsTrace")
        if trace:
            notification_center.add_observer(self)
        else:
            notification_center.discard_observer(self)
예제 #18
0
    def onMessage(self, msg):
        notification_center = NotificationCenter()

        sender_uri = FrozenURI.parse('xmpp:' + msg['from'])
        sender = Identity(sender_uri)
        recipient_uri = FrozenURI.parse('xmpp:' + msg['to'])
        recipient = Identity(recipient_uri)

        msg_type = msg.getAttribute('type')
        msg_id = msg.getAttribute('id', None)
        is_empty = msg.body is None and msg.html is None

        if msg_type == 'error':
            error_type = msg.error['type']
            conditions = [(child.name, child.defaultUri)
                          for child in msg.error.elements()]
            error_message = ErrorStanza('message',
                                        sender,
                                        recipient,
                                        error_type,
                                        conditions,
                                        id=msg_id)
            notification_center.post_notification(
                'XMPPGotErrorMessage',
                sender=self.parent,
                data=NotificationData(error_message=error_message))
            return

        if msg_type in (None, 'normal', 'chat') and not is_empty:
            body = None
            html_body = None
            if msg.html is not None:
                html_body = msg.html.toXml()
            if msg.body is not None:
                body = unicode(msg.body)
            try:
                elem = next(c for c in msg.elements() if c.uri == RECEIPTS_NS)
            except StopIteration:
                use_receipt = False
            else:
                use_receipt = elem.name == u'request'
            if msg_type == 'chat':
                message = ChatMessage(sender,
                                      recipient,
                                      body,
                                      html_body,
                                      id=msg_id,
                                      use_receipt=use_receipt)
                notification_center.post_notification(
                    'XMPPGotChatMessage',
                    sender=self.parent,
                    data=NotificationData(message=message))
            else:
                message = NormalMessage(sender,
                                        recipient,
                                        body,
                                        html_body,
                                        id=msg_id,
                                        use_receipt=use_receipt)
                notification_center.post_notification(
                    'XMPPGotNormalMessage',
                    sender=self.parent,
                    data=NotificationData(message=message))
            return

        # Check if it's a composing indication
        if msg_type == 'chat' and is_empty:
            for elem in msg.elements():
                try:
                    elem = next(c for c in msg.elements()
                                if c.uri == CHATSTATES_NS)
                except StopIteration:
                    pass
                else:
                    composing_indication = ChatComposingIndication(sender,
                                                                   recipient,
                                                                   elem.name,
                                                                   id=msg_id)
                    notification_center.post_notification(
                        'XMPPGotComposingIndication',
                        sender=self.parent,
                        data=NotificationData(
                            composing_indication=composing_indication))
                    return

        # Check if it's a receipt acknowledgement
        if is_empty:
            try:
                elem = next(c for c in msg.elements() if c.uri == RECEIPTS_NS)
            except StopIteration:
                pass
            else:
                if elem.name == u'received' and msg_id is not None:
                    receipt = MessageReceipt(sender, recipient, msg_id)
                    notification_center.post_notification(
                        'XMPPGotReceipt',
                        sender=self.parent,
                        data=NotificationData(receipt=receipt))
예제 #19
0
 def dealloc(self):
     BlinkLogger().log_info(u"Disposing %s" % self)
     self.stream = None
     self.sessionController = None
     NotificationCenter().discard_observer(self, name="MSRPTransportTrace")
     super(DesktopSharingController, self).dealloc()
예제 #20
0
 def onSessionInitiate(self, request):
     reactor.callLater(0,
                       NotificationCenter().post_notification,
                       'XMPPGotJingleSessionInitiate',
                       sender=self.parent,
                       data=NotificationData(stanza=request, protocol=self))
예제 #21
0
class JanusClientProtocol(WebSocketClientProtocol):
    _event_handlers = None
    _pending_transactions = None
    _keepalive_timers = None
    _keepalive_interval = 45

    notification_center = NotificationCenter()

    def onOpen(self):
        self.notification_center.post_notification('JanusBackendConnected',
                                                   sender=self)
        self._pending_transactions = {}
        self._keepalive_timers = {}
        self._event_handlers = {}

    def onMessage(self, payload, isBinary):
        if isBinary:
            log.warn('Unexpected binary payload received')
            return

        self.notification_center.post_notification('WebRTCJanusTrace',
                                                   sender=self,
                                                   data=NotificationData(
                                                       direction='INCOMING',
                                                       message=payload,
                                                       peer=self.peer))

        try:
            message = janus.JanusMessage.from_payload(json.loads(payload))
        except Exception as e:
            log.warning('Error decoding Janus message: {!s}'.format(e))
            return

        if isinstance(message, (janus.CoreEvent, janus.PluginEvent)):
            # some of the plugin events might have the transaction, but we do not finalize
            # the transaction for them as they are not direct responses for the transaction
            handler = self._event_handlers.get(message.sender, Null)
            try:
                handler(message)
            except Exception as e:
                log.exception(
                    'Error while running Janus event handler: {!s}'.format(e))
            return

        # at this point it can only be a response. clear the transaction and return the answer.
        try:
            request, deferred = self._pending_transactions.pop(
                message.transaction)
        except KeyError:
            log.warn('Discarding unexpected response: %s' % payload)
            return

        if isinstance(message, janus.AckResponse):
            deferred.callback(None)
        elif isinstance(message, janus.SuccessResponse):
            deferred.callback(message)
        elif isinstance(message, janus.ErrorResponse):
            deferred.errback(
                JanusError(message.error.code, message.error.reason))
        else:
            assert isinstance(message, janus.PluginResponse)
            plugin_data = message.plugindata.data
            if isinstance(plugin_data,
                          (janus.SIPErrorEvent, janus.VideoroomErrorEvent)):
                deferred.errback(
                    JanusError(plugin_data.error_code, plugin_data.error))
            else:
                deferred.callback(message)

    def connectionLost(self, reason):
        super(JanusClientProtocol, self).connectionLost(reason)
        self.notification_center.post_notification(
            'JanusBackendDisconnected',
            sender=self,
            data=NotificationData(reason=reason.getErrorMessage()))

    def disconnect(self, code=1000, reason=u''):
        self.sendClose(code, reason)

    def _send_request(self, request):
        if request.janus != 'keepalive' and 'session_id' in request:  # postpone keepalive messages as long as we have non-keepalive traffic for a given session
            keepalive_timer = self._keepalive_timers.get(
                request.session_id, None)
            if keepalive_timer is not None and keepalive_timer.active():
                keepalive_timer.reset(self._keepalive_interval)
        deferred = defer.Deferred()
        message = json.dumps(request.__data__)
        self.notification_center.post_notification('WebRTCJanusTrace',
                                                   sender=self,
                                                   data=NotificationData(
                                                       direction='OUTGOING',
                                                       message=message,
                                                       peer=self.peer))
        self.sendMessage(message)
        self._pending_transactions[request.transaction] = request, deferred
        return deferred

    def _start_keepalive(self, response):
        session_id = response.data.id
        self._keepalive_timers[session_id] = reactor.callLater(
            self._keepalive_interval, self._send_keepalive, session_id)
        return response

    def _stop_keepalive(self, session_id):
        timer = self._keepalive_timers.pop(session_id, None)
        if timer is not None and timer.active():
            timer.cancel()

    def _send_keepalive(self, session_id):
        deferred = self._send_request(
            janus.SessionKeepaliveRequest(session_id=session_id))
        deferred.addBoth(self._keepalive_callback, session_id)

    def _keepalive_callback(self, result, session_id):
        if isinstance(result, Failure):
            self._keepalive_timers.pop(session_id)
        else:
            self._keepalive_timers[session_id] = reactor.callLater(
                self._keepalive_interval, self._send_keepalive, session_id)

    # Public API

    def set_event_handler(self, handle_id, event_handler):
        if event_handler is None:
            self._event_handlers.pop(handle_id, None)
            log.debug("Destroy Janus session, %d handlers in use" %
                      len(self._event_handlers.keys()))
        else:
            assert callable(event_handler)
            self._event_handlers[handle_id] = event_handler
            log.debug("Create Janus session, %d handlers in use" %
                      len(self._event_handlers.keys()))

    def info(self):
        return self._send_request(janus.InfoRequest())

    def create_session(self):
        return self._send_request(janus.SessionCreateRequest()).addCallback(
            self._start_keepalive)

    def destroy_session(self, session_id):
        self._stop_keepalive(session_id)
        return self._send_request(
            janus.SessionDestroyRequest(session_id=session_id))

    def attach_plugin(self, session_id, plugin):
        return self._send_request(
            janus.PluginAttachRequest(session_id=session_id, plugin=plugin))

    def detach_plugin(self, session_id, handle_id):
        return self._send_request(
            janus.PluginDetachRequest(session_id=session_id,
                                      handle_id=handle_id))

    def message(self, session_id, handle_id, body, jsep=None):
        if jsep is not None:
            return self._send_request(
                janus.MessageRequest(session_id=session_id,
                                     handle_id=handle_id,
                                     body=body,
                                     jsep=jsep))
        else:
            return self._send_request(
                janus.MessageRequest(session_id=session_id,
                                     handle_id=handle_id,
                                     body=body))

    def trickle(self, session_id, handle_id, candidates):
        return self._send_request(
            janus.TrickleRequest(session_id=session_id,
                                 handle_id=handle_id,
                                 candidates=candidates))
예제 #22
0
 def onSessionAccept(self, request):
     reactor.callLater(0,
                       NotificationCenter().post_notification,
                       'XMPPGotJingleSessionAccept',
                       sender=self.parent,
                       data=NotificationData(stanza=request))
예제 #23
0
 def _lookup_srv_records(self,
                         resolver,
                         srv_names,
                         additional_records=[],
                         log_context={}):
     notification_center = NotificationCenter()
     additional_services = dict((rset.name.to_text(), rset)
                                for rset in additional_records
                                if rset.rdtype == rdatatype.SRV)
     services = {}
     for srv_name in srv_names:
         services[srv_name] = []
         if srv_name in additional_services:
             addresses = self._lookup_a_records(resolver, [
                 r.target.to_text() for r in additional_services[srv_name]
             ], additional_records)
             for record in additional_services[srv_name]:
                 services[srv_name].extend(
                     SRVResult(record.priority, record.weight, record.port,
                               addr)
                     for addr in addresses.get(record.target.to_text(), ()))
         else:
             try:
                 answer = resolver.query(srv_name, rdatatype.SRV)
             except dns.resolver.Timeout, e:
                 notification_center.post_notification(
                     'DNSLookupTrace',
                     sender=self,
                     data=NotificationData(query_type='SRV',
                                           query_name=str(srv_name),
                                           nameservers=resolver.nameservers,
                                           answer=None,
                                           error=e,
                                           **log_context))
                 raise
             except exception.DNSException, e:
                 notification_center.post_notification(
                     'DNSLookupTrace',
                     sender=self,
                     data=NotificationData(query_type='SRV',
                                           query_name=str(srv_name),
                                           nameservers=resolver.nameservers,
                                           answer=None,
                                           error=e,
                                           **log_context))
             else:
                 notification_center.post_notification(
                     'DNSLookupTrace',
                     sender=self,
                     data=NotificationData(query_type='SRV',
                                           query_name=str(srv_name),
                                           nameservers=resolver.nameservers,
                                           answer=answer,
                                           error=None,
                                           **log_context))
                 addresses = self._lookup_a_records(
                     resolver, [r.target.to_text() for r in answer.rrset],
                     answer.response.additional, log_context)
                 for record in answer.rrset:
                     services[srv_name].extend(
                         SRVResult(record.priority, record.weight,
                                   record.port, addr) for addr in
                         addresses.get(record.target.to_text(), ()))
예제 #24
0
 def onTransportInfo(self, request):
     reactor.callLater(0,
                       NotificationCenter().post_notification,
                       'XMPPGotJingleTransportInfo',
                       sender=self.parent,
                       data=NotificationData(stanza=request))
예제 #25
0
    def incoming_session(self, session):
        log.info('New session from %s to %s' %
                 (session.remote_identity.uri, session.local_identity.uri))
        audio_streams = [
            stream for stream in session.proposed_streams
            if stream.type == 'audio'
        ]
        chat_streams = [
            stream for stream in session.proposed_streams
            if stream.type == 'chat'
        ]
        transfer_streams = [
            stream for stream in session.proposed_streams
            if stream.type == 'file-transfer'
        ]
        if not audio_streams and not chat_streams and not transfer_streams:
            log.info(u'Session rejected: invalid media')
            session.reject(488)
            return
        audio_stream = audio_streams[0] if audio_streams else None
        chat_stream = chat_streams[0] if chat_streams else None
        transfer_stream = transfer_streams[0] if transfer_streams else None

        try:
            self.validate_acl(session.request_uri, session.remote_identity.uri)
        except ACLValidationError:
            log.info(u'Session rejected: unauthorized by access list')
            session.reject(403)
            return

        if transfer_stream is not None:
            try:
                room = self.get_room(session.request_uri)
            except RoomNotFoundError:
                log.info(u'Session rejected: room not found')
                session.reject(404)
                return
            if transfer_stream.direction == 'sendonly':
                # file transfer 'pull'
                try:
                    file = next(
                        file for file in room.files
                        if file.hash == transfer_stream.file_selector.hash)
                except StopIteration:
                    log.info(u'Session rejected: requested file not found')
                    session.reject(404)
                    return
                try:
                    transfer_stream.file_selector = file.file_selector
                except EnvironmentError as e:
                    log.info(
                        u'Session rejected: error opening requested file: %s' %
                        e)
                    session.reject(404)
                    return
            else:
                transfer_stream.handler.save_directory = os.path.join(
                    ConferenceConfig.file_transfer_dir.normalized, room.uri)

        NotificationCenter().add_observer(self, sender=session)
        if audio_stream:
            session.send_ring_indication()
        streams = [
            stream for stream in (audio_stream, chat_stream, transfer_stream)
            if stream
        ]
        reactor.callLater(4 if audio_stream is not None else 0,
                          self.accept_session, session, streams)
예제 #26
0
 def _run(self):
     notification_center = NotificationCenter()
     try:
         while True:
             command = self._channel.wait()
             if command.name == 'play':
                 self._wave_file = WaveFile(self.mixer, self.filename)
                 notification_center.add_observer(
                     self,
                     sender=self._wave_file,
                     name='WaveFileDidFinishPlaying')
                 self._wave_file.volume = self.volume
                 try:
                     self._wave_file.start()
                 except SIPCoreError, e:
                     notification_center.post_notification(
                         'WavePlayerDidFail',
                         sender=self,
                         data=NotificationData(error=e))
                     raise WavePlayerError(e)
                 else:
                     if self._current_loop == 0:
                         notification_center.post_notification(
                             'WavePlayerDidStart', sender=self)
                     notification_center.post_notification(
                         'AudioPortDidChangeSlots',
                         sender=self,
                         data=NotificationData(
                             consumer_slot_changed=False,
                             producer_slot_changed=True,
                             old_producer_slot=None,
                             new_producer_slot=self._wave_file.slot))
             elif command.name == 'reschedule':
                 self._current_loop += 1
                 notification_center.remove_observer(
                     self,
                     sender=self._wave_file,
                     name='WaveFileDidFinishPlaying')
                 self._wave_file = None
                 notification_center.post_notification(
                     'AudioPortDidChangeSlots',
                     sender=self,
                     data=NotificationData(consumer_slot_changed=False,
                                           producer_slot_changed=True,
                                           old_producer_slot=None,
                                           new_producer_slot=None))
                 if self.loop_count == 0 or self._current_loop < self.loop_count:
                     reactor.callLater(self.pause_time, self._channel.send,
                                       Command('play'))
                 else:
                     notification_center.post_notification(
                         'WavePlayerDidEnd', sender=self)
                     break
             elif command.name == 'stop':
                 if self._wave_file is not None:
                     notification_center.remove_observer(
                         self,
                         sender=self._wave_file,
                         name='WaveFileDidFinishPlaying')
                     self._wave_file.stop()
                     self._wave_file = None
                     notification_center.post_notification(
                         'AudioPortDidChangeSlots',
                         sender=self,
                         data=NotificationData(consumer_slot_changed=False,
                                               producer_slot_changed=True,
                                               old_producer_slot=None,
                                               new_producer_slot=None))
                     notification_center.post_notification(
                         'WavePlayerDidEnd', sender=self)
                 break
예제 #27
0
 def start(self):
     notification_center = NotificationCenter()
     notification_center.add_observer(self, name='XMPPChatSessionDidStart')
     notification_center.add_observer(self, name='XMPPChatSessionDidEnd')
예제 #28
0
 def start(self):
     notification_center = NotificationCenter()
     notification_center.add_observer(self)
예제 #29
0
 def start(self):
     NotificationCenter().post_notification('XMPPChatSessionDidStart',
                                            sender=self)
     self._proc = proc.spawn(self._run)
     self.state = 'started'
예제 #30
0
 def initialize(self, session, direction):
     self.greenlet = api.getcurrent()
     notification_center = NotificationCenter()
     notification_center.add_observer(self, sender=self)
     settings = SIPSimpleSettings()
     try:
         self.session = session
         self.transport = self.session.account.msrp.transport
         outgoing = direction == 'outgoing'
         logger = NotificationProxyLogger()
         if self.session.account is BonjourAccount():
             if outgoing:
                 self.msrp_connector = DirectConnector(logger=logger)
                 self.local_role = 'active'
             else:
                 if self.transport == 'tls' and settings.tls.certificate is None:
                     raise MSRPStreamError(
                         "Cannot accept MSRP connection without a TLS certificate"
                     )
                 self.msrp_connector = DirectAcceptor(logger=logger)
                 self.local_role = 'passive'
         else:
             if self.session.account.msrp.connection_model == 'relay':
                 if not outgoing and self.remote_role in ('actpass',
                                                          'passive'):
                     # 'passive' not allowed by the RFC but play nice for interoperability. -Saul
                     self.msrp_connector = DirectConnector(
                         logger=logger, use_sessmatch=True)
                     self.local_role = 'active'
                 elif outgoing and not self.session.account.nat_traversal.use_msrp_relay_for_outbound:
                     self.msrp_connector = DirectConnector(
                         logger=logger, use_sessmatch=True)
                     self.local_role = 'active'
                 else:
                     if self.session.account.nat_traversal.msrp_relay is None:
                         relay_host = relay_port = None
                     else:
                         if self.transport != self.session.account.nat_traversal.msrp_relay.transport:
                             raise MSRPStreamError(
                                 "MSRP relay transport conflicts with MSRP transport setting"
                             )
                         relay_host = self.session.account.nat_traversal.msrp_relay.host
                         relay_port = self.session.account.nat_traversal.msrp_relay.port
                     relay = MSRPRelaySettings(
                         domain=self.session.account.uri.host.decode(),
                         username=self.session.account.uri.user.decode(),
                         password=self.session.account.credentials.password.
                         decode(),
                         host=relay_host,
                         port=relay_port,
                         use_tls=self.transport == 'tls')
                     self.msrp_connector = RelayConnection(
                         relay,
                         'passive',
                         logger=logger,
                         use_sessmatch=True)
                     self.local_role = 'actpass' if outgoing else 'passive'
             else:
                 if not outgoing and self.remote_role in ('actpass',
                                                          'passive'):
                     # 'passive' not allowed by the RFC but play nice for interoperability. -Saul
                     self.msrp_connector = DirectConnector(
                         logger=logger, use_sessmatch=True)
                     self.local_role = 'active'
                 else:
                     if not outgoing and self.transport == 'tls' and settings.tls.certificate is None:
                         raise MSRPStreamError(
                             "Cannot accept MSRP connection without a TLS certificate"
                         )
                     self.msrp_connector = DirectAcceptor(
                         logger=logger, use_sessmatch=True)
                     self.local_role = 'actpass' if outgoing else 'passive'
         full_local_path = self.msrp_connector.prepare(local_uri=URI(
             host=host.default_ip,
             port=0,
             use_tls=self.transport == 'tls',
             credentials=self.session.account.tls_credentials))
         self.local_media = self._create_local_media(full_local_path)
     except (CertificateError, CertificateAuthorityError,
             CertificateExpiredError, CertificateSecurityError,
             CertificateRevokedError) as e:
         reason = "%s for %s" % (e.error, e.certificate.subject.CN.lower())
         notification_center.post_notification(
             'MediaStreamDidNotInitialize',
             sender=self,
             data=NotificationData(
                 reason=reason,
                 transport=self.transport,
                 credentials=self.session.account.tls_credentials))
     except Exception as e:
         notification_center.post_notification(
             'MediaStreamDidNotInitialize',
             sender=self,
             data=NotificationData(
                 reason=str(e),
                 transport=self.transport,
                 credentials=self.session.account.tls_credentials))
     else:
         notification_center.post_notification('MediaStreamDidInitialize',
                                               sender=self)
     finally:
         self._initialize_done = True
         self.greenlet = None