Gstreamer WebRTC callee can't send video to remote
It is originally posted here.
We are writing a sample code of webrtc to transmit/receive video/audio to/from browser with GStreamer. We are referencing the demo: https://github.com/centricular/gstwebrtc-demos/blob/master/sendrecv/gst/webrtc_sendrecv.py. It works fine.
But there is a small difference in our code of cloud side. In the gstwebrtc
demo code, webrtcbin
creates an offer and the browser responds with an answer. In our project, the browser creates an offer and webrtcbin
responds with an answer.
We modify the demo code above to implement the reverse flow(browser offer -> webrtcbin). But there is no video stream on the browser side. The onTrack
callback in the browser is never invoked.
My question is, how to send video/audio to the browser when webrtcbin
works as a callee? By the way, we are using gstreamer 1.20.3
.
And the code is attached:
import paho.mqtt.client as mqtt
import ssl
import json
import time
import sys
import gi
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
PIPELINE_DESC = '''
webrtcbin name=sendrecv bundle-policy=max-bundle stun-server=stun://turn.jujiucloud.com:3478,
v4l2src ! video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! videoconvert ! queue ! vp8enc deadline=1 ! rtpvp8pay !
queue ! application/x-rtp,media=video,encoding-name=VP8,payload=97 ! sendrecv.
audiotestsrc is-live=true wave=red-noise ! audioconvert ! audioresample ! queue ! opusenc ! rtpopuspay !
queue ! application/x-rtp,media=audio,encoding-name=OPUS,payload=96 ! sendrecv.
'''
MQTT_URL = 'mqtt.abceefg.com'
MQTT_USERNAME = 'abceefg'
MQTT_PASSWORD = 'abceefg'
MQTT_IPC_TOPIC_PREFIX = 'abceefg'
USN = 'abceefg'
webrtc = None
peers = {}
def check_plugins():
needed = ['opus', 'vpx', 'nice', 'webrtc', 'dtls', 'srtp', 'rtp', 'rtpmanager', 'videotestsrc', 'audiotestsrc']
missing = list(filter(lambda p: Gst.Registry.get().find_plugin(p) is None, needed))
if len(missing):
print('Missing gstreamer plugins:', missing)
return False
return True
def on_set_description(promise, webrtc, client, msg_obj):
print('on_set_description')
promise.wait()
promise = Gst.Promise.new_with_change_func(on_answer_created, webrtc, client, msg_obj)
webrtc.emit('create-answer', None, promise)
def on_answer_created(promise, webrtc, client, msg_obj):
print('on_answer_created')
promise.wait()
reply = promise.get_reply()
answer = reply.get_value('answer')
if not answer:
print('no answer created.')
return
promise = Gst.Promise.new()
webrtc.emit('set-local-description', answer, promise)
promise.interrupt()
mqtt_answer = {
'timestamp': time.time(),
'source': msg_obj['destination'],
'destination': msg_obj['source'],
'type': 'webrtc_signal',
'subtype': 'answer',
'answer': {
'type': 'answer',
'sdp': answer.sdp.as_text()
},
}
# print(mqtt_answer)
client.publish(msg_obj['source'], json.dumps(mqtt_answer))
def on_negotiation_needed(element):
print('on_negotiation_needed')
def send_ice_candidate_message(_, mlineindex, candidate, userdata):
(client, msg_obj) = userdata
mqtt_ice = {
'timestamp': time.time(),
'source': msg_obj['destination'],
'destination': msg_obj['source'],
'type': 'webrtc_signal',
'subtype': 'candidate',
'candidate': {
'candidate': candidate,
'sdpMLineIndex': mlineindex,
'sdpMid': '0'
},
}
# print(send_ice_candidate_message, mqtt_ice)
client.publish(msg_obj['source'], json.dumps(mqtt_ice))
def on_connection_state_notify(webrtc, state):
print(webrtc.get_property('connection-state'))
return
def on_incoming_stream(_, pad):
print('on_incoming_stream', pad.direction)
caps = pad.get_current_caps()
name = caps.to_string()
print('on_incoming_stream', name)
def on_connect(client, userdata, flags, rc, properties):
print('mqtt connected')
client.subscribe(MQTT_IPC_TOPIC_PREFIX + USN)
def on_disconnect(client, userdata, rc, properties):
print('mqtt disconnect')
def on_subscribe(client, userdata, mid, rc, properties):
print('Subscribed.')
def on_message(client, userdata, msg):
msg_obj = json.loads(msg.payload)
# print('mqtt received', msg_obj)
if msg_obj['type'] != 'webrtc_signal':
print('Unknown type: %s' % msg_obj['type'])
return
if msg_obj['subtype'] == 'offer':
print('process offer')
pipe = Gst.parse_launch(PIPELINE_DESC)
webrtc = pipe.get_by_name('sendrecv')
webrtc.connect('on-negotiation-needed', on_negotiation_needed)
webrtc.connect('on-ice-candidate', send_ice_candidate_message, (client, msg_obj))
webrtc.connect('pad-added', on_incoming_stream)
webrtc.connect('notify::connection-state', on_connection_state_notify)
pipe.set_state(Gst.State.PLAYING)
peers[msg_obj['source']] = webrtc
print(peers)
offer_obj = msg_obj['offer']
assert(offer_obj['type'] == 'offer')
sdp = offer_obj['sdp']
res, sdpmsg = GstSdp.SDPMessage.new()
GstSdp.sdp_message_parse_buffer(bytes(sdp.encode()), sdpmsg)
offer = GstWebRTC.WebRTCSessionDescription.new(GstWebRTC.WebRTCSDPType.OFFER, sdpmsg)
promise = Gst.Promise.new_with_change_func(on_set_description, webrtc, client, msg_obj)
webrtc.emit('set-remote-description', offer, promise)
promise.wait()
elif msg_obj['subtype'] == 'candidate':
webrtc = peers[msg_obj['source']]
if not webrtc:
print('Unknown source of candidate')
return
print('Process ice...')
candidate_obj = msg_obj['candidate']
if not candidate_obj:
return
print(candidate_obj)
webrtc.emit('add-ice-candidate', candidate_obj['sdpMLineIndex'], candidate_obj['candidate'])
else:
print('Unknown subtype: %s' % msg_obj['subtype'])
return
Gst.init(None)
if not check_plugins():
sys.exit(1)
print(Gst.version())
client = mqtt.Client(client_id='test_tinker_board_2_webrtc', protocol=mqtt.MQTTv5)
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.connect(MQTT_URL)
client.loop_forever()
The offer sent by the browser:
v=0
o=- 1510238263320950742 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=extmap-allow-mixed
a=msid-semantic: WMS a5532e2e-1efa-46cf-a66c-8c4a100d716f
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:YJn3
a=ice-pwd:QbCvGKsjzFPxFBvQYPRDJdSr
a=ice-options:trickle
a=fingerprint:sha-256 AA:57:14:42:E4:6B:D5:3E:DB:8E:E9:38:DE:63:9D:39:79:08:BA:99:7D:1D:96:CF:1F:96:58:8F:9E:41:16:CF
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=sendrecv
a=msid:a5532e2e-1efa-46cf-a66c-8c4a100d716f c0a53b85-cfb3-43d0-aefe-742abcf5ac88
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000
a=ssrc:3745948409 cname:Q2GFJXf+QUwZmcpV
a=ssrc:3745948409 msid:a5532e2e-1efa-46cf-a66c-8c4a100d716f c0a53b85-cfb3-43d0-aefe-742abcf5ac88
m=video 9 UDP/TLS/RTP/SAVPF 45 46 47 48 35 36 37 38 100 101 98 99 96 97 102 103 104 105 106 107 108 109 127 125 39 40 41 42 43 44 112 113 114 115 116 49
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:YJn3
a=ice-pwd:QbCvGKsjzFPxFBvQYPRDJdSr
a=ice-options:trickle
a=fingerprint:sha-256 AA:57:14:42:E4:6B:D5:3E:DB:8E:E9:38:DE:63:9D:39:79:08:BA:99:7D:1D:96:CF:1F:96:58:8F:9E:41:16:CF
a=setup:actpass
a=mid:1
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=recvonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:45 AV1/90000
a=rtcp-fb:45 goog-remb
a=rtcp-fb:45 transport-cc
a=rtcp-fb:45 ccm fir
a=rtcp-fb:45 nack
a=rtcp-fb:45 nack pli
a=rtpmap:46 rtx/90000
a=fmtp:46 apt=45
a=rtpmap:47 AV1/90000
a=rtcp-fb:47 goog-remb
a=rtcp-fb:47 transport-cc
a=rtcp-fb:47 ccm fir
a=rtcp-fb:47 nack
a=rtcp-fb:47 nack pli
a=fmtp:47 profile=1
a=rtpmap:48 rtx/90000
a=fmtp:48 apt=47
a=rtpmap:35 VP9/90000
a=rtcp-fb:35 goog-remb
a=rtcp-fb:35 transport-cc
a=rtcp-fb:35 ccm fir
a=rtcp-fb:35 nack
a=rtcp-fb:35 nack pli
a=fmtp:35 profile-id=1
a=rtpmap:36 rtx/90000
a=fmtp:36 apt=35
a=rtpmap:37 VP9/90000
a=rtcp-fb:37 goog-remb
a=rtcp-fb:37 transport-cc
a=rtcp-fb:37 ccm fir
a=rtcp-fb:37 nack
a=rtcp-fb:37 nack pli
a=fmtp:37 profile-id=3
a=rtpmap:38 rtx/90000
a=fmtp:38 apt=37
a=rtpmap:100 VP9/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=fmtp:100 profile-id=2
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:102 H264/90000
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 transport-cc
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:103 rtx/90000
a=fmtp:103 apt=102
a=rtpmap:104 H264/90000
a=rtcp-fb:104 goog-remb
a=rtcp-fb:104 transport-cc
a=rtcp-fb:104 ccm fir
a=rtcp-fb:104 nack
a=rtcp-fb:104 nack pli
a=fmtp:104 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtpmap:105 rtx/90000
a=fmtp:105 apt=104
a=rtpmap:106 H264/90000
a=rtcp-fb:106 goog-remb
a=rtcp-fb:106 transport-cc
a=rtcp-fb:106 ccm fir
a=rtcp-fb:106 nack
a=rtcp-fb:106 nack pli
a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=106
a=rtpmap:108 H264/90000
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 transport-cc
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtpmap:127 H264/90000
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 transport-cc
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f
a=rtpmap:125 rtx/90000
a=fmtp:125 apt=127
a=rtpmap:39 H264/90000
a=rtcp-fb:39 goog-remb
a=rtcp-fb:39 transport-cc
a=rtcp-fb:39 ccm fir
a=rtcp-fb:39 nack
a=rtcp-fb:39 nack pli
a=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f
a=rtpmap:40 rtx/90000
a=fmtp:40 apt=39
a=rtpmap:41 H264/90000
a=rtcp-fb:41 goog-remb
a=rtcp-fb:41 transport-cc
a=rtcp-fb:41 ccm fir
a=rtcp-fb:41 nack
a=rtcp-fb:41 nack pli
a=fmtp:41 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=f4001f
a=rtpmap:42 rtx/90000
a=fmtp:42 apt=41
a=rtpmap:43 H264/90000
a=rtcp-fb:43 goog-remb
a=rtcp-fb:43 transport-cc
a=rtcp-fb:43 ccm fir
a=rtcp-fb:43 nack
a=rtcp-fb:43 nack pli
a=fmtp:43 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=f4001f
a=rtpmap:44 rtx/90000
a=fmtp:44 apt=43
a=rtpmap:112 H264/90000
a=rtcp-fb:112 goog-remb
a=rtcp-fb:112 transport-cc
a=rtcp-fb:112 ccm fir
a=rtcp-fb:112 nack
a=rtcp-fb:112 nack pli
a=fmtp:112 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f
a=rtpmap:113 rtx/90000
a=fmtp:113 apt=112
a=rtpmap:114 red/90000
a=rtpmap:115 rtx/90000
a=fmtp:115 apt=114
a=rtpmap:116 ulpfec/90000
a=rtpmap:49 flexfec-03/90000
a=rtcp-fb:49 goog-remb
a=rtcp-fb:49 transport-cc
a=fmtp:49 repair-window=10000000
The answer responded by WebRTCBin
:
v=0
o=- 1510238263320950742 2 IN IP4 0.0.0.0
s=-
t=0 0
a=group:BUNDLE 0 1
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=ice-ufrag:iNopjlp4xw5BzSeD57e9gG50EzJgCtCq
a=ice-pwd:1FDGS7Bl7vZVt9ND6t3qBSVg4o4zbUAO
a=mid:0
a=rtcp-mux
a=setup:active
a=rtpmap:111 OPUS/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=recvonly
a=fingerprint:sha-256 14:23:DD:E9:61:77:1C:74:25:A4:DD:3B:FD:5D:4B:B3:E6:9D:8B:2C:6B:D3:C2:59:62:6D:BB:F1:35:81:31:89
m=video 9 UDP/TLS/RTP/SAVPF 45
c=IN IP4 0.0.0.0
a=ice-ufrag:iNopjlp4xw5BzSeD57e9gG50EzJgCtCq
a=ice-pwd:1FDGS7Bl7vZVt9ND6t3qBSVg4o4zbUAO
a=mid:1
a=rtcp-mux
a=setup:active
a=rtpmap:45 AV1/90000
a=rtcp-fb:45 nack pli
a=rtcp-fb:45 ccm fir
a=rtcp-fb:45 transport-cc
a=inactive
a=fingerprint:sha-256 14:23:DD:E9:61:77:1C:74:25:A4:DD:3B:FD:5D:4B:B3:E6:9D:8B:2C:6B:D3:C2:59:62:6D:BB:F1:35:81:31:89
When I enable the debug information of gstreamer, I see this message:
webrtcbin gstwebrtcbin.c:4569:_create_answer_task:<sendrecv> did not find compatible transceiver for offer caps application/x-rtp, media=(string)video, payload=(int)96, clock-rate=(int)90000, encoding-name=(string)VP8, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)97, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)96; application/x-rtp, media=(string)video, payload=(int)98, clock-rate=(int)90000, encoding-name=(string)VP9, profile-id=(string)0, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)99, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)98; application/x-rtp, media=(string)video, payload=(int)100, clock-rate=(int)90000, encoding-name=(string)VP9, profile-id=(string)2, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)101, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)100; application/x-rtp, media=(string)video, payload=(int)35, clock-rate=(int)90000, encoding-name=(string)VP9, profile-id=(string)1, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)36, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)35; application/x-rtp, media=(string)video, payload=(int)37, clock-rate=(int)90000, encoding-name=(string)VP9, profile-id=(string)3, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)38, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)37; application/x-rtp, media=(string)video, payload=(int)102, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)1, profile=(string)baseline, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)103, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)102; application/x-rtp, media=(string)video, payload=(int)104, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)0, profile=(string)baseline, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)105, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)104; application/x-rtp, media=(string)video, payload=(int)106, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)1, profile=(string)constrained-baseline, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)107, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)106; application/x-rtp, media=(string)video, payload=(int)108, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)0, profile=(string)constrained-baseline, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)109, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)108; application/x-rtp, media=(string)video, payload=(int)127, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)1, profile=(string)main, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)125, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)127; application/x-rtp, media=(string)video, payload=(int)39, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)0, profile=(string)main, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)40, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)39; application/x-rtp, media=(string)video, payload=(int)41, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)1, profile=(string)high-4:4:4, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)42, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)41; application/x-rtp, media=(string)video, payload=(int)43, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)0, profile=(string)high-4:4:4, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)44, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)43; application/x-rtp, media=(string)video, payload=(int)45, clock-rate=(int)90000, encoding-name=(string)AV1, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)46, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)45; application/x-rtp, media=(string)video, payload=(int)47, clock-rate=(int)90000, encoding-name=(string)AV1, profile=(string)1, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, rtcp-fb-ccm-fir=(boolean)true, rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true; application/x-rtp, media=(string)video, payload=(int)48, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)47; application/x-rtp, media=(string)video, payload=(int)112, clock-rate=(int)90000, encoding-name=(string)RED; application/x-rtp, media=(string)video, payload=(int)113, clock-rate=(int)90000, encoding-name=(string)RTX, apt=(string)112; application/x-rtp, media=(string)video, payload=(int)114, clock-rate=(int)90000, encoding-name=(string)ULPFEC; application/x-rtp, media=(string)video, payload=(int)49, clock-rate=(int)90000, encoding-name=(string)FLEXFEC-03, repair-window=(string)10000000, rtcp-fb-goog-remb=(boolean)true, rtcp-fb-transport-cc=(boolean)true, will only receive