WebRTC 的音頻數(shù)據(jù)處理發(fā)送的概念抽象層面的完整流程如下:
----------------------------- -------------------------- ---------------------------
| | | | ==> | webrtc::AudioProcessing |
| webrtc::AudioDeviceModule | ==> | webrtc::AudioTransport | ---------------------------
| | | | ||
----------------------------- -------------------------- ||
||
+=+=========================+=+
| |
\ /
|
----------------------------------------------- ---------------------
| webrtc::AudioSender/webrtc::AudioSendStream | ==> | webrtc::Transport |
----------------------------------------------- ---------------------
||
\ /
-------------------------------------------
| cricket::MediaChannel::NetworkInterface |
-------------------------------------------
AudioDeviceModule 用于控制各個(gè)操作系統(tǒng)平臺(tái)的音頻設(shè)備,主要用來做音頻的采集和播放。webrtc::AudioTransport 是一個(gè)適配和膠水模塊,它把 AudioDeviceModule 的音頻數(shù)據(jù)采集和 webrtc::AudioProcessing 的音頻數(shù)據(jù)處理及 webrtc::AudioSender/webrtc::AudioSendStream 的音頻數(shù)據(jù)編碼和發(fā)送控制粘起來,webrtc::AudioTransport 把采集的音頻數(shù)據(jù)送給 webrtc::AudioProcessing 處理,之后再把處理后的數(shù)據(jù)給到 webrtc::AudioSender/webrtc::AudioSendStream 編碼發(fā)送出去。webrtc::AudioProcessing 用于做音頻數(shù)據(jù)處理,如降噪、自動(dòng)增益控制和回聲消除等。webrtc::AudioSender/webrtc::AudioSendStream 用于對(duì)音頻數(shù)據(jù)做編碼,比如 OPUS、AAC 等,RTP 打包和發(fā)送控制。webrtc::Transport 也是一個(gè)適配和膠水模塊,它把 webrtc::AudioSender/webrtc::AudioSendStream 得到的 RTP 和 RTCP 包發(fā)送給后面的網(wǎng)絡(luò)接口模塊。cricket::MediaChannel::NetworkInterface 用于實(shí)現(xiàn)真正地把 RTP 和 RTCP 包通過底層的網(wǎng)絡(luò)接口和協(xié)議發(fā)送,如 UDP 等,ICE 的作用即為創(chuàng)建一個(gè)工作良好的網(wǎng)絡(luò)接口模塊實(shí)例。
webrtc::AudioTransport 的實(shí)現(xiàn)位于 webrtc/audio/audio_transport_impl.h/webrtc/audio/audio_transport_impl.cc。webrtc::Transport 的實(shí)現(xiàn)為 cricket::WebRtcVoiceMediaChannel(位于 webrtc/media/engine/webrtc_voice_engine.h)。如果將音頻數(shù)據(jù)處理發(fā)送流水線上的適配和膠水模塊省掉,音頻數(shù)據(jù)處理發(fā)送流水線將可簡(jiǎn)化為類似下面這樣:
----------------------------- --------------------------- --------------------------- -------------------------------------------
| | | | | webrtc::AudioSender/ | | |
| webrtc::AudioDeviceModule | ==> | webrtc::AudioProcessing | ==> | webrtc::AudioSendStream | ==> | cricket::MediaChannel::NetworkInterface |
| | | | | | | |
----------------------------- --------------------------- --------------------------- -------------------------------------------
這里來看下 webrtc::AudioSender/webrtc::AudioSendStream 中音頻數(shù)據(jù)編碼,RTP 包打包及發(fā)送控制的設(shè)計(jì)和實(shí)現(xiàn)。webrtc::AudioSender/webrtc::AudioSendStream 的實(shí)現(xiàn)位于 webrtc/audio/audio_send_stream.h / webrtc/audio/audio_send_stream.cc,相關(guān)的類層次結(jié)構(gòu)如下圖:

在 RTC 中,音頻數(shù)據(jù)的編碼發(fā)送不同于 RTMP 之類的推流方案的地方在于,在 RTC 中,音頻編碼碼率需要根據(jù)探測(cè)到的網(wǎng)絡(luò)條件,和接收端發(fā)回來的 RTCP 包,動(dòng)態(tài)地調(diào)整變換;同時(shí),由于沒有 TCP 這樣的傳輸質(zhì)量保障機(jī)制,需要根據(jù)探測(cè)的網(wǎng)絡(luò)狀態(tài),和 RTCP 反饋包,基于 RTP 對(duì)傳輸過程做控制,如 NACK,F(xiàn)EC 等。因而在 RTC 中,音頻數(shù)據(jù)編碼發(fā)送是一個(gè)相當(dāng)復(fù)雜的過程。
webrtc::AudioSendStream 的設(shè)計(jì)與實(shí)現(xiàn)主要可以從兩個(gè)角度來看,一是配置和控制,二是數(shù)據(jù)流。
對(duì)于配置和控制,可以對(duì) webrtc::AudioSendStream 執(zhí)行的配置和控制主要有如下這些:
- 配置音頻編碼的編碼器及編碼參數(shù),如最大碼率、最小碼率、payload type、FEC 等;
- 配置用于把 RTP 發(fā)送到網(wǎng)絡(luò)的
webrtc::Transport、加密參數(shù)及靜音控制等; -
webrtc::AudioSendStream的生命周期控制,如啟動(dòng)停止; - 設(shè)置網(wǎng)絡(luò)傳輸上的額外開銷大小,及動(dòng)態(tài)更新的分配碼率。
對(duì)于數(shù)據(jù)流,一是采集處理的音頻數(shù)據(jù)被送進(jìn) webrtc::AudioSendStream 以做編碼和發(fā)送處理;二是網(wǎng)絡(luò)傳回的 RTCP 包,以對(duì)編碼發(fā)送過程產(chǎn)生影響。
傳回的 RTCP 包和 webrtc::AudioSendStream 的控制接口,共同構(gòu)成音頻數(shù)據(jù)編碼及發(fā)送控制過程的信息來源。
webrtc::AudioSendStream 的實(shí)現(xiàn)中,最主要的數(shù)據(jù)處理流程 —— 音頻數(shù)據(jù)編碼、發(fā)送過程,及相關(guān)模塊如下圖:

這個(gè)圖中的箭頭表示數(shù)據(jù)流動(dòng)的方向,數(shù)據(jù)在各個(gè)模塊中處理的先后順序?yàn)樽宰笙蛴摇?/p>
webrtc::AudioSendStream 的實(shí)現(xiàn)的數(shù)據(jù)處理流程中,輸入數(shù)據(jù)為 PCM,來自于 webrtc::AudioTransport,輸出則為 RTP 包,被送給 webrtc::Transport 發(fā)出去。
webrtc::AudioSendStream 的實(shí)現(xiàn)內(nèi)部,數(shù)據(jù)首先會(huì)經(jīng)過 ACM 模塊 來做編碼,隨后經(jīng)過編碼的音頻幀送進(jìn) rtp_rtcp 模塊 打成 RTP 包,然后 RTP 包被送進(jìn) pacing 模塊 做平滑發(fā)送控制,最后再在 rtp_rtcp 模塊 中被給到webrtc::Transport 發(fā)出去。
站在 webrtc::AudioSendStream 的視角,基于抽象的模塊及接口,搭建數(shù)據(jù)處理流水線是這個(gè)組件的機(jī)制設(shè)計(jì),各個(gè)模塊及接口的具體實(shí)現(xiàn)是機(jī)制下的策略。這里先來看一下,關(guān)于 webrtc::AudioSendStream 的實(shí)現(xiàn)的這個(gè)數(shù)據(jù)處理流水線的搭建過程。
把 webrtc::AudioSendStream 的實(shí)現(xiàn)加進(jìn) webrtc::AudioTransport
webrtc::AudioSendStream 的音頻 PCM 數(shù)據(jù)來源于 webrtc::AudioTransport。webrtc::AudioSendStream 的實(shí)現(xiàn)被作為 webrtc::AudioTransport 的一個(gè) webrtc::AudioSender 加進(jìn) webrtc::AudioTransport,在 webrtc::AudioSendStream 的生命周期函數(shù) Start() 被調(diào)用時(shí)執(zhí)行,這個(gè)添加的過程大體如下:
#0 webrtc::AudioTransportImpl::UpdateAudioSenders(std::vector<webrtc::AudioSender*, std::allocator<webrtc::AudioSender*> >, int, unsigned long) ()
at webrtc/audio/audio_transport_impl.cc:262
#1 webrtc::internal::AudioState::UpdateAudioTransportWithSendingStreams() () at webrtc/audio/audio_state.cc:172
#2 webrtc::internal::AudioState::AddSendingStream(webrtc::AudioSendStream*, int, unsigned long) ()
at webrtc/audio/audio_state.cc:100
#3 webrtc::internal::AudioSendStream::Start() () at webrtc/audio/audio_send_stream.cc:370
webrtc::AudioSendStream 把它自己加進(jìn) webrtc::AudioState,webrtc::AudioState 把新加的 webrtc::AudioSendStream 和之前已經(jīng)添加的 webrtc::AudioSendStream 一起更新進(jìn) webrtc::AudioTransport。這個(gè)過程有幾個(gè)值得關(guān)注的地方:
webrtc::AudioTransport支持把錄制獲得的同一份數(shù)據(jù)同時(shí)發(fā)送給多個(gè)webrtc::AudioSender/webrtc::AudioSendStream,webrtc::AudioSendStream用于管理音頻數(shù)據(jù)的編碼和編碼數(shù)據(jù)的發(fā)送控制,這也就意味著,WebRTC 的音頻數(shù)據(jù)處理管線,支持同時(shí)把錄制獲得的音頻數(shù)據(jù),以不同的編碼方式和編碼數(shù)據(jù)發(fā)送控制機(jī)制及策略發(fā)送到不同的網(wǎng)絡(luò),比如一路發(fā)送到基于 UDP 傳輸?shù)?RTC 網(wǎng)絡(luò),另一路發(fā)送到基于 TCP 傳輸?shù)?RTMP 網(wǎng)絡(luò)。如果添加的
webrtc::AudioSendStream是第一個(gè)webrtc::AudioSendStream,webrtc::AudioState還會(huì)自動(dòng)地初始化并啟動(dòng)錄音。
webrtc::AudioSendStream 實(shí)現(xiàn)內(nèi)部的數(shù)據(jù)處理管線搭建
webrtc::AudioSendStream 實(shí)現(xiàn)內(nèi)部的數(shù)據(jù)處理管線是分步驟搭建的完成的。我們圍繞著上面的 webrtc::AudioSendStream Send Audio 圖 來看這個(gè)過程。
在 webrtc::AudioSendStream 對(duì)象創(chuàng)建,也就是 webrtc::voe::(anonymous namespace)::ChannelSend 對(duì)象創(chuàng)建時(shí),會(huì)創(chuàng)建一些關(guān)鍵對(duì)象,并建立部分各個(gè)對(duì)象之間的聯(lián)系,這個(gè)調(diào)用過程如下:
#0 webrtc::voe::(anonymous namespace)::ChannelSend::ChannelSend(webrtc::Clock*, webrtc::TaskQueueFactory*, webrtc::Transport*, webrtc::RtcpRttStats*, webrtc::RtcEventLog*, webrtc::FrameEncryptorInterface*, webrtc::CryptoOptions const&, bool, int, unsigned int, rtc::scoped_refptr<webrtc::FrameTransformerInterface>, webrtc::TransportFeedbackObserver*) () at webrtc/audio/channel_send.cc:450
#2 webrtc::voe::CreateChannelSend(webrtc::Clock*, webrtc::TaskQueueFactory*, webrtc::Transport*, webrtc::RtcpRttStats*, webrtc::RtcEventLog*, webrtc::FrameEncryptorInterface*, webrtc::CryptoOptions const&, bool, int, unsigned int, rtc::scoped_refptr<webrtc::FrameTransformerInterface>, webrtc::TransportFeedbackObserver*) () at webrtc/audio/channel_send.cc:953
#3 webrtc::internal::AudioSendStream::AudioSendStream(webrtc::Clock*, webrtc::AudioSendStream::Config const&, rtc::scoped_refptr<webrtc::AudioState> const&, webrtc::TaskQueueFactory*, webrtc::RtpTransportControllerSendInterface*, webrtc::BitrateAllocatorInterface*, webrtc::RtcEventLog*, webrtc::RtcpRttStats*, absl::optional<webrtc::RtpState> const&) () at webrtc/audio/audio_send_stream.cc:118
#4 webrtc::internal::Call::CreateAudioSendStream(webrtc::AudioSendStream::Config const&) () at webrtc/call/call.cc:897
webrtc::AudioSendStream 通過 webrtc::Call 創(chuàng)建,傳入了 webrtc::AudioSendStream::Config 包含與編解碼、RTP、加密相關(guān),及 webrtc::Transport 等各種配置。
webrtc::voe::(anonymous namespace)::ChannelSend 對(duì)象的構(gòu)造函數(shù)如下:
ChannelSend::ChannelSend(
Clock* clock,
TaskQueueFactory* task_queue_factory,
Transport* rtp_transport,
RtcpRttStats* rtcp_rtt_stats,
RtcEventLog* rtc_event_log,
FrameEncryptorInterface* frame_encryptor,
const webrtc::CryptoOptions& crypto_options,
bool extmap_allow_mixed,
int rtcp_report_interval_ms,
uint32_t ssrc,
rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
TransportFeedbackObserver* feedback_observer)
: ssrc_(ssrc),
event_log_(rtc_event_log),
_timeStamp(0), // This is just an offset, RTP module will add it's own
// random offset
input_mute_(false),
previous_frame_muted_(false),
_includeAudioLevelIndication(false),
rtcp_observer_(new VoERtcpObserver(this)),
feedback_observer_(feedback_observer),
rtp_packet_pacer_proxy_(new RtpPacketSenderProxy()),
retransmission_rate_limiter_(
new RateLimiter(clock, kMaxRetransmissionWindowMs)),
frame_encryptor_(frame_encryptor),
crypto_options_(crypto_options),
encoder_queue_(task_queue_factory->CreateTaskQueue(
"AudioEncoder",
TaskQueueFactory::Priority::NORMAL)),
fixing_timestamp_stall_(
!field_trial::IsDisabled("WebRTC-Audio-FixTimestampStall")) {
audio_coding_.reset(AudioCodingModule::Create(AudioCodingModule::Config()));
RtpRtcpInterface::Configuration configuration;
configuration.bandwidth_callback = rtcp_observer_.get();
configuration.transport_feedback_callback = feedback_observer_;
configuration.clock = (clock ? clock : Clock::GetRealTimeClock());
configuration.audio = true;
configuration.outgoing_transport = rtp_transport;
configuration.paced_sender = rtp_packet_pacer_proxy_.get();
configuration.event_log = event_log_;
configuration.rtt_stats = rtcp_rtt_stats;
configuration.retransmission_rate_limiter =
retransmission_rate_limiter_.get();
configuration.extmap_allow_mixed = extmap_allow_mixed;
configuration.rtcp_report_interval_ms = rtcp_report_interval_ms;
configuration.rtcp_packet_type_counter_observer = this;
configuration.local_media_ssrc = ssrc;
rtp_rtcp_ = ModuleRtpRtcpImpl2::Create(configuration);
rtp_rtcp_->SetSendingMediaStatus(false);
rtp_sender_audio_ = std::make_unique<RTPSenderAudio>(configuration.clock,
rtp_rtcp_->RtpSender());
// Ensure that RTCP is enabled by default for the created channel.
rtp_rtcp_->SetRTCPStatus(RtcpMode::kCompound);
int error = audio_coding_->RegisterTransportCallback(this);
RTC_DCHECK_EQ(0, error);
if (frame_transformer)
InitFrameTransformerDelegate(std::move(frame_transformer));
}
webrtc::voe::(anonymous namespace)::ChannelSend 對(duì)象的構(gòu)造函數(shù)的執(zhí)行過程如下:
- 創(chuàng)建了一個(gè)
RtpPacketSenderProxy對(duì)象; - 創(chuàng)建了一個(gè)
webrtc::AudioCodingModule對(duì)象,建立起了下圖中標(biāo)號(hào)為 1 的這條連接; - 創(chuàng)建了一個(gè)
webrtc::ModuleRtpRtcpImpl2對(duì)象,在創(chuàng)建這個(gè)對(duì)象時(shí)傳入的configuration參數(shù)的outgoing_transport配置項(xiàng)指向了傳入的webrtc::Transport,建立起了下圖中標(biāo)號(hào)為 10 的這條連接,configuration參數(shù)的paced_sender配置項(xiàng)指向了前面創(chuàng)建的RtpPacketSenderProxy對(duì)象,建立起了下圖中標(biāo)號(hào)為 7 的這條連接; - 創(chuàng)建了一個(gè)
webrtc::RTPSenderAudio對(duì)象,通過rtp_sender_audio_config的rtp_sender配置項(xiàng)傳入了從webrtc::ModuleRtpRtcpImpl2對(duì)象獲得的webrtc::RTPSender對(duì)象,建立起了下圖中標(biāo)號(hào)為 5 和 6 的這條連接; - 把
this作為webrtc::AudioPacketizationCallback注冊(cè)給了webrtc::AudioCodingModule對(duì)象,這樣就建立起了下圖中標(biāo)號(hào)為 2 的這條連接。

圖中標(biāo)為綠色的模塊為這個(gè)階段已經(jīng)接入 webrtc::voe::(anonymous namespace)::ChannelSend 的模塊,標(biāo)為黃色的則為那些還沒有接進(jìn)來的模塊;實(shí)現(xiàn)箭頭表示這個(gè)階段已經(jīng)建立的連接,虛線箭頭則表示還沒有建立的連接。
在 ChannelSend 的 RegisterSenderCongestionControlObjects() 函數(shù)中,PacedSender 發(fā)送控制相關(guān)的模塊被接進(jìn)來:
#0 webrtc::voe::(anonymous namespace)::ChannelSend::RegisterSenderCongestionControlObjects(webrtc::RtpTransportControllerSendInterface*, webrtc::RtcpBandwidthObserver*) () at webrtc/audio/channel_send.cc:713
#1 webrtc::internal::AudioSendStream::ConfigureStream(webrtc::AudioSendStream::Config const&, bool) ()
at webrtc/audio/audio_send_stream.cc:303
#2 webrtc::internal::AudioSendStream::AudioSendStream(webrtc::Clock*, webrtc::AudioSendStream::Config const&, rtc::scoped_refptr<webrtc::AudioState> const&, webrtc::TaskQueueFactory*, webrtc::RtpTransportControllerSendInterface*, webrtc::BitrateAllocatorInterface*, webrtc::RtcEventLog*, absl::optional<webrtc::RtpState> const&, std::unique_ptr<webrtc::voe::ChannelSendInterface, std::default_delete<webrtc::voe::ChannelSendInterface> >) ()
at webrtc/audio/audio_send_stream.cc:170
#3 webrtc::internal::AudioSendStream::AudioSendStream(webrtc::Clock*, webrtc::AudioSendStream::Config const&, rtc::scoped_refptr<webrtc::AudioState> const&, webrtc::TaskQueueFactory*, webrtc::RtpTransportControllerSendInterface*, webrtc::BitrateAllocatorInterface*, webrtc::RtcEventLog*, webrtc::RtcpRttStats*, absl::optional<webrtc::RtpState> const&) () at webrtc/audio/audio_send_stream.cc:110
這個(gè)操作也發(fā)生在 webrtc::AudioSendStream 對(duì)象的創(chuàng)建期間。ChannelSend 的 RegisterSenderCongestionControlObjects() 函數(shù)的實(shí)現(xiàn)如下:
void ChannelSend::RegisterSenderCongestionControlObjects(
RtpTransportControllerSendInterface* transport,
RtcpBandwidthObserver* bandwidth_observer) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
RtpPacketSender* rtp_packet_pacer = transport->packet_sender();
PacketRouter* packet_router = transport->packet_router();
RTC_DCHECK(rtp_packet_pacer);
RTC_DCHECK(packet_router);
RTC_DCHECK(!packet_router_);
rtcp_observer_->SetBandwidthObserver(bandwidth_observer);
rtp_packet_pacer_proxy_->SetPacketPacer(rtp_packet_pacer);
rtp_rtcp_->SetStorePacketsStatus(true, 600);
packet_router_ = packet_router;
}
ChannelSend 從傳入的 webrtc::RtpTransportControllerSendInterface 對(duì)象中獲得 webrtc::RtpPacketSender 和 webrtc::PacketRouter,webrtc::RtpPacketSender 被設(shè)置給前面創(chuàng)建的 RtpPacketSenderProxy 對(duì)象,這樣就建立起了前面的圖中標(biāo)號(hào)為 8 的這條連接,獲得的 webrtc::PacketRouter 保存起來備用。
這樣 webrtc::AudioSendStream 內(nèi)部的數(shù)據(jù)處理管線的狀態(tài)變?yōu)槿缦聢D所示:

音頻編碼器在 webrtc::AudioSendStream 的配置接口 Reconfigure() 被調(diào)用時(shí)創(chuàng)建,并被注入進(jìn) webrtc::AudioCodingModule。這個(gè)調(diào)用過程如下:
#0 webrtc::(anonymous namespace)::AudioCodingModuleImpl::ModifyEncoder(rtc::FunctionView<void (std::unique_ptr<webrtc::AudioEncoder, std::default_delete<webrtc::AudioEncoder> >*)>) () at webrtc/modules/audio_coding/acm2/audio_coding_module.cc:320
#1 webrtc::AudioCodingModule::SetEncoder(std::unique_ptr<webrtc::AudioEncoder, std::default_delete<webrtc::AudioEncoder> >) ()
at webrtc/modules/audio_coding/include/audio_coding_module.h:96
#2 webrtc::voe::(anonymous namespace)::ChannelSend::SetEncoder(int, std::unique_ptr<webrtc::AudioEncoder, std::default_delete<webrtc::AudioEncoder> >) () at webrtc/audio/channel_send.cc:588
#3 webrtc::internal::AudioSendStream::SetupSendCodec(webrtc::AudioSendStream::Config const&) ()
at webrtc/audio/audio_send_stream.cc:657
#4 webrtc::internal::AudioSendStream::ReconfigureSendCodec(webrtc::AudioSendStream::Config const&) ()
at webrtc/audio/audio_send_stream.cc:688
#5 webrtc::internal::AudioSendStream::ConfigureStream(webrtc::AudioSendStream::Config const&, bool) ()
at webrtc/audio/audio_send_stream.cc:323
#6 webrtc::internal::AudioSendStream::Reconfigure(webrtc::AudioSendStream::Config const&) ()
at webrtc/audio/audio_send_stream.cc:195
#7 cricket::WebRtcVoiceMediaChannel::WebRtcAudioSendStream::ReconfigureAudioSendStream() ()
at webrtc/media/engine/webrtc_voice_engine.cc:1181
來看一下 webrtc::AudioSendStream 中創(chuàng)建音頻編碼器的過程:
// Apply current codec settings to a single voe::Channel used for sending.
bool AudioSendStream::SetupSendCodec(const Config& new_config) {
RTC_DCHECK(new_config.send_codec_spec);
const auto& spec = *new_config.send_codec_spec;
RTC_DCHECK(new_config.encoder_factory);
std::unique_ptr<AudioEncoder> encoder =
new_config.encoder_factory->MakeAudioEncoder(
spec.payload_type, spec.format, new_config.codec_pair_id);
if (!encoder) {
RTC_DLOG(LS_ERROR) << "Unable to create encoder for "
<< rtc::ToString(spec.format);
return false;
}
// If a bitrate has been specified for the codec, use it over the
// codec's default.
if (spec.target_bitrate_bps) {
encoder->OnReceivedTargetAudioBitrate(*spec.target_bitrate_bps);
}
// Enable ANA if configured (currently only used by Opus).
if (new_config.audio_network_adaptor_config) {
if (encoder->EnableAudioNetworkAdaptor(
*new_config.audio_network_adaptor_config, event_log_)) {
RTC_LOG(LS_INFO) << "Audio network adaptor enabled on SSRC "
<< new_config.rtp.ssrc;
} else {
RTC_LOG(LS_INFO) << "Failed to enable Audio network adaptor on SSRC "
<< new_config.rtp.ssrc;
}
}
// Wrap the encoder in an AudioEncoderCNG, if VAD is enabled.
if (spec.cng_payload_type) {
AudioEncoderCngConfig cng_config;
cng_config.num_channels = encoder->NumChannels();
cng_config.payload_type = *spec.cng_payload_type;
cng_config.speech_encoder = std::move(encoder);
cng_config.vad_mode = Vad::kVadNormal;
encoder = CreateComfortNoiseEncoder(std::move(cng_config));
RegisterCngPayloadType(*spec.cng_payload_type,
new_config.send_codec_spec->format.clockrate_hz);
}
// Wrap the encoder in a RED encoder, if RED is enabled.
if (spec.red_payload_type) {
AudioEncoderCopyRed::Config red_config;
red_config.payload_type = *spec.red_payload_type;
red_config.speech_encoder = std::move(encoder);
encoder = std::make_unique<AudioEncoderCopyRed>(std::move(red_config));
}
// Set currently known overhead (used in ANA, opus only).
// If overhead changes later, it will be updated in UpdateOverheadForEncoder.
{
MutexLock lock(&overhead_per_packet_lock_);
size_t overhead = GetPerPacketOverheadBytes();
if (overhead > 0) {
encoder->OnReceivedOverhead(overhead);
}
}
StoreEncoderProperties(encoder->SampleRateHz(), encoder->NumChannels());
channel_send_->SetEncoder(new_config.send_codec_spec->payload_type,
std::move(encoder));
return true;
}
RTC 的音頻編碼比較特別的地方,一是編碼的數(shù)據(jù)主要是語音,二是編碼策略總是與弱網(wǎng)對(duì)抗緊密相關(guān)。從 AudioSendStream::SetupSendCodec() 函數(shù)創(chuàng)建音頻編碼器的過程也能看出來。在實(shí)際的音頻數(shù)據(jù)編碼器如 OPUS,AAC 等外面,還可以套上舒適噪音編碼器,或可以生成冗余幀的 RED 編碼器。
音頻編碼器創(chuàng)建完成之后,前面的圖中標(biāo)號(hào)為 3 和 4 的兩條連接就建立起來的。
這樣 webrtc::AudioSendStream 內(nèi)部的數(shù)據(jù)處理管線的狀態(tài)變?yōu)槿缦聢D所示:

在 webrtc::AudioSendStream 的生命周期函數(shù) Start() 被調(diào)用時(shí),webrtc::PacketRouter 和 webrtc::ModuleRtpRtcpImpl2 被連接了起來,這個(gè)調(diào)用過程如下:
#0 webrtc::voe::(anonymous namespace)::ChannelSend::StartSend() () at webrtc/audio/channel_send.cc:531
#1 webrtc::internal::AudioSendStream::Start() () at webrtc/audio/audio_send_stream.cc:368
ChannelSend::StartSend() 函數(shù)實(shí)現(xiàn)如下:
void ChannelSend::StartSend() {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
RTC_DCHECK(!sending_);
sending_ = true;
RTC_DCHECK(packet_router_);
packet_router_->AddSendRtpModule(rtp_rtcp_.get(), /*remb_candidate=*/false);
rtp_rtcp_->SetSendingMediaStatus(true);
int ret = rtp_rtcp_->SetSendingStatus(true);
RTC_DCHECK_EQ(0, ret);
// It is now OK to start processing on the encoder task queue.
encoder_queue_.PostTask([this] {
RTC_DCHECK_RUN_ON(&encoder_queue_);
encoder_queue_is_active_ = true;
});
}
這樣前面的圖中標(biāo)號(hào)為 9 的這條連接也建立起了。 webrtc::AudioSendStream 內(nèi)部的數(shù)據(jù)處理管線最終建立完成。
將上面圖中各箭頭旁邊的標(biāo)號(hào)按照建立的次序來標(biāo),則如下圖所示:

總結(jié)下來,webrtc::AudioSendStream 內(nèi)部的數(shù)據(jù)處理管線分 4 步完成了建立。
本文的分析中,含有一些函數(shù)調(diào)用棧的信息,函數(shù)調(diào)用棧的信息中甚至包含了代碼所在的源文件及行號(hào)。這里的分析基于 OpenRTCClient 中的 WebRTC M98 的源碼進(jìn)行。
后面再分模塊深入研究音頻數(shù)據(jù)編碼及發(fā)送控制的過程。
Done.