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