| OLD | NEW |
| (Empty) |
| 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 <cstring> | |
| 12 | |
| 13 #include "testing/gtest/include/gtest/gtest.h" | |
| 14 #include "webrtc/base/arraysize.h" | |
| 15 #include "webrtc/base/safe_conversions.h" | |
| 16 #include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h" | |
| 17 #include "webrtc/modules/audio_coding/main/acm2/codec_owner.h" | |
| 18 #include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" | |
| 19 | |
| 20 namespace webrtc { | |
| 21 namespace acm2 { | |
| 22 | |
| 23 using ::testing::Return; | |
| 24 using ::testing::InSequence; | |
| 25 | |
| 26 namespace { | |
| 27 const int kDataLengthSamples = 80; | |
| 28 const int kPacketSizeSamples = 2 * kDataLengthSamples; | |
| 29 const int16_t kZeroData[kDataLengthSamples] = {0}; | |
| 30 const CodecInst kDefaultCodecInst = | |
| 31 {0, "pcmu", 8000, kPacketSizeSamples, 1, 64000}; | |
| 32 const int kCngPt = 13; | |
| 33 } // namespace | |
| 34 | |
| 35 class CodecOwnerTest : public ::testing::Test { | |
| 36 protected: | |
| 37 CodecOwnerTest() : timestamp_(0) {} | |
| 38 | |
| 39 void CreateCodec() { | |
| 40 AudioEncoder *enc = rent_a_codec_.RentEncoder(kDefaultCodecInst); | |
| 41 ASSERT_TRUE(enc); | |
| 42 codec_owner_.SetEncoders(enc, kCngPt, VADNormal, -1); | |
| 43 } | |
| 44 | |
| 45 void EncodeAndVerify(size_t expected_out_length, | |
| 46 uint32_t expected_timestamp, | |
| 47 int expected_payload_type, | |
| 48 int expected_send_even_if_empty) { | |
| 49 uint8_t out[kPacketSizeSamples]; | |
| 50 AudioEncoder::EncodedInfo encoded_info; | |
| 51 encoded_info = codec_owner_.Encoder()->Encode(timestamp_, kZeroData, | |
| 52 kPacketSizeSamples, out); | |
| 53 timestamp_ += kDataLengthSamples; | |
| 54 EXPECT_TRUE(encoded_info.redundant.empty()); | |
| 55 EXPECT_EQ(expected_out_length, encoded_info.encoded_bytes); | |
| 56 EXPECT_EQ(expected_timestamp, encoded_info.encoded_timestamp); | |
| 57 if (expected_payload_type >= 0) | |
| 58 EXPECT_EQ(expected_payload_type, encoded_info.payload_type); | |
| 59 if (expected_send_even_if_empty >= 0) | |
| 60 EXPECT_EQ(static_cast<bool>(expected_send_even_if_empty), | |
| 61 encoded_info.send_even_if_empty); | |
| 62 } | |
| 63 | |
| 64 // Verify that the speech encoder's Reset method is called when CNG or RED | |
| 65 // (or both) are switched on, but not when they're switched off. | |
| 66 void TestCngAndRedResetSpeechEncoder(bool use_cng, bool use_red) { | |
| 67 MockAudioEncoder speech_encoder; | |
| 68 EXPECT_CALL(speech_encoder, NumChannels()) | |
| 69 .WillRepeatedly(Return(1)); | |
| 70 EXPECT_CALL(speech_encoder, Max10MsFramesInAPacket()) | |
| 71 .WillRepeatedly(Return(2)); | |
| 72 EXPECT_CALL(speech_encoder, SampleRateHz()) | |
| 73 .WillRepeatedly(Return(8000)); | |
| 74 { | |
| 75 InSequence s; | |
| 76 EXPECT_CALL(speech_encoder, Mark("start off")); | |
| 77 EXPECT_CALL(speech_encoder, Mark("switch on")); | |
| 78 if (use_cng || use_red) | |
| 79 EXPECT_CALL(speech_encoder, Reset()); | |
| 80 EXPECT_CALL(speech_encoder, Mark("start on")); | |
| 81 if (use_cng || use_red) | |
| 82 EXPECT_CALL(speech_encoder, Reset()); | |
| 83 EXPECT_CALL(speech_encoder, Mark("switch off")); | |
| 84 EXPECT_CALL(speech_encoder, Die()); | |
| 85 } | |
| 86 | |
| 87 int cng_pt = use_cng ? 17 : -1; | |
| 88 int red_pt = use_red ? 19 : -1; | |
| 89 speech_encoder.Mark("start off"); | |
| 90 codec_owner_.SetEncoders(&speech_encoder, -1, VADNormal, -1); | |
| 91 speech_encoder.Mark("switch on"); | |
| 92 codec_owner_.ChangeCngAndRed(cng_pt, VADNormal, red_pt); | |
| 93 speech_encoder.Mark("start on"); | |
| 94 codec_owner_.SetEncoders(&speech_encoder, cng_pt, VADNormal, red_pt); | |
| 95 speech_encoder.Mark("switch off"); | |
| 96 codec_owner_.ChangeCngAndRed(-1, VADNormal, -1); | |
| 97 } | |
| 98 | |
| 99 CodecOwner codec_owner_; | |
| 100 RentACodec rent_a_codec_; | |
| 101 uint32_t timestamp_; | |
| 102 }; | |
| 103 | |
| 104 // This test verifies that CNG frames are delivered as expected. Since the frame | |
| 105 // size is set to 20 ms, we expect the first encode call to produce no output | |
| 106 // (which is signaled as 0 bytes output of type kNoEncoding). The next encode | |
| 107 // call should produce one SID frame of 9 bytes. The third call should not | |
| 108 // result in any output (just like the first one). The fourth and final encode | |
| 109 // call should produce an "empty frame", which is like no output, but with | |
| 110 // AudioEncoder::EncodedInfo::send_even_if_empty set to true. (The reason to | |
| 111 // produce an empty frame is to drive sending of DTMF packets in the RTP/RTCP | |
| 112 // module.) | |
| 113 TEST_F(CodecOwnerTest, VerifyCngFrames) { | |
| 114 CreateCodec(); | |
| 115 uint32_t expected_timestamp = timestamp_; | |
| 116 // Verify no frame. | |
| 117 { | |
| 118 SCOPED_TRACE("First encoding"); | |
| 119 EncodeAndVerify(0, expected_timestamp, -1, -1); | |
| 120 } | |
| 121 | |
| 122 // Verify SID frame delivered. | |
| 123 { | |
| 124 SCOPED_TRACE("Second encoding"); | |
| 125 EncodeAndVerify(9, expected_timestamp, kCngPt, 1); | |
| 126 } | |
| 127 | |
| 128 // Verify no frame. | |
| 129 { | |
| 130 SCOPED_TRACE("Third encoding"); | |
| 131 EncodeAndVerify(0, expected_timestamp, -1, -1); | |
| 132 } | |
| 133 | |
| 134 // Verify NoEncoding. | |
| 135 expected_timestamp += 2 * kDataLengthSamples; | |
| 136 { | |
| 137 SCOPED_TRACE("Fourth encoding"); | |
| 138 EncodeAndVerify(0, expected_timestamp, kCngPt, 1); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 TEST_F(CodecOwnerTest, ExternalEncoder) { | |
| 143 MockAudioEncoder external_encoder; | |
| 144 codec_owner_.SetEncoders(&external_encoder, -1, VADNormal, -1); | |
| 145 const int kSampleRateHz = 8000; | |
| 146 const int kPacketSizeSamples = kSampleRateHz / 100; | |
| 147 int16_t audio[kPacketSizeSamples] = {0}; | |
| 148 uint8_t encoded[kPacketSizeSamples]; | |
| 149 AudioEncoder::EncodedInfo info; | |
| 150 EXPECT_CALL(external_encoder, SampleRateHz()) | |
| 151 .WillRepeatedly(Return(kSampleRateHz)); | |
| 152 EXPECT_CALL(external_encoder, NumChannels()).WillRepeatedly(Return(1)); | |
| 153 | |
| 154 { | |
| 155 InSequence s; | |
| 156 info.encoded_timestamp = 0; | |
| 157 EXPECT_CALL(external_encoder, | |
| 158 EncodeInternal(0, rtc::ArrayView<const int16_t>(audio), | |
| 159 arraysize(encoded), encoded)) | |
| 160 .WillOnce(Return(info)); | |
| 161 EXPECT_CALL(external_encoder, Mark("A")); | |
| 162 EXPECT_CALL(external_encoder, Mark("B")); | |
| 163 info.encoded_timestamp = 2; | |
| 164 EXPECT_CALL(external_encoder, | |
| 165 EncodeInternal(2, rtc::ArrayView<const int16_t>(audio), | |
| 166 arraysize(encoded), encoded)) | |
| 167 .WillOnce(Return(info)); | |
| 168 EXPECT_CALL(external_encoder, Die()); | |
| 169 } | |
| 170 | |
| 171 info = codec_owner_.Encoder()->Encode(0, audio, arraysize(encoded), encoded); | |
| 172 EXPECT_EQ(0u, info.encoded_timestamp); | |
| 173 external_encoder.Mark("A"); | |
| 174 | |
| 175 // Change to internal encoder. | |
| 176 CodecInst codec_inst = kDefaultCodecInst; | |
| 177 codec_inst.pacsize = kPacketSizeSamples; | |
| 178 AudioEncoder* enc = rent_a_codec_.RentEncoder(codec_inst); | |
| 179 ASSERT_TRUE(enc); | |
| 180 codec_owner_.SetEncoders(enc, -1, VADNormal, -1); | |
| 181 // Don't expect any more calls to the external encoder. | |
| 182 info = codec_owner_.Encoder()->Encode(1, audio, arraysize(encoded), encoded); | |
| 183 external_encoder.Mark("B"); | |
| 184 | |
| 185 // Change back to external encoder again. | |
| 186 codec_owner_.SetEncoders(&external_encoder, -1, VADNormal, -1); | |
| 187 info = codec_owner_.Encoder()->Encode(2, audio, arraysize(encoded), encoded); | |
| 188 EXPECT_EQ(2u, info.encoded_timestamp); | |
| 189 } | |
| 190 | |
| 191 TEST_F(CodecOwnerTest, CngResetsSpeechEncoder) { | |
| 192 TestCngAndRedResetSpeechEncoder(true, false); | |
| 193 } | |
| 194 | |
| 195 TEST_F(CodecOwnerTest, RedResetsSpeechEncoder) { | |
| 196 TestCngAndRedResetSpeechEncoder(false, true); | |
| 197 } | |
| 198 | |
| 199 TEST_F(CodecOwnerTest, CngAndRedResetsSpeechEncoder) { | |
| 200 TestCngAndRedResetSpeechEncoder(true, true); | |
| 201 } | |
| 202 | |
| 203 TEST_F(CodecOwnerTest, NoCngAndRedNoSpeechEncoderReset) { | |
| 204 TestCngAndRedResetSpeechEncoder(false, false); | |
| 205 } | |
| 206 | |
| 207 } // namespace acm2 | |
| 208 } // namespace webrtc | |
| OLD | NEW |