blob: 082506ab56b5ee5302bbf76e9c0dbdedd5ae6fbf [file] [log] [blame]
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/acm2/acm_receive_test.h"
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +000012
13#include <assert.h>
14#include <stdio.h>
15
kwiberg16c5a962016-02-15 02:27:22 -080016#include <memory>
17
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/audio_codecs/builtin_audio_decoder_factory.h"
19#include "modules/audio_coding/codecs/audio_format_conversion.h"
20#include "modules/audio_coding/include/audio_coding_module.h"
21#include "modules/audio_coding/neteq/tools/audio_sink.h"
22#include "modules/audio_coding/neteq/tools/packet.h"
23#include "modules/audio_coding/neteq/tools/packet_source.h"
24#include "test/gtest.h"
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +000025
26namespace webrtc {
27namespace test {
28
29namespace {
30// Returns true if the codec should be registered, otherwise false. Changes
31// the number of channels for the Opus codec to always be 1.
32bool ModifyAndUseThisCodec(CodecInst* codec_param) {
33 if (STR_CASE_CMP(codec_param->plname, "CN") == 0 &&
34 codec_param->plfreq == 48000)
35 return false; // Skip 48 kHz comfort noise.
36
37 if (STR_CASE_CMP(codec_param->plname, "telephone-event") == 0)
38 return false; // Skip DTFM.
39
40 return true;
41}
42
43// Remaps payload types from ACM's default to those used in the resource file
44// neteq_universal_new.rtp. Returns true if the codec should be registered,
45// otherwise false. The payload types are set as follows (all are mono codecs):
46// PCMu = 0;
47// PCMa = 8;
48// Comfort noise 8 kHz = 13
49// Comfort noise 16 kHz = 98
50// Comfort noise 32 kHz = 99
51// iLBC = 102
52// iSAC wideband = 103
53// iSAC super-wideband = 104
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +000054// AVT/DTMF = 106
55// RED = 117
56// PCM16b 8 kHz = 93
57// PCM16b 16 kHz = 94
58// PCM16b 32 kHz = 95
59// G.722 = 94
60bool RemapPltypeAndUseThisCodec(const char* plname,
61 int plfreq,
Peter Kasting69558702016-01-12 16:26:35 -080062 size_t channels,
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +000063 int* pltype) {
64 if (channels != 1)
65 return false; // Don't use non-mono codecs.
66
67 // Re-map pltypes to those used in the NetEq test files.
68 if (STR_CASE_CMP(plname, "PCMU") == 0 && plfreq == 8000) {
69 *pltype = 0;
70 } else if (STR_CASE_CMP(plname, "PCMA") == 0 && plfreq == 8000) {
71 *pltype = 8;
72 } else if (STR_CASE_CMP(plname, "CN") == 0 && plfreq == 8000) {
73 *pltype = 13;
74 } else if (STR_CASE_CMP(plname, "CN") == 0 && plfreq == 16000) {
75 *pltype = 98;
76 } else if (STR_CASE_CMP(plname, "CN") == 0 && plfreq == 32000) {
77 *pltype = 99;
78 } else if (STR_CASE_CMP(plname, "ILBC") == 0) {
79 *pltype = 102;
80 } else if (STR_CASE_CMP(plname, "ISAC") == 0 && plfreq == 16000) {
81 *pltype = 103;
82 } else if (STR_CASE_CMP(plname, "ISAC") == 0 && plfreq == 32000) {
83 *pltype = 104;
solenberg2779bab2016-11-17 04:45:19 -080084 } else if (STR_CASE_CMP(plname, "telephone-event") == 0 && plfreq == 8000) {
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +000085 *pltype = 106;
solenberg2779bab2016-11-17 04:45:19 -080086 } else if (STR_CASE_CMP(plname, "telephone-event") == 0 && plfreq == 16000) {
87 *pltype = 114;
88 } else if (STR_CASE_CMP(plname, "telephone-event") == 0 && plfreq == 32000) {
89 *pltype = 115;
90 } else if (STR_CASE_CMP(plname, "telephone-event") == 0 && plfreq == 48000) {
91 *pltype = 116;
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +000092 } else if (STR_CASE_CMP(plname, "red") == 0) {
93 *pltype = 117;
94 } else if (STR_CASE_CMP(plname, "L16") == 0 && plfreq == 8000) {
95 *pltype = 93;
96 } else if (STR_CASE_CMP(plname, "L16") == 0 && plfreq == 16000) {
97 *pltype = 94;
98 } else if (STR_CASE_CMP(plname, "L16") == 0 && plfreq == 32000) {
99 *pltype = 95;
100 } else if (STR_CASE_CMP(plname, "G722") == 0) {
101 *pltype = 9;
102 } else {
103 // Don't use any other codecs.
104 return false;
105 }
106 return true;
107}
kwiberg5adaf732016-10-04 09:33:27 -0700108
109AudioCodingModule::Config MakeAcmConfig(
110 Clock* clock,
111 rtc::scoped_refptr<AudioDecoderFactory> decoder_factory) {
112 AudioCodingModule::Config config;
kwiberg5adaf732016-10-04 09:33:27 -0700113 config.clock = clock;
114 config.decoder_factory = std::move(decoder_factory);
115 return config;
116}
117
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000118} // namespace
119
120AcmReceiveTestOldApi::AcmReceiveTestOldApi(
121 PacketSource* packet_source,
122 AudioSink* audio_sink,
123 int output_freq_hz,
kwiberg5adaf732016-10-04 09:33:27 -0700124 NumOutputChannels exptected_output_channels,
125 rtc::scoped_refptr<AudioDecoderFactory> decoder_factory)
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000126 : clock_(0),
kwiberg5adaf732016-10-04 09:33:27 -0700127 acm_(webrtc::AudioCodingModule::Create(
128 MakeAcmConfig(&clock_, std::move(decoder_factory)))),
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000129 packet_source_(packet_source),
130 audio_sink_(audio_sink),
131 output_freq_hz_(output_freq_hz),
kwiberg5adaf732016-10-04 09:33:27 -0700132 exptected_output_channels_(exptected_output_channels) {}
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000133
kwibergb8e56ee2016-08-29 06:37:33 -0700134AcmReceiveTestOldApi::~AcmReceiveTestOldApi() = default;
135
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000136void AcmReceiveTestOldApi::RegisterDefaultCodecs() {
137 CodecInst my_codec_param;
138 for (int n = 0; n < acm_->NumberOfCodecs(); n++) {
139 ASSERT_EQ(0, acm_->Codec(n, &my_codec_param)) << "Failed to get codec.";
140 if (ModifyAndUseThisCodec(&my_codec_param)) {
kwibergda2bf4e2016-10-24 13:47:09 -0700141 ASSERT_EQ(true,
142 acm_->RegisterReceiveCodec(my_codec_param.pltype,
143 CodecInstToSdp(my_codec_param)))
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000144 << "Couldn't register receive codec.\n";
145 }
146 }
147}
148
149void AcmReceiveTestOldApi::RegisterNetEqTestCodecs() {
150 CodecInst my_codec_param;
151 for (int n = 0; n < acm_->NumberOfCodecs(); n++) {
152 ASSERT_EQ(0, acm_->Codec(n, &my_codec_param)) << "Failed to get codec.";
153 if (!ModifyAndUseThisCodec(&my_codec_param)) {
154 // Skip this codec.
155 continue;
156 }
157
158 if (RemapPltypeAndUseThisCodec(my_codec_param.plname,
159 my_codec_param.plfreq,
160 my_codec_param.channels,
161 &my_codec_param.pltype)) {
kwibergda2bf4e2016-10-24 13:47:09 -0700162 ASSERT_EQ(true,
163 acm_->RegisterReceiveCodec(my_codec_param.pltype,
164 CodecInstToSdp(my_codec_param)))
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000165 << "Couldn't register receive codec.\n";
166 }
167 }
168}
169
170void AcmReceiveTestOldApi::Run() {
kwiberg16c5a962016-02-15 02:27:22 -0800171 for (std::unique_ptr<Packet> packet(packet_source_->NextPacket()); packet;
henrik.lundin46ba49c2016-05-24 22:50:47 -0700172 packet = packet_source_->NextPacket()) {
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000173 // Pull audio until time to insert packet.
174 while (clock_.TimeInMilliseconds() < packet->time_ms()) {
175 AudioFrame output_frame;
henrik.lundin834a6ea2016-05-13 03:45:24 -0700176 bool muted;
177 EXPECT_EQ(0,
178 acm_->PlayoutData10Ms(output_freq_hz_, &output_frame, &muted));
henrik.lundin6d8e0112016-03-04 10:34:21 -0800179 ASSERT_EQ(output_freq_hz_, output_frame.sample_rate_hz_);
henrik.lundin834a6ea2016-05-13 03:45:24 -0700180 ASSERT_FALSE(muted);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700181 const size_t samples_per_block =
182 static_cast<size_t>(output_freq_hz_ * 10 / 1000);
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000183 EXPECT_EQ(samples_per_block, output_frame.samples_per_channel_);
184 if (exptected_output_channels_ != kArbitraryChannels) {
185 if (output_frame.speech_type_ == webrtc::AudioFrame::kPLC) {
186 // Don't check number of channels for PLC output, since each test run
187 // usually starts with a short period of mono PLC before decoding the
188 // first packet.
189 } else {
190 EXPECT_EQ(exptected_output_channels_, output_frame.num_channels_);
191 }
192 }
193 ASSERT_TRUE(audio_sink_->WriteAudioFrame(output_frame));
194 clock_.AdvanceTimeMilliseconds(10);
henrik.lundin@webrtc.org81a78932014-10-14 10:49:58 +0000195 AfterGetAudio();
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000196 }
197
198 // Insert packet after converting from RTPHeader to WebRtcRTPHeader.
199 WebRtcRTPHeader header;
200 header.header = packet->header();
201 header.frameType = kAudioFrameSpeech;
202 memset(&header.type.Audio, 0, sizeof(RTPAudioHeader));
203 EXPECT_EQ(0,
204 acm_->IncomingPacket(
205 packet->payload(),
206 static_cast<int32_t>(packet->payload_length_bytes()),
207 header))
208 << "Failure when inserting packet:" << std::endl
209 << " PT = " << static_cast<int>(header.header.payloadType) << std::endl
210 << " TS = " << header.header.timestamp << std::endl
211 << " SN = " << header.header.sequenceNumber;
212 }
213}
214
henrik.lundin@webrtc.org81a78932014-10-14 10:49:58 +0000215AcmReceiveTestToggleOutputFreqOldApi::AcmReceiveTestToggleOutputFreqOldApi(
216 PacketSource* packet_source,
217 AudioSink* audio_sink,
218 int output_freq_hz_1,
219 int output_freq_hz_2,
220 int toggle_period_ms,
221 NumOutputChannels exptected_output_channels)
222 : AcmReceiveTestOldApi(packet_source,
223 audio_sink,
224 output_freq_hz_1,
kwiberg5adaf732016-10-04 09:33:27 -0700225 exptected_output_channels,
226 CreateBuiltinAudioDecoderFactory()),
henrik.lundin@webrtc.org81a78932014-10-14 10:49:58 +0000227 output_freq_hz_1_(output_freq_hz_1),
228 output_freq_hz_2_(output_freq_hz_2),
229 toggle_period_ms_(toggle_period_ms),
kwiberg5adaf732016-10-04 09:33:27 -0700230 last_toggle_time_ms_(clock_.TimeInMilliseconds()) {}
henrik.lundin@webrtc.org81a78932014-10-14 10:49:58 +0000231
232void AcmReceiveTestToggleOutputFreqOldApi::AfterGetAudio() {
233 if (clock_.TimeInMilliseconds() >= last_toggle_time_ms_ + toggle_period_ms_) {
234 output_freq_hz_ = (output_freq_hz_ == output_freq_hz_1_)
235 ? output_freq_hz_2_
236 : output_freq_hz_1_;
237 last_toggle_time_ms_ = clock_.TimeInMilliseconds();
238 }
239}
240
henrik.lundin@webrtc.org0e6e4d22014-09-23 12:05:34 +0000241} // namespace test
242} // namespace webrtc