A question regarding the proper handling of pipelines and webrtcbin

Neil Young foreverneilyoung at googlemail.com
Tue Aug 17 13:38:21 UTC 2021


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
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")
        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/b437581a/attachment-0001.htm>


More information about the gstreamer-devel mailing list