From 7dd164df7f184df0145a4640dec1e819252c63c1 Mon Sep 17 00:00:00 2001 From: Henrik Lundin Date: Mon, 30 Sep 2024 11:27:40 +0000 Subject: [PATCH] Reland "Delete AcmReceiver" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a reland of commit 0d3dcc499767166b32a941abc9563e259ce1770f. Downstream problems were resolved. Original change's description: > Delete AcmReceiver > > The code now uses NetEq directly instead of AcmReceiver. > > Bug: webrtc:14867 > Change-Id: I11c7e2ca00060ab15bba5ec67dfd92ec413196f6 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/364140 > Commit-Queue: Henrik Lundin > Reviewed-by: Jakob Ivarsson‎ > Cr-Commit-Position: refs/heads/main@{#43108} Bug: webrtc:14867 Change-Id: Ic8d5c5ca62692fbc7caeaa76bf2e8c9c860b3ac5 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/364480 Commit-Queue: Henrik Lundin Reviewed-by: Jakob Ivarsson‎ Cr-Commit-Position: refs/heads/main@{#43143} --- modules/audio_coding/BUILD.gn | 3 - modules/audio_coding/acm2/acm_receiver.cc | 273 ------------ modules/audio_coding/acm2/acm_receiver.h | 236 ---------- .../acm2/acm_receiver_unittest.cc | 418 ------------------ 4 files changed, 930 deletions(-) delete mode 100644 modules/audio_coding/acm2/acm_receiver.cc delete mode 100644 modules/audio_coding/acm2/acm_receiver.h delete mode 100644 modules/audio_coding/acm2/acm_receiver_unittest.cc diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn index c77719a135..30d66566af 100644 --- a/modules/audio_coding/BUILD.gn +++ b/modules/audio_coding/BUILD.gn @@ -22,8 +22,6 @@ rtc_source_set("audio_coding_module_typedefs") { rtc_library("audio_coding") { visibility += [ "*" ] sources = [ - "acm2/acm_receiver.cc", - "acm2/acm_receiver.h", "acm2/acm_remixing.cc", "acm2/acm_remixing.h", "acm2/acm_resampler.cc", @@ -1571,7 +1569,6 @@ if (rtc_include_tests) { visibility += webrtc_default_visibility sources = [ - "acm2/acm_receiver_unittest.cc", "acm2/acm_remixing_unittest.cc", "acm2/audio_coding_module_unittest.cc", "acm2/call_statistics_unittest.cc", diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc deleted file mode 100644 index 674ed868c9..0000000000 --- a/modules/audio_coding/acm2/acm_receiver.cc +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2013 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 "modules/audio_coding/acm2/acm_receiver.h" - -#include -#include - -#include -#include - -#include "absl/strings/match.h" -#include "api/audio/audio_frame.h" -#include "api/audio_codecs/audio_decoder.h" -#include "api/neteq/default_neteq_factory.h" -#include "api/neteq/neteq.h" -#include "api/units/timestamp.h" -#include "modules/audio_coding/acm2/acm_resampler.h" -#include "modules/audio_coding/acm2/call_statistics.h" -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" -#include "rtc_base/numerics/safe_conversions.h" -#include "rtc_base/strings/audio_format_to_string.h" -#include "system_wrappers/include/clock.h" - -namespace webrtc { - -namespace acm2 { - -namespace { - -std::unique_ptr CreateNetEq( - NetEqFactory* neteq_factory, - const NetEq::Config& config, - const Environment& env, - scoped_refptr decoder_factory) { - if (neteq_factory) { - return neteq_factory->Create(env, config, std::move(decoder_factory)); - } - return DefaultNetEqFactory().Create(env, config, std::move(decoder_factory)); -} - -} // namespace - -AcmReceiver::Config::Config( - rtc::scoped_refptr decoder_factory) - : decoder_factory(decoder_factory) {} - -AcmReceiver::Config::Config(const Config&) = default; -AcmReceiver::Config::~Config() = default; - -AcmReceiver::AcmReceiver(const Environment& env, Config config) - : env_(env), - neteq_(CreateNetEq(config.neteq_factory, - config.neteq_config, - env_, - std::move(config.decoder_factory))) {} - -AcmReceiver::~AcmReceiver() = default; - -int AcmReceiver::SetMinimumDelay(int delay_ms) { - if (neteq_->SetMinimumDelay(delay_ms)) - return 0; - RTC_LOG(LS_ERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; - return -1; -} - -int AcmReceiver::SetMaximumDelay(int delay_ms) { - if (neteq_->SetMaximumDelay(delay_ms)) - return 0; - RTC_LOG(LS_ERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; - return -1; -} - -bool AcmReceiver::SetBaseMinimumDelayMs(int delay_ms) { - return neteq_->SetBaseMinimumDelayMs(delay_ms); -} - -int AcmReceiver::GetBaseMinimumDelayMs() const { - return neteq_->GetBaseMinimumDelayMs(); -} - -std::optional AcmReceiver::last_packet_sample_rate_hz() const { - std::optional decoder = - neteq_->GetCurrentDecoderFormat(); - if (!decoder) { - return std::nullopt; - } - return decoder->sample_rate_hz; -} - -int AcmReceiver::last_output_sample_rate_hz() const { - return neteq_->last_output_sample_rate_hz(); -} - -int AcmReceiver::InsertPacket(const RTPHeader& rtp_header, - rtc::ArrayView incoming_payload, - Timestamp receive_time) { - if (incoming_payload.empty()) { - neteq_->InsertEmptyPacket(rtp_header); - return 0; - } - if (neteq_->InsertPacket(rtp_header, incoming_payload, receive_time) < 0) { - RTC_LOG(LS_ERROR) << "AcmReceiver::InsertPacket " - << static_cast(rtp_header.payloadType) - << " Failed to insert packet"; - return -1; - } - return 0; -} - -int AcmReceiver::GetAudio(int desired_freq_hz, - AudioFrame* audio_frame, - bool* muted) { - int current_sample_rate_hz = 0; - if (neteq_->GetAudio(audio_frame, muted, ¤t_sample_rate_hz) != - NetEq::kOK) { - RTC_LOG(LS_ERROR) << "AcmReceiver::GetAudio - NetEq Failed."; - return -1; - } - RTC_DCHECK_EQ(audio_frame->sample_rate_hz_, current_sample_rate_hz); - - // Accessing members, take the lock. - MutexLock lock(&mutex_); - if (!resampler_helper_.MaybeResample(desired_freq_hz, audio_frame)) { - return -1; - } - call_stats_.DecodedByNetEq(audio_frame->speech_type_, audio_frame->muted()); - return 0; -} - -void AcmReceiver::SetCodecs(const std::map& codecs) { - neteq_->SetCodecs(codecs); -} - -void AcmReceiver::FlushBuffers() { - neteq_->FlushBuffers(); -} - -std::optional AcmReceiver::GetPlayoutTimestamp() { - return neteq_->GetPlayoutTimestamp(); -} - -int AcmReceiver::FilteredCurrentDelayMs() const { - return neteq_->FilteredCurrentDelayMs(); -} - -int AcmReceiver::TargetDelayMs() const { - return neteq_->TargetDelayMs(); -} - -std::optional> AcmReceiver::LastDecoder() const { - std::optional decoder = - neteq_->GetCurrentDecoderFormat(); - if (!decoder) { - return std::nullopt; - } - return std::make_pair(decoder->payload_type, decoder->sdp_format); -} - -void AcmReceiver::GetNetworkStatistics( - NetworkStatistics* acm_stat, - bool get_and_clear_legacy_stats /* = true */) const { - NetEqNetworkStatistics neteq_stat; - if (get_and_clear_legacy_stats) { - // NetEq function always returns zero, so we don't check the return value. - neteq_->NetworkStatistics(&neteq_stat); - - acm_stat->currentExpandRate = neteq_stat.expand_rate; - acm_stat->currentSpeechExpandRate = neteq_stat.speech_expand_rate; - acm_stat->currentPreemptiveRate = neteq_stat.preemptive_rate; - acm_stat->currentAccelerateRate = neteq_stat.accelerate_rate; - acm_stat->currentSecondaryDecodedRate = neteq_stat.secondary_decoded_rate; - acm_stat->currentSecondaryDiscardedRate = - neteq_stat.secondary_discarded_rate; - acm_stat->meanWaitingTimeMs = neteq_stat.mean_waiting_time_ms; - acm_stat->maxWaitingTimeMs = neteq_stat.max_waiting_time_ms; - } else { - neteq_stat = neteq_->CurrentNetworkStatistics(); - acm_stat->currentExpandRate = 0; - acm_stat->currentSpeechExpandRate = 0; - acm_stat->currentPreemptiveRate = 0; - acm_stat->currentAccelerateRate = 0; - acm_stat->currentSecondaryDecodedRate = 0; - acm_stat->currentSecondaryDiscardedRate = 0; - acm_stat->meanWaitingTimeMs = -1; - acm_stat->maxWaitingTimeMs = 1; - } - acm_stat->currentBufferSize = neteq_stat.current_buffer_size_ms; - acm_stat->preferredBufferSize = neteq_stat.preferred_buffer_size_ms; - acm_stat->jitterPeaksFound = neteq_stat.jitter_peaks_found ? true : false; - - NetEqLifetimeStatistics neteq_lifetime_stat = neteq_->GetLifetimeStatistics(); - acm_stat->totalSamplesReceived = neteq_lifetime_stat.total_samples_received; - acm_stat->concealedSamples = neteq_lifetime_stat.concealed_samples; - acm_stat->silentConcealedSamples = - neteq_lifetime_stat.silent_concealed_samples; - acm_stat->concealmentEvents = neteq_lifetime_stat.concealment_events; - acm_stat->jitterBufferDelayMs = neteq_lifetime_stat.jitter_buffer_delay_ms; - acm_stat->jitterBufferTargetDelayMs = - neteq_lifetime_stat.jitter_buffer_target_delay_ms; - acm_stat->jitterBufferMinimumDelayMs = - neteq_lifetime_stat.jitter_buffer_minimum_delay_ms; - acm_stat->jitterBufferEmittedCount = - neteq_lifetime_stat.jitter_buffer_emitted_count; - acm_stat->delayedPacketOutageSamples = - neteq_lifetime_stat.delayed_packet_outage_samples; - acm_stat->relativePacketArrivalDelayMs = - neteq_lifetime_stat.relative_packet_arrival_delay_ms; - acm_stat->interruptionCount = neteq_lifetime_stat.interruption_count; - acm_stat->totalInterruptionDurationMs = - neteq_lifetime_stat.total_interruption_duration_ms; - acm_stat->insertedSamplesForDeceleration = - neteq_lifetime_stat.inserted_samples_for_deceleration; - acm_stat->removedSamplesForAcceleration = - neteq_lifetime_stat.removed_samples_for_acceleration; - acm_stat->fecPacketsReceived = neteq_lifetime_stat.fec_packets_received; - acm_stat->fecPacketsDiscarded = neteq_lifetime_stat.fec_packets_discarded; - acm_stat->totalProcessingDelayUs = - neteq_lifetime_stat.total_processing_delay_us; - acm_stat->packetsDiscarded = neteq_lifetime_stat.packets_discarded; - - NetEqOperationsAndState neteq_operations_and_state = - neteq_->GetOperationsAndState(); - acm_stat->packetBufferFlushes = - neteq_operations_and_state.packet_buffer_flushes; -} - -int AcmReceiver::EnableNack(size_t max_nack_list_size) { - neteq_->EnableNack(max_nack_list_size); - return 0; -} - -void AcmReceiver::DisableNack() { - neteq_->DisableNack(); -} - -std::vector AcmReceiver::GetNackList( - int64_t round_trip_time_ms) const { - return neteq_->GetNackList(round_trip_time_ms); -} - -void AcmReceiver::ResetInitialDelay() { - neteq_->SetMinimumDelay(0); - // TODO(turajs): Should NetEq Buffer be flushed? -} - -uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const { - // Down-cast the time to (32-6)-bit since we only care about - // the least significant bits. (32-6) bits cover 2^(32-6) = 67108864 ms. - // We masked 6 most significant bits of 32-bit so there is no overflow in - // the conversion from milliseconds to timestamp. - const uint32_t now_in_ms = - static_cast(env_.clock().TimeInMilliseconds() & 0x03ffffff); - return static_cast((decoder_sampling_rate / 1000) * now_in_ms); -} - -void AcmReceiver::GetDecodingCallStatistics( - AudioDecodingCallStats* stats) const { - MutexLock lock(&mutex_); - *stats = call_stats_.GetDecodingStatistics(); -} - -} // namespace acm2 - -} // namespace webrtc diff --git a/modules/audio_coding/acm2/acm_receiver.h b/modules/audio_coding/acm2/acm_receiver.h deleted file mode 100644 index 47de3bc9fd..0000000000 --- a/modules/audio_coding/acm2/acm_receiver.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2013 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. - */ - -#ifndef MODULES_AUDIO_CODING_ACM2_ACM_RECEIVER_H_ -#define MODULES_AUDIO_CODING_ACM2_ACM_RECEIVER_H_ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "api/array_view.h" -#include "api/audio/audio_frame.h" -#include "api/audio_codecs/audio_decoder.h" -#include "api/audio_codecs/audio_decoder_factory.h" -#include "api/audio_codecs/audio_format.h" -#include "api/environment/environment.h" -#include "api/neteq/neteq.h" -#include "api/neteq/neteq_factory.h" -#include "api/units/timestamp.h" -#include "modules/audio_coding/acm2/acm_resampler.h" -#include "modules/audio_coding/acm2/call_statistics.h" -#include "modules/audio_coding/include/audio_coding_module_typedefs.h" -#include "rtc_base/synchronization/mutex.h" -#include "rtc_base/thread_annotations.h" - -namespace webrtc { - -class NetEq; -struct RTPHeader; - -namespace acm2 { - -// This class is deprecated. See https://issues.webrtc.org/issues/42225167. -class AcmReceiver { - public: - struct Config { - explicit Config( - rtc::scoped_refptr decoder_factory = nullptr); - Config(const Config&); - ~Config(); - - NetEq::Config neteq_config; - rtc::scoped_refptr decoder_factory; - NetEqFactory* neteq_factory = nullptr; - }; - - AcmReceiver(const Environment& env, Config config); - - // Destructor of the class. - ~AcmReceiver(); - - // - // Inserts a payload with its associated RTP-header into NetEq. - // - // Input: - // - rtp_header : RTP header for the incoming payload containing - // information about payload type, sequence number, - // timestamp, SSRC and marker bit. - // - incoming_payload : Incoming audio payload. - // - receive_time : Timestamp when the packet has been seen on the - // network card. - // - // Return value : 0 if OK. - // <0 if NetEq returned an error. - // - int InsertPacket(const RTPHeader& rtp_header, - rtc::ArrayView incoming_payload, - Timestamp receive_time = Timestamp::MinusInfinity()); - - // - // Asks NetEq for 10 milliseconds of decoded audio. - // - // Input: - // -desired_freq_hz : specifies the sampling rate [Hz] of the output - // audio. If set -1 indicates to resampling is - // is required and the audio returned at the - // sampling rate of the decoder. - // - // Output: - // -audio_frame : an audio frame were output data and - // associated parameters are written to. - // -muted : if true, the sample data in audio_frame is not - // populated, and must be interpreted as all zero. - // - // Return value : 0 if OK. - // -1 if NetEq returned an error. - // - int GetAudio(int desired_freq_hz, - AudioFrame* audio_frame, - bool* muted = nullptr); - - // Replace the current set of decoders with the specified set. - void SetCodecs(const std::map& codecs); - - // - // Sets a minimum delay for packet buffer. The given delay is maintained, - // unless channel condition dictates a higher delay. - // - // Input: - // - delay_ms : minimum delay in milliseconds. - // - // Return value : 0 if OK. - // <0 if NetEq returned an error. - // - int SetMinimumDelay(int delay_ms); - - // - // Sets a maximum delay [ms] for the packet buffer. The target delay does not - // exceed the given value, even if channel condition requires so. - // - // Input: - // - delay_ms : maximum delay in milliseconds. - // - // Return value : 0 if OK. - // <0 if NetEq returned an error. - // - int SetMaximumDelay(int delay_ms); - - // Sets a base minimum delay in milliseconds for the packet buffer. - // Base minimum delay sets lower bound minimum delay value which - // is set via SetMinimumDelay. - // - // Returns true if value was successfully set, false overwise. - bool SetBaseMinimumDelayMs(int delay_ms); - - // Returns current value of base minimum delay in milliseconds. - int GetBaseMinimumDelayMs() const; - - // - // Resets the initial delay to zero. - // - void ResetInitialDelay(); - - // Returns the sample rate of the decoder associated with the last incoming - // packet. If no packet of a registered non-CNG codec has been received, the - // return value is empty. Also, if the decoder was unregistered since the last - // packet was inserted, the return value is empty. - std::optional last_packet_sample_rate_hz() const; - - // Returns last_output_sample_rate_hz from the NetEq instance. - int last_output_sample_rate_hz() const; - - // - // Get the current network statistics from NetEq. - // - // Output: - // - statistics : The current network statistics. - // - void GetNetworkStatistics(NetworkStatistics* statistics, - bool get_and_clear_legacy_stats = true) const; - - // - // Flushes the NetEq packet and speech buffers. - // - void FlushBuffers(); - - // Returns the RTP timestamp for the last sample delivered by GetAudio(). - // The return value will be empty if no valid timestamp is available. - std::optional GetPlayoutTimestamp(); - - // Returns the current total delay from NetEq (packet buffer and sync buffer) - // in ms, with smoothing applied to even out short-time fluctuations due to - // jitter. The packet buffer part of the delay is not updated during DTX/CNG - // periods. - // - int FilteredCurrentDelayMs() const; - - // Returns the current target delay for NetEq in ms. - // - int TargetDelayMs() const; - - // - // Get payload type and format of the last non-CNG/non-DTMF received payload. - // If no non-CNG/non-DTMF packet is received std::nullopt is returned. - // - std::optional> LastDecoder() const; - - // - // Enable NACK and set the maximum size of the NACK list. If NACK is already - // enabled then the maximum NACK list size is modified accordingly. - // - // If the sequence number of last received packet is N, the sequence numbers - // of NACK list are in the range of [N - `max_nack_list_size`, N). - // - // `max_nack_list_size` should be positive (none zero) and less than or - // equal to `Nack::kNackListSizeLimit`. Otherwise, No change is applied and -1 - // is returned. 0 is returned at success. - // - int EnableNack(size_t max_nack_list_size); - - // Disable NACK. - void DisableNack(); - - // - // Get a list of packets to be retransmitted. `round_trip_time_ms` is an - // estimate of the round-trip-time (in milliseconds). Missing packets which - // will be playout in a shorter time than the round-trip-time (with respect - // to the time this API is called) will not be included in the list. - // - // Negative `round_trip_time_ms` results is an error message and empty list - // is returned. - // - std::vector GetNackList(int64_t round_trip_time_ms) const; - - // - // Get statistics of calls to GetAudio(). - void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const; - - private: - uint32_t NowInTimestamp(int decoder_sampling_rate) const; - - const Environment env_; - mutable Mutex mutex_; - CallStatistics call_stats_ RTC_GUARDED_BY(mutex_); - const std::unique_ptr neteq_; // NetEq is thread-safe; no lock needed. - ResamplerHelper resampler_helper_ RTC_GUARDED_BY(mutex_); -}; - -} // namespace acm2 - -} // namespace webrtc - -#endif // MODULES_AUDIO_CODING_ACM2_ACM_RECEIVER_H_ diff --git a/modules/audio_coding/acm2/acm_receiver_unittest.cc b/modules/audio_coding/acm2/acm_receiver_unittest.cc deleted file mode 100644 index 55b5c49663..0000000000 --- a/modules/audio_coding/acm2/acm_receiver_unittest.cc +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2013 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 "modules/audio_coding/acm2/acm_receiver.h" - -#include // std::min -#include -#include - -#include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "api/audio_codecs/builtin_audio_encoder_factory.h" -#include "api/environment/environment.h" -#include "api/environment/environment_factory.h" -#include "api/units/timestamp.h" -#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h" -#include "modules/audio_coding/include/audio_coding_module.h" -#include "modules/audio_coding/neteq/tools/rtp_generator.h" -#include "modules/include/module_common_types.h" -#include "rtc_base/checks.h" -#include "rtc_base/numerics/safe_conversions.h" -#include "system_wrappers/include/clock.h" -#include "test/gtest.h" -#include "test/testsupport/file_utils.h" - -namespace webrtc { - -namespace acm2 { - -class AcmReceiverTestOldApi : public AudioPacketizationCallback, - public ::testing::Test { - protected: - AcmReceiverTestOldApi() - : timestamp_(0), - packet_sent_(false), - last_packet_send_timestamp_(timestamp_), - last_frame_type_(AudioFrameType::kEmptyFrame) { - config_.decoder_factory = decoder_factory_; - } - - ~AcmReceiverTestOldApi() {} - - void SetUp() override { - acm_ = AudioCodingModule::Create(); - receiver_ = std::make_unique(env_, config_); - ASSERT_TRUE(receiver_.get() != NULL); - ASSERT_TRUE(acm_.get() != NULL); - acm_->RegisterTransportCallback(this); - - rtp_header_.sequenceNumber = 0; - rtp_header_.timestamp = 0; - rtp_header_.markerBit = false; - rtp_header_.ssrc = 0x12345678; // Arbitrary. - rtp_header_.numCSRCs = 0; - rtp_header_.payloadType = 0; - } - - void TearDown() override {} - - AudioCodecInfo SetEncoder(int payload_type, - const SdpAudioFormat& format, - const std::map cng_payload_types = {}) { - // Create the speech encoder. - std::optional info = - encoder_factory_->QueryAudioEncoder(format); - RTC_CHECK(info.has_value()); - std::unique_ptr enc = - encoder_factory_->Create(env_, format, {.payload_type = payload_type}); - - // If we have a compatible CN specification, stack a CNG on top. - auto it = cng_payload_types.find(info->sample_rate_hz); - if (it != cng_payload_types.end()) { - AudioEncoderCngConfig config; - config.speech_encoder = std::move(enc); - config.num_channels = 1; - config.payload_type = it->second; - config.vad_mode = Vad::kVadNormal; - enc = CreateComfortNoiseEncoder(std::move(config)); - } - - // Actually start using the new encoder. - acm_->SetEncoder(std::move(enc)); - return *info; - } - - int InsertOnePacketOfSilence(const AudioCodecInfo& info) { - // Frame setup according to the codec. - AudioFrame frame; - frame.sample_rate_hz_ = info.sample_rate_hz; - frame.samples_per_channel_ = info.sample_rate_hz / 100; // 10 ms. - frame.num_channels_ = info.num_channels; - frame.Mute(); - packet_sent_ = false; - last_packet_send_timestamp_ = timestamp_; - int num_10ms_frames = 0; - while (!packet_sent_) { - frame.timestamp_ = timestamp_; - timestamp_ += rtc::checked_cast(frame.samples_per_channel_); - EXPECT_GE(acm_->Add10MsData(frame), 0); - ++num_10ms_frames; - } - return num_10ms_frames; - } - - int SendData(AudioFrameType frame_type, - uint8_t payload_type, - uint32_t timestamp, - const uint8_t* payload_data, - size_t payload_len_bytes, - int64_t absolute_capture_timestamp_ms) override { - if (frame_type == AudioFrameType::kEmptyFrame) - return 0; - - rtp_header_.payloadType = payload_type; - rtp_header_.timestamp = timestamp; - - int ret_val = receiver_->InsertPacket( - rtp_header_, - rtc::ArrayView(payload_data, payload_len_bytes), - Timestamp::MinusInfinity()); - if (ret_val < 0) { - RTC_DCHECK_NOTREACHED(); - return -1; - } - rtp_header_.sequenceNumber++; - packet_sent_ = true; - last_frame_type_ = frame_type; - return 0; - } - - const Environment env_ = CreateEnvironment(); - const rtc::scoped_refptr encoder_factory_ = - CreateBuiltinAudioEncoderFactory(); - const rtc::scoped_refptr decoder_factory_ = - CreateBuiltinAudioDecoderFactory(); - acm2::AcmReceiver::Config config_; - std::unique_ptr receiver_; - std::unique_ptr acm_; - RTPHeader rtp_header_; - uint32_t timestamp_; - bool packet_sent_; // Set when SendData is called reset when inserting audio. - uint32_t last_packet_send_timestamp_; - AudioFrameType last_frame_type_; -}; - -#if defined(WEBRTC_ANDROID) -#define MAYBE_SampleRate DISABLED_SampleRate -#else -#define MAYBE_SampleRate SampleRate -#endif -TEST_F(AcmReceiverTestOldApi, MAYBE_SampleRate) { - const std::map codecs = {{0, {"OPUS", 48000, 2}}}; - receiver_->SetCodecs(codecs); - - constexpr int kOutSampleRateHz = 8000; // Different than codec sample rate. - for (size_t i = 0; i < codecs.size(); ++i) { - const int payload_type = rtc::checked_cast(i); - const int num_10ms_frames = - InsertOnePacketOfSilence(SetEncoder(payload_type, codecs.at(i))); - for (int k = 0; k < num_10ms_frames; ++k) { - AudioFrame frame; - bool muted; - EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame, &muted)); - } - EXPECT_EQ(encoder_factory_->QueryAudioEncoder(codecs.at(i))->sample_rate_hz, - receiver_->last_output_sample_rate_hz()); - } -} - -class AcmReceiverTestFaxModeOldApi : public AcmReceiverTestOldApi { - protected: - AcmReceiverTestFaxModeOldApi() { - config_.neteq_config.for_test_no_time_stretching = true; - } - - void RunVerifyAudioFrame(const SdpAudioFormat& codec) { - // Make sure "fax mode" is enabled. This will avoid delay changes unless the - // packet-loss concealment is made. We do this in order to make the - // timestamp increments predictable; in normal mode, NetEq may decide to do - // accelerate or pre-emptive expand operations after some time, offsetting - // the timestamp. - EXPECT_TRUE(config_.neteq_config.for_test_no_time_stretching); - - constexpr int payload_type = 17; - receiver_->SetCodecs({{payload_type, codec}}); - - const AudioCodecInfo info = SetEncoder(payload_type, codec); - const int output_sample_rate_hz = info.sample_rate_hz; - const size_t output_channels = info.num_channels; - const size_t samples_per_ms = rtc::checked_cast( - rtc::CheckedDivExact(output_sample_rate_hz, 1000)); - - // Expect the first output timestamp to be 5*fs/8000 samples before the - // first inserted timestamp (because of NetEq's look-ahead). (This value is - // defined in Expand::overlap_length_.) - uint32_t expected_output_ts = - last_packet_send_timestamp_ - - rtc::CheckedDivExact(5 * output_sample_rate_hz, 8000); - - AudioFrame frame; - bool muted; - EXPECT_EQ(0, receiver_->GetAudio(output_sample_rate_hz, &frame, &muted)); - // Expect timestamp = 0 before first packet is inserted. - EXPECT_EQ(0u, frame.timestamp_); - for (int i = 0; i < 5; ++i) { - const int num_10ms_frames = InsertOnePacketOfSilence(info); - for (int k = 0; k < num_10ms_frames; ++k) { - EXPECT_EQ(0, - receiver_->GetAudio(output_sample_rate_hz, &frame, &muted)); - EXPECT_EQ(expected_output_ts, frame.timestamp_); - expected_output_ts += rtc::checked_cast(10 * samples_per_ms); - EXPECT_EQ(10 * samples_per_ms, frame.samples_per_channel_); - EXPECT_EQ(output_sample_rate_hz, frame.sample_rate_hz_); - EXPECT_EQ(output_channels, frame.num_channels_); - EXPECT_EQ(AudioFrame::kNormalSpeech, frame.speech_type_); - EXPECT_FALSE(muted); - } - } - } -}; - -#if defined(WEBRTC_ANDROID) -#define MAYBE_VerifyAudioFramePCMU DISABLED_VerifyAudioFramePCMU -#else -#define MAYBE_VerifyAudioFramePCMU VerifyAudioFramePCMU -#endif -TEST_F(AcmReceiverTestFaxModeOldApi, MAYBE_VerifyAudioFramePCMU) { - RunVerifyAudioFrame({"PCMU", 8000, 1}); -} - -#if defined(WEBRTC_ANDROID) -#define MAYBE_VerifyAudioFrameOpus DISABLED_VerifyAudioFrameOpus -#else -#define MAYBE_VerifyAudioFrameOpus VerifyAudioFrameOpus -#endif -TEST_F(AcmReceiverTestFaxModeOldApi, MAYBE_VerifyAudioFrameOpus) { - RunVerifyAudioFrame({"opus", 48000, 2}); -} - -#if defined(WEBRTC_ANDROID) -#define MAYBE_LastAudioCodec DISABLED_LastAudioCodec -#else -#define MAYBE_LastAudioCodec LastAudioCodec -#endif -#if defined(WEBRTC_CODEC_OPUS) -TEST_F(AcmReceiverTestOldApi, MAYBE_LastAudioCodec) { - const std::map codecs = { - {0, {"PCMU", 8000, 1}}, {1, {"PCMA", 8000, 1}}, {2, {"L16", 32000, 1}}}; - const std::map cng_payload_types = { - {8000, 100}, {16000, 101}, {32000, 102}}; - { - std::map receive_codecs = codecs; - for (const auto& cng_type : cng_payload_types) { - receive_codecs.emplace(std::make_pair( - cng_type.second, SdpAudioFormat("CN", cng_type.first, 1))); - } - receiver_->SetCodecs(receive_codecs); - } - - // No audio payload is received. - EXPECT_EQ(std::nullopt, receiver_->LastDecoder()); - - // Start with sending DTX. - packet_sent_ = false; - InsertOnePacketOfSilence( - SetEncoder(0, codecs.at(0), cng_payload_types)); // Enough to test - // with one codec. - ASSERT_TRUE(packet_sent_); - EXPECT_EQ(AudioFrameType::kAudioFrameCN, last_frame_type_); - - // Has received, only, DTX. Last Audio codec is undefined. - EXPECT_EQ(std::nullopt, receiver_->LastDecoder()); - EXPECT_EQ(std::nullopt, receiver_->last_packet_sample_rate_hz()); - - for (size_t i = 0; i < codecs.size(); ++i) { - // Set DTX off to send audio payload. - packet_sent_ = false; - const int payload_type = rtc::checked_cast(i); - const AudioCodecInfo info_without_cng = - SetEncoder(payload_type, codecs.at(i)); - InsertOnePacketOfSilence(info_without_cng); - - // Sanity check if Actually an audio payload received, and it should be - // of type "speech." - ASSERT_TRUE(packet_sent_); - ASSERT_EQ(AudioFrameType::kAudioFrameSpeech, last_frame_type_); - EXPECT_EQ(info_without_cng.sample_rate_hz, - receiver_->last_packet_sample_rate_hz()); - - // Set VAD on to send DTX. Then check if the "Last Audio codec" returns - // the expected codec. Encode repeatedly until a DTX is sent. - const AudioCodecInfo info_with_cng = - SetEncoder(payload_type, codecs.at(i), cng_payload_types); - while (last_frame_type_ != AudioFrameType::kAudioFrameCN) { - packet_sent_ = false; - InsertOnePacketOfSilence(info_with_cng); - ASSERT_TRUE(packet_sent_); - } - EXPECT_EQ(info_with_cng.sample_rate_hz, - receiver_->last_packet_sample_rate_hz()); - EXPECT_EQ(codecs.at(i), receiver_->LastDecoder()->second); - } -} -#endif - -// Check if the statistics are initialized correctly. Before any call to ACM -// all fields have to be zero. -#if defined(WEBRTC_ANDROID) -#define MAYBE_InitializedToZero DISABLED_InitializedToZero -#else -#define MAYBE_InitializedToZero InitializedToZero -#endif -TEST_F(AcmReceiverTestOldApi, MAYBE_InitializedToZero) { - AudioDecodingCallStats stats; - receiver_->GetDecodingCallStatistics(&stats); - EXPECT_EQ(0, stats.calls_to_neteq); - EXPECT_EQ(0, stats.calls_to_silence_generator); - EXPECT_EQ(0, stats.decoded_normal); - EXPECT_EQ(0, stats.decoded_cng); - EXPECT_EQ(0, stats.decoded_neteq_plc); - EXPECT_EQ(0, stats.decoded_plc_cng); - EXPECT_EQ(0, stats.decoded_muted_output); -} - -#if defined(WEBRTC_ANDROID) -#define MAYBE_VerifyOutputFrame DISABLED_VerifyOutputFrame -#else -#define MAYBE_VerifyOutputFrame VerifyOutputFrame -#endif -TEST_F(AcmReceiverTestOldApi, MAYBE_VerifyOutputFrame) { - AudioFrame audio_frame; - const int kSampleRateHz = 32000; - bool muted; - EXPECT_EQ(0, receiver_->GetAudio(kSampleRateHz, &audio_frame, &muted)); - ASSERT_FALSE(muted); - EXPECT_EQ(0u, audio_frame.timestamp_); - EXPECT_GT(audio_frame.num_channels_, 0u); - EXPECT_EQ(static_cast(kSampleRateHz / 100), - audio_frame.samples_per_channel_); - EXPECT_EQ(kSampleRateHz, audio_frame.sample_rate_hz_); -} - -// Insert some packets and pull audio. Check statistics are valid. Then, -// simulate packet loss and check if PLC and PLC-to-CNG statistics are -// correctly updated. -#if defined(WEBRTC_ANDROID) -#define MAYBE_NetEqCalls DISABLED_NetEqCalls -#else -#define MAYBE_NetEqCalls NetEqCalls -#endif -TEST_F(AcmReceiverTestOldApi, MAYBE_NetEqCalls) { - AudioDecodingCallStats stats; - const int kNumNormalCalls = 10; - const int kSampleRateHz = 16000; - const int kNumSamples10ms = kSampleRateHz / 100; - const int kFrameSizeMs = 10; // Multiple of 10. - const int kFrameSizeSamples = kFrameSizeMs / 10 * kNumSamples10ms; - const int kPayloadSizeBytes = kFrameSizeSamples * sizeof(int16_t); - const uint8_t kPayloadType = 111; - RTPHeader rtp_header; - AudioFrame audio_frame; - bool muted; - - receiver_->SetCodecs( - {{kPayloadType, SdpAudioFormat("L16", kSampleRateHz, 1)}}); - rtp_header.sequenceNumber = 0xABCD; - rtp_header.timestamp = 0xABCDEF01; - rtp_header.payloadType = kPayloadType; - rtp_header.markerBit = false; - rtp_header.ssrc = 0x1234; - rtp_header.numCSRCs = 0; - - for (int num_calls = 0; num_calls < kNumNormalCalls; ++num_calls) { - const uint8_t kPayload[kPayloadSizeBytes] = {0}; - ASSERT_EQ(0, receiver_->InsertPacket(rtp_header, kPayload, - Timestamp::MinusInfinity())); - ++rtp_header.sequenceNumber; - rtp_header.timestamp += kFrameSizeSamples; - ASSERT_EQ(0, receiver_->GetAudio(-1, &audio_frame, &muted)); - EXPECT_FALSE(muted); - } - receiver_->GetDecodingCallStatistics(&stats); - EXPECT_EQ(kNumNormalCalls, stats.calls_to_neteq); - EXPECT_EQ(0, stats.calls_to_silence_generator); - EXPECT_EQ(kNumNormalCalls, stats.decoded_normal); - EXPECT_EQ(0, stats.decoded_cng); - EXPECT_EQ(0, stats.decoded_neteq_plc); - EXPECT_EQ(0, stats.decoded_plc_cng); - EXPECT_EQ(0, stats.decoded_muted_output); - - const int kNumPlc = 3; - const int kNumPlcCng = 5; - - // Simulate packet-loss. NetEq first performs PLC then PLC fades to CNG. - for (int n = 0; n < kNumPlc + kNumPlcCng; ++n) { - ASSERT_EQ(0, receiver_->GetAudio(-1, &audio_frame, &muted)); - EXPECT_FALSE(muted); - } - receiver_->GetDecodingCallStatistics(&stats); - EXPECT_EQ(kNumNormalCalls + kNumPlc + kNumPlcCng, stats.calls_to_neteq); - EXPECT_EQ(0, stats.calls_to_silence_generator); - EXPECT_EQ(kNumNormalCalls, stats.decoded_normal); - EXPECT_EQ(0, stats.decoded_cng); - EXPECT_EQ(kNumPlc, stats.decoded_neteq_plc); - EXPECT_EQ(kNumPlcCng, stats.decoded_plc_cng); - EXPECT_EQ(0, stats.decoded_muted_output); - // TODO(henrik.lundin) Add a test with muted state enabled. -} - -} // namespace acm2 - -} // namespace webrtc