diff --git a/data/gui/chat_control.ui b/data/gui/chat_control.ui
index e1ea08927..e5b8b1e40 100644
--- a/data/gui/chat_control.ui
+++ b/data/gui/chat_control.ui
@@ -12,111 +12,171 @@
vertical
1
-
-
-
+
+
@@ -727,8 +783,8 @@ audio-mic-volume-low
1
2
-
-
+
+
@@ -742,8 +798,8 @@ audio-mic-volume-low
2
3
-
-
+
+
@@ -757,8 +813,8 @@ audio-mic-volume-low
1
2
-
-
+
+
@@ -774,8 +830,8 @@ audio-mic-volume-low
2
1
2
-
-
+
+
@@ -791,8 +847,8 @@ audio-mic-volume-low
3
1
2
-
-
+
+
@@ -806,8 +862,8 @@ audio-mic-volume-low
2
3
-
-
+
+
@@ -823,8 +879,8 @@ audio-mic-volume-low
2
2
3
-
-
+
+
@@ -840,8 +896,8 @@ audio-mic-volume-low
3
2
3
-
-
+
+
@@ -855,8 +911,8 @@ audio-mic-volume-low
3
4
-
-
+
+
@@ -872,8 +928,8 @@ audio-mic-volume-low
2
3
4
-
-
+
+
@@ -889,8 +945,8 @@ audio-mic-volume-low
3
3
4
-
-
+
+
diff --git a/data/gui/preferences_window.ui b/data/gui/preferences_window.ui
index 0136e037b..16c118040 100644
--- a/data/gui/preferences_window.ui
+++ b/data/gui/preferences_window.ui
@@ -2174,7 +2174,7 @@ $T will be replaced by auto-not-available timeout
True
- 4
+ 5
2
6
6
@@ -2270,6 +2270,21 @@ $T will be replaced by auto-not-available timeout
4
+
+
+ View own video source
+ True
+ True
+ False
+ True
+
+
+
+ 2
+ 4
+ 5
+
+
diff --git a/src/chat_control.py b/src/chat_control.py
index 466ce7ba0..ddb2a916c 100644
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -2151,10 +2151,27 @@ class ChatControl(ChatControlBase):
if widget.get_active():
if getattr(self, jingle_type + '_state') == \
self.JINGLE_STATE_NULL:
- sid = getattr(gajim.connections[self.account],
+ if jingle_type == 'video':
+ video_hbox = self.xml.get_object('video_hbox')
+ video_hbox.set_no_show_all(False)
+ if gajim.config.get('video_see_self'):
+ fixed = self.xml.get_object('outgoing_fixed')
+ fixed.set_no_show_all(False)
+ video_hbox.show_all()
+ in_xid = self.xml.get_object('incoming_drawingarea').window.xid
+ out_xid = self.xml.get_object('outgoing_drawingarea').window.xid
+ sid = gajim.connections[self.account].start_video(
+ self.contact.get_full_jid(), in_xid, out_xid)
+ else:
+ sid = getattr(gajim.connections[self.account],
'start_' + jingle_type)(self.contact.get_full_jid())
getattr(self, 'set_' + jingle_type + '_state')('connecting', sid)
else:
+ video_hbox = self.xml.get_object('video_hbox')
+ video_hbox.set_no_show_all(True)
+ video_hbox.hide()
+ fixed = self.xml.get_object('outgoing_fixed')
+ fixed.set_no_show_all(True)
self.close_jingle_content(jingle_type)
img = getattr(self, '_' + jingle_type + '_button').get_property('image')
diff --git a/src/common/config.py b/src/common/config.py
index 928912f9e..addbd3b63 100644
--- a/src/common/config.py
+++ b/src/common/config.py
@@ -305,6 +305,7 @@ class Config:
'video_output_device': [opt_str, 'autovideosink'],
'video_framerate': [opt_str, '', _('Optionally fix jingle output video framerate. Example: 10/1 or 25/2')],
'video_size': [opt_str, '', _('Optionally resize jingle output video. Example: 320x240')],
+ 'video_see_self': [opt_bool, True, _('If True, You will also see your webcam')],
'audio_input_volume': [opt_int, 50],
'audio_output_volume': [opt_int, 50],
'use_stun_server': [opt_bool, False, _('If True, Gajim will try to use a STUN server when using jingle. The one in "stun_server" option, or the one given by the jabber server.')],
diff --git a/src/common/jingle.py b/src/common/jingle.py
index 57e26c3b1..0bb0b9d48 100644
--- a/src/common/jingle.py
+++ b/src/common/jingle.py
@@ -120,16 +120,18 @@ class ConnectionJingle(object):
jingle.start_session()
return jingle.sid
- def start_video(self, jid):
+ def start_video(self, jid, in_xid, out_xid):
if self.get_jingle_session(jid, media='video'):
return self.get_jingle_session(jid, media='video').sid
jingle = self.get_jingle_session(jid, media='audio')
if jingle:
- jingle.add_content('video', JingleVideo(jingle))
+ jingle.add_content('video', JingleVideo(jingle, in_xid=in_xid,
+ out_xid=out_xid))
else:
jingle = JingleSession(self, weinitiate=True, jid=jid)
self._sessions[jingle.sid] = jingle
- jingle.add_content('video', JingleVideo(jingle))
+ jingle.add_content('video', JingleVideo(jingle, in_xid=in_xid,
+ out_xid=out_xid))
jingle.start_session()
return jingle.sid
diff --git a/src/common/jingle_rtp.py b/src/common/jingle_rtp.py
index 44b0a22fa..1691e2097 100644
--- a/src/common/jingle_rtp.py
+++ b/src/common/jingle_rtp.py
@@ -22,6 +22,7 @@ import socket
import nbxmpp
import farstream, gst
+import gst.interfaces
from glib import GError
import gajim
@@ -63,6 +64,7 @@ class JingleRTPContent(JingleContent):
# pipeline and bus
self.pipeline = gst.Pipeline()
bus = self.pipeline.get_bus()
+ bus.enable_sync_message_emission()
bus.add_signal_watch()
bus.connect('message', self._on_gst_message)
@@ -366,8 +368,11 @@ class JingleAudio(JingleRTPContent):
class JingleVideo(JingleRTPContent):
- def __init__(self, session, transport=None):
+ def __init__(self, session, transport=None, in_xid=0, out_xid=0):
JingleRTPContent.__init__(self, session, 'video', transport)
+ self.in_xid = in_xid
+ self.out_xid = out_xid
+ self.out_xid_set = False
self.setup_stream()
def setup_stream(self):
@@ -375,6 +380,8 @@ class JingleVideo(JingleRTPContent):
# sometimes, one window won't show up,
# sometimes it'll freeze...
JingleRTPContent.setup_stream(self, self._on_src_pad_added)
+ bus = self.pipeline.get_bus()
+ bus.connect('sync-message::element', self._on_sync_message)
# the local parts
if gajim.config.get('video_framerate'):
@@ -390,17 +397,25 @@ class JingleVideo(JingleRTPContent):
video_size = 'video/x-raw-yuv,width=%s,height=%s ! ' % (w, h)
else:
video_size = ''
+ if gajim.config.get('video_see_self'):
+ tee = '! tee name=t ! queue ! videoscale ! ' + \
+ 'video/x-raw-yuv,width=160,height=120 ! ffmpegcolorspace ! ' + \
+ '%s t. ! queue ' % gajim.config.get(
+ 'video_output_device')
+ else:
+ tee = ''
+
self.src_bin = self.make_bin_from_config('video_input_device',
- '%%s ! %svideoscale ! %sffmpegcolorspace' % (framerate, video_size),
- _("video input"))
- #caps = gst.element_factory_make('capsfilter')
- #caps.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=320, height=240'))
+ '%%s %s! %svideoscale ! %sffmpegcolorspace' % (tee, framerate,
+ video_size), _("video input"))
+
self.pipeline.add(self.src_bin)#, caps)
+ self.pipeline.set_state(gst.STATE_PLAYING)
#src_bin.link(caps)
self.sink = self.make_bin_from_config('video_output_device',
- 'videoscale ! ffmpegcolorspace ! %s force-aspect-ratio=True',
+ 'videoscale ! ffmpegcolorspace ! %s',
_("video output"))
self.pipeline.add(self.sink)
@@ -410,11 +425,27 @@ class JingleVideo(JingleRTPContent):
# The following is needed for farstream to process ICE requests:
self.pipeline.set_state(gst.STATE_PLAYING)
+ def _on_sync_message(self, bus, message):
+ if message.structure is None:
+ return False
+ if message.structure.get_name() == 'prepare-xwindow-id':
+ message.src.set_property('force-aspect-ratio', True)
+ imagesink = message.src
+ if gajim.config.get('video_see_self') and not self.out_xid_set:
+ imagesink.set_xwindow_id(self.out_xid)
+ self.out_xid_set = True
+ else:
+ imagesink.set_xwindow_id(self.in_xid)
+
def get_fallback_src(self):
# TODO: Use avatar?
pipeline = 'videotestsrc is-live=true ! video/x-raw-yuv,framerate=10/1 ! ffmpegcolorspace'
return gst.parse_bin_from_description(pipeline, True)
+ def destroy(self):
+ JingleRTPContent.destroy(self)
+ self.pipeline.get_bus().disconnect_by_func(self._on_sync_message)
+
def get_content(desc):
if desc['media'] == 'audio':
return JingleAudio
diff --git a/src/common/multimedia_helpers.py b/src/common/multimedia_helpers.py
index 98a91a26a..59270f0d7 100644
--- a/src/common/multimedia_helpers.py
+++ b/src/common/multimedia_helpers.py
@@ -102,7 +102,7 @@ class VideoOutputManager(DeviceManager):
def detect(self):
self.devices = {}
# Fake video output
- self.detect_element('fakesink', _('Fake audio output'))
+ self.detect_element('fakesink', _('Fake video output'))
# Auto sink
self.detect_element('xvimagesink',
_('X Window System (X11/XShm/Xv): %s'))
diff --git a/src/config.py b/src/config.py
index 8a140ca00..ded12ffbb 100644
--- a/src/config.py
+++ b/src/config.py
@@ -478,6 +478,8 @@ class PreferencesWindow:
'800x600': '800x600', '640x480': '640x480',
'320x240': '320x240'}, 'video_size', key=lambda x: -1 if \
not x[1] else int(x[0][:3]))
+ st = gajim.config.get('video_see_self')
+ self.xml.get_object('video_see_self_checkbutton').set_active(st)
else:
for opt_name in ('audio_input', 'audio_output', 'video_input',
@@ -1131,6 +1133,9 @@ class PreferencesWindow:
def on_video_size_combobox_changed(self, widget):
self.on_av_combobox_changed(widget, 'video_size')
+ def on_video_see_self_checkbutton_toggled(self, widget):
+ self.on_checkbutton_toggled(widget, 'video_see_self')
+
def on_stun_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'use_stun_server',
[self.xml.get_object('stun_server_entry')])
diff --git a/src/gajim.py b/src/gajim.py
index 894d7186e..c66f1b964 100644
--- a/src/gajim.py
+++ b/src/gajim.py
@@ -73,7 +73,7 @@ demandimport.enable()
demandimport.ignore += ['gobject._gobject', 'libasyncns', 'i18n',
'logging.NullHandler', 'dbus.service', 'OpenSSL.SSL', 'OpenSSL.crypto',
'common.sleepy', 'DLFCN', 'dl', 'xml.sax', 'xml.sax.handler', 'ic',
- 'Crypto.PublicKey', 'IPython']
+ 'Crypto.PublicKey', 'IPython', 'gst.interfaces']
if os.name == 'nt':
import locale