ability to see out own video in the same time we send it and show both outging and incoming videos inside chat control
This commit is contained in:
parent
6879730568
commit
c88522e5de
File diff suppressed because it is too large
Load Diff
|
@ -2174,7 +2174,7 @@ $T will be replaced by auto-not-available timeout</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTable" id="table8">
|
<object class="GtkTable" id="table8">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="n_rows">4</property>
|
<property name="n_rows">5</property>
|
||||||
<property name="n_columns">2</property>
|
<property name="n_columns">2</property>
|
||||||
<property name="column_spacing">6</property>
|
<property name="column_spacing">6</property>
|
||||||
<property name="row_spacing">6</property>
|
<property name="row_spacing">6</property>
|
||||||
|
@ -2270,6 +2270,21 @@ $T will be replaced by auto-not-available timeout</property>
|
||||||
<property name="bottom_attach">4</property>
|
<property name="bottom_attach">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="video_see_self_checkbutton">
|
||||||
|
<property name="label" translatable="yes">View own video source</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="on_video_see_self_checkbutton_toggled"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
<property name="bottom_attach">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -2151,10 +2151,27 @@ class ChatControl(ChatControlBase):
|
||||||
if widget.get_active():
|
if widget.get_active():
|
||||||
if getattr(self, jingle_type + '_state') == \
|
if getattr(self, jingle_type + '_state') == \
|
||||||
self.JINGLE_STATE_NULL:
|
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())
|
'start_' + jingle_type)(self.contact.get_full_jid())
|
||||||
getattr(self, 'set_' + jingle_type + '_state')('connecting', sid)
|
getattr(self, 'set_' + jingle_type + '_state')('connecting', sid)
|
||||||
else:
|
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)
|
self.close_jingle_content(jingle_type)
|
||||||
|
|
||||||
img = getattr(self, '_' + jingle_type + '_button').get_property('image')
|
img = getattr(self, '_' + jingle_type + '_button').get_property('image')
|
||||||
|
|
|
@ -305,6 +305,7 @@ class Config:
|
||||||
'video_output_device': [opt_str, 'autovideosink'],
|
'video_output_device': [opt_str, 'autovideosink'],
|
||||||
'video_framerate': [opt_str, '', _('Optionally fix jingle output video framerate. Example: 10/1 or 25/2')],
|
'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_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_input_volume': [opt_int, 50],
|
||||||
'audio_output_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.')],
|
'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.')],
|
||||||
|
|
|
@ -120,16 +120,18 @@ class ConnectionJingle(object):
|
||||||
jingle.start_session()
|
jingle.start_session()
|
||||||
return jingle.sid
|
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'):
|
if self.get_jingle_session(jid, media='video'):
|
||||||
return self.get_jingle_session(jid, media='video').sid
|
return self.get_jingle_session(jid, media='video').sid
|
||||||
jingle = self.get_jingle_session(jid, media='audio')
|
jingle = self.get_jingle_session(jid, media='audio')
|
||||||
if jingle:
|
if jingle:
|
||||||
jingle.add_content('video', JingleVideo(jingle))
|
jingle.add_content('video', JingleVideo(jingle, in_xid=in_xid,
|
||||||
|
out_xid=out_xid))
|
||||||
else:
|
else:
|
||||||
jingle = JingleSession(self, weinitiate=True, jid=jid)
|
jingle = JingleSession(self, weinitiate=True, jid=jid)
|
||||||
self._sessions[jingle.sid] = jingle
|
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()
|
jingle.start_session()
|
||||||
return jingle.sid
|
return jingle.sid
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import socket
|
||||||
|
|
||||||
import nbxmpp
|
import nbxmpp
|
||||||
import farstream, gst
|
import farstream, gst
|
||||||
|
import gst.interfaces
|
||||||
from glib import GError
|
from glib import GError
|
||||||
|
|
||||||
import gajim
|
import gajim
|
||||||
|
@ -63,6 +64,7 @@ class JingleRTPContent(JingleContent):
|
||||||
# pipeline and bus
|
# pipeline and bus
|
||||||
self.pipeline = gst.Pipeline()
|
self.pipeline = gst.Pipeline()
|
||||||
bus = self.pipeline.get_bus()
|
bus = self.pipeline.get_bus()
|
||||||
|
bus.enable_sync_message_emission()
|
||||||
bus.add_signal_watch()
|
bus.add_signal_watch()
|
||||||
bus.connect('message', self._on_gst_message)
|
bus.connect('message', self._on_gst_message)
|
||||||
|
|
||||||
|
@ -366,8 +368,11 @@ class JingleAudio(JingleRTPContent):
|
||||||
|
|
||||||
|
|
||||||
class JingleVideo(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)
|
JingleRTPContent.__init__(self, session, 'video', transport)
|
||||||
|
self.in_xid = in_xid
|
||||||
|
self.out_xid = out_xid
|
||||||
|
self.out_xid_set = False
|
||||||
self.setup_stream()
|
self.setup_stream()
|
||||||
|
|
||||||
def setup_stream(self):
|
def setup_stream(self):
|
||||||
|
@ -375,6 +380,8 @@ class JingleVideo(JingleRTPContent):
|
||||||
# sometimes, one window won't show up,
|
# sometimes, one window won't show up,
|
||||||
# sometimes it'll freeze...
|
# sometimes it'll freeze...
|
||||||
JingleRTPContent.setup_stream(self, self._on_src_pad_added)
|
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
|
# the local parts
|
||||||
if gajim.config.get('video_framerate'):
|
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)
|
video_size = 'video/x-raw-yuv,width=%s,height=%s ! ' % (w, h)
|
||||||
else:
|
else:
|
||||||
video_size = ''
|
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',
|
self.src_bin = self.make_bin_from_config('video_input_device',
|
||||||
'%%s ! %svideoscale ! %sffmpegcolorspace' % (framerate, video_size),
|
'%%s %s! %svideoscale ! %sffmpegcolorspace' % (tee, framerate,
|
||||||
_("video input"))
|
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'))
|
|
||||||
|
|
||||||
self.pipeline.add(self.src_bin)#, caps)
|
self.pipeline.add(self.src_bin)#, caps)
|
||||||
|
self.pipeline.set_state(gst.STATE_PLAYING)
|
||||||
#src_bin.link(caps)
|
#src_bin.link(caps)
|
||||||
|
|
||||||
self.sink = self.make_bin_from_config('video_output_device',
|
self.sink = self.make_bin_from_config('video_output_device',
|
||||||
'videoscale ! ffmpegcolorspace ! %s force-aspect-ratio=True',
|
'videoscale ! ffmpegcolorspace ! %s',
|
||||||
_("video output"))
|
_("video output"))
|
||||||
self.pipeline.add(self.sink)
|
self.pipeline.add(self.sink)
|
||||||
|
|
||||||
|
@ -410,11 +425,27 @@ class JingleVideo(JingleRTPContent):
|
||||||
# The following is needed for farstream to process ICE requests:
|
# The following is needed for farstream to process ICE requests:
|
||||||
self.pipeline.set_state(gst.STATE_PLAYING)
|
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):
|
def get_fallback_src(self):
|
||||||
# TODO: Use avatar?
|
# TODO: Use avatar?
|
||||||
pipeline = 'videotestsrc is-live=true ! video/x-raw-yuv,framerate=10/1 ! ffmpegcolorspace'
|
pipeline = 'videotestsrc is-live=true ! video/x-raw-yuv,framerate=10/1 ! ffmpegcolorspace'
|
||||||
return gst.parse_bin_from_description(pipeline, True)
|
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):
|
def get_content(desc):
|
||||||
if desc['media'] == 'audio':
|
if desc['media'] == 'audio':
|
||||||
return JingleAudio
|
return JingleAudio
|
||||||
|
|
|
@ -102,7 +102,7 @@ class VideoOutputManager(DeviceManager):
|
||||||
def detect(self):
|
def detect(self):
|
||||||
self.devices = {}
|
self.devices = {}
|
||||||
# Fake video output
|
# Fake video output
|
||||||
self.detect_element('fakesink', _('Fake audio output'))
|
self.detect_element('fakesink', _('Fake video output'))
|
||||||
# Auto sink
|
# Auto sink
|
||||||
self.detect_element('xvimagesink',
|
self.detect_element('xvimagesink',
|
||||||
_('X Window System (X11/XShm/Xv): %s'))
|
_('X Window System (X11/XShm/Xv): %s'))
|
||||||
|
|
|
@ -478,6 +478,8 @@ class PreferencesWindow:
|
||||||
'800x600': '800x600', '640x480': '640x480',
|
'800x600': '800x600', '640x480': '640x480',
|
||||||
'320x240': '320x240'}, 'video_size', key=lambda x: -1 if \
|
'320x240': '320x240'}, 'video_size', key=lambda x: -1 if \
|
||||||
not x[1] else int(x[0][:3]))
|
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:
|
else:
|
||||||
for opt_name in ('audio_input', 'audio_output', 'video_input',
|
for opt_name in ('audio_input', 'audio_output', 'video_input',
|
||||||
|
@ -1131,6 +1133,9 @@ class PreferencesWindow:
|
||||||
def on_video_size_combobox_changed(self, widget):
|
def on_video_size_combobox_changed(self, widget):
|
||||||
self.on_av_combobox_changed(widget, 'video_size')
|
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):
|
def on_stun_checkbutton_toggled(self, widget):
|
||||||
self.on_checkbutton_toggled(widget, 'use_stun_server',
|
self.on_checkbutton_toggled(widget, 'use_stun_server',
|
||||||
[self.xml.get_object('stun_server_entry')])
|
[self.xml.get_object('stun_server_entry')])
|
||||||
|
|
|
@ -73,7 +73,7 @@ demandimport.enable()
|
||||||
demandimport.ignore += ['gobject._gobject', 'libasyncns', 'i18n',
|
demandimport.ignore += ['gobject._gobject', 'libasyncns', 'i18n',
|
||||||
'logging.NullHandler', 'dbus.service', 'OpenSSL.SSL', 'OpenSSL.crypto',
|
'logging.NullHandler', 'dbus.service', 'OpenSSL.SSL', 'OpenSSL.crypto',
|
||||||
'common.sleepy', 'DLFCN', 'dl', 'xml.sax', 'xml.sax.handler', 'ic',
|
'common.sleepy', 'DLFCN', 'dl', 'xml.sax', 'xml.sax.handler', 'ic',
|
||||||
'Crypto.PublicKey', 'IPython']
|
'Crypto.PublicKey', 'IPython', 'gst.interfaces']
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
import locale
|
import locale
|
||||||
|
|
Loading…
Reference in New Issue