1 /*
2 * Copyright (c) 2015 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 "audio/audio_send_stream.h"
12
13 #include <memory>
14 #include <string>
15 #include <thread>
16 #include <utility>
17 #include <vector>
18
19 #include "api/task_queue/default_task_queue_factory.h"
20 #include "api/test/mock_frame_encryptor.h"
21 #include "audio/audio_state.h"
22 #include "audio/conversion.h"
23 #include "audio/mock_voe_channel_proxy.h"
24 #include "call/test/mock_rtp_transport_controller_send.h"
25 #include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
26 #include "modules/audio_device/include/mock_audio_device.h"
27 #include "modules/audio_mixer/audio_mixer_impl.h"
28 #include "modules/audio_mixer/sine_wave_generator.h"
29 #include "modules/audio_processing/include/audio_processing_statistics.h"
30 #include "modules/audio_processing/include/mock_audio_processing.h"
31 #include "modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h"
32 #include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
33 #include "modules/utility/maybe_worker_thread.h"
34 #include "system_wrappers/include/clock.h"
35 #include "test/gtest.h"
36 #include "test/mock_audio_encoder.h"
37 #include "test/mock_audio_encoder_factory.h"
38 #include "test/scoped_key_value_config.h"
39 #include "test/time_controller/real_time_controller.h"
40
41 namespace webrtc {
42 namespace test {
43 namespace {
44
45 using ::testing::_;
46 using ::testing::AnyNumber;
47 using ::testing::Eq;
48 using ::testing::Field;
49 using ::testing::InSequence;
50 using ::testing::Invoke;
51 using ::testing::Ne;
52 using ::testing::NiceMock;
53 using ::testing::Return;
54 using ::testing::StrEq;
55
56 static const float kTolerance = 0.0001f;
57
58 const uint32_t kSsrc = 1234;
59 const char* kCName = "foo_name";
60 const int kAudioLevelId = 2;
61 const int kTransportSequenceNumberId = 4;
62 const int32_t kEchoDelayMedian = 254;
63 const int32_t kEchoDelayStdDev = -3;
64 const double kDivergentFilterFraction = 0.2f;
65 const double kEchoReturnLoss = -65;
66 const double kEchoReturnLossEnhancement = 101;
67 const double kResidualEchoLikelihood = -1.0f;
68 const double kResidualEchoLikelihoodMax = 23.0f;
69 const CallSendStatistics kCallStats = {112, 12, 13456, 17890};
70 const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354};
71 const int kTelephoneEventPayloadType = 123;
72 const int kTelephoneEventPayloadFrequency = 65432;
73 const int kTelephoneEventCode = 45;
74 const int kTelephoneEventDuration = 6789;
75 constexpr int kIsacPayloadType = 103;
76 const SdpAudioFormat kIsacFormat = {"isac", 16000, 1};
77 const SdpAudioFormat kOpusFormat = {"opus", 48000, 2};
78 const SdpAudioFormat kG722Format = {"g722", 8000, 1};
79 const AudioCodecSpec kCodecSpecs[] = {
80 {kIsacFormat, {16000, 1, 32000, 10000, 32000}},
81 {kOpusFormat, {48000, 1, 32000, 6000, 510000}},
82 {kG722Format, {16000, 1, 64000}}};
83
84 // TODO(dklee): This mirrors calculation in audio_send_stream.cc, which
85 // should be made more precise in the future. This can be changed when that
86 // logic is more accurate.
87 const DataSize kOverheadPerPacket = DataSize::Bytes(20 + 8 + 10 + 12);
88 const TimeDelta kMinFrameLength = TimeDelta::Millis(20);
89 const TimeDelta kMaxFrameLength = TimeDelta::Millis(120);
90 const DataRate kMinOverheadRate = kOverheadPerPacket / kMaxFrameLength;
91 const DataRate kMaxOverheadRate = kOverheadPerPacket / kMinFrameLength;
92
93 class MockLimitObserver : public BitrateAllocator::LimitObserver {
94 public:
95 MOCK_METHOD(void,
96 OnAllocationLimitsChanged,
97 (BitrateAllocationLimits),
98 (override));
99 };
100
SetupAudioEncoderMock(int payload_type,const SdpAudioFormat & format)101 std::unique_ptr<MockAudioEncoder> SetupAudioEncoderMock(
102 int payload_type,
103 const SdpAudioFormat& format) {
104 for (const auto& spec : kCodecSpecs) {
105 if (format == spec.format) {
106 std::unique_ptr<MockAudioEncoder> encoder(
107 new ::testing::NiceMock<MockAudioEncoder>());
108 ON_CALL(*encoder.get(), SampleRateHz())
109 .WillByDefault(Return(spec.info.sample_rate_hz));
110 ON_CALL(*encoder.get(), NumChannels())
111 .WillByDefault(Return(spec.info.num_channels));
112 ON_CALL(*encoder.get(), RtpTimestampRateHz())
113 .WillByDefault(Return(spec.format.clockrate_hz));
114 ON_CALL(*encoder.get(), GetFrameLengthRange())
115 .WillByDefault(Return(absl::optional<std::pair<TimeDelta, TimeDelta>>{
116 {TimeDelta::Millis(20), TimeDelta::Millis(120)}}));
117 return encoder;
118 }
119 }
120 return nullptr;
121 }
122
SetupEncoderFactoryMock()123 rtc::scoped_refptr<MockAudioEncoderFactory> SetupEncoderFactoryMock() {
124 rtc::scoped_refptr<MockAudioEncoderFactory> factory =
125 rtc::make_ref_counted<MockAudioEncoderFactory>();
126 ON_CALL(*factory.get(), GetSupportedEncoders())
127 .WillByDefault(Return(std::vector<AudioCodecSpec>(
128 std::begin(kCodecSpecs), std::end(kCodecSpecs))));
129 ON_CALL(*factory.get(), QueryAudioEncoder(_))
130 .WillByDefault(Invoke(
131 [](const SdpAudioFormat& format) -> absl::optional<AudioCodecInfo> {
132 for (const auto& spec : kCodecSpecs) {
133 if (format == spec.format) {
134 return spec.info;
135 }
136 }
137 return absl::nullopt;
138 }));
139 ON_CALL(*factory.get(), MakeAudioEncoderMock(_, _, _, _))
140 .WillByDefault(Invoke([](int payload_type, const SdpAudioFormat& format,
141 absl::optional<AudioCodecPairId> codec_pair_id,
142 std::unique_ptr<AudioEncoder>* return_value) {
143 *return_value = SetupAudioEncoderMock(payload_type, format);
144 }));
145 return factory;
146 }
147
148 struct ConfigHelper {
ConfigHelperwebrtc::test::__anon417973d70111::ConfigHelper149 ConfigHelper(bool audio_bwe_enabled,
150 bool expect_set_encoder_call,
151 bool use_null_audio_processing)
152 : stream_config_(/*send_transport=*/nullptr),
153 audio_processing_(
154 use_null_audio_processing
155 ? nullptr
156 : rtc::make_ref_counted<NiceMock<MockAudioProcessing>>()),
157 bitrate_allocator_(&limit_observer_),
158 worker_queue_(field_trials,
159 "ConfigHelper_worker_queue",
160 time_controller_.GetTaskQueueFactory()),
161 audio_encoder_(nullptr) {
162 using ::testing::Invoke;
163
164 AudioState::Config config;
165 config.audio_mixer = AudioMixerImpl::Create();
166 config.audio_processing = audio_processing_;
167 config.audio_device_module = rtc::make_ref_counted<MockAudioDeviceModule>();
168 audio_state_ = AudioState::Create(config);
169
170 SetupDefaultChannelSend(audio_bwe_enabled);
171 SetupMockForSetupSendCodec(expect_set_encoder_call);
172 SetupMockForCallEncoder();
173
174 // Use ISAC as default codec so as to prevent unnecessary `channel_proxy_`
175 // calls from the default ctor behavior.
176 stream_config_.send_codec_spec =
177 AudioSendStream::Config::SendCodecSpec(kIsacPayloadType, kIsacFormat);
178 stream_config_.rtp.ssrc = kSsrc;
179 stream_config_.rtp.c_name = kCName;
180 stream_config_.rtp.extensions.push_back(
181 RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelId));
182 if (audio_bwe_enabled) {
183 AddBweToConfig(&stream_config_);
184 }
185 stream_config_.encoder_factory = SetupEncoderFactoryMock();
186 stream_config_.min_bitrate_bps = 10000;
187 stream_config_.max_bitrate_bps = 65000;
188 }
189
CreateAudioSendStreamwebrtc::test::__anon417973d70111::ConfigHelper190 std::unique_ptr<internal::AudioSendStream> CreateAudioSendStream() {
191 EXPECT_CALL(rtp_transport_, GetWorkerQueue())
192 .WillRepeatedly(Return(&worker_queue_));
193 return std::unique_ptr<internal::AudioSendStream>(
194 new internal::AudioSendStream(
195 time_controller_.GetClock(), stream_config_, audio_state_,
196 time_controller_.GetTaskQueueFactory(), &rtp_transport_,
197 &bitrate_allocator_, &event_log_, absl::nullopt,
198 std::unique_ptr<voe::ChannelSendInterface>(channel_send_),
199 field_trials));
200 }
201
configwebrtc::test::__anon417973d70111::ConfigHelper202 AudioSendStream::Config& config() { return stream_config_; }
mock_encoder_factorywebrtc::test::__anon417973d70111::ConfigHelper203 MockAudioEncoderFactory& mock_encoder_factory() {
204 return *static_cast<MockAudioEncoderFactory*>(
205 stream_config_.encoder_factory.get());
206 }
rtp_rtcpwebrtc::test::__anon417973d70111::ConfigHelper207 MockRtpRtcpInterface* rtp_rtcp() { return &rtp_rtcp_; }
channel_sendwebrtc::test::__anon417973d70111::ConfigHelper208 MockChannelSend* channel_send() { return channel_send_; }
transportwebrtc::test::__anon417973d70111::ConfigHelper209 RtpTransportControllerSendInterface* transport() { return &rtp_transport_; }
210
AddBweToConfigwebrtc::test::__anon417973d70111::ConfigHelper211 static void AddBweToConfig(AudioSendStream::Config* config) {
212 config->rtp.extensions.push_back(RtpExtension(
213 RtpExtension::kTransportSequenceNumberUri, kTransportSequenceNumberId));
214 config->send_codec_spec->transport_cc_enabled = true;
215 }
216
SetupDefaultChannelSendwebrtc::test::__anon417973d70111::ConfigHelper217 void SetupDefaultChannelSend(bool audio_bwe_enabled) {
218 EXPECT_TRUE(channel_send_ == nullptr);
219 channel_send_ = new ::testing::StrictMock<MockChannelSend>();
220 EXPECT_CALL(*channel_send_, GetRtpRtcp()).WillRepeatedly(Invoke([this]() {
221 return &this->rtp_rtcp_;
222 }));
223 EXPECT_CALL(rtp_rtcp_, SSRC).WillRepeatedly(Return(kSsrc));
224 EXPECT_CALL(*channel_send_, SetRTCP_CNAME(StrEq(kCName))).Times(1);
225 EXPECT_CALL(*channel_send_, SetFrameEncryptor(_)).Times(1);
226 EXPECT_CALL(*channel_send_, SetEncoderToPacketizerFrameTransformer(_))
227 .Times(1);
228 EXPECT_CALL(rtp_rtcp_, SetExtmapAllowMixed(false)).Times(1);
229 EXPECT_CALL(*channel_send_,
230 SetSendAudioLevelIndicationStatus(true, kAudioLevelId))
231 .Times(1);
232 EXPECT_CALL(rtp_transport_, GetBandwidthObserver())
233 .WillRepeatedly(Return(&bandwidth_observer_));
234 if (audio_bwe_enabled) {
235 EXPECT_CALL(rtp_rtcp_,
236 RegisterRtpHeaderExtension(TransportSequenceNumber::Uri(),
237 kTransportSequenceNumberId))
238 .Times(1);
239 EXPECT_CALL(*channel_send_,
240 RegisterSenderCongestionControlObjects(
241 &rtp_transport_, Eq(&bandwidth_observer_)))
242 .Times(1);
243 } else {
244 EXPECT_CALL(*channel_send_, RegisterSenderCongestionControlObjects(
245 &rtp_transport_, Eq(nullptr)))
246 .Times(1);
247 }
248 EXPECT_CALL(*channel_send_, ResetSenderCongestionControlObjects()).Times(1);
249 }
250
SetupMockForSetupSendCodecwebrtc::test::__anon417973d70111::ConfigHelper251 void SetupMockForSetupSendCodec(bool expect_set_encoder_call) {
252 if (expect_set_encoder_call) {
253 EXPECT_CALL(*channel_send_, SetEncoder)
254 .WillOnce(
255 [this](int payload_type, std::unique_ptr<AudioEncoder> encoder) {
256 this->audio_encoder_ = std::move(encoder);
257 return true;
258 });
259 }
260 }
261
SetupMockForCallEncoderwebrtc::test::__anon417973d70111::ConfigHelper262 void SetupMockForCallEncoder() {
263 // Let ModifyEncoder to invoke mock audio encoder.
264 EXPECT_CALL(*channel_send_, CallEncoder(_))
265 .WillRepeatedly(
266 [this](rtc::FunctionView<void(AudioEncoder*)> modifier) {
267 if (this->audio_encoder_)
268 modifier(this->audio_encoder_.get());
269 });
270 }
271
SetupMockForSendTelephoneEventwebrtc::test::__anon417973d70111::ConfigHelper272 void SetupMockForSendTelephoneEvent() {
273 EXPECT_TRUE(channel_send_);
274 EXPECT_CALL(*channel_send_, SetSendTelephoneEventPayloadType(
275 kTelephoneEventPayloadType,
276 kTelephoneEventPayloadFrequency));
277 EXPECT_CALL(
278 *channel_send_,
279 SendTelephoneEventOutband(kTelephoneEventCode, kTelephoneEventDuration))
280 .WillOnce(Return(true));
281 }
282
SetupMockForGetStatswebrtc::test::__anon417973d70111::ConfigHelper283 void SetupMockForGetStats(bool use_null_audio_processing) {
284 using ::testing::DoAll;
285 using ::testing::SetArgPointee;
286 using ::testing::SetArgReferee;
287
288 std::vector<ReportBlock> report_blocks;
289 webrtc::ReportBlock block = kReportBlock;
290 report_blocks.push_back(block); // Has wrong SSRC.
291 block.source_SSRC = kSsrc;
292 report_blocks.push_back(block); // Correct block.
293 block.fraction_lost = 0;
294 report_blocks.push_back(block); // Duplicate SSRC, bad fraction_lost.
295
296 EXPECT_TRUE(channel_send_);
297 EXPECT_CALL(*channel_send_, GetRTCPStatistics())
298 .WillRepeatedly(Return(kCallStats));
299 EXPECT_CALL(*channel_send_, GetRemoteRTCPReportBlocks())
300 .WillRepeatedly(Return(report_blocks));
301 EXPECT_CALL(*channel_send_, GetANAStatistics())
302 .WillRepeatedly(Return(ANAStats()));
303 EXPECT_CALL(*channel_send_, GetTargetBitrate()).WillRepeatedly(Return(0));
304
305 audio_processing_stats_.echo_return_loss = kEchoReturnLoss;
306 audio_processing_stats_.echo_return_loss_enhancement =
307 kEchoReturnLossEnhancement;
308 audio_processing_stats_.delay_median_ms = kEchoDelayMedian;
309 audio_processing_stats_.delay_standard_deviation_ms = kEchoDelayStdDev;
310 audio_processing_stats_.divergent_filter_fraction =
311 kDivergentFilterFraction;
312 audio_processing_stats_.residual_echo_likelihood = kResidualEchoLikelihood;
313 audio_processing_stats_.residual_echo_likelihood_recent_max =
314 kResidualEchoLikelihoodMax;
315 if (!use_null_audio_processing) {
316 ASSERT_TRUE(audio_processing_);
317 EXPECT_CALL(*audio_processing_, GetStatistics(true))
318 .WillRepeatedly(Return(audio_processing_stats_));
319 }
320 }
321
workerwebrtc::test::__anon417973d70111::ConfigHelper322 MaybeWorkerThread* worker() { return &worker_queue_; }
323
324 test::ScopedKeyValueConfig field_trials;
325
326 private:
327 RealTimeController time_controller_;
328 rtc::scoped_refptr<AudioState> audio_state_;
329 AudioSendStream::Config stream_config_;
330 ::testing::StrictMock<MockChannelSend>* channel_send_ = nullptr;
331 rtc::scoped_refptr<MockAudioProcessing> audio_processing_;
332 AudioProcessingStats audio_processing_stats_;
333 ::testing::StrictMock<MockRtcpBandwidthObserver> bandwidth_observer_;
334 ::testing::NiceMock<MockRtcEventLog> event_log_;
335 ::testing::NiceMock<MockRtpTransportControllerSend> rtp_transport_;
336 ::testing::NiceMock<MockRtpRtcpInterface> rtp_rtcp_;
337 ::testing::NiceMock<MockLimitObserver> limit_observer_;
338 BitrateAllocator bitrate_allocator_;
339 // `worker_queue` is defined last to ensure all pending tasks are cancelled
340 // and deleted before any other members.
341 MaybeWorkerThread worker_queue_;
342 std::unique_ptr<AudioEncoder> audio_encoder_;
343 };
344
345 // The audio level ranges linearly [0,32767].
CreateAudioFrame1kHzSineWave(int16_t audio_level,int duration_ms,int sample_rate_hz,size_t num_channels)346 std::unique_ptr<AudioFrame> CreateAudioFrame1kHzSineWave(int16_t audio_level,
347 int duration_ms,
348 int sample_rate_hz,
349 size_t num_channels) {
350 size_t samples_per_channel = sample_rate_hz / (1000 / duration_ms);
351 std::vector<int16_t> audio_data(samples_per_channel * num_channels, 0);
352 std::unique_ptr<AudioFrame> audio_frame = std::make_unique<AudioFrame>();
353 audio_frame->UpdateFrame(0 /* RTP timestamp */, &audio_data[0],
354 samples_per_channel, sample_rate_hz,
355 AudioFrame::SpeechType::kNormalSpeech,
356 AudioFrame::VADActivity::kVadUnknown, num_channels);
357 SineWaveGenerator wave_generator(1000.0, audio_level);
358 wave_generator.GenerateNextFrame(audio_frame.get());
359 return audio_frame;
360 }
361
362 } // namespace
363
TEST(AudioSendStreamTest,ConfigToString)364 TEST(AudioSendStreamTest, ConfigToString) {
365 AudioSendStream::Config config(/*send_transport=*/nullptr);
366 config.rtp.ssrc = kSsrc;
367 config.rtp.c_name = kCName;
368 config.min_bitrate_bps = 12000;
369 config.max_bitrate_bps = 34000;
370 config.has_dscp = true;
371 config.send_codec_spec =
372 AudioSendStream::Config::SendCodecSpec(kIsacPayloadType, kIsacFormat);
373 config.send_codec_spec->nack_enabled = true;
374 config.send_codec_spec->transport_cc_enabled = false;
375 config.send_codec_spec->cng_payload_type = 42;
376 config.send_codec_spec->red_payload_type = 43;
377 config.encoder_factory = MockAudioEncoderFactory::CreateUnusedFactory();
378 config.rtp.extmap_allow_mixed = true;
379 config.rtp.extensions.push_back(
380 RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelId));
381 config.rtcp_report_interval_ms = 2500;
382 EXPECT_EQ(
383 "{rtp: {ssrc: 1234, extmap-allow-mixed: true, extensions: [{uri: "
384 "urn:ietf:params:rtp-hdrext:ssrc-audio-level, id: 2}], "
385 "c_name: foo_name}, rtcp_report_interval_ms: 2500, "
386 "send_transport: null, "
387 "min_bitrate_bps: 12000, max_bitrate_bps: 34000, has "
388 "audio_network_adaptor_config: false, has_dscp: true, "
389 "send_codec_spec: {nack_enabled: true, transport_cc_enabled: false, "
390 "enable_non_sender_rtt: false, cng_payload_type: 42, "
391 "red_payload_type: 43, payload_type: 103, "
392 "format: {name: isac, clockrate_hz: 16000, num_channels: 1, "
393 "parameters: {}}}}",
394 config.ToString());
395 }
396
TEST(AudioSendStreamTest,ConstructDestruct)397 TEST(AudioSendStreamTest, ConstructDestruct) {
398 for (bool use_null_audio_processing : {false, true}) {
399 ConfigHelper helper(false, true, use_null_audio_processing);
400 auto send_stream = helper.CreateAudioSendStream();
401 }
402 }
403
TEST(AudioSendStreamTest,SendTelephoneEvent)404 TEST(AudioSendStreamTest, SendTelephoneEvent) {
405 for (bool use_null_audio_processing : {false, true}) {
406 ConfigHelper helper(false, true, use_null_audio_processing);
407 auto send_stream = helper.CreateAudioSendStream();
408 helper.SetupMockForSendTelephoneEvent();
409 EXPECT_TRUE(send_stream->SendTelephoneEvent(
410 kTelephoneEventPayloadType, kTelephoneEventPayloadFrequency,
411 kTelephoneEventCode, kTelephoneEventDuration));
412 }
413 }
414
TEST(AudioSendStreamTest,SetMuted)415 TEST(AudioSendStreamTest, SetMuted) {
416 for (bool use_null_audio_processing : {false, true}) {
417 ConfigHelper helper(false, true, use_null_audio_processing);
418 auto send_stream = helper.CreateAudioSendStream();
419 EXPECT_CALL(*helper.channel_send(), SetInputMute(true));
420 send_stream->SetMuted(true);
421 }
422 }
423
TEST(AudioSendStreamTest,AudioBweCorrectObjectsOnChannelProxy)424 TEST(AudioSendStreamTest, AudioBweCorrectObjectsOnChannelProxy) {
425 for (bool use_null_audio_processing : {false, true}) {
426 ConfigHelper helper(true, true, use_null_audio_processing);
427 auto send_stream = helper.CreateAudioSendStream();
428 }
429 }
430
TEST(AudioSendStreamTest,NoAudioBweCorrectObjectsOnChannelProxy)431 TEST(AudioSendStreamTest, NoAudioBweCorrectObjectsOnChannelProxy) {
432 for (bool use_null_audio_processing : {false, true}) {
433 ConfigHelper helper(false, true, use_null_audio_processing);
434 auto send_stream = helper.CreateAudioSendStream();
435 }
436 }
437
TEST(AudioSendStreamTest,GetStats)438 TEST(AudioSendStreamTest, GetStats) {
439 for (bool use_null_audio_processing : {false, true}) {
440 ConfigHelper helper(false, true, use_null_audio_processing);
441 auto send_stream = helper.CreateAudioSendStream();
442 helper.SetupMockForGetStats(use_null_audio_processing);
443 AudioSendStream::Stats stats = send_stream->GetStats(true);
444 EXPECT_EQ(kSsrc, stats.local_ssrc);
445 EXPECT_EQ(kCallStats.payload_bytes_sent, stats.payload_bytes_sent);
446 EXPECT_EQ(kCallStats.header_and_padding_bytes_sent,
447 stats.header_and_padding_bytes_sent);
448 EXPECT_EQ(kCallStats.packetsSent, stats.packets_sent);
449 EXPECT_EQ(kReportBlock.cumulative_num_packets_lost, stats.packets_lost);
450 EXPECT_EQ(Q8ToFloat(kReportBlock.fraction_lost), stats.fraction_lost);
451 EXPECT_EQ(kIsacFormat.name, stats.codec_name);
452 EXPECT_EQ(static_cast<int32_t>(kReportBlock.interarrival_jitter /
453 (kIsacFormat.clockrate_hz / 1000)),
454 stats.jitter_ms);
455 EXPECT_EQ(kCallStats.rttMs, stats.rtt_ms);
456 EXPECT_EQ(0, stats.audio_level);
457 EXPECT_EQ(0, stats.total_input_energy);
458 EXPECT_EQ(0, stats.total_input_duration);
459
460 if (!use_null_audio_processing) {
461 EXPECT_EQ(kEchoDelayMedian, stats.apm_statistics.delay_median_ms);
462 EXPECT_EQ(kEchoDelayStdDev,
463 stats.apm_statistics.delay_standard_deviation_ms);
464 EXPECT_EQ(kEchoReturnLoss, stats.apm_statistics.echo_return_loss);
465 EXPECT_EQ(kEchoReturnLossEnhancement,
466 stats.apm_statistics.echo_return_loss_enhancement);
467 EXPECT_EQ(kDivergentFilterFraction,
468 stats.apm_statistics.divergent_filter_fraction);
469 EXPECT_EQ(kResidualEchoLikelihood,
470 stats.apm_statistics.residual_echo_likelihood);
471 EXPECT_EQ(kResidualEchoLikelihoodMax,
472 stats.apm_statistics.residual_echo_likelihood_recent_max);
473 }
474 }
475 }
476
TEST(AudioSendStreamTest,GetStatsAudioLevel)477 TEST(AudioSendStreamTest, GetStatsAudioLevel) {
478 for (bool use_null_audio_processing : {false, true}) {
479 ConfigHelper helper(false, true, use_null_audio_processing);
480 auto send_stream = helper.CreateAudioSendStream();
481 helper.SetupMockForGetStats(use_null_audio_processing);
482 EXPECT_CALL(*helper.channel_send(), ProcessAndEncodeAudio)
483 .Times(AnyNumber());
484
485 constexpr int kSampleRateHz = 48000;
486 constexpr size_t kNumChannels = 1;
487
488 constexpr int16_t kSilentAudioLevel = 0;
489 constexpr int16_t kMaxAudioLevel = 32767; // Audio level is [0,32767].
490 constexpr int kAudioFrameDurationMs = 10;
491
492 // Process 10 audio frames (100 ms) of silence. After this, on the next
493 // (11-th) frame, the audio level will be updated with the maximum audio
494 // level of the first 11 frames. See AudioLevel.
495 for (size_t i = 0; i < 10; ++i) {
496 send_stream->SendAudioData(
497 CreateAudioFrame1kHzSineWave(kSilentAudioLevel, kAudioFrameDurationMs,
498 kSampleRateHz, kNumChannels));
499 }
500 AudioSendStream::Stats stats = send_stream->GetStats();
501 EXPECT_EQ(kSilentAudioLevel, stats.audio_level);
502 EXPECT_NEAR(0.0f, stats.total_input_energy, kTolerance);
503 EXPECT_NEAR(0.1f, stats.total_input_duration,
504 kTolerance); // 100 ms = 0.1 s
505
506 // Process 10 audio frames (100 ms) of maximum audio level.
507 // Note that AudioLevel updates the audio level every 11th frame, processing
508 // 10 frames above was needed to see a non-zero audio level here.
509 for (size_t i = 0; i < 10; ++i) {
510 send_stream->SendAudioData(CreateAudioFrame1kHzSineWave(
511 kMaxAudioLevel, kAudioFrameDurationMs, kSampleRateHz, kNumChannels));
512 }
513 stats = send_stream->GetStats();
514 EXPECT_EQ(kMaxAudioLevel, stats.audio_level);
515 // Energy increases by energy*duration, where energy is audio level in
516 // [0,1].
517 EXPECT_NEAR(0.1f, stats.total_input_energy, kTolerance); // 0.1 s of max
518 EXPECT_NEAR(0.2f, stats.total_input_duration,
519 kTolerance); // 200 ms = 0.2 s
520 }
521 }
522
TEST(AudioSendStreamTest,SendCodecAppliesAudioNetworkAdaptor)523 TEST(AudioSendStreamTest, SendCodecAppliesAudioNetworkAdaptor) {
524 for (bool use_null_audio_processing : {false, true}) {
525 ConfigHelper helper(true, true, use_null_audio_processing);
526 helper.config().send_codec_spec =
527 AudioSendStream::Config::SendCodecSpec(0, kOpusFormat);
528 const std::string kAnaConfigString = "abcde";
529 const std::string kAnaReconfigString = "12345";
530
531 helper.config().audio_network_adaptor_config = kAnaConfigString;
532
533 EXPECT_CALL(helper.mock_encoder_factory(), MakeAudioEncoderMock(_, _, _, _))
534 .WillOnce(Invoke([&kAnaConfigString, &kAnaReconfigString](
535 int payload_type, const SdpAudioFormat& format,
536 absl::optional<AudioCodecPairId> codec_pair_id,
537 std::unique_ptr<AudioEncoder>* return_value) {
538 auto mock_encoder = SetupAudioEncoderMock(payload_type, format);
539 EXPECT_CALL(*mock_encoder,
540 EnableAudioNetworkAdaptor(StrEq(kAnaConfigString), _))
541 .WillOnce(Return(true));
542 EXPECT_CALL(*mock_encoder,
543 EnableAudioNetworkAdaptor(StrEq(kAnaReconfigString), _))
544 .WillOnce(Return(true));
545 *return_value = std::move(mock_encoder);
546 }));
547
548 auto send_stream = helper.CreateAudioSendStream();
549
550 auto stream_config = helper.config();
551 stream_config.audio_network_adaptor_config = kAnaReconfigString;
552
553 send_stream->Reconfigure(stream_config, nullptr);
554 }
555 }
556
TEST(AudioSendStreamTest,AudioNetworkAdaptorReceivesOverhead)557 TEST(AudioSendStreamTest, AudioNetworkAdaptorReceivesOverhead) {
558 for (bool use_null_audio_processing : {false, true}) {
559 ConfigHelper helper(true, true, use_null_audio_processing);
560 helper.config().send_codec_spec =
561 AudioSendStream::Config::SendCodecSpec(0, kOpusFormat);
562 const std::string kAnaConfigString = "abcde";
563
564 EXPECT_CALL(helper.mock_encoder_factory(), MakeAudioEncoderMock(_, _, _, _))
565 .WillOnce(Invoke(
566 [&kAnaConfigString](int payload_type, const SdpAudioFormat& format,
567 absl::optional<AudioCodecPairId> codec_pair_id,
568 std::unique_ptr<AudioEncoder>* return_value) {
569 auto mock_encoder = SetupAudioEncoderMock(payload_type, format);
570 InSequence s;
571 EXPECT_CALL(
572 *mock_encoder,
573 OnReceivedOverhead(Eq(kOverheadPerPacket.bytes<size_t>())))
574 .Times(2);
575 EXPECT_CALL(*mock_encoder,
576 EnableAudioNetworkAdaptor(StrEq(kAnaConfigString), _))
577 .WillOnce(Return(true));
578 // Note: Overhead is received AFTER ANA has been enabled.
579 EXPECT_CALL(
580 *mock_encoder,
581 OnReceivedOverhead(Eq(kOverheadPerPacket.bytes<size_t>())))
582 .WillOnce(Return());
583 *return_value = std::move(mock_encoder);
584 }));
585 EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
586 .WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
587
588 auto send_stream = helper.CreateAudioSendStream();
589
590 auto stream_config = helper.config();
591 stream_config.audio_network_adaptor_config = kAnaConfigString;
592
593 send_stream->Reconfigure(stream_config, nullptr);
594 }
595 }
596
597 // VAD is applied when codec is mono and the CNG frequency matches the codec
598 // clock rate.
TEST(AudioSendStreamTest,SendCodecCanApplyVad)599 TEST(AudioSendStreamTest, SendCodecCanApplyVad) {
600 for (bool use_null_audio_processing : {false, true}) {
601 ConfigHelper helper(false, false, use_null_audio_processing);
602 helper.config().send_codec_spec =
603 AudioSendStream::Config::SendCodecSpec(9, kG722Format);
604 helper.config().send_codec_spec->cng_payload_type = 105;
605 std::unique_ptr<AudioEncoder> stolen_encoder;
606 EXPECT_CALL(*helper.channel_send(), SetEncoder)
607 .WillOnce([&stolen_encoder](int payload_type,
608 std::unique_ptr<AudioEncoder> encoder) {
609 stolen_encoder = std::move(encoder);
610 return true;
611 });
612 EXPECT_CALL(*helper.channel_send(), RegisterCngPayloadType(105, 8000));
613
614 auto send_stream = helper.CreateAudioSendStream();
615
616 // We cannot truly determine if the encoder created is an AudioEncoderCng.
617 // It is the only reasonable implementation that will return something from
618 // ReclaimContainedEncoders, though.
619 ASSERT_TRUE(stolen_encoder);
620 EXPECT_FALSE(stolen_encoder->ReclaimContainedEncoders().empty());
621 }
622 }
623
TEST(AudioSendStreamTest,DoesNotPassHigherBitrateThanMaxBitrate)624 TEST(AudioSendStreamTest, DoesNotPassHigherBitrateThanMaxBitrate) {
625 for (bool use_null_audio_processing : {false, true}) {
626 ConfigHelper helper(false, true, use_null_audio_processing);
627 auto send_stream = helper.CreateAudioSendStream();
628 EXPECT_CALL(
629 *helper.channel_send(),
630 OnBitrateAllocation(
631 Field(&BitrateAllocationUpdate::target_bitrate,
632 Eq(DataRate::BitsPerSec(helper.config().max_bitrate_bps)))));
633 BitrateAllocationUpdate update;
634 update.target_bitrate =
635 DataRate::BitsPerSec(helper.config().max_bitrate_bps + 5000);
636 update.packet_loss_ratio = 0;
637 update.round_trip_time = TimeDelta::Millis(50);
638 update.bwe_period = TimeDelta::Millis(6000);
639 helper.worker()->RunSynchronous(
640 [&] { send_stream->OnBitrateUpdated(update); });
641 }
642 }
643
TEST(AudioSendStreamTest,SSBweTargetInRangeRespected)644 TEST(AudioSendStreamTest, SSBweTargetInRangeRespected) {
645 for (bool use_null_audio_processing : {false, true}) {
646 ConfigHelper helper(true, true, use_null_audio_processing);
647 auto send_stream = helper.CreateAudioSendStream();
648 EXPECT_CALL(
649 *helper.channel_send(),
650 OnBitrateAllocation(Field(
651 &BitrateAllocationUpdate::target_bitrate,
652 Eq(DataRate::BitsPerSec(helper.config().max_bitrate_bps - 5000)))));
653 BitrateAllocationUpdate update;
654 update.target_bitrate =
655 DataRate::BitsPerSec(helper.config().max_bitrate_bps - 5000);
656 helper.worker()->RunSynchronous(
657 [&] { send_stream->OnBitrateUpdated(update); });
658 }
659 }
660
TEST(AudioSendStreamTest,SSBweFieldTrialMinRespected)661 TEST(AudioSendStreamTest, SSBweFieldTrialMinRespected) {
662 for (bool use_null_audio_processing : {false, true}) {
663 ConfigHelper helper(true, true, use_null_audio_processing);
664 ScopedKeyValueConfig field_trials(
665 helper.field_trials, "WebRTC-Audio-Allocation/min:6kbps,max:64kbps/");
666 auto send_stream = helper.CreateAudioSendStream();
667 EXPECT_CALL(
668 *helper.channel_send(),
669 OnBitrateAllocation(Field(&BitrateAllocationUpdate::target_bitrate,
670 Eq(DataRate::KilobitsPerSec(6)))));
671 BitrateAllocationUpdate update;
672 update.target_bitrate = DataRate::KilobitsPerSec(1);
673 helper.worker()->RunSynchronous(
674 [&] { send_stream->OnBitrateUpdated(update); });
675 }
676 }
677
TEST(AudioSendStreamTest,SSBweFieldTrialMaxRespected)678 TEST(AudioSendStreamTest, SSBweFieldTrialMaxRespected) {
679 for (bool use_null_audio_processing : {false, true}) {
680 ConfigHelper helper(true, true, use_null_audio_processing);
681 ScopedKeyValueConfig field_trials(
682 helper.field_trials, "WebRTC-Audio-Allocation/min:6kbps,max:64kbps/");
683 auto send_stream = helper.CreateAudioSendStream();
684 EXPECT_CALL(
685 *helper.channel_send(),
686 OnBitrateAllocation(Field(&BitrateAllocationUpdate::target_bitrate,
687 Eq(DataRate::KilobitsPerSec(64)))));
688 BitrateAllocationUpdate update;
689 update.target_bitrate = DataRate::KilobitsPerSec(128);
690 helper.worker()->RunSynchronous(
691 [&] { send_stream->OnBitrateUpdated(update); });
692 }
693 }
694
TEST(AudioSendStreamTest,SSBweWithOverhead)695 TEST(AudioSendStreamTest, SSBweWithOverhead) {
696 for (bool use_null_audio_processing : {false, true}) {
697 ConfigHelper helper(true, true, use_null_audio_processing);
698 ScopedKeyValueConfig field_trials(helper.field_trials,
699 "WebRTC-Audio-LegacyOverhead/Disabled/");
700 EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
701 .WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
702 auto send_stream = helper.CreateAudioSendStream();
703 const DataRate bitrate =
704 DataRate::BitsPerSec(helper.config().max_bitrate_bps) +
705 kMaxOverheadRate;
706 EXPECT_CALL(*helper.channel_send(),
707 OnBitrateAllocation(Field(
708 &BitrateAllocationUpdate::target_bitrate, Eq(bitrate))));
709 BitrateAllocationUpdate update;
710 update.target_bitrate = bitrate;
711 helper.worker()->RunSynchronous(
712 [&] { send_stream->OnBitrateUpdated(update); });
713 }
714 }
715
TEST(AudioSendStreamTest,SSBweWithOverheadMinRespected)716 TEST(AudioSendStreamTest, SSBweWithOverheadMinRespected) {
717 for (bool use_null_audio_processing : {false, true}) {
718 ConfigHelper helper(true, true, use_null_audio_processing);
719 ScopedKeyValueConfig field_trials(
720 helper.field_trials,
721 "WebRTC-Audio-LegacyOverhead/Disabled/"
722 "WebRTC-Audio-Allocation/min:6kbps,max:64kbps/");
723 EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
724 .WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
725 auto send_stream = helper.CreateAudioSendStream();
726 const DataRate bitrate = DataRate::KilobitsPerSec(6) + kMinOverheadRate;
727 EXPECT_CALL(*helper.channel_send(),
728 OnBitrateAllocation(Field(
729 &BitrateAllocationUpdate::target_bitrate, Eq(bitrate))));
730 BitrateAllocationUpdate update;
731 update.target_bitrate = DataRate::KilobitsPerSec(1);
732 helper.worker()->RunSynchronous(
733 [&] { send_stream->OnBitrateUpdated(update); });
734 }
735 }
736
TEST(AudioSendStreamTest,SSBweWithOverheadMaxRespected)737 TEST(AudioSendStreamTest, SSBweWithOverheadMaxRespected) {
738 for (bool use_null_audio_processing : {false, true}) {
739 ConfigHelper helper(true, true, use_null_audio_processing);
740 ScopedKeyValueConfig field_trials(
741 helper.field_trials,
742 "WebRTC-Audio-LegacyOverhead/Disabled/"
743 "WebRTC-Audio-Allocation/min:6kbps,max:64kbps/");
744 EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
745 .WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
746 auto send_stream = helper.CreateAudioSendStream();
747 const DataRate bitrate = DataRate::KilobitsPerSec(64) + kMaxOverheadRate;
748 EXPECT_CALL(*helper.channel_send(),
749 OnBitrateAllocation(Field(
750 &BitrateAllocationUpdate::target_bitrate, Eq(bitrate))));
751 BitrateAllocationUpdate update;
752 update.target_bitrate = DataRate::KilobitsPerSec(128);
753 helper.worker()->RunSynchronous(
754 [&] { send_stream->OnBitrateUpdated(update); });
755 }
756 }
757
TEST(AudioSendStreamTest,ProbingIntervalOnBitrateUpdated)758 TEST(AudioSendStreamTest, ProbingIntervalOnBitrateUpdated) {
759 for (bool use_null_audio_processing : {false, true}) {
760 ConfigHelper helper(false, true, use_null_audio_processing);
761 auto send_stream = helper.CreateAudioSendStream();
762
763 EXPECT_CALL(*helper.channel_send(),
764 OnBitrateAllocation(Field(&BitrateAllocationUpdate::bwe_period,
765 Eq(TimeDelta::Millis(5000)))));
766 BitrateAllocationUpdate update;
767 update.target_bitrate =
768 DataRate::BitsPerSec(helper.config().max_bitrate_bps + 5000);
769 update.packet_loss_ratio = 0;
770 update.round_trip_time = TimeDelta::Millis(50);
771 update.bwe_period = TimeDelta::Millis(5000);
772 helper.worker()->RunSynchronous(
773 [&] { send_stream->OnBitrateUpdated(update); });
774 }
775 }
776
777 // Test that AudioSendStream doesn't recreate the encoder unnecessarily.
TEST(AudioSendStreamTest,DontRecreateEncoder)778 TEST(AudioSendStreamTest, DontRecreateEncoder) {
779 for (bool use_null_audio_processing : {false, true}) {
780 ConfigHelper helper(false, false, use_null_audio_processing);
781 // WillOnce is (currently) the default used by ConfigHelper if asked to set
782 // an expectation for SetEncoder. Since this behavior is essential for this
783 // test to be correct, it's instead set-up manually here. Otherwise a simple
784 // change to ConfigHelper (say to WillRepeatedly) would silently make this
785 // test useless.
786 EXPECT_CALL(*helper.channel_send(), SetEncoder).WillOnce(Return());
787
788 EXPECT_CALL(*helper.channel_send(), RegisterCngPayloadType(105, 8000));
789
790 helper.config().send_codec_spec =
791 AudioSendStream::Config::SendCodecSpec(9, kG722Format);
792 helper.config().send_codec_spec->cng_payload_type = 105;
793 auto send_stream = helper.CreateAudioSendStream();
794 send_stream->Reconfigure(helper.config(), nullptr);
795 }
796 }
797
TEST(AudioSendStreamTest,ReconfigureTransportCcResetsFirst)798 TEST(AudioSendStreamTest, ReconfigureTransportCcResetsFirst) {
799 for (bool use_null_audio_processing : {false, true}) {
800 ConfigHelper helper(false, true, use_null_audio_processing);
801 auto send_stream = helper.CreateAudioSendStream();
802 auto new_config = helper.config();
803 ConfigHelper::AddBweToConfig(&new_config);
804
805 EXPECT_CALL(*helper.rtp_rtcp(),
806 RegisterRtpHeaderExtension(TransportSequenceNumber::Uri(),
807 kTransportSequenceNumberId))
808 .Times(1);
809 {
810 ::testing::InSequence seq;
811 EXPECT_CALL(*helper.channel_send(), ResetSenderCongestionControlObjects())
812 .Times(1);
813 EXPECT_CALL(*helper.channel_send(),
814 RegisterSenderCongestionControlObjects(helper.transport(),
815 Ne(nullptr)))
816 .Times(1);
817 }
818
819 send_stream->Reconfigure(new_config, nullptr);
820 }
821 }
822
TEST(AudioSendStreamTest,OnTransportOverheadChanged)823 TEST(AudioSendStreamTest, OnTransportOverheadChanged) {
824 for (bool use_null_audio_processing : {false, true}) {
825 ConfigHelper helper(false, true, use_null_audio_processing);
826 auto send_stream = helper.CreateAudioSendStream();
827 auto new_config = helper.config();
828
829 // CallEncoder will be called on overhead change.
830 EXPECT_CALL(*helper.channel_send(), CallEncoder);
831
832 const size_t transport_overhead_per_packet_bytes = 333;
833 send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes);
834
835 EXPECT_EQ(transport_overhead_per_packet_bytes,
836 send_stream->TestOnlyGetPerPacketOverheadBytes());
837 }
838 }
839
TEST(AudioSendStreamTest,DoesntCallEncoderWhenOverheadUnchanged)840 TEST(AudioSendStreamTest, DoesntCallEncoderWhenOverheadUnchanged) {
841 for (bool use_null_audio_processing : {false, true}) {
842 ConfigHelper helper(false, true, use_null_audio_processing);
843 auto send_stream = helper.CreateAudioSendStream();
844 auto new_config = helper.config();
845
846 // CallEncoder will be called on overhead change.
847 EXPECT_CALL(*helper.channel_send(), CallEncoder);
848 const size_t transport_overhead_per_packet_bytes = 333;
849 send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes);
850
851 // Set the same overhead again, CallEncoder should not be called again.
852 EXPECT_CALL(*helper.channel_send(), CallEncoder).Times(0);
853 send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes);
854
855 // New overhead, call CallEncoder again
856 EXPECT_CALL(*helper.channel_send(), CallEncoder);
857 send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes + 1);
858 }
859 }
860
TEST(AudioSendStreamTest,AudioOverheadChanged)861 TEST(AudioSendStreamTest, AudioOverheadChanged) {
862 for (bool use_null_audio_processing : {false, true}) {
863 ConfigHelper helper(false, true, use_null_audio_processing);
864 const size_t audio_overhead_per_packet_bytes = 555;
865 EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
866 .WillRepeatedly(Return(audio_overhead_per_packet_bytes));
867 auto send_stream = helper.CreateAudioSendStream();
868 auto new_config = helper.config();
869
870 BitrateAllocationUpdate update;
871 update.target_bitrate =
872 DataRate::BitsPerSec(helper.config().max_bitrate_bps) +
873 kMaxOverheadRate;
874 EXPECT_CALL(*helper.channel_send(), OnBitrateAllocation);
875 helper.worker()->RunSynchronous(
876 [&] { send_stream->OnBitrateUpdated(update); });
877
878 EXPECT_EQ(audio_overhead_per_packet_bytes,
879 send_stream->TestOnlyGetPerPacketOverheadBytes());
880
881 EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
882 .WillRepeatedly(Return(audio_overhead_per_packet_bytes + 20));
883 EXPECT_CALL(*helper.channel_send(), OnBitrateAllocation);
884 helper.worker()->RunSynchronous(
885 [&] { send_stream->OnBitrateUpdated(update); });
886
887 EXPECT_EQ(audio_overhead_per_packet_bytes + 20,
888 send_stream->TestOnlyGetPerPacketOverheadBytes());
889 }
890 }
891
TEST(AudioSendStreamTest,OnAudioAndTransportOverheadChanged)892 TEST(AudioSendStreamTest, OnAudioAndTransportOverheadChanged) {
893 for (bool use_null_audio_processing : {false, true}) {
894 ConfigHelper helper(false, true, use_null_audio_processing);
895 const size_t audio_overhead_per_packet_bytes = 555;
896 EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
897 .WillRepeatedly(Return(audio_overhead_per_packet_bytes));
898 auto send_stream = helper.CreateAudioSendStream();
899 auto new_config = helper.config();
900
901 const size_t transport_overhead_per_packet_bytes = 333;
902 send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes);
903
904 BitrateAllocationUpdate update;
905 update.target_bitrate =
906 DataRate::BitsPerSec(helper.config().max_bitrate_bps) +
907 kMaxOverheadRate;
908 EXPECT_CALL(*helper.channel_send(), OnBitrateAllocation);
909 helper.worker()->RunSynchronous(
910 [&] { send_stream->OnBitrateUpdated(update); });
911
912 EXPECT_EQ(
913 transport_overhead_per_packet_bytes + audio_overhead_per_packet_bytes,
914 send_stream->TestOnlyGetPerPacketOverheadBytes());
915 }
916 }
917
918 // Validates that reconfiguring the AudioSendStream with a Frame encryptor
919 // correctly reconfigures on the object without crashing.
TEST(AudioSendStreamTest,ReconfigureWithFrameEncryptor)920 TEST(AudioSendStreamTest, ReconfigureWithFrameEncryptor) {
921 for (bool use_null_audio_processing : {false, true}) {
922 ConfigHelper helper(false, true, use_null_audio_processing);
923 auto send_stream = helper.CreateAudioSendStream();
924 auto new_config = helper.config();
925
926 rtc::scoped_refptr<FrameEncryptorInterface> mock_frame_encryptor_0(
927 rtc::make_ref_counted<MockFrameEncryptor>());
928 new_config.frame_encryptor = mock_frame_encryptor_0;
929 EXPECT_CALL(*helper.channel_send(), SetFrameEncryptor(Ne(nullptr)))
930 .Times(1);
931 send_stream->Reconfigure(new_config, nullptr);
932
933 // Not updating the frame encryptor shouldn't force it to reconfigure.
934 EXPECT_CALL(*helper.channel_send(), SetFrameEncryptor(_)).Times(0);
935 send_stream->Reconfigure(new_config, nullptr);
936
937 // Updating frame encryptor to a new object should force a call to the
938 // proxy.
939 rtc::scoped_refptr<FrameEncryptorInterface> mock_frame_encryptor_1(
940 rtc::make_ref_counted<MockFrameEncryptor>());
941 new_config.frame_encryptor = mock_frame_encryptor_1;
942 new_config.crypto_options.sframe.require_frame_encryption = true;
943 EXPECT_CALL(*helper.channel_send(), SetFrameEncryptor(Ne(nullptr)))
944 .Times(1);
945 send_stream->Reconfigure(new_config, nullptr);
946 }
947 }
948 } // namespace test
949 } // namespace webrtc
950