编解码器类关系图
Add10MsData 用于向编码器输入数据
PlayoutData10Ms 用于从解码器获取数据
IncomingPacket用于从网络获取音频包,数据是没有rtp头的
创建音频编码器的步骤
创建音频编码器的函数调用过程
右边的第一步走完后,才会执行第二步。
最后调用SetEncoder将构造好的AudioEncoderOpusImpl赋值给创建好的AudioCodingModuleImpl。
音频编码器的选择
代码分析
ChannelSend::ChannelSend
H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\audio\channel_send.cc
ChannelSend::ChannelSend(
Clock* clock,
TaskQueueFactory* task_queue_factory,
ProcessThread* module_process_thread,
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)
: event_log_(rtc_event_log),
_timeStamp(0), // This is just an offset, RTP module will add it's own
// random offset
_moduleProcessThreadPtr(module_process_thread),
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")) {
RTC_DCHECK(module_process_thread);
module_process_thread_checker_.Detach();
// 创建音频编码器
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.local_media_ssrc = ssrc;
// 创建ModuleRtpRtcpImpl2
rtp_rtcp_ = ModuleRtpRtcpImpl2::Create(configuration);
rtp_rtcp_->SetSendingMediaStatus(false);
rtp_sender_audio_ = std::make_unique<RTPSenderAudio>(configuration.clock,
rtp_rtcp_->RtpSender());
_moduleProcessThreadPtr->RegisterModule(rtp_rtcp_.get(), RTC_FROM_HERE);
// 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));
}
WebRtcVoiceMediaChannel::SetSendCodecs
// Utility function called from SetSendParameters() to extract current send
// codec settings from the given list of codecs (originally from SDP). Both send
// and receive streams may be reconfigured based on the new settings.
bool WebRtcVoiceMediaChannel::SetSendCodecs(
const std::vector<AudioCodec>& codecs) {
RTC_DCHECK_RUN_ON(worker_thread_);
dtmf_payload_type_ = absl::nullopt;
dtmf_payload_freq_ = -1;
// Validate supplied codecs list.
for (const AudioCodec& codec : codecs) {
// TODO(solenberg): Validate more aspects of input - that payload types
// don't overlap, remove redundant/unsupported codecs etc -
// the same way it is done for RtpHeaderExtensions.
if (codec.id < kMinPayloadType || codec.id > kMaxPayloadType) {
RTC_LOG(LS_WARNING) << "Codec payload type out of range: "
<< ToString(codec);
return false;
}
}
// Find PT of telephone-event codec with lowest clockrate, as a fallback, in
// case we don't have a DTMF codec with a rate matching the send codec's, or
// if this function returns early.
std::vector<AudioCodec> dtmf_codecs;
for (const AudioCodec& codec : codecs) {
if (IsCodec(codec, kDtmfCodecName)) {
dtmf_codecs.push_back(codec);
if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) {
dtmf_payload_type_ = codec.id;
dtmf_payload_freq_ = codec.clockrate;
}
}
}
// Scan through the list to figure out the codec to use for sending.
absl::optional<webrtc::AudioSendStream::Config::SendCodecSpec>
send_codec_spec;
webrtc::BitrateConstraints bitrate_config;
absl::optional<webrtc::AudioCodecInfo> voice_codec_info;
size_t send_codec_position = 0;
for (const AudioCodec& voice_codec : codecs) {
if (!(IsCodec(voice_codec, kCnCodecName) ||
IsCodec(voice_codec, kDtmfCodecName) ||
IsCodec(voice_codec, kRedCodecName))) {
webrtc::SdpAudioFormat format(voice_codec.name, voice_codec.clockrate,
voice_codec.channels, voice_codec.params);
voice_codec_info = engine()->encoder_factory_->QueryAudioEncoder(format);
if (!voice_codec_info) {
RTC_LOG(LS_WARNING) << "Unknown codec " << ToString(voice_codec);
continue;
}
send_codec_spec = webrtc::AudioSendStream::Config::SendCodecSpec(
voice_codec.id, format);
if (voice_codec.bitrate > 0) {
send_codec_spec->target_bitrate_bps = voice_codec.bitrate;
}
send_codec_spec->transport_cc_enabled = HasTransportCc(voice_codec);
send_codec_spec->nack_enabled = HasNack(voice_codec);
bitrate_config = GetBitrateConfigForCodec(voice_codec);
break;
}
send_codec_position++;
}
if (!send_codec_spec) {
return false;
}
RTC_DCHECK(voice_codec_info);
if (voice_codec_info->allow_comfort_noise) {
// Loop through the codecs list again to find the CN codec.
// TODO(solenberg): Break out into a separate function?
for (const AudioCodec& cn_codec : codecs) {
if (IsCodec(cn_codec, kCnCodecName) &&
cn_codec.clockrate == send_codec_spec->format.clockrate_hz &&
cn_codec.channels == voice_codec_info->num_channels) {
if (cn_codec.channels != 1) {
RTC_LOG(LS_WARNING)
<< "CN #channels " << cn_codec.channels << " not supported.";
} else if (cn_codec.clockrate != 8000 && cn_codec.clockrate != 16000 &&
cn_codec.clockrate != 32000) {
RTC_LOG(LS_WARNING)
<< "CN frequency " << cn_codec.clockrate << " not supported.";
} else {
send_codec_spec->cng_payload_type = cn_codec.id;
}
break;
}
}
// Find the telephone-event PT exactly matching the preferred send codec.
for (const AudioCodec& dtmf_codec : dtmf_codecs) {
if (dtmf_codec.clockrate == send_codec_spec->format.clockrate_hz) {
dtmf_payload_type_ = dtmf_codec.id;
dtmf_payload_freq_ = dtmf_codec.clockrate;
break;
}
}
}
if (audio_red_for_opus_trial_enabled_) {
// Loop through the codecs to find the RED codec that matches opus
// with respect to clockrate and number of channels.
size_t red_codec_position = 0;
for (const AudioCodec& red_codec : codecs) {
if (red_codec_position < send_codec_position &&
IsCodec(red_codec, kRedCodecName) &&
red_codec.clockrate == send_codec_spec->format.clockrate_hz &&
red_codec.channels == send_codec_spec->format.num_channels) {
send_codec_spec->red_payload_type = red_codec.id;
break;
}
red_codec_position++;
}
}
if (send_codec_spec_ != send_codec_spec) {
send_codec_spec_ = std::move(send_codec_spec);
// Apply new settings to all streams.
for (const auto& kv : send_streams_) {
kv.second->SetSendCodecSpec(*send_codec_spec_);
}
} else {
// If the codec isn't changing, set the start bitrate to -1 which means
// "unchanged" so that BWE isn't affected.
bitrate_config.start_bitrate_bps = -1;
}
call_->GetTransportControllerSend()->SetSdpBitrateParameters(bitrate_config);
// Check if the transport cc feedback or NACK status has changed on the
// preferred send codec, and in that case reconfigure all receive streams.
if (recv_transport_cc_enabled_ != send_codec_spec_->transport_cc_enabled ||
recv_nack_enabled_ != send_codec_spec_->nack_enabled) {
RTC_LOG(LS_INFO) << "Recreate all the receive streams because the send "
"codec has changed.";
recv_transport_cc_enabled_ = send_codec_spec_->transport_cc_enabled;
recv_nack_enabled_ = send_codec_spec_->nack_enabled;
for (auto& kv : recv_streams_) {
kv.second->SetUseTransportCcAndRecreateStream(recv_transport_cc_enabled_,
recv_nack_enabled_);
}
}
send_codecs_ = codecs;
return true;
}