Skip to content

Instantly share code, notes, and snippets.

@le-chat
Created July 7, 2022 10:30
Show Gist options
  • Save le-chat/f0aa4222b5a978446ce937ac59341ba8 to your computer and use it in GitHub Desktop.
Save le-chat/f0aa4222b5a978446ce937ac59341ba8 to your computer and use it in GitHub Desktop.
gst-python bug: webrtcbin create-answer returns unknown SDP type

Run nix-shell --run "python test.py" and observe unknown, random-looking and changing at each run WebRTCSDPType instead of ANSWER.

If replace answer = promise.get_reply().get_value("answer") with

reply = promise.get_reply()
answer = reply.get_value("answer")

you will get correct SDP type and non-empty SDP in WebRTCSessionDescription.

INFO __main__:BEGIN WRB TEST
0:00:00.014021381 40 0x55a9d2315500 DEBUG webrtcbin gstwebrtcbin.c:6904:gst_webrtc_bin_change_state: changing state: NULL => READY
0:00:00.014205180 40 0x55a9d2315500 LOG webrtcbin gstwebrtcbin.c:1498:_check_if_negotiation_is_needed:<wrb> checking if negotiation is needed
0:00:00.014227474 40 0x55a9d2315500 LOG webrtcbin gstwebrtcbin.c:1514:_check_if_negotiation_is_needed:<wrb> no local description set
0:00:00.014305243 40 0x55a9d2315500 DEBUG webrtcbin gstwebrtcbin.c:6904:gst_webrtc_bin_change_state: changing state: READY => PAUSED
0:00:00.014301520 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:1656:_check_need_negotiation_task:<wrb> emitting on-negotiation-needed
0:00:00.014361117 40 0x55a9d2315500 DEBUG webrtcbin gstwebrtcbin.c:6904:gst_webrtc_bin_change_state: changing state: PAUSED => PLAYING
0:00:00.015169101 40 0x55a9d21270c0 INFO webrtcbin gstwebrtcbin.c:5497:_set_description_task:<wrb> Attempting to set remote offer in the stable state
0:00:00.015177543 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:5499:_set_description_task:<wrb> SDP contents
v=0
o=- 1657097603554088 1 IN IP4 192.168.0.95
s=Mountpoint 7595272868738783
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS janus
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 192.168.0.95
a=sendonly
a=mid:video
a=rtcp-mux
a=ice-ufrag:Qrt1
a=ice-pwd:2SYwnMmbQHXD5Ew0C/2bNm
a=ice-options:trickle
a=fingerprint:sha-256 E5:B5:7A:3F:B3:FF:3C:DF:3B:1A:C9:A1:03:EB:FB:14:F9:E7:97:0F:BE:0D:BB:A2:6C:59:08:B9:D7:9C:F9:53
a=setup:actpass
a=rtpmap:96 H264/90000
a=fmtp:96 profile-level-id=42e01f;packetization-mode=1
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 goog-remb
a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=ssrc-group:FID 2109758724 594261311
a=msid:janus janusv0
a=ssrc:2109758724 cname:janus
a=ssrc:2109758724 msid:janus janusv0
a=ssrc:2109758724 mslabel:janus
a=ssrc:2109758724 label:janusv0
a=ssrc:594261311 cname:janus
a=ssrc:594261311 msid:janus janusv0
a=ssrc:594261311 mslabel:janus
a=ssrc:594261311 label:janusv0
a=candidate:1 1 udp 2013266431 192.168.0.95 10053 typ host
a=candidate:2 1 udp 2013266430 10.8.0.1 10027 typ host
a=candidate:3 1 udp 2013266429 10.7.1.1 10085 typ host
a=candidate:4 1 udp 2013266428 172.17.0.1 10016 typ host
a=candidate:5 1 udp 2013266427 192.168.64.1 10147 typ host
a=end-of-candidates
0:00:00.015211794 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:4375:_find_transceiver_for_sdp_media:<wrb> Found transceiver (NULL)
0:00:00.015227198 40 0x55a9d21270c0 DEBUG webrtcbin gstwebrtcbin.c:5669:_set_description_task:<wrb> we are in ice controlling mode: true
0:00:00.015235589 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:675:_find_transport_for_session:<wrb> Found transport (NULL) for session 0
0:00:00.074514331 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:576:_find_ice_stream_for_session:<wrb> No ice stream available for session 0
0:00:00.074604638 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:587:_add_ice_stream_item:<wrb> adding ice stream <webrtcicestream0> for session 0
0:00:00.076315242 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:6379:on_rtpbin_pad_added:<wrb> new rtpbin pad recv_rtcp_sink_0
0:00:00.076436204 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:6379:on_rtpbin_pad_added:<wrb> new rtpbin pad send_rtcp_src_0
0:00:00.076502735 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:2260:_create_transport_channel:<wrb> Create transport <transportstream0> for session 0
0:00:00.076515239 40 0x55a9d21270c0 DEBUG webrtctransportsendbin transportsendbin.c:165:transport_send_bin_change_state:<transportsendbin0> changing state: NULL => READY
0:00:00.076543062 40 0x55a9d21270c0 DEBUG webrtctransportsendbin transportsendbin.c:165:transport_send_bin_change_state:<transportsendbin0> changing state: READY => PAUSED
0:00:00.076574512 40 0x55a9d21270c0 DEBUG webrtctransportsendbin transportsendbin.c:165:transport_send_bin_change_state:<transportsendbin0> changing state: PAUSED => PLAYING
0:00:00.076597930 40 0x55a9d21270c0 DEBUG webrtctransportreceivebin transportreceivebin.c:237:transport_receive_bin_change_state: changing state: NULL => READY
0:00:00.076692200 40 0x55a9d21270c0 DEBUG webrtctransportreceivebin transportreceivebin.c:237:transport_receive_bin_change_state: changing state: READY => PAUSED
0:00:00.076703408 40 0x7f4c84001980 FIXME default gstutils.c:4025:gst_pad_create_stream_id_internal:<nicesrc0:src> Creating random stream-id, consider implementing a deterministic way of creating a stream-id
0:00:00.076727214 40 0x7f4c84001980 WARN GST_PADS gstpad.c:4351:gst_pad_peer_query:<nicesrc0:src> could not send sticky events
0:00:00.076789487 40 0x55a9d21270c0 DEBUG webrtctransportreceivebin transportreceivebin.c:237:transport_receive_bin_change_state: changing state: PAUSED => PLAYING
0:00:00.076835819 40 0x55a9d21270c0 DEBUG webrtcice gstwebrtcice.c:720:gst_webrtc_ice_set_remote_credentials:<webrtcbin0:ice> Setting remote ICE credentials on ICE stream 1 ufrag:Qrt1 pwd:2SYwnMmbQHXD5Ew0C/2bNm
0:00:00.076844463 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:5827:_set_description_task:<wrb> notify signaling-state from have-remote-offer to have-remote-offer
0:00:00.077065776 40 0x55a9d21270c0 INFO webrtcbin gstwebrtcbin.c:4237:_create_sdp_task:<wrb> creating answer sdp with options (NULL)
0:00:00.077163275 40 0x55a9d21270c0 LOG webrtcbin gstwebrtcbin.c:4062:_create_answer_task:<wrb> Created new transceiver <webrtctransceiver0> for mline 0 with media kind 2
0:00:00.077171278 40 0x55a9d21270c0 LOG webrtcbin gstwebrtcbin.c:1761:_find_codec_preferences:<wrb> retrieving codec preferences from <webrtctransceiver0>
0:00:00.077178623 40 0x55a9d21270c0 DEBUG webrtcbin gstwebrtcbin.c:1874:_find_codec_preferences:<webrtctransceiver0> Could not find caps for mline 0
0:00:00.077192888 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:4071:_create_answer_task:<wrb> trying to compare application/x-rtp, media=(string)video, payload=(int)96, clock-rate=(int)90000, encoding-name=(string)H264, profile-level-id=(string)42e01f, packetization-mode=(string)1, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true, rtcp-fb-goog-remb=(boolean)true; application/x-rtp, media=(string)video, payload=(int)97, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)96 and (NULL)
0:00:00.077212358 40 0x55a9d21270c0 TRACE webrtcbin gstwebrtcbin.c:675:_find_transport_for_session:<wrb> Found transport <transportstream0> for session 0
0:00:00.077220391 40 0x55a9d21270c0 DEBUG webrtctransportsendbin transportsendbin.c:165:transport_send_bin_change_state:<transportsendbin0> changing state: PLAYING => PLAYING
0:00:00.077237207 40 0x55a9d21270c0 DEBUG webrtctransportreceivebin transportreceivebin.c:237:transport_receive_bin_change_state: changing state: PLAYING => PLAYING
INFO __main__:on answer: <Gst.Promise object at 0x7f4c976b6d40 (GstPromise at 0x55a9d232b590)> <__gi__.GstWebRTCBin object at 0x7f4c974cb700 (GstWebRTCBin at 0x55a9d230a1b0)> None
INFO __main__:answer: <GstWebRTC.WebRTCSessionDescription object at 0x7f4c976b6e60 (GstWebRTCSessionDescription at 0x7f4c84109130)>
INFO __main__:answer fields: <enum 1893465641 of type GstWebRTC.WebRTCSDPType>
INFO __main__:answer fields: <enum 1893465641 of type GstWebRTC.WebRTCSDPType> 1893465641
INFO __main__:answer fields: <enum 1893465641 of type GstWebRTC.WebRTCSDPType> unknown
INFO __main__:answer sdp is None: True
INFO __main__:answer fields: None
Traceback (most recent call last):
File "/opt/pysetup/jord/test.py", line 83, in on_answer_created
sdp = answer.sdp.as_text()
AttributeError: 'NoneType' object has no attribute 'as_text'
(python:40): GStreamer-CRITICAL **: 10:13:51.057:
Trying to dispose element rtpbin, but it is in PLAYING instead of the NULL state.
You need to explicitly set elements to the NULL state before
dropping the final reference, to allow them to clean up.
This problem may also be caused by a refcounting bug in the
application or some element.
(python:40): GStreamer-CRITICAL **: 10:13:51.057:
Trying to dispose element wrb, but it is in PLAYING instead of the NULL state.
You need to explicitly set elements to the NULL state before
dropping the final reference, to allow them to clean up.
This problem may also be caused by a refcounting bug in the
application or some element.
(python:40): GStreamer-CRITICAL **: 10:13:51.057:
Trying to dispose element nicesink0, but it is in PLAYING instead of the NULL state.
You need to explicitly set elements to the NULL state before
dropping the final reference, to allow them to clean up.
This problem may also be caused by a refcounting bug in the
application or some element.
(python:40): GStreamer-CRITICAL **: 10:13:51.058:
Trying to dispose element transportsendbin0, but it is in PLAYING instead of the NULL state.
You need to explicitly set elements to the NULL state before
dropping the final reference, to allow them to clean up.
This problem may also be caused by a refcounting bug in the
application or some element.
let pkgs = import <nixpkgs> {};
pyEnv = pkgs.python3.withPackages (p: [ p.pygobject3 p.gst-python ]);
in pkgs.mkShell {
buildInputs = with pkgs; [
pyEnv
gobject-introspection
gst_all_1.gst-rtsp-server
gst_all_1.gstreamer
gst_all_1.gst-plugins-base
gst_all_1.gst-plugins-bad
gst_all_1.gst-plugins-ugly
gst_all_1.gst-plugins-good
libnice
];
shellHook = ''export GST_DEBUG=3,*webrtc*:7'';
}
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstWebRTC', '1.0')
gi.require_version('GstSdp', '1.0')
from gi.repository import GLib, Gst, GstWebRTC, GstSdp
import time
import logging
import sys
logging.basicConfig(level=logging.INFO,
stream=sys.stdout,
format='%(levelname)-8s %(name)s:%(message)s')
logger = logging.getLogger(__name__)
SDP_EXAMPLE = """v=0
o=- 1657097603554088 1 IN IP4 192.168.0.95
s=Mountpoint 7595272868738783
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS janus
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 192.168.0.95
a=sendonly
a=mid:video
a=rtcp-mux
a=ice-ufrag:Qrt1
a=ice-pwd:2SYwnMmbQHXD5Ew0C/2bNm
a=ice-options:trickle
a=fingerprint:sha-256 E5:B5:7A:3F:B3:FF:3C:DF:3B:1A:C9:A1:03:EB:FB:14:F9:E7:97:0F:BE:0D:BB:A2:6C:59:08:B9:D7:9C:F9:53
a=setup:actpass
a=rtpmap:96 H264/90000
a=fmtp:96 profile-level-id=42e01f;packetization-mode=1
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 goog-remb
a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=ssrc-group:FID 2109758724 594261311
a=msid:janus janusv0
a=ssrc:2109758724 cname:janus
a=ssrc:2109758724 msid:janus janusv0
a=ssrc:2109758724 mslabel:janus
a=ssrc:2109758724 label:janusv0
a=ssrc:594261311 cname:janus
a=ssrc:594261311 msid:janus janusv0
a=ssrc:594261311 mslabel:janus
a=ssrc:594261311 label:janusv0
a=candidate:1 1 udp 2013266431 192.168.0.95 10053 typ host
a=candidate:2 1 udp 2013266430 10.8.0.1 10027 typ host
a=candidate:3 1 udp 2013266429 10.7.1.1 10085 typ host
a=candidate:4 1 udp 2013266428 172.17.0.1 10016 typ host
a=candidate:5 1 udp 2013266427 192.168.64.1 10147 typ host
a=end-of-candidates
"""
def wrb_test():
logger.info("BEGIN WRB TEST")
Gst.init(None)
webrtc = Gst.parse_launch("webrtcbin name=wrb")
webrtc.set_state(Gst.State.PLAYING)
sdp = SDP_EXAMPLE
res, sdpmsg = GstSdp.SDPMessage.new()
assert res == GstSdp.SDPResult.OK, f"unexpected res {res}"
GstSdp.sdp_message_parse_buffer(bytes(sdp.encode()), sdpmsg)
offer = GstWebRTC.WebRTCSessionDescription.new(GstWebRTC.WebRTCSDPType.OFFER, sdpmsg)
promise1 = Gst.Promise.new()
webrtc.emit('set-remote-description', offer, promise1)
promise1.wait()
def on_answer_created(promise, _, __):
logger.info(f"on answer: {promise} {_} {__}") # debug
answer = promise.get_reply().get_value("answer")
logger.info(f"answer: {answer}")
logger.info(f"answer fields: {answer.type}")
logger.info(f"answer fields: {answer.type} {answer.type.real}")
logger.info(f"answer fields: {answer.type} {answer.type.to_string(answer.type)}")
logger.info(f"answer sdp is None: {answer.sdp is None}")
logger.info(f"answer fields: {answer.sdp}")
sdp = answer.sdp.as_text()
logger.info(f"answer sdp: {sdp}")
promise3 = Gst.Promise.new()
webrtc.emit('set-local-description', answer, promise3)
promise2 = Gst.Promise.new_with_change_func(on_answer_created, webrtc, None)
webrtc.emit('create-answer', None, promise2)
promise2.wait()
time.sleep(15)
if __name__ == "__main__":
wrb_test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment