From fbf9a769d88629c314e71c2b44bd4f905ad1c126 Mon Sep 17 00:00:00 2001 From: Thibaut GIRKA Date: Sun, 21 Mar 2010 21:45:45 +0100 Subject: [PATCH] Delete invalid jingle sessions. Kick audio/video availability from jingle states. Fixes #5668, #5651 --- src/chat_control.py | 81 ++++++++----------- src/command_system/implementation/standard.py | 6 +- src/common/jingle.py | 5 +- src/common/jingle_session.py | 2 - src/dialogs.py | 9 +++ src/gui_interface.py | 26 +++--- 6 files changed, 63 insertions(+), 66 deletions(-) diff --git a/src/chat_control.py b/src/chat_control.py index 10c128bc2..f8d7b0a9a 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -1259,13 +1259,12 @@ class ChatControl(ChatControlBase): A control for standard 1-1 chat """ ( - JINGLE_STATE_NOT_AVAILABLE, - JINGLE_STATE_AVAILABLE, + JINGLE_STATE_NULL, JINGLE_STATE_CONNECTING, JINGLE_STATE_CONNECTION_RECEIVED, JINGLE_STATE_CONNECTED, JINGLE_STATE_ERROR - ) = range(6) + ) = range(5) TYPE_ID = message_control.TYPE_CHAT old_msg_kind = None # last kind of the printed message @@ -1352,9 +1351,11 @@ class ChatControl(ChatControlBase): self._audio_banner_image = self.xml.get_object('audio_banner_image') self._video_banner_image = self.xml.get_object('video_banner_image') self.audio_sid = None - self.audio_state = self.JINGLE_STATE_NOT_AVAILABLE + self.audio_state = self.JINGLE_STATE_NULL + self.audio_available = False self.video_sid = None - self.video_state = self.JINGLE_STATE_NOT_AVAILABLE + self.video_state = self.JINGLE_STATE_NULL + self.video_available = False self.update_toolbar() @@ -1480,34 +1481,19 @@ class ChatControl(ChatControlBase): # Jingle detection if self.contact.supports(NS_JINGLE_ICE_UDP) and \ gajim.HAVE_FARSIGHT and self.contact.resource: - if self.contact.supports(NS_JINGLE_RTP_AUDIO): - if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: - self.set_audio_state('available') - else: - self.set_audio_state('not_available') - - if self.contact.supports(NS_JINGLE_RTP_VIDEO): - if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE: - self.set_video_state('available') - else: - self.set_video_state('not_available') + self.audio_available = self.contact.supports(NS_JINGLE_RTP_AUDIO) + self.video_available = self.contact.supports(NS_JINGLE_RTP_VIDEO) else: - if self.audio_state != self.JINGLE_STATE_NOT_AVAILABLE: - self.set_audio_state('not_available') - if self.video_state != self.JINGLE_STATE_NOT_AVAILABLE: - self.set_video_state('not_available') + if self.video_available or self.audio_available: + self.stop_jingle() + self.video_available = False + self.audio_available = False # Audio buttons - if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: - self._audio_button.set_sensitive(False) - else: - self._audio_button.set_sensitive(True) + self._audio_button.set_sensitive(self.audio_available) # Video buttons - if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE: - self._video_button.set_sensitive(False) - else: - self._video_button.set_sensitive(True) + self._video_button.set_sensitive(self.video_available) # Send file if self.contact.supports(NS_FILE) and self.contact.resource: @@ -1551,8 +1537,7 @@ class ChatControl(ChatControlBase): return banner_image = getattr(self, '_' + jingle_type + '_banner_image') state = getattr(self, jingle_type + '_state') - if state in (self.JINGLE_STATE_NOT_AVAILABLE, - self.JINGLE_STATE_AVAILABLE): + if state == self.JINGLE_STATE_NULL: banner_image.hide() else: banner_image.show() @@ -1604,24 +1589,29 @@ class ChatControl(ChatControlBase): # update MessageWindow._controls self.parent_win.change_jid(self.account, old_full_jid, new_full_jid) + def stop_jingle(self, sid=None, reason=None): + if self.audio_sid and sid in (self.audio_sid, None): + self.close_jingle_content('audio') + if self.video_sid and sid in (self.video_sid, None): + self.close_jingle_content('video') + + def _set_jingle_state(self, jingle_type, state, sid=None, reason=None): if jingle_type not in ('audio', 'video'): return - if state in ('connecting', 'connected', 'stop') and reason: + if state in ('connecting', 'connected', 'stop', 'error') and reason: str = _('%(type)s state : %(state)s, reason: %(reason)s') % { 'type': jingle_type.capitalize(), 'state': state, 'reason': reason} self.print_conversation(str, 'info') - states = {'not_available': self.JINGLE_STATE_NOT_AVAILABLE, - 'available': self.JINGLE_STATE_AVAILABLE, - 'connecting': self.JINGLE_STATE_CONNECTING, + states = {'connecting': self.JINGLE_STATE_CONNECTING, 'connection_received': self.JINGLE_STATE_CONNECTION_RECEIVED, 'connected': self.JINGLE_STATE_CONNECTED, - 'stop': self.JINGLE_STATE_AVAILABLE, + 'stop': self.JINGLE_STATE_NULL, 'error': self.JINGLE_STATE_ERROR} jingle_state = states[state] - if getattr(self, jingle_type + '_state') == jingle_state: + if getattr(self, jingle_type + '_state') == jingle_state or state == 'error': return if state == 'stop' and getattr(self, jingle_type + '_sid') not in (None, sid): @@ -1629,21 +1619,12 @@ class ChatControl(ChatControlBase): setattr(self, jingle_type + '_state', jingle_state) - # Destroy existing session with the user when he signs off - # We need to do that before modifying the sid - if state == 'not_available': - gajim.connections[self.account].delete_jingle_session( - getattr(self, jingle_type + '_sid')) - - if state in ('not_available', 'available', 'stop'): + if jingle_state == self.JINGLE_STATE_NULL: setattr(self, jingle_type + '_sid', None) if state in ('connection_received', 'connecting'): setattr(self, jingle_type + '_sid', sid) - if state in ('connecting', 'connected', 'connection_received'): - getattr(self, '_' + jingle_type + '_button').set_active(True) - elif state in ('not_available', 'stop'): - getattr(self, '_' + jingle_type + '_button').set_active(False) + getattr(self, '_' + jingle_type + '_button').set_active(jingle_state != self.JINGLE_STATE_NULL) getattr(self, 'update_' + jingle_type)() @@ -1892,12 +1873,16 @@ class ChatControl(ChatControlBase): sid = getattr(self, jingle_type + '_sid') if not sid: return + setattr(self, jingle_type + '_sid', None) + setattr(self, jingle_type + '_state', self.JINGLE_STATE_NULL) session = gajim.connections[self.account].get_jingle_session( self.contact.get_full_jid(), sid) if session: content = session.get_content(jingle_type) if content: session.remove_content(content.creator, content.name) + getattr(self, '_' + jingle_type + '_button').set_active(False) + getattr(self, 'update_' + jingle_type)() def on_jingle_button_toggled(self, widget, jingle_type): img_name = 'gajim-%s_%s' % ({'audio': 'mic', 'video': 'cam'}[jingle_type], @@ -1906,7 +1891,7 @@ class ChatControl(ChatControlBase): if widget.get_active(): if getattr(self, jingle_type + '_state') == \ - self.JINGLE_STATE_AVAILABLE: + self.JINGLE_STATE_NULL: sid = getattr(gajim.connections[self.account], 'start_' + jingle_type)(self.contact.get_full_jid()) getattr(self, 'set_' + jingle_type + '_state')('connecting', sid) diff --git a/src/command_system/implementation/standard.py b/src/command_system/implementation/standard.py index 68e41a00f..2b064610c 100644 --- a/src/command_system/implementation/standard.py +++ b/src/command_system/implementation/standard.py @@ -195,8 +195,8 @@ class StandardCommonChatCommands(CommandContainer): @command @doc(_("Toggle audio session")) def audio(self): - if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: - raise CommandError(_("Video sessions are not available")) + if not self.audio_available: + raise CommandError(_("Audio sessions are not available")) else: # A state of an audio session is toggled by inverting a state of the # appropriate button. @@ -206,7 +206,7 @@ class StandardCommonChatCommands(CommandContainer): @command @doc(_("Toggle video session")) def video(self): - if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE: + if not self.video_available: raise CommandError(_("Video sessions are not available")) else: # A state of a video session is toggled by inverting a state of the diff --git a/src/common/jingle.py b/src/common/jingle.py index edc933156..da2a5d031 100644 --- a/src/common/jingle.py +++ b/src/common/jingle.py @@ -33,7 +33,7 @@ Handles the jingle signalling protocol import xmpp import helpers -from jingle_session import JingleSession +from jingle_session import JingleSession, JingleStates from jingle_rtp import JingleAudio, JingleVideo @@ -92,6 +92,9 @@ class ConnectionJingle(object): # we already have such session in dispatcher... self.__sessions[sid].on_stanza(stanza) + # Delete invalid/unneeded sessions + if sid in self.__sessions and self.__sessions[sid].state == JingleStates.ended: + self.delete_jingle_session(sid) raise xmpp.NodeProcessed diff --git a/src/common/jingle_session.py b/src/common/jingle_session.py index df13dcc01..f756b5b7e 100644 --- a/src/common/jingle_session.py +++ b/src/common/jingle_session.py @@ -320,8 +320,6 @@ class JingleSession(object): xmpp_error = child.getName() self.__dispatch_error(xmpp_error, jingle_error, text) # FIXME: Not sure when we would want to do that... - if xmpp_error == 'item-not-found': - self.connection.delete_jingle_session(self.sid) def __on_transport_replace(self, stanza, jingle, error, action): for content in jingle.iterTags('content'): diff --git a/src/dialogs.py b/src/dialogs.py index 7bcb308fa..5c1ece1e4 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -4907,6 +4907,15 @@ class VoIPCallReceivedDialog(object): self.content_types.add(type_) self.set_secondary_text() + def remove_contents(self, content_types): + for type_ in content_types: + if type_ in self.content_types: + self.content_types.remove(type_) + if not self.content_types: + self.dialog.destroy() + else: + self.set_secondary_text() + def on_voip_call_received_messagedialog_destroy(self, dialog): if (self.fjid, self.sid) in self.instances: del self.instances[(self.fjid, self.sid)] diff --git a/src/gui_interface.py b/src/gui_interface.py index 7035b6999..81aeaca79 100644 --- a/src/gui_interface.py +++ b/src/gui_interface.py @@ -1810,9 +1810,8 @@ class Interface: if media in ('audio', 'video'): jid = gajim.get_jid_without_resource(peerjid) resource = gajim.get_resource_from_jid(peerjid) - ctrl = self.msg_win_mgr.get_control(peerjid, account) - if not ctrl: - ctrl = self.msg_win_mgr.get_control(jid, account) + ctrl = (self.msg_win_mgr.get_control(peerjid, account) + or self.msg_win_mgr.get_control(jid, account)) if ctrl: if media == 'audio': ctrl.set_audio_state('connected', sid) @@ -1824,26 +1823,29 @@ class Interface: peerjid, sid, media, reason = data jid = gajim.get_jid_without_resource(peerjid) resource = gajim.get_resource_from_jid(peerjid) - ctrl = self.msg_win_mgr.get_control(peerjid, account) - if not ctrl: - ctrl = self.msg_win_mgr.get_control(jid, account) + ctrl = (self.msg_win_mgr.get_control(peerjid, account) + or self.msg_win_mgr.get_control(jid, account)) if ctrl: - if media in ('audio', None): + if media is None: + ctrl.stop_jingle(sid=sid, reason=reason) + elif media == 'audio': ctrl.set_audio_state('stop', sid=sid, reason=reason) - if media in ('video', None): + elif media == 'video': ctrl.set_video_state('stop', sid=sid, reason=reason) dialog = dialogs.VoIPCallReceivedDialog.get_dialog(peerjid, sid) if dialog: - dialog.dialog.destroy() + if media is None: + dialog.dialog.destroy() + else: + dialog.remove_contents((media, )) def handle_event_jingle_error(self, account, data): # ('JINGLE_ERROR', account, (peerjid, sid, reason)) peerjid, sid, reason = data jid = gajim.get_jid_without_resource(peerjid) resource = gajim.get_resource_from_jid(peerjid) - ctrl = self.msg_win_mgr.get_control(peerjid, account) - if not ctrl: - ctrl = self.msg_win_mgr.get_control(jid, account) + ctrl = (self.msg_win_mgr.get_control(peerjid, account) + or self.msg_win_mgr.get_control(jid, account)) if ctrl: ctrl.set_audio_state('error', reason=reason)