|  | /* | 
|  | *  Copyright (c) 2012 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/test/iSACTest.h" | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #include "absl/strings/match.h" | 
|  | #include "api/audio_codecs/builtin_audio_decoder_factory.h" | 
|  | #include "api/audio_codecs/isac/audio_encoder_isac_float.h" | 
|  | #include "rtc_base/strings/string_builder.h" | 
|  | #include "rtc_base/time_utils.h" | 
|  | #include "test/gmock.h" | 
|  | #include "test/gtest.h" | 
|  | #include "test/testsupport/file_utils.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | using ::testing::AnyOf; | 
|  | using ::testing::Eq; | 
|  | using ::testing::StrCaseEq; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | constexpr int kISAC16kPayloadType = 103; | 
|  | constexpr int kISAC32kPayloadType = 104; | 
|  | const SdpAudioFormat kISAC16kFormat = {"ISAC", 16000, 1}; | 
|  | const SdpAudioFormat kISAC32kFormat = {"ISAC", 32000, 1}; | 
|  |  | 
|  | AudioEncoderIsacFloat::Config TweakConfig( | 
|  | AudioEncoderIsacFloat::Config config, | 
|  | const ACMTestISACConfig& test_config) { | 
|  | if (test_config.currentRateBitPerSec > 0) { | 
|  | config.bit_rate = test_config.currentRateBitPerSec; | 
|  | } | 
|  | if (test_config.currentFrameSizeMsec != 0) { | 
|  | config.frame_size_ms = test_config.currentFrameSizeMsec; | 
|  | } | 
|  | EXPECT_THAT(config.IsOk(), Eq(true)); | 
|  | return config; | 
|  | } | 
|  |  | 
|  | void SetISACConfigDefault(ACMTestISACConfig& isacConfig) { | 
|  | isacConfig.currentRateBitPerSec = 0; | 
|  | isacConfig.currentFrameSizeMsec = 0; | 
|  | isacConfig.encodingMode = -1; | 
|  | isacConfig.initRateBitPerSec = 0; | 
|  | isacConfig.initFrameSizeInMsec = 0; | 
|  | isacConfig.enforceFrameSize = false; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | ISACTest::ISACTest() | 
|  | : _acmA(AudioCodingModule::Create( | 
|  | AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))), | 
|  | _acmB(AudioCodingModule::Create( | 
|  | AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))) {} | 
|  |  | 
|  | ISACTest::~ISACTest() {} | 
|  |  | 
|  | void ISACTest::Setup() { | 
|  | // Register both iSAC-wb & iSAC-swb in both sides as receiver codecs. | 
|  | std::map<int, SdpAudioFormat> receive_codecs = { | 
|  | {kISAC16kPayloadType, kISAC16kFormat}, | 
|  | {kISAC32kPayloadType, kISAC32kFormat}}; | 
|  | _acmA->SetReceiveCodecs(receive_codecs); | 
|  | _acmB->SetReceiveCodecs(receive_codecs); | 
|  |  | 
|  | //--- Set A-to-B channel | 
|  | _channel_A2B.reset(new Channel); | 
|  | EXPECT_EQ(0, _acmA->RegisterTransportCallback(_channel_A2B.get())); | 
|  | _channel_A2B->RegisterReceiverACM(_acmB.get()); | 
|  |  | 
|  | //--- Set B-to-A channel | 
|  | _channel_B2A.reset(new Channel); | 
|  | EXPECT_EQ(0, _acmB->RegisterTransportCallback(_channel_B2A.get())); | 
|  | _channel_B2A->RegisterReceiverACM(_acmA.get()); | 
|  |  | 
|  | file_name_swb_ = | 
|  | webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); | 
|  |  | 
|  | _acmB->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC16kFormat), | 
|  | kISAC16kPayloadType)); | 
|  | _acmA->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC32kFormat), | 
|  | kISAC32kPayloadType)); | 
|  |  | 
|  | _inFileA.Open(file_name_swb_, 32000, "rb"); | 
|  | // Set test length to 500 ms (50 blocks of 10 ms each). | 
|  | _inFileA.SetNum10MsBlocksToRead(50); | 
|  | // Fast-forward 1 second (100 blocks) since the files start with silence. | 
|  | _inFileA.FastForward(100); | 
|  | std::string fileNameA = webrtc::test::OutputPath() + "testisac_a.pcm"; | 
|  | std::string fileNameB = webrtc::test::OutputPath() + "testisac_b.pcm"; | 
|  | _outFileA.Open(fileNameA, 32000, "wb"); | 
|  | _outFileB.Open(fileNameB, 32000, "wb"); | 
|  |  | 
|  | while (!_inFileA.EndOfFile()) { | 
|  | Run10ms(); | 
|  | } | 
|  |  | 
|  | _inFileA.Close(); | 
|  | _outFileA.Close(); | 
|  | _outFileB.Close(); | 
|  | } | 
|  |  | 
|  | void ISACTest::Perform() { | 
|  | Setup(); | 
|  |  | 
|  | int16_t testNr = 0; | 
|  | ACMTestISACConfig wbISACConfig; | 
|  | ACMTestISACConfig swbISACConfig; | 
|  |  | 
|  | SetISACConfigDefault(wbISACConfig); | 
|  | SetISACConfigDefault(swbISACConfig); | 
|  |  | 
|  | wbISACConfig.currentRateBitPerSec = -1; | 
|  | swbISACConfig.currentRateBitPerSec = -1; | 
|  | testNr++; | 
|  | EncodeDecode(testNr, wbISACConfig, swbISACConfig); | 
|  |  | 
|  | SetISACConfigDefault(wbISACConfig); | 
|  | SetISACConfigDefault(swbISACConfig); | 
|  | testNr++; | 
|  | EncodeDecode(testNr, wbISACConfig, swbISACConfig); | 
|  |  | 
|  | testNr++; | 
|  | SwitchingSamplingRate(testNr, 4); | 
|  | } | 
|  |  | 
|  | void ISACTest::Run10ms() { | 
|  | AudioFrame audioFrame; | 
|  | EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0); | 
|  | EXPECT_GE(_acmA->Add10MsData(audioFrame), 0); | 
|  | EXPECT_GE(_acmB->Add10MsData(audioFrame), 0); | 
|  | bool muted; | 
|  | EXPECT_EQ(0, _acmA->PlayoutData10Ms(32000, &audioFrame, &muted)); | 
|  | ASSERT_FALSE(muted); | 
|  | _outFileA.Write10MsData(audioFrame); | 
|  | EXPECT_EQ(0, _acmB->PlayoutData10Ms(32000, &audioFrame, &muted)); | 
|  | ASSERT_FALSE(muted); | 
|  | _outFileB.Write10MsData(audioFrame); | 
|  | } | 
|  |  | 
|  | void ISACTest::EncodeDecode(int testNr, | 
|  | ACMTestISACConfig& wbISACConfig, | 
|  | ACMTestISACConfig& swbISACConfig) { | 
|  | // Files in Side A and B | 
|  | _inFileA.Open(file_name_swb_, 32000, "rb", true); | 
|  | _inFileB.Open(file_name_swb_, 32000, "rb", true); | 
|  |  | 
|  | std::string file_name_out; | 
|  | rtc::StringBuilder file_stream_a; | 
|  | rtc::StringBuilder file_stream_b; | 
|  | file_stream_a << webrtc::test::OutputPath(); | 
|  | file_stream_b << webrtc::test::OutputPath(); | 
|  | file_stream_a << "out_iSACTest_A_" << testNr << ".pcm"; | 
|  | file_stream_b << "out_iSACTest_B_" << testNr << ".pcm"; | 
|  | file_name_out = file_stream_a.str(); | 
|  | _outFileA.Open(file_name_out, 32000, "wb"); | 
|  | file_name_out = file_stream_b.str(); | 
|  | _outFileB.Open(file_name_out, 32000, "wb"); | 
|  |  | 
|  | // Side A is sending super-wideband, and side B is sending wideband. | 
|  | _acmA->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | TweakConfig(*AudioEncoderIsacFloat::SdpToConfig(kISAC32kFormat), | 
|  | swbISACConfig), | 
|  | kISAC32kPayloadType)); | 
|  | _acmB->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | TweakConfig(*AudioEncoderIsacFloat::SdpToConfig(kISAC16kFormat), | 
|  | wbISACConfig), | 
|  | kISAC16kPayloadType)); | 
|  |  | 
|  | _channel_A2B->ResetStats(); | 
|  | _channel_B2A->ResetStats(); | 
|  |  | 
|  | while (!(_inFileA.EndOfFile() || _inFileA.Rewinded())) { | 
|  | Run10ms(); | 
|  | } | 
|  |  | 
|  | _channel_A2B->ResetStats(); | 
|  | _channel_B2A->ResetStats(); | 
|  |  | 
|  | _outFileA.Close(); | 
|  | _outFileB.Close(); | 
|  | _inFileA.Close(); | 
|  | _inFileB.Close(); | 
|  | } | 
|  |  | 
|  | void ISACTest::SwitchingSamplingRate(int testNr, int maxSampRateChange) { | 
|  | // Files in Side A | 
|  | _inFileA.Open(file_name_swb_, 32000, "rb"); | 
|  | _inFileB.Open(file_name_swb_, 32000, "rb"); | 
|  |  | 
|  | std::string file_name_out; | 
|  | rtc::StringBuilder file_stream_a; | 
|  | rtc::StringBuilder file_stream_b; | 
|  | file_stream_a << webrtc::test::OutputPath(); | 
|  | file_stream_b << webrtc::test::OutputPath(); | 
|  | file_stream_a << "out_iSACTest_A_" << testNr << ".pcm"; | 
|  | file_stream_b << "out_iSACTest_B_" << testNr << ".pcm"; | 
|  | file_name_out = file_stream_a.str(); | 
|  | _outFileA.Open(file_name_out, 32000, "wb"); | 
|  | file_name_out = file_stream_b.str(); | 
|  | _outFileB.Open(file_name_out, 32000, "wb"); | 
|  |  | 
|  | // Start with side A sending super-wideband and side B seding wideband. | 
|  | // Toggle sending wideband/super-wideband in this test. | 
|  | _acmA->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC32kFormat), | 
|  | kISAC32kPayloadType)); | 
|  | _acmB->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC16kFormat), | 
|  | kISAC16kPayloadType)); | 
|  |  | 
|  | int numSendCodecChanged = 0; | 
|  | while (numSendCodecChanged < (maxSampRateChange << 1)) { | 
|  | Run10ms(); | 
|  | if (_inFileA.EndOfFile()) { | 
|  | if (_inFileA.SamplingFrequency() == 16000) { | 
|  | // Switch side A to send super-wideband. | 
|  | _inFileA.Close(); | 
|  | _inFileA.Open(file_name_swb_, 32000, "rb"); | 
|  | _acmA->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC32kFormat), | 
|  | kISAC32kPayloadType)); | 
|  | } else { | 
|  | // Switch side A to send wideband. | 
|  | _inFileA.Close(); | 
|  | _inFileA.Open(file_name_swb_, 32000, "rb"); | 
|  | _acmA->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC16kFormat), | 
|  | kISAC16kPayloadType)); | 
|  | } | 
|  | numSendCodecChanged++; | 
|  | } | 
|  |  | 
|  | if (_inFileB.EndOfFile()) { | 
|  | if (_inFileB.SamplingFrequency() == 16000) { | 
|  | // Switch side B to send super-wideband. | 
|  | _inFileB.Close(); | 
|  | _inFileB.Open(file_name_swb_, 32000, "rb"); | 
|  | _acmB->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC32kFormat), | 
|  | kISAC32kPayloadType)); | 
|  | } else { | 
|  | // Switch side B to send wideband. | 
|  | _inFileB.Close(); | 
|  | _inFileB.Open(file_name_swb_, 32000, "rb"); | 
|  | _acmB->SetEncoder(AudioEncoderIsacFloat::MakeAudioEncoder( | 
|  | *AudioEncoderIsacFloat::SdpToConfig(kISAC16kFormat), | 
|  | kISAC16kPayloadType)); | 
|  | } | 
|  | numSendCodecChanged++; | 
|  | } | 
|  | } | 
|  | _outFileA.Close(); | 
|  | _outFileB.Close(); | 
|  | _inFileA.Close(); | 
|  | _inFileB.Close(); | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |