From b2b8ac4b7680dd425ebe02a3002d4ded41705a00 Mon Sep 17 00:00:00 2001 From: Thibaut GIRKA Date: Sat, 3 Oct 2009 22:40:12 +0200 Subject: [PATCH] Connect only if user accepts, move jingle detection to 'update_toolbar' This allows jingle availability to be updated if contact sign in/out. This patch will also wait for user acceptance before connecting. This will, among other things, ensure that audio/video state won't be set to JINGLE_STATE_CONNECTING while the connection is already up. --- src/chat_control.py | 64 +++++++++++++++++++++++++++++--------------- src/common/jingle.py | 12 +++++++-- src/dialogs.py | 12 ++++++--- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/chat_control.py b/src/chat_control.py index ef77870ba..e66ff82ba 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -50,7 +50,7 @@ from common.logger import constants from common.pep import MOODS, ACTIVITIES from common.xmpp.protocol import NS_XHTML, NS_XHTML_IM, NS_FILE, NS_MUC from common.xmpp.protocol import NS_RECEIPTS, NS_ESESSION -from common.xmpp.protocol import NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO +from common.xmpp.protocol import NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO, NS_JINGLE_ICE_UDP from commands.implementation import CommonCommands, ChatCommands @@ -1256,16 +1256,6 @@ class ChatControl(ChatControlBase, ChatCommands): self.audio_state = self.JINGLE_STATE_NOT_AVAILABLE self.video_sid = None self.video_state = self.JINGLE_STATE_NOT_AVAILABLE - if gajim.capscache.is_supported(contact, NS_JINGLE_RTP_AUDIO) and \ - gajim.HAVE_FARSIGHT: - self.set_audio_state('available') - else: - self.set_audio_state('not_available') - if gajim.capscache.is_supported(contact, NS_JINGLE_RTP_VIDEO) and \ - gajim.HAVE_FARSIGHT: - self.set_video_state('available') - else: - self.set_video_state('not_available') self.update_toolbar() @@ -1375,6 +1365,26 @@ class ChatControl(ChatControlBase, ChatCommands): else: self._add_to_roster_button.hide() + # Jingle detection + if gajim.capscache.is_supported(self.contact, NS_JINGLE_ICE_UDP) and \ + gajim.HAVE_FARSIGHT and self.contact.resource: + if gajim.capscache.is_supported(self.contact, 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 gajim.capscache.is_supported(self.contact, 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') + 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') + # Audio buttons if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: self._audio_button.set_sensitive(False) @@ -1579,22 +1589,26 @@ class ChatControl(ChatControlBase, ChatCommands): elif state == 'connecting': self.audio_state = self.JINGLE_STATE_CONNECTING self.audio_sid = sid - self._audio_button.set_active(True) elif state == 'connection_received': self.audio_state = self.JINGLE_STATE_CONNECTION_RECEIVED self.audio_sid = sid - self._audio_button.set_active(True) elif state == 'connected': self.audio_state = self.JINGLE_STATE_CONNECTED elif state == 'stop': self.audio_state = self.JINGLE_STATE_AVAILABLE self.audio_sid = None - self._audio_button.set_active(False) elif state == 'error': self.audio_state = self.JINGLE_STATE_ERROR + + if state in ('connecting', 'connected', 'connection_received'): + self._audio_button.set_active(True) + elif state in ('not_available', 'stop'): + #TODO: Destroy existing session(s) with this user? + self._audio_button.set_active(False) self.update_audio() def set_video_state(self, state, sid=None, reason=None): + #TODO: Share code with set_audio_state? if state in ('connecting', 'connected', 'stop'): str = _('Video state : %s') % state if reason: @@ -1608,11 +1622,9 @@ class ChatControl(ChatControlBase, ChatCommands): self.video_sid = None elif state == 'connecting': self.video_state = self.JINGLE_STATE_CONNECTING - self._video_button.set_active(True) self.video_sid = sid elif state == 'connection_received': self.video_state = self.JINGLE_STATE_CONNECTION_RECEIVED - self._video_button.set_active(True) self.video_sid = sid elif state == 'connected': self.video_state = self.JINGLE_STATE_CONNECTED @@ -1622,6 +1634,12 @@ class ChatControl(ChatControlBase, ChatCommands): self._video_button.set_active(False) elif state == 'error': self.video_state = self.JINGLE_STATE_ERROR + + if state in ('connecting', 'connected', 'connection_received'): + self._video_button.set_active(True) + elif state in ('not_available', 'stop'): + #TODO: Destroy existing session(s) with this user? + self._video_button.set_active(False) self.update_video() def on_avatar_eventbox_enter_notify_event(self, widget, event): @@ -1826,9 +1844,10 @@ class ChatControl(ChatControlBase, ChatCommands): def on_audio_button_toggled(self, widget): if widget.get_active(): - sid = gajim.connections[self.account].startVoIP( - self.contact.get_full_jid()) - self.set_audio_state('connecting', sid) + if self.audio_state == self.JINGLE_STATE_AVAILABLE: + sid = gajim.connections[self.account].startVoIP( + self.contact.get_full_jid()) + self.set_audio_state('connecting', sid) else: session = gajim.connections[self.account].get_jingle_session( self.contact.get_full_jid(), self.audio_sid) @@ -1839,9 +1858,10 @@ class ChatControl(ChatControlBase, ChatCommands): def on_video_button_toggled(self, widget): if widget.get_active(): - sid = gajim.connections[self.account].startVideoIP( - self.contact.get_full_jid()) - self.set_video_state('connecting', sid) + if self.video_state == self.JINGLE_STATE_AVAILABLE: + sid = gajim.connections[self.account].startVideoIP( + self.contact.get_full_jid()) + self.set_video_state('connecting', sid) else: session = gajim.connections[self.account].get_jingle_session( self.contact.get_full_jid(), self.video_sid) diff --git a/src/common/jingle.py b/src/common/jingle.py index 417e024ab..7d79182fc 100644 --- a/src/common/jingle.py +++ b/src/common/jingle.py @@ -671,6 +671,7 @@ class JingleContent(object): self.accepted = False self.sent = False self.candidates = [] # Local transport candidates + self.remote_candidates = [] # Remote transport candidates self.senders = 'both' #FIXME self.allow_sending = True # Used for stream direction, attribute 'senders' @@ -750,8 +751,12 @@ class JingleContent(object): #FIXME: connectivity should not be etablished yet # Instead, it should be etablished after session-accept! if len(candidates) > 0: - self.p2pstream.set_remote_candidates(candidates) - print self.media, self.creator, self.name, candidates + if self.sent: + self.p2pstream.set_remote_candidates(candidates) + else: + self.remote_candidates.extend(candidates) + #self.p2pstream.set_remote_candidates(candidates) + #print self.media, self.creator, self.name, candidates def __content(self, payload=[]): ''' Build a XML content-wrapper for our data. ''' @@ -917,6 +922,9 @@ class JingleRTPContent(JingleContent): def __contentAcceptCB(self, stanza, content, error, action): if self.accepted: + if len(self.remote_candidates) > 0: + self.p2pstream.set_remote_candidates(self.remote_candidates) + self.remote_candidates = [] #TODO: farsight.DIRECTION_BOTH only if senders='both' self.p2pstream.set_property('direction', farsight.DIRECTION_BOTH) self.session.content_negociated(self.media) diff --git a/src/dialogs.py b/src/dialogs.py index 59f8cb42a..a93583aab 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -4518,10 +4518,7 @@ class VoIPCallReceivedDialog(object): if not session: return if response == gtk.RESPONSE_YES: - if not session.accepted: - session.approve_session() - for content in self.content_types: - session.approve_content(content) + #TODO: Ensure that ctrl.contact.resource == resource jid = gajim.get_jid_without_resource(self.fjid) resource = gajim.get_resource_from_jid(self.fjid) ctrl = gajim.interface.msg_win_mgr.get_control(self.fjid, self.account) @@ -4535,10 +4532,17 @@ class VoIPCallReceivedDialog(object): if not contact: return ctrl = gajim.interface.new_chat(contact, self.account) + # Chat control opened, update content's status if session.get_content('audio'): ctrl.set_audio_state('connecting', self.sid) if session.get_content('video'): ctrl.set_video_state('connecting', self.sid) + # Now, accept the content/sessions. + # This should be done after the chat control is running + if not session.accepted: + session.approve_session() + for content in self.content_types: + session.approve_content(content) else: # response==gtk.RESPONSE_NO if not session.accepted: session.decline_session()