A question regarding the proper handling of pipelines and webrtcbin

Neil Young foreverneilyoung at googlemail.com
Tue Aug 17 18:19:24 UTC 2021


OK, doing it manually works great. And fast. 

Just the commented part doesn't work, since "trans" is None. That's why the OFFER goes out with "sendrecv"

The "get-transceivers" returns a GArray, but I wouldn't know how to subscribe this in Python...


    def start_pipeline(self):
        self.webrtcbin = Gst.ElementFactory.make("webrtcbin")
        self.webrtcbin.set_property("bundle-policy", "max-bundle")
        self.webrtcbin.set_property("stun-server", "stun://stun.l.google.com:19302")
        # if Gst.version().major >= 1 and Gst.version().minor >= 17:
        #     trans = self.webrtcbin.emit('get-transceiver', 0)
        #     print(trans)
            
        #     if self.direction == 'sendonly':
        #         trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.SENDONLY)
        #     elif self.direction == 'recvonly':
        #         trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.RECVONLY)
        #     else:
        #         trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.SENDRECV)
        self.webrtcbin.connect('on-negotiation-needed', self.on_negotiation_needed) 
        self.webrtcbin.connect('on-ice-candidate', self.on_ice_candidate)
        self.webrtcbin.connect('pad-added', self.on_pad_added)
        self.webrtcbin.connect('notify::connection-state', self.on_connection_state)
        self.webrtcbin.connect('notify::signaling-state', self.on_signaling_state)
        self.webrtcbin.connect('notify::ice-connection-state', self.on_ice_connection_state)
        self.webrtcbin.connect('notify::ice-gathering-state', self.on_ice_gathering_state)

        self.pipeline = Gst.Pipeline.new()
        self.pipeline.add(self.webrtcbin)

        videotestsrc = Gst.ElementFactory.make("videotestsrc", "videotestsrc")
        videotestsrc.set_property("is-live", True)
        videotestsrc.set_property("pattern", "ball")

        videoconvert = Gst.ElementFactory.make("videoconvert", "videoconvert")
        vp8enc = Gst.ElementFactory.make("vp8enc", "vp8enc")
        vp8enc.set_property("deadline", 1)

        rtpvp8pay = Gst.ElementFactory.make("rtpvp8pay", "rtpvp8pay")

        rtpvp8pay_caps = Gst.caps_from_string("application/x-rtp")
        rtpvp8pay_caps.set_value("media", "video")
        rtpvp8pay_caps.set_value("encoding-name", "VP8")

        rtpvp8pay_caps_filter = Gst.ElementFactory.make("capsfilter")
        rtpvp8pay_caps_filter.set_property("caps", rtpvp8pay_caps)

        self.pipeline.add(videotestsrc)
        self.pipeline.add(videoconvert)
        self.pipeline.add(vp8enc)
        self.pipeline.add(rtpvp8pay)
        self.pipeline.add(rtpvp8pay_caps_filter)

        if not Gst.Element.link(videotestsrc, videoconvert):
            print("Failed to link videotestsrc -> videoconvert")

        if not Gst.Element.link(videoconvert, vp8enc):
            print("Failed to link videoconvert -> vp8enc")

        if not Gst.Element.link(vp8enc, rtpvp8pay):
            print("Failed to link vp8enc -> rtpvp8pay")

        if not Gst.Element.link(rtpvp8pay, rtpvp8pay_caps_filter):
            print("Failed to link rtpvp8pay -> rtpvp8pay_caps_filter")

        if not Gst.Element.link(rtpvp8pay_caps_filter, self.webrtcbin):
            print("Failed to link rtpvp8pay_caps_filter -> self.webrtcbin")

        self.pipeline.add(self.webrtcbin)
        self.pipeline.set_state(Gst.State.PLAYING)




> Am 17.08.2021 um 15:38 schrieb Neil Young <foreverneilyoung at googlemail.com>:
> 
> I'm trying to refactor some working sample code which is using this pattern:
> 
> - A webrtcbin pipeline is created from string
> - The "on_negotiation_needed" callback triggers the OFFER creation.
> 
> Basically this is the Python code, which appears in many forms on the Internet and is originated from one of the GStreamer sample codes:
> 
> PIPELINE_TEST_VP8 = '''
> webrtcbin name=webrtcbin bundle-policy=max-bundle stun-server=stun://stun.l.google.com:19302 <stun://stun.l.google.com:19302>
> videotestsrc is-live=true pattern=ball ! videoconvert ! queue ! vp8enc deadline=1 ! queue ! rtpvp8pay !
> queue ! application/x-rtp,media=video,encoding-name=VP8 ! webrtcbin.
> '''
> 
> 
>     def start_pipeline(self):
>         self.pipe = Gst.parse_launch(PIPELINE_TEST_VP8)
>         self.webrtcbin = self.pipe.get_by_name('webrtcbin')
>         if Gst.version().major >= 1 and Gst.version().minor >= 17:
>             trans = self.webrtcbin.emit('get-transceiver', 0)
>             if self.direction == 'sendonly':
>                 trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.SENDONLY)
>             elif self.direction == 'recvonly':
>                 trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.RECVONLY)
>             else:
>                 trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.SENDRECV)
>         self.webrtcbin.connect('on-negotiation-needed', self.on_negotiation_needed) 
>         self.webrtcbin.connect('on-ice-candidate', self.on_ice_candidate)
>         self.webrtcbin.connect('pad-added', self.on_pad_added)
>         self.webrtcbin.connect('notify::connection-state', self.on_connection_state)
>         self.webrtcbin.connect('notify::signaling-state', self.on_signaling_state)
>         self.webrtcbin.connect('notify::ice-connection-state', self.on_ice_connection_state)
>         self.webrtcbin.connect('notify::ice-gathering-state', self.on_ice_gathering_state)
>         self.pipe.set_state(Gst.State.PLAYING)
> 
> 
> The offer looks good and is answered correctly, video flows.
> 
> v=0
> o=- 7638256982687930899 0 IN IP4 0.0.0.0
> s=-
> t=0 0
> a=ice-options:trickle
> a=group:BUNDLE video0
> m=video 9 UDP/TLS/RTP/SAVPF 96
> c=IN IP4 0.0.0.0
> a=setup:actpass
> a=ice-ufrag:bGQItiwLYlgcID/WCvvmBOvCOn7T5c/I
> a=ice-pwd:7XItJ6VJFOoh8jcwd4Rvq34OW1/KYRSD
> a=rtcp-mux
> a=rtcp-rsize
> a=sendrecv
> a=rtpmap:96 H264/90000
> a=rtcp-fb:96 nack pli
> a=framerate:30
> a=fmtp:96 packetization-mode=1;profile-level-id=42c01e;sprop-parameter-sets=Z0LAHtkAoD2wFqDAwNSgAAADACAAAAeR4sXJ,aMuMsg==
> a=ssrc:480748954 msid:user4125901687 at host-1eadd0cf webrtctransceiver0
> a=ssrc:480748954 cname:user4125901687 at host-1eadd0cf
> a=mid:video0
> a=fingerprint:sha-256 54:82:06:0C:5D:7C:47:63:C2:1A:8D:D0:CC:0E:9D:20:47:A8:6C:B0:CF:31:74:0D:E2:5F:D6:D9:F5:21:D5:94
> 
> 
> 
> Because this approach of a pre-canned pipeline seems to have difficulties in a mode, in which I try to ANSWER an incoming OFFER I was trying to refactor it and split the webrtcbin object generation from the input pipeline.
> 
> PIPELINE_TEST_VP8_2 = '''
> videotestsrc is-live=true pattern=ball ! 
> videoconvert ! 
> queue ! 
> vp8enc deadline=1 ! 
> queue ! 
> rtpvp8pay ! 
> queue ! 
> application/x-rtp,media=video,encoding-name=VP8  ! 
> webrtcbin
> '''
> 
>     def start_pipeline(self):
>         self.pipe = Gst.parse_launch(PIPELINE_TEST_VP8_2)
>         self.webrtcbin = Gst.ElementFactory.make("webrtcbin")
>         self.webrtcbin.set_property("bundle-policy", "max-bundle")
>         self.webrtcbin.set_property("name", "webrtcbin")
>         self.webrtcbin.set_property("stun-server", "stun://stun.l.google.com:19302 <stun://stun.l.google.com:19302>")
>         if Gst.version().major >= 1 and Gst.version().minor >= 17:
>             trans = self.webrtcbin.emit('get-transceiver', 0)
>             if self.direction == 'sendonly':
>                 trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.SENDONLY)
>             elif self.direction == 'recvonly':
>                 trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.RECVONLY)
>             else:
>                 trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.SENDRECV)
>         self.webrtcbin.connect('on-negotiation-needed', self.on_negotiation_needed) 
>         self.webrtcbin.connect('on-ice-candidate', self.on_ice_candidate)
>         self.webrtcbin.connect('pad-added', self.on_pad_added)
>         self.webrtcbin.connect('notify::connection-state', self.on_connection_state)
>         self.webrtcbin.connect('notify::signaling-state', self.on_signaling_state)
>         self.webrtcbin.connect('notify::ice-connection-state', self.on_ice_connection_state)
>         self.webrtcbin.connect('notify::ice-gathering-state', self.on_ice_gathering_state)
>         self.pipe.add(self.webrtcbin)
>         self.pipe.set_state(Gst.State.PLAYING)
> 
> 
> The first problem with this is the missing "trans":
> 
> 0:00:00.352922991 11197 0xb2847240 ERROR              webrtcbin gstwebrtcbin.c:5032:gst_webrtc_bin_get_transceiver:<webrtcbin> No transceiver for idx 0
> 
> 
> trans.set_property('direction', GstWebRTC.WebRTCRTPTransceiverDirection.SENDONLY)
> AttributeError: 'NoneType' object has no attribute 'set_property'
> 
> But even if I omit the entire part to determine the transceiver, the result is still not working, because this is my OFFER then:
> 
> v=0
> o=- 4039551208253794554 0 IN IP4 0.0.0.0
> s=-
> t=0 0
> a=ice-options:trickle
> a=group:BUNDLE
> 
> 
> I suppose there is something wrong with the inputs definitions, but before I go and create them manually I wanted to at least have some success with this.
> 
> Does anybody have a pointer, what's going wrong here?
> 
> 
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20210817/566eb206/attachment-0001.htm>


More information about the gstreamer-devel mailing list