Delete invalid jingle sessions. Kick audio/video availability from jingle states.

Fixes #5668, #5651
This commit is contained in:
Thibaut GIRKA 2010-03-21 21:45:45 +01:00
parent 8b497d64ec
commit fbf9a769d8
6 changed files with 63 additions and 66 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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'):

View File

@ -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)]

View File

@ -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)