OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <memory> | 11 #include <memory> |
12 | 12 |
13 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
14 #include "webrtc/base/checks.h" | 14 #include "webrtc/base/checks.h" |
15 #include "webrtc/common_types.h" | 15 #include "webrtc/common_types.h" |
| 16 #include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_audio_netw
ork_adaptor.h" |
16 #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" | 17 #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" |
17 | 18 |
18 namespace webrtc { | 19 namespace webrtc { |
| 20 using ::testing::NiceMock; |
| 21 using ::testing::Return; |
19 | 22 |
20 namespace { | 23 namespace { |
21 const CodecInst kOpusSettings = {105, "opus", 48000, 960, 1, 32000}; | 24 |
| 25 const CodecInst kDefaultOpusSettings = {105, "opus", 48000, 960, 1, 32000}; |
| 26 |
| 27 AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst, |
| 28 bool enable_audio_network_adaptor) { |
| 29 AudioEncoderOpus::Config config; |
| 30 config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); |
| 31 config.num_channels = codec_inst.channels; |
| 32 config.bitrate_bps = rtc::Optional<int>(codec_inst.rate); |
| 33 config.payload_type = codec_inst.pltype; |
| 34 config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip |
| 35 : AudioEncoderOpus::kAudio; |
| 36 return config; |
| 37 } |
| 38 |
| 39 struct AudioEncoderOpusStates { |
| 40 MockAudioNetworkAdaptor* mock_audio_network_adaptor; |
| 41 std::unique_ptr<AudioEncoderOpus> encoder; |
| 42 }; |
| 43 |
| 44 AudioEncoderOpusStates CreateCodec(size_t num_channels, |
| 45 bool enable_audio_network_adaptor = false) { |
| 46 AudioEncoderOpusStates states; |
| 47 std::unique_ptr<MockAudioNetworkAdaptor> mock_audio_network_adaptor( |
| 48 new NiceMock<MockAudioNetworkAdaptor>()); |
| 49 EXPECT_CALL(*mock_audio_network_adaptor, Die()); |
| 50 states.mock_audio_network_adaptor = mock_audio_network_adaptor.get(); |
| 51 CodecInst codec_inst = kDefaultOpusSettings; |
| 52 codec_inst.channels = num_channels; |
| 53 auto config = CreateConfig(codec_inst, enable_audio_network_adaptor); |
| 54 states.encoder.reset( |
| 55 new AudioEncoderOpus(config, std::move(mock_audio_network_adaptor))); |
| 56 return states; |
| 57 } |
| 58 |
| 59 AudioNetworkAdaptor::EncoderRuntimeConfig CreateEncoderRuntimeConfig() { |
| 60 constexpr int kBitrate = 40000; |
| 61 constexpr int kFrameLength = 60; |
| 62 constexpr bool kEnableFec = true; |
| 63 constexpr bool kEnableDtx = false; |
| 64 constexpr size_t kNumChannels = 1; |
| 65 constexpr float kPacketLossFraction = 0.1f; |
| 66 AudioNetworkAdaptor::EncoderRuntimeConfig config; |
| 67 config.bitrate_bps = rtc::Optional<int>(kBitrate); |
| 68 config.frame_length_ms = rtc::Optional<int>(kFrameLength); |
| 69 config.enable_fec = rtc::Optional<bool>(kEnableFec); |
| 70 config.enable_dtx = rtc::Optional<bool>(kEnableDtx); |
| 71 config.num_channels = rtc::Optional<size_t>(kNumChannels); |
| 72 config.uplink_packet_loss_fraction = |
| 73 rtc::Optional<float>(kPacketLossFraction); |
| 74 return config; |
| 75 } |
| 76 |
| 77 void CheckEncoderRuntimeConfig( |
| 78 const AudioEncoderOpus* encoder, |
| 79 const AudioNetworkAdaptor::EncoderRuntimeConfig& config) { |
| 80 EXPECT_EQ(*config.bitrate_bps, encoder->GetTargetBitrate()); |
| 81 EXPECT_EQ(*config.frame_length_ms, encoder->next_frame_length_ms()); |
| 82 EXPECT_EQ(*config.enable_fec, encoder->fec_enabled()); |
| 83 EXPECT_EQ(*config.enable_dtx, encoder->GetDtx()); |
| 84 EXPECT_EQ(*config.num_channels, encoder->num_channels_to_encode()); |
| 85 } |
| 86 |
22 } // namespace | 87 } // namespace |
23 | 88 |
24 class AudioEncoderOpusTest : public ::testing::Test { | 89 TEST(AudioEncoderOpusTest, DefaultApplicationModeMono) { |
25 protected: | 90 auto states = CreateCodec(1); |
26 void CreateCodec(int num_channels) { | 91 EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
27 codec_inst_.channels = num_channels; | |
28 encoder_.reset(new AudioEncoderOpus(codec_inst_)); | |
29 auto expected_app = | |
30 num_channels == 1 ? AudioEncoderOpus::kVoip : AudioEncoderOpus::kAudio; | |
31 EXPECT_EQ(expected_app, encoder_->application()); | |
32 } | |
33 | |
34 CodecInst codec_inst_ = kOpusSettings; | |
35 std::unique_ptr<AudioEncoderOpus> encoder_; | |
36 }; | |
37 | |
38 TEST_F(AudioEncoderOpusTest, DefaultApplicationModeMono) { | |
39 CreateCodec(1); | |
40 } | 92 } |
41 | 93 |
42 TEST_F(AudioEncoderOpusTest, DefaultApplicationModeStereo) { | 94 TEST(AudioEncoderOpusTest, DefaultApplicationModeStereo) { |
43 CreateCodec(2); | 95 auto states = CreateCodec(2); |
| 96 EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); |
44 } | 97 } |
45 | 98 |
46 TEST_F(AudioEncoderOpusTest, ChangeApplicationMode) { | 99 TEST(AudioEncoderOpusTest, ChangeApplicationMode) { |
47 CreateCodec(2); | 100 auto states = CreateCodec(2); |
48 EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech)); | 101 EXPECT_TRUE( |
49 EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application()); | 102 states.encoder->SetApplication(AudioEncoder::Application::kSpeech)); |
| 103 EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
50 } | 104 } |
51 | 105 |
52 TEST_F(AudioEncoderOpusTest, ResetWontChangeApplicationMode) { | 106 TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) { |
53 CreateCodec(2); | 107 auto states = CreateCodec(2); |
54 | 108 |
55 // Trigger a reset. | 109 // Trigger a reset. |
56 encoder_->Reset(); | 110 states.encoder->Reset(); |
57 // Verify that the mode is still kAudio. | 111 // Verify that the mode is still kAudio. |
58 EXPECT_EQ(AudioEncoderOpus::kAudio, encoder_->application()); | 112 EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); |
59 | 113 |
60 // Now change to kVoip. | 114 // Now change to kVoip. |
61 EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech)); | 115 EXPECT_TRUE( |
62 EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application()); | 116 states.encoder->SetApplication(AudioEncoder::Application::kSpeech)); |
| 117 EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
63 | 118 |
64 // Trigger a reset again. | 119 // Trigger a reset again. |
65 encoder_->Reset(); | 120 states.encoder->Reset(); |
66 // Verify that the mode is still kVoip. | 121 // Verify that the mode is still kVoip. |
67 EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application()); | 122 EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
68 } | 123 } |
69 | 124 |
70 TEST_F(AudioEncoderOpusTest, ToggleDtx) { | 125 TEST(AudioEncoderOpusTest, ToggleDtx) { |
71 CreateCodec(2); | 126 auto states = CreateCodec(2); |
72 // Enable DTX | 127 // Enable DTX |
73 EXPECT_TRUE(encoder_->SetDtx(true)); | 128 EXPECT_TRUE(states.encoder->SetDtx(true)); |
74 // Verify that the mode is still kAudio. | 129 // Verify that the mode is still kAudio. |
75 EXPECT_EQ(AudioEncoderOpus::kAudio, encoder_->application()); | 130 EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); |
76 // Turn off DTX. | 131 // Turn off DTX. |
77 EXPECT_TRUE(encoder_->SetDtx(false)); | 132 EXPECT_TRUE(states.encoder->SetDtx(false)); |
78 } | 133 } |
79 | 134 |
80 TEST_F(AudioEncoderOpusTest, SetBitrate) { | 135 TEST(AudioEncoderOpusTest, SetBitrate) { |
81 CreateCodec(1); | 136 auto states = CreateCodec(1); |
82 // Constants are replicated from audio_encoder_opus.cc. | 137 // Constants are replicated from audio_states.encoderopus.cc. |
83 const int kMinBitrateBps = 500; | 138 const int kMinBitrateBps = 500; |
84 const int kMaxBitrateBps = 512000; | 139 const int kMaxBitrateBps = 512000; |
85 // Set a too low bitrate. | 140 // Set a too low bitrate. |
86 encoder_->SetTargetBitrate(kMinBitrateBps - 1); | 141 states.encoder->SetTargetBitrate(kMinBitrateBps - 1); |
87 EXPECT_EQ(kMinBitrateBps, encoder_->GetTargetBitrate()); | 142 EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); |
88 // Set a too high bitrate. | 143 // Set a too high bitrate. |
89 encoder_->SetTargetBitrate(kMaxBitrateBps + 1); | 144 states.encoder->SetTargetBitrate(kMaxBitrateBps + 1); |
90 EXPECT_EQ(kMaxBitrateBps, encoder_->GetTargetBitrate()); | 145 EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); |
91 // Set the minimum rate. | 146 // Set the minimum rate. |
92 encoder_->SetTargetBitrate(kMinBitrateBps); | 147 states.encoder->SetTargetBitrate(kMinBitrateBps); |
93 EXPECT_EQ(kMinBitrateBps, encoder_->GetTargetBitrate()); | 148 EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); |
94 // Set the maximum rate. | 149 // Set the maximum rate. |
95 encoder_->SetTargetBitrate(kMaxBitrateBps); | 150 states.encoder->SetTargetBitrate(kMaxBitrateBps); |
96 EXPECT_EQ(kMaxBitrateBps, encoder_->GetTargetBitrate()); | 151 EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); |
97 // Set rates from 1000 up to 32000 bps. | 152 // Set rates from 1000 up to 32000 bps. |
98 for (int rate = 1000; rate <= 32000; rate += 1000) { | 153 for (int rate = 1000; rate <= 32000; rate += 1000) { |
99 encoder_->SetTargetBitrate(rate); | 154 states.encoder->SetTargetBitrate(rate); |
100 EXPECT_EQ(rate, encoder_->GetTargetBitrate()); | 155 EXPECT_EQ(rate, states.encoder->GetTargetBitrate()); |
101 } | 156 } |
102 } | 157 } |
103 | 158 |
104 namespace { | 159 namespace { |
105 | 160 |
106 // Returns a vector with the n evenly-spaced numbers a, a + (b - a)/(n - 1), | 161 // Returns a vector with the n evenly-spaced numbers a, a + (b - a)/(n - 1), |
107 // ..., b. | 162 // ..., b. |
108 std::vector<double> IntervalSteps(double a, double b, size_t n) { | 163 std::vector<double> IntervalSteps(double a, double b, size_t n) { |
109 RTC_DCHECK_GT(n, 1u); | 164 RTC_DCHECK_GT(n, 1u); |
110 const double step = (b - a) / (n - 1); | 165 const double step = (b - a) / (n - 1); |
(...skipping 10 matching lines...) Loading... |
121 const std::vector<double>& losses, | 176 const std::vector<double>& losses, |
122 double expected_return) { | 177 double expected_return) { |
123 for (double loss : losses) { | 178 for (double loss : losses) { |
124 encoder->SetProjectedPacketLossRate(loss); | 179 encoder->SetProjectedPacketLossRate(loss); |
125 EXPECT_DOUBLE_EQ(expected_return, encoder->packet_loss_rate()); | 180 EXPECT_DOUBLE_EQ(expected_return, encoder->packet_loss_rate()); |
126 } | 181 } |
127 } | 182 } |
128 | 183 |
129 } // namespace | 184 } // namespace |
130 | 185 |
131 TEST_F(AudioEncoderOpusTest, PacketLossRateOptimized) { | 186 TEST(AudioEncoderOpusTest, PacketLossRateOptimized) { |
132 CreateCodec(1); | 187 auto states = CreateCodec(1); |
133 auto I = [](double a, double b) { return IntervalSteps(a, b, 10); }; | 188 auto I = [](double a, double b) { return IntervalSteps(a, b, 10); }; |
134 const double eps = 1e-15; | 189 const double eps = 1e-15; |
135 | 190 |
136 // Note that the order of the following calls is critical. | 191 // Note that the order of the following calls is critical. |
137 | 192 |
138 // clang-format off | 193 // clang-format off |
139 TestSetPacketLossRate(encoder_.get(), I(0.00 , 0.01 - eps), 0.00); | 194 TestSetPacketLossRate(states.encoder.get(), I(0.00 , 0.01 - eps), 0.00); |
140 TestSetPacketLossRate(encoder_.get(), I(0.01 + eps, 0.06 - eps), 0.01); | 195 TestSetPacketLossRate(states.encoder.get(), I(0.01 + eps, 0.06 - eps), 0.01); |
141 TestSetPacketLossRate(encoder_.get(), I(0.06 + eps, 0.11 - eps), 0.05); | 196 TestSetPacketLossRate(states.encoder.get(), I(0.06 + eps, 0.11 - eps), 0.05); |
142 TestSetPacketLossRate(encoder_.get(), I(0.11 + eps, 0.22 - eps), 0.10); | 197 TestSetPacketLossRate(states.encoder.get(), I(0.11 + eps, 0.22 - eps), 0.10); |
143 TestSetPacketLossRate(encoder_.get(), I(0.22 + eps, 1.00 ), 0.20); | 198 TestSetPacketLossRate(states.encoder.get(), I(0.22 + eps, 1.00 ), 0.20); |
144 | 199 |
145 TestSetPacketLossRate(encoder_.get(), I(1.00 , 0.18 + eps), 0.20); | 200 TestSetPacketLossRate(states.encoder.get(), I(1.00 , 0.18 + eps), 0.20); |
146 TestSetPacketLossRate(encoder_.get(), I(0.18 - eps, 0.09 + eps), 0.10); | 201 TestSetPacketLossRate(states.encoder.get(), I(0.18 - eps, 0.09 + eps), 0.10); |
147 TestSetPacketLossRate(encoder_.get(), I(0.09 - eps, 0.04 + eps), 0.05); | 202 TestSetPacketLossRate(states.encoder.get(), I(0.09 - eps, 0.04 + eps), 0.05); |
148 TestSetPacketLossRate(encoder_.get(), I(0.04 - eps, 0.01 + eps), 0.01); | 203 TestSetPacketLossRate(states.encoder.get(), I(0.04 - eps, 0.01 + eps), 0.01); |
149 TestSetPacketLossRate(encoder_.get(), I(0.01 - eps, 0.00 ), 0.00); | 204 TestSetPacketLossRate(states.encoder.get(), I(0.01 - eps, 0.00 ), 0.00); |
150 // clang-format on | 205 // clang-format on |
151 } | 206 } |
152 | 207 |
| 208 TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnSetUplinkBandwidth) { |
| 209 auto states = CreateCodec(2, true); |
| 210 |
| 211 auto config = CreateEncoderRuntimeConfig(); |
| 212 EXPECT_CALL(*states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| 213 .WillOnce(Return(config)); |
| 214 |
| 215 // Since using mock audio network adaptor, any bandwidth value is fine. |
| 216 constexpr int kUplinkBandwidth = 50000; |
| 217 EXPECT_CALL(*states.mock_audio_network_adaptor, |
| 218 SetUplinkBandwidth(kUplinkBandwidth)); |
| 219 states.encoder->OnReceivedUplinkBandwidth(kUplinkBandwidth); |
| 220 |
| 221 CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| 222 } |
| 223 |
| 224 TEST(AudioEncoderOpusTest, |
| 225 InvokeAudioNetworkAdaptorOnSetUplinkPacketLossFraction) { |
| 226 auto states = CreateCodec(2, true); |
| 227 |
| 228 auto config = CreateEncoderRuntimeConfig(); |
| 229 EXPECT_CALL(*states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| 230 .WillOnce(Return(config)); |
| 231 |
| 232 // Since using mock audio network adaptor, any packet loss fraction is fine. |
| 233 constexpr float kUplinkPacketLoss = 0.1f; |
| 234 EXPECT_CALL(*states.mock_audio_network_adaptor, |
| 235 SetUplinkPacketLossFraction(kUplinkPacketLoss)); |
| 236 states.encoder->OnReceivedUplinkPacketLossFraction(kUplinkPacketLoss); |
| 237 |
| 238 CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| 239 } |
| 240 |
| 241 TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnSetTargetAudioBitrate) { |
| 242 auto states = CreateCodec(2, true); |
| 243 |
| 244 auto config = CreateEncoderRuntimeConfig(); |
| 245 EXPECT_CALL(*states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| 246 .WillOnce(Return(config)); |
| 247 |
| 248 // Since using mock audio network adaptor, any target audio bitrate is fine. |
| 249 constexpr int kTargetAudioBitrate = 30000; |
| 250 EXPECT_CALL(*states.mock_audio_network_adaptor, |
| 251 SetTargetAudioBitrate(kTargetAudioBitrate)); |
| 252 states.encoder->OnReceivedTargetAudioBitrate(kTargetAudioBitrate); |
| 253 |
| 254 CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| 255 } |
| 256 |
| 257 TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnSetRtt) { |
| 258 auto states = CreateCodec(2, true); |
| 259 |
| 260 auto config = CreateEncoderRuntimeConfig(); |
| 261 EXPECT_CALL(*states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| 262 .WillOnce(Return(config)); |
| 263 |
| 264 // Since using mock audio network adaptor, any rtt is fine. |
| 265 constexpr int kRtt = 30; |
| 266 EXPECT_CALL(*states.mock_audio_network_adaptor, SetRtt(kRtt)); |
| 267 states.encoder->OnReceivedRtt(kRtt); |
| 268 |
| 269 CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| 270 } |
| 271 |
| 272 TEST(AudioEncoderOpusTest, |
| 273 InvokeAudioNetworkAdaptorOnSetReceiverFrameLengthRange) { |
| 274 auto states = CreateCodec(2, true); |
| 275 |
| 276 auto config = CreateEncoderRuntimeConfig(); |
| 277 EXPECT_CALL(*states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| 278 .WillOnce(Return(config)); |
| 279 |
| 280 constexpr int kMinFrameLength = 10; |
| 281 constexpr int kMaxFrameLength = 60; |
| 282 EXPECT_CALL(*states.mock_audio_network_adaptor, |
| 283 SetReceiverFrameLengthRange(kMinFrameLength, kMaxFrameLength)); |
| 284 states.encoder->SetReceiverFrameLengthRange(kMinFrameLength, kMaxFrameLength); |
| 285 |
| 286 CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| 287 } |
| 288 |
153 } // namespace webrtc | 289 } // namespace webrtc |
OLD | NEW |