Philipp Hörist pushed to branch master at gajim / gajim

Commits:

8 changed files:

Changes:

  • gajim/chat_control.py
    ... ... @@ -79,6 +79,20 @@ from gajim.command_system.implementation.hosts import ChatCommands
    79 79
     from gajim.command_system.framework import CommandHost  # pylint: disable=unused-import
    
    80 80
     from gajim.chat_control_base import ChatControlBase
    
    81 81
     
    
    82
    +
    
    83
    +class JingleState:
    
    84
    +    __slots__ = ('sid', 'state', 'available', 'banner_image', 'action', 'set_state', 'update')
    
    85
    +
    
    86
    +    def __init__(self, state, banner_image, set_state, update):
    
    87
    +        self.sid = None
    
    88
    +        self.state = state
    
    89
    +        self.available = False
    
    90
    +        self.banner_image = banner_image
    
    91
    +        self.action = None
    
    92
    +        self.set_state = set_state
    
    93
    +        self.update = update
    
    94
    +
    
    95
    +
    
    82 96
     ################################################################################
    
    83 97
     class ChatControl(ChatControlBase):
    
    84 98
         """
    
    ... ... @@ -126,12 +140,10 @@ class ChatControl(ChatControlBase):
    126 140
             # Settings menu
    
    127 141
             self.xml.settings_menu.set_menu_model(self.control_menu)
    
    128 142
     
    
    129
    -        self.audio_sid = None
    
    130
    -        self.audio_state = self.JINGLE_STATE_NULL
    
    131
    -        self.audio_available = False
    
    132
    -        self.video_sid = None
    
    133
    -        self.video_state = self.JINGLE_STATE_NULL
    
    134
    -        self.video_available = False
    
    143
    +        self.jingle = {
    
    144
    +            'audio': JingleState(self.JINGLE_STATE_NULL, self.xml.audio_banner_image, self.set_audio_state, self.update_audio),
    
    145
    +            'video': JingleState(self.JINGLE_STATE_NULL, self.xml.video_banner_image, self.set_video_state, self.update_video),
    
    146
    +        }
    
    135 147
     
    
    136 148
             self.update_toolbar()
    
    137 149
             self.update_all_pep_types()
    
    ... ... @@ -254,17 +266,19 @@ class ChatControl(ChatControlBase):
    254 266
                 act.connect("activate", func)
    
    255 267
                 self.parent_win.window.add_action(act)
    
    256 268
     
    
    257
    -        self.audio_action = Gio.SimpleAction.new_stateful(
    
    269
    +        audio = self.jingle['audio']
    
    270
    +        audio.action = Gio.SimpleAction.new_stateful(
    
    258 271
                 'toggle-audio-' + self.control_id, None,
    
    259 272
                 GLib.Variant.new_boolean(False))
    
    260
    -        self.audio_action.connect('change-state', self._on_audio)
    
    261
    -        self.parent_win.window.add_action(self.audio_action)
    
    273
    +        audio.action.connect('change-state', self._on_audio)
    
    274
    +        self.parent_win.window.add_action(audio.action)
    
    262 275
     
    
    263
    -        self.video_action = Gio.SimpleAction.new_stateful(
    
    276
    +        video = self.jingle['video']
    
    277
    +        video.action = Gio.SimpleAction.new_stateful(
    
    264 278
                 'toggle-video-' + self.control_id,
    
    265 279
                 None, GLib.Variant.new_boolean(False))
    
    266
    -        self.video_action.connect('change-state', self._on_video)
    
    267
    -        self.parent_win.window.add_action(self.video_action)
    
    280
    +        video.action.connect('change-state', self._on_video)
    
    281
    +        self.parent_win.window.add_action(video.action)
    
    268 282
     
    
    269 283
             default_chatstate = app.config.get('send_chatstate_default')
    
    270 284
             chatstate = app.config.get_per(
    
    ... ... @@ -294,11 +308,11 @@ class ChatControl(ChatControlBase):
    294 308
     
    
    295 309
             # Audio
    
    296 310
             win.lookup_action('toggle-audio-' + self.control_id).set_enabled(
    
    297
    -            online and self.audio_available)
    
    311
    +            online and self.jingle['audio'].available)
    
    298 312
     
    
    299 313
             # Video
    
    300 314
             win.lookup_action('toggle-video-' + self.control_id).set_enabled(
    
    301
    -            online and self.video_available)
    
    315
    +            online and self.jingle['video'].available)
    
    302 316
     
    
    303 317
             # Send file (HTTP File Upload)
    
    304 318
             httpupload = win.lookup_action(
    
    ... ... @@ -419,15 +433,17 @@ class ChatControl(ChatControlBase):
    419 433
                     _('This contact does not support HTML'))
    
    420 434
     
    
    421 435
             # Jingle detection
    
    436
    +        jingle_audio = self.jingle['audio']
    
    437
    +        jingle_video = self.jingle['video']
    
    422 438
             if self.contact.supports(NS_JINGLE_ICE_UDP) and \
    
    423 439
             app.is_installed('FARSTREAM') and self.contact.resource:
    
    424
    -            self.audio_available = self.contact.supports(NS_JINGLE_RTP_AUDIO)
    
    425
    -            self.video_available = self.contact.supports(NS_JINGLE_RTP_VIDEO)
    
    440
    +            jingle_audio.available = self.contact.supports(NS_JINGLE_RTP_AUDIO)
    
    441
    +            jingle_video.available = self.contact.supports(NS_JINGLE_RTP_VIDEO)
    
    426 442
             else:
    
    427
    -            if self.video_available or self.audio_available:
    
    443
    +            if jingle_video.available or jingle_audio.available:
    
    428 444
                     self.stop_jingle()
    
    429
    -            self.video_available = False
    
    430
    -            self.audio_available = False
    
    445
    +            jingle_video.available = False
    
    446
    +            jingle_audio.available = False
    
    431 447
     
    
    432 448
         def update_all_pep_types(self):
    
    433 449
             self._update_pep(PEPEventType.LOCATION)
    
    ... ... @@ -630,11 +646,10 @@ class ChatControl(ChatControlBase):
    630 646
             elif event.name == 'ping-error':
    
    631 647
                 self.add_info_message(_('Error.'))
    
    632 648
     
    
    633
    -    def _update_jingle(self, jingle_type):
    
    634
    -        if jingle_type not in ('audio', 'video'):
    
    635
    -            return
    
    636
    -        banner_image = getattr(self, '_' + jingle_type + '_banner_image')
    
    637
    -        state = getattr(self, jingle_type + '_state')
    
    649
    +    def _update_jingle(self, jingle_type: str) -> None:
    
    650
    +        jingle = self.jingle[jingle_type]
    
    651
    +        banner_image = jingle.banner_image
    
    652
    +        state = jingle.state
    
    638 653
             if state == self.JINGLE_STATE_NULL:
    
    639 654
                 banner_image.hide()
    
    640 655
             else:
    
    ... ... @@ -656,7 +671,7 @@ class ChatControl(ChatControlBase):
    656 671
         def update_audio(self):
    
    657 672
             self._update_jingle('audio')
    
    658 673
             hbox = self.xml.audio_buttons_hbox
    
    659
    -        if self.audio_state == self.JINGLE_STATE_CONNECTED:
    
    674
    +        if self.jingle['audio'].state == self.JINGLE_STATE_CONNECTED:
    
    660 675
                 # Set volume from config
    
    661 676
                 input_vol = app.config.get('audio_input_volume')
    
    662 677
                 output_vol = app.config.get('audio_output_volume')
    
    ... ... @@ -667,7 +682,7 @@ class ChatControl(ChatControlBase):
    667 682
                 # Show vbox
    
    668 683
                 hbox.set_no_show_all(False)
    
    669 684
                 hbox.show_all()
    
    670
    -        elif not self.audio_sid:
    
    685
    +        elif not self.jingle['audio'].sid:
    
    671 686
                 hbox.set_no_show_all(True)
    
    672 687
                 hbox.hide()
    
    673 688
     
    
    ... ... @@ -687,15 +702,17 @@ class ChatControl(ChatControlBase):
    687 702
             # update MessageWindow._controls
    
    688 703
             self.parent_win.change_jid(self.account, old_full_jid, new_full_jid)
    
    689 704
     
    
    690
    -    def stop_jingle(self, sid=None, _reason=None):
    
    691
    -        if self.audio_sid and sid in (self.audio_sid, None):
    
    705
    +    def stop_jingle(self, sid=None, reason=None):
    
    706
    +        audio_sid = self.jingle['audio'].sid
    
    707
    +        video_sid = self.jingle['video'].sid
    
    708
    +        if audio_sid and sid in (audio_sid, None):
    
    692 709
                 self.close_jingle_content('audio')
    
    693
    -        if self.video_sid and sid in (self.video_sid, None):
    
    710
    +        if video_sid and sid in (video_sid, None):
    
    694 711
                 self.close_jingle_content('video')
    
    695 712
     
    
    696
    -    def _set_jingle_state(self, jingle_type, state, sid=None, reason=None):
    
    697
    -        if jingle_type not in ('audio', 'video'):
    
    698
    -            return
    
    713
    +    def _set_jingle_state(self, jingle_type: str, state: str, sid: str = None,
    
    714
    +                          reason: str = None) -> None:
    
    715
    +        jingle = self.jingle[jingle_type]
    
    699 716
             if state in ('connecting', 'connected', 'stop', 'error') and reason:
    
    700 717
                 info = _('%(type)s state : %(state)s, reason: %(reason)s') % {
    
    701 718
                     'type': jingle_type.capitalize(),
    
    ... ... @@ -710,25 +727,25 @@ class ChatControl(ChatControlBase):
    710 727
                       'error': self.JINGLE_STATE_ERROR}
    
    711 728
     
    
    712 729
             jingle_state = states[state]
    
    713
    -        if (getattr(self, jingle_type + '_state') == jingle_state or
    
    714
    -                state == 'error'):
    
    730
    +        if jingle.state == jingle_state or state == 'error':
    
    715 731
                 return
    
    716 732
     
    
    717
    -        if (state == 'stop' and
    
    718
    -                getattr(self, jingle_type + '_sid') not in (None, sid)):
    
    733
    +        if (state == 'stop' and jingle.sid not in (None, sid)):
    
    719 734
                 return
    
    720 735
     
    
    721
    -        setattr(self, jingle_type + '_state', jingle_state)
    
    722
    -
    
    736
    +        new_sid = None
    
    723 737
             if jingle_state == self.JINGLE_STATE_NULL:
    
    724
    -            setattr(self, jingle_type + '_sid', None)
    
    738
    +            new_sid = None
    
    725 739
             if state in ('connection_received', 'connecting'):
    
    726
    -            setattr(self, jingle_type + '_sid', sid)
    
    740
    +            new_sid = sid
    
    741
    +
    
    742
    +        jingle.state = jingle_state
    
    743
    +        jingle.sid = new_sid
    
    727 744
     
    
    728 745
             var = GLib.Variant.new_boolean(jingle_state != self.JINGLE_STATE_NULL)
    
    729
    -        getattr(self, jingle_type + '_action').change_state(var)
    
    746
    +        jingle.action.change_state(var)
    
    730 747
     
    
    731
    -        getattr(self, 'update_' + jingle_type)()
    
    748
    +        jingle.update()
    
    732 749
     
    
    733 750
         def set_audio_state(self, state, sid=None, reason=None):
    
    734 751
             self._set_jingle_state('audio', state, sid=sid, reason=reason)
    
    ... ... @@ -739,7 +756,7 @@ class ChatControl(ChatControlBase):
    739 756
         def _get_audio_content(self):
    
    740 757
             con = app.connections[self.account]
    
    741 758
             session = con.get_module('Jingle').get_jingle_session(
    
    742
    -            self.contact.get_full_jid(), self.audio_sid)
    
    759
    +            self.contact.get_full_jid(), self.jingle['audio'].sid)
    
    743 760
             return session.get_content('audio')
    
    744 761
     
    
    745 762
         def on_num_button_pressed(self, _widget, num):
    
    ... ... @@ -864,28 +881,31 @@ class ChatControl(ChatControlBase):
    864 881
             self.xml.banner_name_label.set_markup(label_text)
    
    865 882
             self.xml.banner_name_label.set_tooltip_text(label_tooltip)
    
    866 883
     
    
    867
    -    def close_jingle_content(self, jingle_type):
    
    868
    -        sid = getattr(self, jingle_type + '_sid')
    
    869
    -        if not sid:
    
    884
    +    def close_jingle_content(self, jingle_type: str) -> None:
    
    885
    +        jingle = self.jingle[jingle_type]
    
    886
    +        if not jingle.sid:
    
    870 887
                 return
    
    871
    -        setattr(self, jingle_type + '_sid', None)
    
    872
    -        setattr(self, jingle_type + '_state', self.JINGLE_STATE_NULL)
    
    888
    +
    
    889
    +        jingle.sid = None
    
    890
    +        jingle.state = self.JINGLE_STATE_NULL
    
    891
    +
    
    873 892
             con = app.connections[self.account]
    
    874 893
             session = con.get_module('Jingle').get_jingle_session(
    
    875
    -            self.contact.get_full_jid(), sid)
    
    894
    +            self.contact.get_full_jid(), jingle.sid)
    
    876 895
             if session:
    
    877 896
                 content = session.get_content(jingle_type)
    
    878 897
                 if content:
    
    879 898
                     session.remove_content(content.creator, content.name)
    
    880 899
             var = GLib.Variant.new_boolean(False)
    
    881
    -        getattr(self, jingle_type + '_action').change_state(var)
    
    882
    -        getattr(self, 'update_' + jingle_type)()
    
    900
    +
    
    901
    +        jingle.action.change_state(var)
    
    902
    +        jingle.update()
    
    883 903
     
    
    884 904
         def on_jingle_button_toggled(self, state, jingle_type):
    
    885 905
             con = app.connections[self.account]
    
    886 906
             if state:
    
    887
    -            if getattr(self, jingle_type + '_state') == \
    
    888
    -            self.JINGLE_STATE_NULL:
    
    907
    +            if self.jingle[jingle_type].state == self.JINGLE_STATE_NULL:
    
    908
    +                con = app.connections[self.account]
    
    889 909
                     if jingle_type == 'video':
    
    890 910
                         video_hbox = self.xml.video_hbox
    
    891 911
                         video_hbox.set_no_show_all(False)
    
    ... ... @@ -893,26 +913,15 @@ class ChatControl(ChatControlBase):
    893 913
                             fixed = self.xml.outgoing_fixed
    
    894 914
                             fixed.set_no_show_all(False)
    
    895 915
                             video_hbox.show_all()
    
    896
    -                        out_da = self.xml.outgoing_drawingarea
    
    897
    -                        out_da.realize()
    
    898
    -                        if os.name == 'nt':
    
    899
    -                            out_xid = out_da.get_window().handle
    
    900
    -                        else:
    
    901
    -                            out_xid = out_da.get_window().get_xid()
    
    902
    -                    else:
    
    903
    -                        out_xid = None
    
    904 916
                         video_hbox.show_all()
    
    905
    -                    in_da = self.xml.incoming_drawingarea
    
    906
    -                    in_da.realize()
    
    907
    -                    in_xid = in_da.get_window().get_xid()
    
    908 917
                         sid = con.get_module('Jingle').start_video(
    
    909
    -                        self.contact.get_full_jid(), in_xid, out_xid)
    
    918
    +                        self.contact.get_full_jid())
    
    910 919
     
    
    911 920
                     else:
    
    912 921
                         sid = con.get_module('Jingle').start_audio(
    
    913 922
                             self.contact.get_full_jid())
    
    914 923
     
    
    915
    -                getattr(self, 'set_' + jingle_type + '_state')('connecting', sid)
    
    924
    +                self.jingle[jingle_type].set_state('connecting', sid)
    
    916 925
             else:
    
    917 926
                 video_hbox = self.xml.video_hbox
    
    918 927
                 video_hbox.set_no_show_all(True)
    

  • gajim/common/jingle_rtp.py
    ... ... @@ -412,11 +412,8 @@ class JingleAudio(JingleRTPContent):
    412 412
     
    
    413 413
     
    
    414 414
     class JingleVideo(JingleRTPContent):
    
    415
    -    def __init__(self, session, transport=None, in_xid=0, out_xid=0):
    
    415
    +    def __init__(self, session, transport=None):
    
    416 416
             JingleRTPContent.__init__(self, session, 'video', transport)
    
    417
    -        self.in_xid = in_xid
    
    418
    -        self.out_xid = out_xid
    
    419
    -        self.out_xid_set = False
    
    420 417
             self.setup_stream()
    
    421 418
     
    
    422 419
         def setup_stream(self):
    
    ... ... @@ -426,42 +423,24 @@ class JingleVideo(JingleRTPContent):
    426 423
             JingleRTPContent.setup_stream(self, self._on_src_pad_added)
    
    427 424
             bus = self.pipeline.get_bus()
    
    428 425
             bus.enable_sync_message_emission()
    
    429
    -        bus.connect('sync-message::element', self._on_sync_message)
    
    430 426
     
    
    431
    -        # the local parts
    
    432
    -        if app.config.get('video_framerate'):
    
    433
    -            framerate = 'videorate ! video/x-raw,framerate=%s ! ' % \
    
    434
    -                app.config.get('video_framerate')
    
    435
    -        else:
    
    436
    -            framerate = ''
    
    437
    -        try:
    
    438
    -            w, h = app.config.get('video_size').split('x')
    
    439
    -        except Exception:
    
    440
    -            w = h = None
    
    441
    -        if w and h:
    
    442
    -            video_size = 'video/x-raw,width=%s,height=%s ! ' % (w, h)
    
    443
    -        else:
    
    444
    -            video_size = ''
    
    427
    +    def do_setup(self, self_display_sink, other_sink):
    
    445 428
             if app.config.get('video_see_self'):
    
    446
    -            tee = '! tee name=t ! queue ! videoscale ! ' + \
    
    447
    -                'video/x-raw,width=160,height=120 ! videoconvert ! ' + \
    
    448
    -                '%s t. ! queue ' % app.config.get(
    
    449
    -                    'video_output_device')
    
    429
    +            tee = '! tee name=split ! queue name=self-display-queue split. ! queue name=network-queue'
    
    450 430
             else:
    
    451 431
                 tee = ''
    
    452 432
     
    
    453 433
             self.src_bin = self.make_bin_from_config('video_input_device',
    
    454
    -                                                 '%%s %s! %svideoscale ! %svideoconvert' %
    
    455
    -                                                 (tee, framerate, video_size),
    
    434
    +                                                 '%%s %s' % tee,
    
    456 435
                                                      _("video input"))
    
    457
    -
    
    458 436
             self.pipeline.add(self.src_bin)
    
    437
    +        if app.config.get('video_see_self'):
    
    438
    +            self.pipeline.add(self_display_sink)
    
    439
    +            self_display_queue = self.src_bin.get_by_name('self-display-queue')
    
    440
    +            self_display_queue.get_static_pad('src').link_maybe_ghosting(self_display_sink.get_static_pad('sink'))
    
    459 441
             self.pipeline.set_state(Gst.State.PLAYING)
    
    460 442
     
    
    461
    -        self.sink = self.make_bin_from_config('video_output_device',
    
    462
    -                                              'videoscale ! videoconvert ! %s',
    
    463
    -                                              _("video output"))
    
    464
    -
    
    443
    +        self.sink = other_sink
    
    465 444
             self.pipeline.add(self.sink)
    
    466 445
     
    
    467 446
             self.src_bin.get_static_pad('src').link(self.p2psession.get_property(
    
    ... ... @@ -469,28 +448,13 @@ class JingleVideo(JingleRTPContent):
    469 448
     
    
    470 449
             # The following is needed for farstream to process ICE requests:
    
    471 450
             self.pipeline.set_state(Gst.State.PLAYING)
    
    472
    -
    
    473
    -    def _on_sync_message(self, bus, message):
    
    474
    -        if message.get_structure() is None:
    
    475
    -            return False
    
    476
    -        if message.get_structure().get_name() == 'prepare-window-handle':
    
    477
    -            message.src.set_property('force-aspect-ratio', True)
    
    478
    -            imagesink = message.src
    
    479
    -            if app.config.get('video_see_self') and not self.out_xid_set:
    
    480
    -                imagesink.set_window_handle(self.out_xid)
    
    481
    -                self.out_xid_set = True
    
    482
    -            else:
    
    483
    -                imagesink.set_window_handle(self.in_xid)
    
    451
    +        Gst.debug_bin_to_dot_file(self.pipeline, Gst.DebugGraphDetails.ALL, 'video-graph')
    
    484 452
     
    
    485 453
         def get_fallback_src(self):
    
    486 454
             # TODO: Use avatar?
    
    487 455
             pipeline = 'videotestsrc is-live=true ! video/x-raw,framerate=10/1 ! videoconvert'
    
    488 456
             return Gst.parse_bin_from_description(pipeline, True)
    
    489 457
     
    
    490
    -    def destroy(self):
    
    491
    -        JingleRTPContent.destroy(self)
    
    492
    -        self.pipeline.get_bus().disconnect_by_func(self._on_sync_message)
    
    493
    -
    
    494 458
     def get_content(desc):
    
    495 459
         if desc['media'] == 'audio':
    
    496 460
             return JingleAudio
    

  • gajim/common/modules/jingle.py
    ... ... @@ -165,18 +165,18 @@ class Jingle(BaseModule):
    165 165
                 jingle.start_session()
    
    166 166
             return jingle.sid
    
    167 167
     
    
    168
    -    def start_video(self, jid, in_xid, out_xid):
    
    168
    +    def start_video(self, jid):
    
    169 169
             if self.get_jingle_session(jid, media='video'):
    
    170 170
                 return self.get_jingle_session(jid, media='video').sid
    
    171 171
             jingle = self.get_jingle_session(jid, media='audio')
    
    172 172
             if jingle:
    
    173
    -            jingle.add_content('video', JingleVideo(jingle, in_xid=in_xid,
    
    174
    -                                                    out_xid=out_xid))
    
    173
    +            video = JingleVideo(jingle)
    
    174
    +            jingle.add_content('video', video)
    
    175 175
             else:
    
    176 176
                 jingle = JingleSession(self._con, weinitiate=True, jid=jid)
    
    177 177
                 self._sessions[jingle.sid] = jingle
    
    178
    -            jingle.add_content('video', JingleVideo(jingle, in_xid=in_xid,
    
    179
    -                                                    out_xid=out_xid))
    
    178
    +            video = JingleVideo(jingle)
    
    179
    +            jingle.add_content('video', video)
    
    180 180
                 jingle.start_session()
    
    181 181
             return jingle.sid
    
    182 182
     
    

  • gajim/data/gui/chat_control.ui
    ... ... @@ -942,16 +942,13 @@ microphone-sensitivity-high-symbolic</property>
    942 942
                     <property name="can_focus">False</property>
    
    943 943
                     <property name="no_show_all">True</property>
    
    944 944
                     <child>
    
    945
    -                  <object class="GtkViewport" id="viewport1">
    
    945
    +                  <object class="GtkViewport" id="outgoing_viewport">
    
    946 946
                         <property name="width_request">160</property>
    
    947 947
                         <property name="height_request">120</property>
    
    948 948
                         <property name="visible">True</property>
    
    949 949
                         <property name="can_focus">False</property>
    
    950 950
                         <child>
    
    951
    -                      <object class="GtkDrawingArea" id="outgoing_drawingarea">
    
    952
    -                        <property name="visible">True</property>
    
    953
    -                        <property name="can_focus">False</property>
    
    954
    -                      </object>
    
    951
    +                      <placeholder/>
    
    955 952
                         </child>
    
    956 953
                       </object>
    
    957 954
                     </child>
    
    ... ... @@ -968,16 +965,11 @@ microphone-sensitivity-high-symbolic</property>
    968 965
                     <property name="can_focus">False</property>
    
    969 966
                     <property name="orientation">vertical</property>
    
    970 967
                     <child>
    
    971
    -                  <object class="GtkViewport" id="viewport2">
    
    968
    +                  <object class="GtkViewport" id="incoming_viewport">
    
    972 969
                         <property name="visible">True</property>
    
    973 970
                         <property name="can_focus">False</property>
    
    974 971
                         <child>
    
    975
    -                      <object class="GtkDrawingArea" id="incoming_drawingarea">
    
    976
    -                        <property name="width_request">320</property>
    
    977
    -                        <property name="height_request">240</property>
    
    978
    -                        <property name="visible">True</property>
    
    979
    -                        <property name="can_focus">False</property>
    
    980
    -                      </object>
    
    972
    +                      <placeholder/>
    
    981 973
                         </child>
    
    982 974
                       </object>
    
    983 975
                       <packing>
    

  • gajim/dialogs.py
    ... ... @@ -29,7 +29,6 @@ from typing import Dict # pylint: disable=unused-import
    29 29
     from typing import List  # pylint: disable=unused-import
    
    30 30
     from typing import Tuple  # pylint: disable=unused-import
    
    31 31
     
    
    32
    -import os
    
    33 32
     import uuid
    
    34 33
     import logging
    
    35 34
     
    
    ... ... @@ -54,6 +53,7 @@ from gajim.gtk.util import get_icon_name
    54 53
     from gajim.gtk.util import get_builder
    
    55 54
     from gajim.gtk.util import get_activity_icon_name
    
    56 55
     from gajim.gtk.util import get_app_window
    
    56
    +from gajim.gtk import gstreamer
    
    57 57
     
    
    58 58
     if app.is_installed('GSPELL'):
    
    59 59
         from gi.repository import Gspell  # pylint: disable=ungrouped-imports
    
    ... ... @@ -1100,34 +1100,12 @@ class VoIPCallReceivedDialog:
    1100 1100
                         fixed = ctrl.xml.get_object('outgoing_fixed')
    
    1101 1101
                         fixed.set_no_show_all(False)
    
    1102 1102
                     video_hbox.show_all()
    
    1103
    -                ctrl.xml.get_object('incoming_drawingarea').realize()
    
    1104
    -                if os.name == 'nt':
    
    1105
    -                    in_xid = ctrl.xml.get_object('incoming_drawingarea').\
    
    1106
    -                        get_window().handle
    
    1107
    -                else:
    
    1108
    -                    in_xid = ctrl.xml.get_object('incoming_drawingarea').\
    
    1109
    -                        get_property('window').get_xid()
    
    1110 1103
                     content = session.get_content('video')
    
    1111
    -                # move outgoing stream to chat window
    
    1112
    -                if app.config.get('video_see_self'):
    
    1113
    -                    ctrl.xml.get_object('outgoing_drawingarea').realize()
    
    1114
    -                    if os.name == 'nt':
    
    1115
    -                        out_xid = ctrl.xml.get_object('outgoing_drawingarea').\
    
    1116
    -                            get_window().handle
    
    1117
    -                    else:
    
    1118
    -                        out_xid = ctrl.xml.get_object('outgoing_drawingarea').\
    
    1119
    -                            get_property('window').get_xid()
    
    1120
    -                    b = content.src_bin
    
    1121
    -                    for e in b.children:
    
    1122
    -                        if not e.get_name().startswith('autovideosink'):
    
    1123
    -                            continue
    
    1124
    -                        for f in e.children:
    
    1125
    -                            if f.get_name().startswith('autovideosink'):
    
    1126
    -                                f.set_window_handle(out_xid)
    
    1127
    -                                content.out_xid = out_xid
    
    1128
    -                                break
    
    1129
    -                        break
    
    1130
    -                content.in_xid = in_xid
    
    1104
    +                sink_other, widget_other, _ = gstreamer.create_gtk_widget()
    
    1105
    +                sink_self, widget_self, _ = gstreamer.create_gtk_widget()
    
    1106
    +                ctrl.xml.incoming_viewport.add(widget_other)
    
    1107
    +                ctrl.xml.outgoing_viewport.add(widget_self)
    
    1108
    +                content.do_setup(sink_self, sink_other)
    
    1131 1109
                     ctrl.set_video_state('connecting', self.sid)
    
    1132 1110
                 # Now, accept the content/sessions.
    
    1133 1111
                 # This should be done after the chat control is running
    

  • gajim/gtk/gstreamer.py
    1
    +from typing import Tuple, Optional
    
    2
    +
    
    3
    +from gi.repository import Gst
    
    4
    +from gi.repository import Gtk
    
    5
    +
    
    6
    +def create_gtk_widget() -> Tuple[Optional[Gst.Element], Optional[Gtk.Widget], Optional[str]]:
    
    7
    +    gtkglsink = Gst.ElementFactory.make('gtkglsink', None)
    
    8
    +    if gtkglsink is not None:
    
    9
    +        glsinkbin = Gst.ElementFactory.make('glsinkbin', None)
    
    10
    +        if glsinkbin is None:
    
    11
    +            return None, None, None
    
    12
    +        glsinkbin.set_property('sink', gtkglsink)
    
    13
    +        sink = glsinkbin
    
    14
    +        widget = gtkglsink.get_property('widget')
    
    15
    +        name = 'gtkglsink'
    
    16
    +    else:
    
    17
    +        sink = Gst.ElementFactory.make('gtksink', None)
    
    18
    +        if sink is None:
    
    19
    +            return None, None, None
    
    20
    +        widget = sink.get_property('widget')
    
    21
    +        name = 'gtksink'
    
    22
    +    widget.set_visible(True)
    
    23
    +    widget.set_property('expand', True)
    
    24
    +    return sink, widget, name

  • gajim/gtk/preferences.py
    ... ... @@ -38,6 +38,7 @@ from gajim.gtk.util import open_window
    38 38
     from gajim.gtk.dialogs import AspellDictError
    
    39 39
     from gajim.gtk.sounds import ManageSounds
    
    40 40
     from gajim.gtk.const import ControlType
    
    41
    +from gajim.gtk import gstreamer
    
    41 42
     
    
    42 43
     try:
    
    43 44
         from gajim.common.multimedia_helpers import AudioInputManager, AudioOutputManager
    
    ... ... @@ -384,7 +385,7 @@ class Preferences(Gtk.ApplicationWindow):
    384 385
     
    
    385 386
                 def on_av_map(tab):
    
    386 387
                     label = self._ui.selected_video_output
    
    387
    -                sink, widget, name = self.setup_video_output()
    
    388
    +                sink, widget, name = gstreamer.create_gtk_widget()
    
    388 389
                     if sink is None:
    
    389 390
                         log.error('Failed to obtain a working Gstreamer GTK+ sink, '
    
    390 391
                                   'video support will be disabled')
    
    ... ... @@ -508,27 +509,6 @@ class Preferences(Gtk.ApplicationWindow):
    508 509
             if event.keyval == Gdk.KEY_Escape:
    
    509 510
                 self.destroy()
    
    510 511
     
    
    511
    -    @staticmethod
    
    512
    -    def setup_video_output():
    
    513
    -        gtkglsink = Gst.ElementFactory.make('gtkglsink', None)
    
    514
    -        if gtkglsink is not None:
    
    515
    -            glsinkbin = Gst.ElementFactory.make('glsinkbin', None)
    
    516
    -            if glsinkbin is None:
    
    517
    -                return None, None, None
    
    518
    -            glsinkbin.set_property('sink', gtkglsink)
    
    519
    -            sink = glsinkbin
    
    520
    -            widget = gtkglsink.get_property('widget')
    
    521
    -            name = 'gtkglsink'
    
    522
    -        else:
    
    523
    -            sink = Gst.ElementFactory.make('gtksink', None)
    
    524
    -            if sink is None:
    
    525
    -                return None, None, None
    
    526
    -            widget = sink.get_property('widget')
    
    527
    -            name = 'gtksink'
    
    528
    -        widget.set_visible(True)
    
    529
    -        widget.set_property('expand', True)
    
    530
    -        return sink, widget, name
    
    531
    -
    
    532 512
         def get_per_account_option(self, opt):
    
    533 513
             """
    
    534 514
             Return the value of the option opt if it's the same in all accounts else
    

  • gajim/gui_interface.py
    ... ... @@ -1024,7 +1024,7 @@ class Interface:
    1024 1024
             account = obj.conn.name
    
    1025 1025
             ctrl = (self.msg_win_mgr.get_control(obj.fjid, account)
    
    1026 1026
                 or self.msg_win_mgr.get_control(obj.jid, account))
    
    1027
    -        if ctrl and obj.sid == ctrl.audio_sid:
    
    1027
    +        if ctrl and obj.sid == ctrl.jingle['audio'].sid:
    
    1028 1028
                 ctrl.set_audio_state('error', reason=obj.reason)
    
    1029 1029
     
    
    1030 1030
         @staticmethod