mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00

Bug: webrtc:342905193 No-Try: True Change-Id: Icc968be43b8830038ea9a1f5f604307220457807 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/361021 Auto-Submit: Florent Castelli <orphis@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Florent Castelli <orphis@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42911}
293 lines
9.9 KiB
C++
293 lines
9.9 KiB
C++
/*
|
|
* Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "audio/voip/audio_ingress.h"
|
|
|
|
#include <algorithm>
|
|
#include <ctime>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "api/audio_codecs/audio_format.h"
|
|
#include "audio/utility/audio_frame_operations.h"
|
|
#include "modules/audio_coding/include/audio_coding_module.h"
|
|
#include "modules/rtp_rtcp/source/byte_io.h"
|
|
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
|
|
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
|
|
#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/numerics/safe_minmax.h"
|
|
#include "rtc_base/time_utils.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
acm2::AcmReceiver::Config CreateAcmConfig(
|
|
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory) {
|
|
acm2::AcmReceiver::Config acm_config;
|
|
acm_config.neteq_config.enable_muted_state = true;
|
|
acm_config.decoder_factory = decoder_factory;
|
|
return acm_config;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
AudioIngress::AudioIngress(
|
|
const Environment& env,
|
|
RtpRtcpInterface* rtp_rtcp,
|
|
ReceiveStatistics* receive_statistics,
|
|
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory)
|
|
: env_(env),
|
|
playing_(false),
|
|
remote_ssrc_(0),
|
|
first_rtp_timestamp_(-1),
|
|
rtp_receive_statistics_(receive_statistics),
|
|
rtp_rtcp_(rtp_rtcp),
|
|
acm_receiver_(env_, CreateAcmConfig(decoder_factory)),
|
|
ntp_estimator_(&env_.clock()) {}
|
|
|
|
AudioIngress::~AudioIngress() = default;
|
|
|
|
AudioMixer::Source::AudioFrameInfo AudioIngress::GetAudioFrameWithInfo(
|
|
int sampling_rate,
|
|
AudioFrame* audio_frame) {
|
|
audio_frame->sample_rate_hz_ = sampling_rate;
|
|
|
|
// Get 10ms raw PCM data from the ACM.
|
|
bool muted = false;
|
|
if (acm_receiver_.GetAudio(sampling_rate, audio_frame, &muted) == -1) {
|
|
RTC_DLOG(LS_ERROR) << "GetAudio() failed!";
|
|
// In all likelihood, the audio in this frame is garbage. We return an
|
|
// error so that the audio mixer module doesn't add it to the mix. As
|
|
// a result, it won't be played out and the actions skipped here are
|
|
// irrelevant.
|
|
return AudioMixer::Source::AudioFrameInfo::kError;
|
|
}
|
|
|
|
if (muted) {
|
|
AudioFrameOperations::Mute(audio_frame);
|
|
}
|
|
|
|
// Measure audio level.
|
|
constexpr double kAudioSampleDurationSeconds = 0.01;
|
|
output_audio_level_.ComputeLevel(*audio_frame, kAudioSampleDurationSeconds);
|
|
|
|
// If caller invoked StopPlay(), then mute the frame.
|
|
if (!playing_) {
|
|
AudioFrameOperations::Mute(audio_frame);
|
|
muted = true;
|
|
}
|
|
|
|
// Set first rtp timestamp with first audio frame with valid timestamp.
|
|
if (first_rtp_timestamp_ < 0 && audio_frame->timestamp_ != 0) {
|
|
first_rtp_timestamp_ = audio_frame->timestamp_;
|
|
}
|
|
|
|
if (first_rtp_timestamp_ >= 0) {
|
|
// Compute elapsed and NTP times.
|
|
int64_t unwrap_timestamp;
|
|
{
|
|
MutexLock lock(&lock_);
|
|
unwrap_timestamp =
|
|
timestamp_wrap_handler_.Unwrap(audio_frame->timestamp_);
|
|
audio_frame->ntp_time_ms_ =
|
|
ntp_estimator_.Estimate(audio_frame->timestamp_);
|
|
}
|
|
// For clock rate, default to the playout sampling rate if we haven't
|
|
// received any packets yet.
|
|
std::optional<std::pair<int, SdpAudioFormat>> decoder =
|
|
acm_receiver_.LastDecoder();
|
|
int clock_rate = decoder ? decoder->second.clockrate_hz
|
|
: acm_receiver_.last_output_sample_rate_hz();
|
|
RTC_DCHECK_GT(clock_rate, 0);
|
|
audio_frame->elapsed_time_ms_ =
|
|
(unwrap_timestamp - first_rtp_timestamp_) / (clock_rate / 1000);
|
|
}
|
|
|
|
return muted ? AudioMixer::Source::AudioFrameInfo::kMuted
|
|
: AudioMixer::Source::AudioFrameInfo::kNormal;
|
|
}
|
|
|
|
bool AudioIngress::StartPlay() {
|
|
{
|
|
MutexLock lock(&lock_);
|
|
if (receive_codec_info_.empty()) {
|
|
RTC_DLOG(LS_WARNING) << "Receive codecs have not been set yet";
|
|
return false;
|
|
}
|
|
}
|
|
playing_ = true;
|
|
return true;
|
|
}
|
|
|
|
void AudioIngress::SetReceiveCodecs(
|
|
const std::map<int, SdpAudioFormat>& codecs) {
|
|
{
|
|
MutexLock lock(&lock_);
|
|
for (const auto& kv : codecs) {
|
|
receive_codec_info_[kv.first] = kv.second.clockrate_hz;
|
|
}
|
|
}
|
|
acm_receiver_.SetCodecs(codecs);
|
|
}
|
|
|
|
void AudioIngress::ReceivedRTPPacket(rtc::ArrayView<const uint8_t> rtp_packet) {
|
|
RtpPacketReceived rtp_packet_received;
|
|
rtp_packet_received.Parse(rtp_packet.data(), rtp_packet.size());
|
|
|
|
// Set payload type's sampling rate before we feed it into ReceiveStatistics.
|
|
{
|
|
MutexLock lock(&lock_);
|
|
const auto& it =
|
|
receive_codec_info_.find(rtp_packet_received.PayloadType());
|
|
// If sampling rate info is not available in our received codec set, it
|
|
// would mean that remote media endpoint is sending incorrect payload id
|
|
// which can't be processed correctly especially on payload type id in
|
|
// dynamic range.
|
|
if (it == receive_codec_info_.end()) {
|
|
RTC_DLOG(LS_WARNING) << "Unexpected payload id received: "
|
|
<< rtp_packet_received.PayloadType();
|
|
return;
|
|
}
|
|
rtp_packet_received.set_payload_type_frequency(it->second);
|
|
}
|
|
|
|
// Track current remote SSRC.
|
|
if (rtp_packet_received.Ssrc() != remote_ssrc_) {
|
|
rtp_rtcp_->SetRemoteSSRC(rtp_packet_received.Ssrc());
|
|
remote_ssrc_.store(rtp_packet_received.Ssrc());
|
|
}
|
|
|
|
rtp_receive_statistics_->OnRtpPacket(rtp_packet_received);
|
|
|
|
RTPHeader header;
|
|
rtp_packet_received.GetHeader(&header);
|
|
|
|
size_t packet_length = rtp_packet_received.size();
|
|
if (packet_length < header.headerLength ||
|
|
(packet_length - header.headerLength) < header.paddingLength) {
|
|
RTC_DLOG(LS_ERROR) << "Packet length(" << packet_length << ") header("
|
|
<< header.headerLength << ") padding("
|
|
<< header.paddingLength << ")";
|
|
return;
|
|
}
|
|
|
|
const uint8_t* payload = rtp_packet_received.data() + header.headerLength;
|
|
size_t payload_length = packet_length - header.headerLength;
|
|
size_t payload_data_length = payload_length - header.paddingLength;
|
|
auto data_view = rtc::ArrayView<const uint8_t>(payload, payload_data_length);
|
|
|
|
// Push the incoming payload (parsed and ready for decoding) into the ACM.
|
|
if (acm_receiver_.InsertPacket(header, data_view,
|
|
env_.clock().CurrentTime()) != 0) {
|
|
RTC_DLOG(LS_ERROR) << "AudioIngress::ReceivedRTPPacket() unable to "
|
|
"push data to the ACM";
|
|
}
|
|
}
|
|
|
|
void AudioIngress::ReceivedRTCPPacket(
|
|
rtc::ArrayView<const uint8_t> rtcp_packet) {
|
|
rtcp::CommonHeader rtcp_header;
|
|
if (rtcp_header.Parse(rtcp_packet.data(), rtcp_packet.size()) &&
|
|
(rtcp_header.type() == rtcp::SenderReport::kPacketType ||
|
|
rtcp_header.type() == rtcp::ReceiverReport::kPacketType)) {
|
|
RTC_DCHECK_GE(rtcp_packet.size(), 8);
|
|
|
|
uint32_t sender_ssrc =
|
|
ByteReader<uint32_t>::ReadBigEndian(rtcp_packet.data() + 4);
|
|
|
|
// If we don't have remote ssrc at this point, it's likely that remote
|
|
// endpoint is receive-only or it could have restarted the media.
|
|
if (sender_ssrc != remote_ssrc_) {
|
|
rtp_rtcp_->SetRemoteSSRC(sender_ssrc);
|
|
remote_ssrc_.store(sender_ssrc);
|
|
}
|
|
}
|
|
|
|
// Deliver RTCP packet to RTP/RTCP module for parsing and processing.
|
|
rtp_rtcp_->IncomingRtcpPacket(rtcp_packet);
|
|
|
|
std::optional<TimeDelta> rtt = rtp_rtcp_->LastRtt();
|
|
if (!rtt.has_value()) {
|
|
// Waiting for valid RTT.
|
|
return;
|
|
}
|
|
|
|
std::optional<RtpRtcpInterface::SenderReportStats> last_sr =
|
|
rtp_rtcp_->GetSenderReportStats();
|
|
if (!last_sr.has_value()) {
|
|
// Waiting for RTCP.
|
|
return;
|
|
}
|
|
|
|
{
|
|
MutexLock lock(&lock_);
|
|
ntp_estimator_.UpdateRtcpTimestamp(*rtt, last_sr->last_remote_timestamp,
|
|
last_sr->last_remote_rtp_timestamp);
|
|
}
|
|
}
|
|
|
|
ChannelStatistics AudioIngress::GetChannelStatistics() {
|
|
ChannelStatistics channel_stats;
|
|
|
|
// Get clockrate for current decoder ahead of jitter calculation.
|
|
uint32_t clockrate_hz = 0;
|
|
std::optional<std::pair<int, SdpAudioFormat>> decoder =
|
|
acm_receiver_.LastDecoder();
|
|
if (decoder) {
|
|
clockrate_hz = decoder->second.clockrate_hz;
|
|
}
|
|
|
|
StreamStatistician* statistician =
|
|
rtp_receive_statistics_->GetStatistician(remote_ssrc_);
|
|
if (statistician) {
|
|
RtpReceiveStats stats = statistician->GetStats();
|
|
channel_stats.packets_lost = stats.packets_lost;
|
|
channel_stats.packets_received = stats.packet_counter.packets;
|
|
channel_stats.bytes_received = stats.packet_counter.payload_bytes;
|
|
channel_stats.remote_ssrc = remote_ssrc_;
|
|
if (clockrate_hz > 0) {
|
|
channel_stats.jitter = static_cast<double>(stats.jitter) / clockrate_hz;
|
|
}
|
|
}
|
|
|
|
// Get RTCP report using remote SSRC.
|
|
const std::vector<ReportBlockData>& report_data =
|
|
rtp_rtcp_->GetLatestReportBlockData();
|
|
for (const ReportBlockData& rtcp_report : report_data) {
|
|
if (rtp_rtcp_->SSRC() != rtcp_report.source_ssrc() ||
|
|
remote_ssrc_ != rtcp_report.sender_ssrc()) {
|
|
continue;
|
|
}
|
|
RemoteRtcpStatistics remote_stat;
|
|
remote_stat.packets_lost = rtcp_report.cumulative_lost();
|
|
remote_stat.fraction_lost = rtcp_report.fraction_lost();
|
|
if (clockrate_hz > 0) {
|
|
remote_stat.jitter = rtcp_report.jitter(clockrate_hz).seconds<double>();
|
|
}
|
|
if (rtcp_report.has_rtt()) {
|
|
remote_stat.round_trip_time = rtcp_report.last_rtt().seconds<double>();
|
|
}
|
|
remote_stat.last_report_received_timestamp_ms =
|
|
rtcp_report.report_block_timestamp_utc().ms();
|
|
channel_stats.remote_rtcp = remote_stat;
|
|
|
|
// Receive only channel won't send any RTP packets.
|
|
if (!channel_stats.remote_ssrc.has_value()) {
|
|
channel_stats.remote_ssrc = remote_ssrc_;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return channel_stats;
|
|
}
|
|
|
|
} // namespace webrtc
|