webrtcbin recvonly opus transceiver creates wrong SDP rtpmap line
Issue
Creating a recvonly transceiver by signal emission for OPUS on a webrtcbin and then generate offer SDP creates the wrong rtpmap line (without the required /2
):
v=0 o=- 7654366125257590231 0 IN IP4 0.0.0.0
s=-
t=0 0
a=ice-options:trickle
m=audio 9 UDP/TLS/RTP/SAVPF 96
c=IN IP4 0.0.0.0
a=setup:actpass
a=ice-ufrag:jY1LEwLDg8JgXVAsAVKGyXQxWDTj/8BH
a=ice-pwd:1m23h3zZR1E5Ko4dYBZDt/4saYK94kmP
a=rtcp-mux
a=rtcp-rsize
a=recvonly
a=rtpmap:96 OPUS/48000
a=rtcp-fb:96 nack pli
a=mid:audio0
a=fingerprint:sha-256 C4:87:88:21:F0:B9:67:4B:22:B0:73:F7:0F:E1:C7:5D:72:AE:68:C6:C9:B7:CD:46:AC:15:22:6F:21:BC:30:F5
The transceiver seems to have the correct caps(print transceiver codec_preferences):
Transceiver: application/x-rtp, media=(string)audio, encoding-name=(string)OPUS, clock-rate=(int)48000, channels=(int)2, payload=(int)96;
Expected Behaviour
The SDP should look like (with the /2
):
a=recvonly
a=rtpmap:96 OPUS/48000/2
How to reproduce
I got the pattern (how to create recvonly webrtcbin) from this post: https://stackoverflow.com/questions/57430215/how-to-use-webrtcbin-create-offer-only-receive-video
import sys
import gi
import time
gi.require_version("Gst", "1.0")
from gi.repository import Gst
gi.require_version("GstWebRTC", "1.0")
from gi.repository import GstWebRTC
gi.require_version("GstSdp", "1.0")
from gi.repository import GstSdp
class WebRTCWrapper:
def send_sdp_offer(self, offer):
# dump SDP here and error exit
text = offer.sdp.as_text()
print("Sending offer:\n%s" % text)
sys.exit(1)
def on_offer_created(self, promise, _, __):
promise.wait()
reply = promise.get_reply()
offer = reply["offer"]
promise = Gst.Promise.new()
self.webrtc.emit("set-local-description", offer, promise)
promise.interrupt()
self.send_sdp_offer(offer)
def on_negotiation_needed(self, element):
promise = Gst.Promise.new_with_change_func(self.on_offer_created, element, None)
element.emit("create-offer", None, promise)
def start_pipeline(self):
self.pipe = Gst.Pipeline()
self.webrtc = Gst.ElementFactory.make("webrtcbin")
self.pipe.add(self.webrtc)
self.webrtc.connect("on-negotiation-needed", self.on_negotiation_needed)
direction = GstWebRTC.WebRTCRTPTransceiverDirection.RECVONLY
caps = Gst.caps_from_string(
"application/x-rtp,media=audio,encoding-name=OPUS,clock-rate=48000,channels=2,payload=96"
)
tcvr = self.webrtc.emit("add-transceiver", direction, caps)
print(f"==== Transceiver: {tcvr.codec_preferences[0].to_string()} ====")
self.webrtc.sync_state_with_parent()
if __name__ == "__main__":
Gst.init(None)
obj = WebRTCWrapper()
obj.start_pipeline()
obj.pipe.set_state(Gst.State.PLAYING)
time.sleep(10.0)
Observations
- The SDP is almost correct: if I mangle the SDP in the application (add
/2
to rtpmap) before sending to the peer, the application works. Application is a Kurento-based media server and rejects the pre-mangled SDP.