xref: /aosp_15_r20/external/webrtc/modules/audio_coding/acm2/acm_send_test.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/audio_coding/acm2/acm_send_test.h"
12 
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include "absl/strings/match.h"
17 #include "absl/strings/string_view.h"
18 #include "api/audio_codecs/audio_encoder.h"
19 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
20 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
21 #include "modules/audio_coding/include/audio_coding_module.h"
22 #include "modules/audio_coding/neteq/tools/input_audio_file.h"
23 #include "modules/audio_coding/neteq/tools/packet.h"
24 #include "rtc_base/checks.h"
25 #include "rtc_base/string_encode.h"
26 #include "test/gtest.h"
27 
28 namespace webrtc {
29 namespace test {
30 
AcmSendTestOldApi(InputAudioFile * audio_source,int source_rate_hz,int test_duration_ms)31 AcmSendTestOldApi::AcmSendTestOldApi(InputAudioFile* audio_source,
32                                      int source_rate_hz,
33                                      int test_duration_ms)
34     : clock_(0),
35       acm_(webrtc::AudioCodingModule::Create([this] {
36         AudioCodingModule::Config config;
37         config.clock = &clock_;
38         config.decoder_factory = CreateBuiltinAudioDecoderFactory();
39         return config;
40       }())),
41       audio_source_(audio_source),
42       source_rate_hz_(source_rate_hz),
43       input_block_size_samples_(
44           static_cast<size_t>(source_rate_hz_ * kBlockSizeMs / 1000)),
45       codec_registered_(false),
46       test_duration_ms_(test_duration_ms),
47       frame_type_(AudioFrameType::kAudioFrameSpeech),
48       payload_type_(0),
49       timestamp_(0),
50       sequence_number_(0) {
51   input_frame_.sample_rate_hz_ = source_rate_hz_;
52   input_frame_.num_channels_ = 1;
53   input_frame_.samples_per_channel_ = input_block_size_samples_;
54   RTC_DCHECK_LE(input_block_size_samples_ * input_frame_.num_channels_,
55                 AudioFrame::kMaxDataSizeSamples);
56   acm_->RegisterTransportCallback(this);
57 }
58 
59 AcmSendTestOldApi::~AcmSendTestOldApi() = default;
60 
RegisterCodec(absl::string_view payload_name,int clockrate_hz,int num_channels,int payload_type,int frame_size_samples)61 bool AcmSendTestOldApi::RegisterCodec(absl::string_view payload_name,
62                                       int clockrate_hz,
63                                       int num_channels,
64                                       int payload_type,
65                                       int frame_size_samples) {
66   SdpAudioFormat format(payload_name, clockrate_hz, num_channels);
67   if (absl::EqualsIgnoreCase(payload_name, "g722")) {
68     RTC_CHECK_EQ(16000, clockrate_hz);
69     format.clockrate_hz = 8000;
70   } else if (absl::EqualsIgnoreCase(payload_name, "opus")) {
71     RTC_CHECK(num_channels == 1 || num_channels == 2);
72     if (num_channels == 2) {
73       format.parameters["stereo"] = "1";
74     }
75     format.num_channels = 2;
76   }
77   format.parameters["ptime"] = rtc::ToString(rtc::CheckedDivExact(
78       frame_size_samples, rtc::CheckedDivExact(clockrate_hz, 1000)));
79   auto factory = CreateBuiltinAudioEncoderFactory();
80   acm_->SetEncoder(
81       factory->MakeAudioEncoder(payload_type, format, absl::nullopt));
82   codec_registered_ = true;
83   input_frame_.num_channels_ = num_channels;
84   RTC_DCHECK_LE(input_block_size_samples_ * input_frame_.num_channels_,
85                 AudioFrame::kMaxDataSizeSamples);
86   return codec_registered_;
87 }
88 
RegisterExternalCodec(std::unique_ptr<AudioEncoder> external_speech_encoder)89 void AcmSendTestOldApi::RegisterExternalCodec(
90     std::unique_ptr<AudioEncoder> external_speech_encoder) {
91   input_frame_.num_channels_ = external_speech_encoder->NumChannels();
92   acm_->SetEncoder(std::move(external_speech_encoder));
93   RTC_DCHECK_LE(input_block_size_samples_ * input_frame_.num_channels_,
94                 AudioFrame::kMaxDataSizeSamples);
95   codec_registered_ = true;
96 }
97 
NextPacket()98 std::unique_ptr<Packet> AcmSendTestOldApi::NextPacket() {
99   RTC_DCHECK(codec_registered_);
100   if (filter_.test(static_cast<size_t>(payload_type_))) {
101     // This payload type should be filtered out. Since the payload type is the
102     // same throughout the whole test run, no packet at all will be delivered.
103     // We can just as well signal that the test is over by returning NULL.
104     return nullptr;
105   }
106   // Insert audio and process until one packet is produced.
107   while (clock_.TimeInMilliseconds() < test_duration_ms_) {
108     clock_.AdvanceTimeMilliseconds(kBlockSizeMs);
109     RTC_CHECK(audio_source_->Read(
110         input_block_size_samples_ * input_frame_.num_channels_,
111         input_frame_.mutable_data()));
112     data_to_send_ = false;
113     RTC_CHECK_GE(acm_->Add10MsData(input_frame_), 0);
114     input_frame_.timestamp_ += static_cast<uint32_t>(input_block_size_samples_);
115     if (data_to_send_) {
116       // Encoded packet received.
117       return CreatePacket();
118     }
119   }
120   // Test ended.
121   return nullptr;
122 }
123 
124 // This method receives the callback from ACM when a new packet is produced.
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)125 int32_t AcmSendTestOldApi::SendData(AudioFrameType frame_type,
126                                     uint8_t payload_type,
127                                     uint32_t timestamp,
128                                     const uint8_t* payload_data,
129                                     size_t payload_len_bytes,
130                                     int64_t absolute_capture_timestamp_ms) {
131   // Store the packet locally.
132   frame_type_ = frame_type;
133   payload_type_ = payload_type;
134   timestamp_ = timestamp;
135   last_payload_vec_.assign(payload_data, payload_data + payload_len_bytes);
136   RTC_DCHECK_EQ(last_payload_vec_.size(), payload_len_bytes);
137   data_to_send_ = true;
138   return 0;
139 }
140 
CreatePacket()141 std::unique_ptr<Packet> AcmSendTestOldApi::CreatePacket() {
142   const size_t kRtpHeaderSize = 12;
143   rtc::CopyOnWriteBuffer packet_buffer(last_payload_vec_.size() +
144                                        kRtpHeaderSize);
145   uint8_t* packet_memory = packet_buffer.MutableData();
146   // Populate the header bytes.
147   packet_memory[0] = 0x80;
148   packet_memory[1] = static_cast<uint8_t>(payload_type_);
149   packet_memory[2] = (sequence_number_ >> 8) & 0xFF;
150   packet_memory[3] = (sequence_number_)&0xFF;
151   packet_memory[4] = (timestamp_ >> 24) & 0xFF;
152   packet_memory[5] = (timestamp_ >> 16) & 0xFF;
153   packet_memory[6] = (timestamp_ >> 8) & 0xFF;
154   packet_memory[7] = timestamp_ & 0xFF;
155   // Set SSRC to 0x12345678.
156   packet_memory[8] = 0x12;
157   packet_memory[9] = 0x34;
158   packet_memory[10] = 0x56;
159   packet_memory[11] = 0x78;
160 
161   ++sequence_number_;
162 
163   // Copy the payload data.
164   memcpy(packet_memory + kRtpHeaderSize, &last_payload_vec_[0],
165          last_payload_vec_.size());
166   auto packet = std::make_unique<Packet>(std::move(packet_buffer),
167                                          clock_.TimeInMilliseconds());
168   RTC_DCHECK(packet);
169   RTC_DCHECK(packet->valid_header());
170   return packet;
171 }
172 
173 }  // namespace test
174 }  // namespace webrtc
175