在 webrtcbin 上启用 RED 以获取音频

问题描述 投票:0回答:1

我用 C++ 构建一个管道,接收 SDP 报价并对其做出响应。它与“仅”OPUS 一起工作正常,但有时音频不是很好,所以我正在考虑使用 RED,但我很难让它工作。我在这里找到了启用 RED 的方法(https://github.com/hissinger/gstreamer-webrtcbin-demo/blob/main/webrtc-sendrecv.c - 第 306-317 行),但那是在什么时候我正在提出报价,而不是回应。

代码片段

对于通用 OPUS,我以多种方式构建管道(希望下面的内容足以给出这个想法):

GstElement * _audio_depay = gst_element_factory_make("rtpopusdepay", "webrtcaudiodepay");
GstElement * _audio_dec = gst_element_factory_make("opusdec", "audiodecode");
GstElement * _audio_converter_caps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, "S16LE", "layout", G_TYPE_STRING, "interleaved", NULL);

std::stringstream ss;
ss << "webrtcbin name=webrtcbin "
   << "appsrc name=webrtcaudioappsrc ! audioconvert ! audioresample ! audiorate ! "
   << "opusenc inband-fec=true audio-type=restricted-lowdelay bitrate-type=cbr packet-loss-percentage=100 bandwidth=1102 dtx=true ! rtpopuspay dtx=true pt=111 ! "
   << "application/x-rtp,media=audio,encoding-name=OPUS,payload=111 ! webrtcbin. ";

GError * error = nullptr;
_pipeline = gst_parse_launch(ss.str().c_str(), &error);

GstElement * _webrtc = gst_bin_get_by_name(GST_BIN(_pipeline), "webrtcbin");

然后,我聆听来自

pad-added
_webrtcbin
信号,以链接我手动构建的元素,以创建一个看起来像这样的管道

webrtcbin -> rtpopusdepay -> opusdec -> audioconvert -> appsink

尝试使用RED

我从浏览器收到的 SDP 报价包含一个红色条目(我编辑了以下内容以节省空间):

m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 102 0 8 13 110 126
...
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
...

我尝试修改此报价,将

63
放在
111
行中的
m
之前,然后将其提交到我的 webrtcbin 以生成答案。

GstSDPMessage * sdp = nullptr;

gst_sdp_message_new_from_text(sdp_data.c_str(), &sdp); // sdp_data is the string sent from the browser after I've munged it

GstWebRTCSessionDescription * offer = nullptr;
offer = gst_webrtc_session_description_new(GST_WEBRTC_SDP_TYPE_OFFER, sdp);

auto promise = gst_promise_new();
g_signal_emit_by_name(_webrtc, "set-remote-description", offer, promise);
gst_promise_wait(promise);

gst_webrtc_session_description_free(offer);
gst_promise_unref(promise);

promise = gst_promise_new_with_change_func(on_answer, this, NULL);
g_signal_emit_by_name(_webrtc, "create-answer", NULL, promise);

但是,看看我给出的答案,它仍然默认使用 OPUS (111)。也许

webrtcbin
使用
rtpmap
的排序(尽管我认为不应该,对吧?),但我认为更有可能是因为
webrtcbin
链接到基于 opus 的元素,因此链接需要使用 OPUS。

我尝试手动将元素添加到管道中,以便管道看起来像

appsrc -> opusenc -> rtpopuspay -> rtpulpfecenc -> rtpredenc -> webrtcbin
webrtcbin -> rtpreddec -> rtpstorage -> rtpssrcdemux -> rtpjitterbuffer -> rtpulpfecdec -> rtpopusdepay -> opusdec -> audioconvert -> appsink

(尝试重新创建https://gstreamer.freedesktop.org/documentation/rtp/rtpredenc.html?gi-language=chttps://gstreamer.freedesktop.org/documentation/rtp/中提到的管道rtpreddec.html?gi-语言=c#rtpreddec) 目前,这会产生一个仅接收元素,当我运行时会出现警告:

0:00:13.919634921 41106 0x7756b8004940 WARN               webrtcbin gstwebrtcbin.c:4636:_create_answer_task:<webrtcbin> did not find compatible transceiver for offer caps application/x-rtp, media=(string)audio, payload=(int)63, clock-rate=(int)48000, encoding-name=(string)RED, encoding-params=(string)2, 111/111=(string)1; application/x-rtp, media=(string)audio, payload=(int)111, clock-rate=(int)48000, encoding-name=(string)OPUS, encoding-params=(string)2, minptime=(string)10, useinbandfec=(string)1, rtcp-fb-transport-cc=(boolean)true; application/x-rtp, media=(string)audio, payload=(int)9, clock-rate=(int)8000, encoding-name=(string)G722; application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU; application/x-rtp, media=(string)audio, payload=(int)8, clock-rate=(int)8000, encoding-name=(string)PCMA; application/x-rtp, media=(string)audio, payload=(int)13, clock-rate=(int)8000, encoding-name=(string)CN; application/x-rtp, media=(string)audio, payload=(int)110, clock-rate=(int)48000, encoding-name=(string)TELEPHONE-EVENT; application/x-rtp, media=(string)audio, payload=(int)126, clock-rate=(int)8000, encoding-name=(string)TELEPHONE-EVENT, will only receive

令人沮丧的是,当我构建管道的点文件时,看起来

webrtcbin
包含红色编码器和解码器,所以我认为最好的解决方案是以某种方式使用它们,而无需我重复自己,但是我不知道如何打开它们?

编辑/更新

我得到将 RED 置于 OPUS 之前的答案的唯一方法是从 m 行中完全删除 OPUS。

如果我然后尝试

get-transceivers
,我似乎没有设置
kind
,直到为时已晚。如果我将所有收发器设置为
fec-type=GST_WEBRTC_FEC_TYPE_ULP_RED
do-nack=true
,然后尽快恢复视频收发器(显然是在 ICE 候选设置期间),那么我会将视频板添加到
webrtcbin
,但不是- 协商错误。如果我对收发器不做任何事情(希望它们能自行解决)或在我拥有这种收发器后立即设置音频收发器,那么视频就会流动,但我仍然没有添加音频垫,并且会收到有关“询问”的警告创建没有远程描述的答案”)

c++ audio webrtc gstreamer opus
1个回答
0
投票

这是迄今为止我能做到的最好的。我已经更改了构建方法以删除

_pipeline = gst_parse_launch(ss.str().c_str(), &error);

我现在使用工厂构建所有元素,然后手动链接它们。一旦我构建了 webrtcbin,我就会连接到

add-transceiver
信号。然后,我将 webrtcbin 首先链接到视频负载器,然后链接到音频负载器。每个链接都会导致
add-transceiver
信号触发,因此我知道第二次触发时我会更改生成的收发器:

g_object_set(G_OBJECT(transceiver),
             "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED,
             "fec-percentage", 100,
             "do-nack", true, NULL);

我必须这样做,因为收发器的

kind
在流开始流动之前仍然未知,但为时已晚。我继续考虑我的 SDP 提议,将 RED 置于 OPUS 之前。

然而,即使采取了所有这些操作,webrtcbin 生成的答案仍将 OPUS 置于首选位置。它有红色作为第二选择,但这是它能做到的最好选择。使用 Wireshark,我相当有信心将 RED 发送给我的客户端(因为 munged 报价告诉 webrtcbin 这是客户端喜欢的),但客户端继续向我发送正常的 OPUS(因为这就是答案告诉它的内容)。天真地试图在任何时候咀嚼答案只会破坏事情。

TLDR - 进展,就我可以从服务器向客户端发送红色而言,但我仍然无法说服客户端向我发送红色。

© www.soinside.com 2019 - 2024. All rights reserved.