new GUI to start audio and video sessions. TODO: ability to add/remove audio/video content to an existing session

This commit is contained in:
Yann Leboulanger 2009-09-25 13:52:44 +02:00
parent d7560ed764
commit 32965a948e
3 changed files with 157 additions and 74 deletions

View file

@ -102,7 +102,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkImage" id="audio_image"> <widget class="GtkImage" id="audio_banner_image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="stock">None</property> <property name="stock">None</property>
<property name="icon-size">1</property> <property name="icon-size">1</property>
@ -333,15 +333,13 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkButton" id="start_audio_button"> <widget class="GtkToggleButton" id="audio_togglebutton">
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="no_show_all">True</property> <property name="tooltip" translatable="yes">Toggle audio session</property>
<property name="tooltip" translatable="yes">Start audio session</property>
<property name="relief">none</property> <property name="relief">none</property>
<signal name="activate" handler="on_start_audio_button_activate"/>
<child> <child>
<widget class="GtkImage" id="start_audio_image"> <widget class="GtkImage" id="audio_image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="stock">gtk-missing-image</property> <property name="stock">gtk-missing-image</property>
<property name="icon-size">1</property> <property name="icon-size">1</property>
@ -354,15 +352,13 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkButton" id="stop_audio_button"> <widget class="GtkToggleButton" id="video_togglebutton">
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="no_show_all">True</property> <property name="tooltip" translatable="yes">Toggle video session</property>
<property name="tooltip" translatable="yes">Stop audio session</property>
<property name="relief">none</property> <property name="relief">none</property>
<signal name="activate" handler="on_stop_audio_button_activate"/>
<child> <child>
<widget class="GtkImage" id="stop_audio_image"> <widget class="GtkImage" id="video_image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="stock">gtk-missing-image</property> <property name="stock">gtk-missing-image</property>
<property name="icon-size">1</property> <property name="icon-size">1</property>

View file

@ -1167,12 +1167,12 @@ class ChatControlBase(MessageControl, CommonCommands):
class ChatControl(ChatControlBase, ChatCommands): class ChatControl(ChatControlBase, ChatCommands):
'''A control for standard 1-1 chat''' '''A control for standard 1-1 chat'''
( (
AUDIO_STATE_NOT_AVAILABLE, JINGLE_STATE_NOT_AVAILABLE,
AUDIO_STATE_AVAILABLE, JINGLE_STATE_AVAILABLE,
AUDIO_STATE_CONNECTING, JINGLE_STATE_CONNECTING,
AUDIO_STATE_CONNECTION_RECEIVED, JINGLE_STATE_CONNECTION_RECEIVED,
AUDIO_STATE_CONNECTED, JINGLE_STATE_CONNECTED,
AUDIO_STATE_ERROR JINGLE_STATE_ERROR
) = range(6) ) = range(6)
TYPE_ID = message_control.TYPE_CHAT TYPE_ID = message_control.TYPE_CHAT
@ -1200,15 +1200,13 @@ class ChatControl(ChatControlBase, ChatCommands):
self._on_add_to_roster_menuitem_activate) self._on_add_to_roster_menuitem_activate)
self.handlers[id_] = self._add_to_roster_button self.handlers[id_] = self._add_to_roster_button
self._start_audio_button = self.xml.get_widget('start_audio_button') self._audio_button = self.xml.get_widget('audio_togglebutton')
id_ = self._start_audio_button.connect('clicked', id_ = self._audio_button.connect('toggled', self.on_audio_button_toggled)
self.on_start_audio_button_activate) self.handlers[id_] = self._audio_button
self.handlers[id_] = self._start_audio_button
self._stop_audio_button = self.xml.get_widget('stop_audio_button') self._video_button = self.xml.get_widget('video_togglebutton')
id_ = self._stop_audio_button.connect('clicked', id_ = self._video_button.connect('toggled', self.on_video_button_toggled)
self.on_stop_audio_button_activate) self.handlers[id_] = self._video_button
self.handlers[id_] = self._stop_audio_button
self._send_file_button = self.xml.get_widget('send_file_button') self._send_file_button = self.xml.get_widget('send_file_button')
# add a special img for send file button # add a special img for send file button
@ -1252,13 +1250,20 @@ class ChatControl(ChatControlBase, ChatCommands):
img.set_from_pixbuf(gtkgui_helpers.load_icon( img.set_from_pixbuf(gtkgui_helpers.load_icon(
'muc_active').get_pixbuf()) 'muc_active').get_pixbuf())
self._audio_image = self.xml.get_widget('audio_image') self._audio_banner_image = self.xml.get_widget('audio_banner_image')
self._video_banner_image = self.xml.get_widget('video_banner_image')
if gajim.capscache.is_supported(contact, NS_JINGLE_RTP_AUDIO) and \ if gajim.capscache.is_supported(contact, NS_JINGLE_RTP_AUDIO) and \
gajim.HAVE_FARSIGHT: gajim.HAVE_FARSIGHT:
self.set_audio_state('available') self.set_audio_state('available')
else: else:
self.set_audio_state('not_available') 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.audio_sid = None self.audio_sid = None
self.video_sid = None
self.update_toolbar() self.update_toolbar()
@ -1369,18 +1374,16 @@ class ChatControl(ChatControlBase, ChatCommands):
self._add_to_roster_button.hide() self._add_to_roster_button.hide()
# Audio buttons # Audio buttons
if self.audio_state == self.AUDIO_STATE_NOT_AVAILABLE: if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE:
self._start_audio_button.show() self._audio_button.set_sensitive(False)
self._start_audio_button.set_sensitive(False)
self._stop_audio_button.hide()
elif self.audio_state in (self.AUDIO_STATE_AVAILABLE,
self.AUDIO_STATE_ERROR):
self._start_audio_button.show()
self._start_audio_button.set_sensitive(True)
self._stop_audio_button.hide()
else: else:
self._start_audio_button.hide() self._audio_button.set_sensitive(True)
self._stop_audio_button.show()
# Video buttons
if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE:
self._video_button.set_sensitive(False)
else:
self._video_button.set_sensitive(True)
# Send file # Send file
if gajim.capscache.is_supported(self.contact, NS_FILE) and \ if gajim.capscache.is_supported(self.contact, NS_FILE) and \
@ -1515,19 +1518,35 @@ class ChatControl(ChatControlBase, ChatCommands):
self._tune_image.hide() self._tune_image.hide()
def update_audio(self): def update_audio(self):
if self.audio_state in (self.AUDIO_STATE_NOT_AVAILABLE, if self.audio_state in (self.JINGLE_STATE_NOT_AVAILABLE,
self.AUDIO_STATE_AVAILABLE): self.JINGLE_STATE_AVAILABLE):
self._audio_image.hide() self._audio_banner_image.hide()
else: else:
self._audio_image.show() self._audio_banner_image.show()
if self.audio_state == self.AUDIO_STATE_CONNECTING: if self.audio_state == self.JINGLE_STATE_CONNECTING:
self._audio_image.set_from_stock(gtk.STOCK_CONVERT, 1) self._audio_banner_image.set_from_stock(gtk.STOCK_CONVERT, 1)
elif self.audio_state == self.AUDIO_STATE_CONNECTION_RECEIVED: elif self.audio_state == self.JINGLE_STATE_CONNECTION_RECEIVED:
self._audio_image.set_from_stock(gtk.STOCK_NETWORK, 1) self._audio_banner_image.set_from_stock(gtk.STOCK_NETWORK, 1)
elif self.audio_state == self.AUDIO_STATE_CONNECTED: elif self.audio_state == self.JINGLE_STATE_CONNECTED:
self._audio_image.set_from_stock(gtk.STOCK_CONNECT, 1) self._audio_banner_image.set_from_stock(gtk.STOCK_CONNECT, 1)
elif self.audio_state == self.AUDIO_STATE_ERROR: elif self.audio_state == self.JINGLE_STATE_ERROR:
self._audio_image.set_from_stock(gtk.STOCK_DIALOG_WARNING, 1) self._audio_banner_image.set_from_stock(gtk.STOCK_DIALOG_WARNING, 1)
self.update_toolbar()
def update_video(self):
if self.video_state in (self.JINGLE_STATE_NOT_AVAILABLE,
self.JINGLE_STATE_AVAILABLE):
self._video_banner_image.hide()
else:
self._video_banner_image.show()
if self.video_state == self.JINGLE_STATE_CONNECTING:
self._video_banner_image.set_from_stock(gtk.STOCK_CONVERT, 1)
elif self.video_state == self.JINGLE_STATE_CONNECTION_RECEIVED:
self._video_banner_image.set_from_stock(gtk.STOCK_NETWORK, 1)
elif self.video_state == self.JINGLE_STATE_CONNECTED:
self._video_banner_image.set_from_stock(gtk.STOCK_CONNECT, 1)
elif self.video_state == self.JINGLE_STATE_ERROR:
self._video_banner_image.set_from_stock(gtk.STOCK_DIALOG_WARNING, 1)
self.update_toolbar() self.update_toolbar()
def change_resource(self, resource): def change_resource(self, resource):
@ -1550,26 +1569,53 @@ class ChatControl(ChatControlBase, ChatCommands):
str += ', ' + _('reason: %s') % reason str += ', ' + _('reason: %s') % reason
self.print_conversation(str, 'info') self.print_conversation(str, 'info')
if state == 'not_available': if state == 'not_available':
self.audio_state = self.AUDIO_STATE_NOT_AVAILABLE self.audio_state = self.JINGLE_STATE_NOT_AVAILABLE
self.audio_sid = None self.audio_sid = None
elif state == 'available': elif state == 'available':
self.audio_state = self.AUDIO_STATE_AVAILABLE self.audio_state = self.JINGLE_STATE_AVAILABLE
self.audio_sid = None self.audio_sid = None
elif state == 'connecting': elif state == 'connecting':
self.audio_state = self.AUDIO_STATE_CONNECTING self.audio_state = self.JINGLE_STATE_CONNECTING
self.audio_sid = sid self.audio_sid = sid
elif state == 'connection_received': elif state == 'connection_received':
self.audio_state = self.AUDIO_STATE_CONNECTION_RECEIVED self.audio_state = self.JINGLE_STATE_CONNECTION_RECEIVED
self.audio_sid = sid self.audio_sid = sid
elif state == 'connected': elif state == 'connected':
self.audio_state = self.AUDIO_STATE_CONNECTED self.audio_state = self.JINGLE_STATE_CONNECTED
elif state == 'stop': elif state == 'stop':
self.audio_state = self.AUDIO_STATE_AVAILABLE self.audio_state = self.JINGLE_STATE_AVAILABLE
self.audio_sid = None self.audio_sid = None
elif state == 'error': elif state == 'error':
self.audio_state = self.AUDIO_STATE_ERROR self.audio_state = self.JINGLE_STATE_ERROR
self.update_audio() self.update_audio()
def set_video_state(self, state, sid=None, reason=None):
if state in ('connecting', 'connected', 'stop'):
str = _('Video state : %s') % state
if reason:
str += ', ' + _('reason: %s') % reason
self.print_conversation(str, 'info')
if state == 'not_available':
self.video_state = self.JINGLE_STATE_NOT_AVAILABLE
self.video_sid = None
elif state == 'available':
self.video_state = self.JINGLE_STATE_AVAILABLE
self.video_sid = None
elif state == 'connecting':
self.video_state = self.JINGLE_STATE_CONNECTING
self.video_sid = sid
elif state == 'connection_received':
self.video_state = self.JINGLE_STATE_CONNECTION_RECEIVED
self.video_sid = sid
elif state == 'connected':
self.video_state = self.JINGLE_STATE_CONNECTED
elif state == 'stop':
self.video_state = self.JINGLE_STATE_AVAILABLE
self.video_sid = None
elif state == 'error':
self.video_state = self.JINGLE_STATE_ERROR
self.update_video()
def on_avatar_eventbox_enter_notify_event(self, widget, event): def on_avatar_eventbox_enter_notify_event(self, widget, event):
''' '''
we enter the eventbox area so we under conditions add a timeout we enter the eventbox area so we under conditions add a timeout
@ -1770,15 +1816,28 @@ class ChatControl(ChatControlBase, ChatCommands):
banner_name_label.set_markup(label_text) banner_name_label.set_markup(label_text)
banner_name_tooltip.set_tip(banner_name_label, label_tooltip) banner_name_tooltip.set_tip(banner_name_label, label_tooltip)
def on_start_audio_button_activate(self, *things): def on_audio_button_toggled(self, widget):
sid = gajim.connections[self.account].startVoIP(self.contact.get_full_jid( if widget.get_active():
)) sid = gajim.connections[self.account].startVoIP(
self.contact.get_full_jid())
self.set_audio_state('connecting', sid) self.set_audio_state('connecting', sid)
else:
def on_stop_audio_button_activate(self, *things):
session = gajim.connections[self.account].get_jingle_session( session = gajim.connections[self.account].get_jingle_session(
self.contact.get_full_jid(), self.audio_sid) self.contact.get_full_jid(), self.audio_sid)
if session: if session:
# TODO: end only audio
session.end_session()
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)
else:
session = gajim.connections[self.account].get_jingle_session(
self.contact.get_full_jid(), self.video_sid)
if session:
# TODO: end only video
session.end_session() session.end_session()
def _toggle_gpg(self): def _toggle_gpg(self):

View file

@ -953,14 +953,42 @@ class ConnectionJingle(object):
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
def startVoIP(self, jid): def startVoIP(self, jid):
jingle = self.get_jingle_session(jid, media='video')
if jingle:
jingle.add_content('voice', JingleVoIP(jingle))
else:
jingle = JingleSession(self, weinitiate=True, jid=jid) jingle = JingleSession(self, weinitiate=True, jid=jid)
self.add_jingle(jingle) self.add_jingle(jingle)
jingle.add_content('voice', JingleVoIP(jingle)) jingle.add_content('voice', JingleVoIP(jingle))
jingle.start_session() jingle.start_session()
return jingle.sid return jingle.sid
def get_jingle_session(self, jid, sid): def startVideoIP(self, jid):
try: jingle = self.get_jingle_session(jid, media='audio')
if jingle:
jingle.add_content('video', JingleVideo(jingle))
else:
jingle = JingleSession(self, weinitiate=True, jid=jid)
self.add_jingle(jingle)
jingle.add_content('video', JingleVideo(jingle))
jingle.start_session()
return jingle.sid
def get_jingle_session(self, jid, sid=None, media=None):
if sid:
if (jid, sid) in self.__sessions:
return self.__sessions[(jid, sid)] return self.__sessions[(jid, sid)]
except KeyError: else:
return None
elif media:
if media == 'audio':
cls = JingleVoIP
elif media == 'video':
cls = JingleVideo
else:
return None
for session in self.__sessions.values():
for content in session.contents.values():
if isinstance(content, cls):
return session
return None return None