diff --git a/webrtc/modules/audio_coding/neteq4/audio_decoder.cc b/webrtc/modules/audio_coding/neteq4/audio_decoder.cc index 3e9b4645d5..5a745ff133 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder.cc +++ b/webrtc/modules/audio_coding/neteq4/audio_decoder.cc @@ -30,6 +30,7 @@ bool AudioDecoder::CodecSupported(NetEqDecoder codec_type) { #endif #ifdef WEBRTC_CODEC_ISAC case kDecoderISACswb: + case kDecoderISACfb: #endif #ifdef WEBRTC_CODEC_PCM16 case kDecoderPCM16B: @@ -96,6 +97,7 @@ int AudioDecoder::CodecSampleRateHz(NetEqDecoder codec_type) { } #ifdef WEBRTC_CODEC_ISAC case kDecoderISACswb: + case kDecoderISACfb: #endif #ifdef WEBRTC_CODEC_PCM16 case kDecoderPCM16Bswb32kHz: @@ -153,6 +155,8 @@ AudioDecoder* AudioDecoder::CreateAudioDecoder(NetEqDecoder codec_type) { #ifdef WEBRTC_CODEC_ISAC case kDecoderISACswb: return new AudioDecoderIsacSwb; + case kDecoderISACfb: + return new AudioDecoderIsacFb; #endif #ifdef WEBRTC_CODEC_PCM16 case kDecoderPCM16B: diff --git a/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc index 4ab7984e36..1d000ff067 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc +++ b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc @@ -209,6 +209,11 @@ AudioDecoderIsacSwb::AudioDecoderIsacSwb() : AudioDecoderIsac() { codec_type_ = kDecoderISACswb; WebRtcIsac_SetDecSampRate(static_cast(state_), 32000); } + +// iSAC FB +AudioDecoderIsacFb::AudioDecoderIsacFb() : AudioDecoderIsacSwb() { + codec_type_ = kDecoderISACfb; +} #endif // iSAC fix diff --git a/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h index 1776a39045..7aaa69af1d 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h +++ b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h @@ -143,6 +143,14 @@ class AudioDecoderIsacSwb : public AudioDecoderIsac { private: DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacSwb); }; + +class AudioDecoderIsacFb : public AudioDecoderIsacSwb { + public: + AudioDecoderIsacFb(); + + private: + DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacFb); +}; #endif #ifdef WEBRTC_CODEC_ISACFX diff --git a/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc index b7e328659c..f91438fc6b 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc @@ -377,6 +377,19 @@ class AudioDecoderIsacSwbTest : public AudioDecoderTest { int input_size_; }; +// This test is identical to AudioDecoderIsacSwbTest, except that it creates +// an AudioDecoderIsacFb decoder object. +class AudioDecoderIsacFbTest : public AudioDecoderIsacSwbTest { + protected: + AudioDecoderIsacFbTest() : AudioDecoderIsacSwbTest() { + // Delete the |decoder_| that was created by AudioDecoderIsacSwbTest and + // create an AudioDecoderIsacFb object instead. + delete decoder_; + decoder_ = new AudioDecoderIsacFb; + assert(decoder_); + } +}; + class AudioDecoderIsacFixTest : public AudioDecoderTest { protected: AudioDecoderIsacFixTest() : AudioDecoderTest() { @@ -549,6 +562,17 @@ TEST_F(AudioDecoderIsacSwbTest, EncodeDecode) { DecodePlcTest(); } +TEST_F(AudioDecoderIsacFbTest, EncodeDecode) { + int tolerance = 19757; + double mse = 8.18e6; + int delay = 160; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISACswb)); + EncodeDecodeTest(853, tolerance, mse, delay); + ReInitTest(); + EXPECT_TRUE(decoder_->HasDecodePlc()); + DecodePlcTest(); +} + TEST_F(AudioDecoderIsacFixTest, DISABLED_EncodeDecode) { int tolerance = 11034; double mse = 3.46e6; @@ -587,6 +611,7 @@ TEST(AudioDecoder, CodecSampleRateHz) { EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderILBC)); EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderISAC)); EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderISACswb)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderISACfb)); EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16B)); EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bwb)); EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bswb32kHz)); @@ -620,6 +645,7 @@ TEST(AudioDecoder, CodecSupported) { EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderILBC)); EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISAC)); EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISACswb)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISACfb)); EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16B)); EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bwb)); EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bswb32kHz)); diff --git a/webrtc/modules/audio_coding/neteq4/interface/audio_decoder.h b/webrtc/modules/audio_coding/neteq4/interface/audio_decoder.h index 0b23c767d9..7668f33711 100644 --- a/webrtc/modules/audio_coding/neteq4/interface/audio_decoder.h +++ b/webrtc/modules/audio_coding/neteq4/interface/audio_decoder.h @@ -26,6 +26,7 @@ enum NetEqDecoder { kDecoderILBC, kDecoderISAC, kDecoderISACswb, + kDecoderISACfb, kDecoderPCM16B, kDecoderPCM16Bwb, kDecoderPCM16Bswb32kHz, diff --git a/webrtc/modules/audio_coding/neteq4/neteq_unittest.cc b/webrtc/modules/audio_coding/neteq4/neteq_unittest.cc index 65cc393886..250ca0e79c 100644 --- a/webrtc/modules/audio_coding/neteq4/neteq_unittest.cc +++ b/webrtc/modules/audio_coding/neteq4/neteq_unittest.cc @@ -235,6 +235,8 @@ void NetEqDecodingTest::LoadDecoders() { ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISAC, 103)); // Load iSAC SWB. ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACswb, 104)); + // Load iSAC FB. + ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACfb, 105)); // Load PCM16B nb. ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16B, 93)); // Load PCM16B wb. diff --git a/webrtc/modules/audio_coding/neteq4/timestamp_scaler.cc b/webrtc/modules/audio_coding/neteq4/timestamp_scaler.cc index 6bb22d5148..d58d5ddbad 100644 --- a/webrtc/modules/audio_coding/neteq4/timestamp_scaler.cc +++ b/webrtc/modules/audio_coding/neteq4/timestamp_scaler.cc @@ -49,6 +49,7 @@ uint32_t TimestampScaler::ToInternal(uint32_t external_timestamp, } case kDecoderOpus: case kDecoderOpus_2ch: + case kDecoderISACfb: case kDecoderCNGswb48kHz: { // Use timestamp scaling with factor 2/3 (32 kHz sample rate, but RTP // timestamps run on 48 kHz). diff --git a/webrtc/modules/audio_coding/neteq4/timestamp_scaler_unittest.cc b/webrtc/modules/audio_coding/neteq4/timestamp_scaler_unittest.cc index ecbed98585..c676094672 100644 --- a/webrtc/modules/audio_coding/neteq4/timestamp_scaler_unittest.cc +++ b/webrtc/modules/audio_coding/neteq4/timestamp_scaler_unittest.cc @@ -252,6 +252,62 @@ TEST(TimestampScaler, TestG722Reset) { EXPECT_CALL(db, Die()); // Called when database object is deleted. } +TEST(TimestampScaler, TestOpusLargeStep) { + MockDecoderDatabase db; + DecoderDatabase::DecoderInfo info; + info.codec_type = kDecoderOpus; // Uses a factor 2/3 scaling. + static const uint8_t kRtpPayloadType = 17; + EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) + .WillRepeatedly(Return(&info)); + + TimestampScaler scaler(db); + // Test both sides of the timestamp wrap-around. + static const uint32_t kStep = 960; + uint32_t external_timestamp = 0; + // |external_timestamp| will be a large positive value. + external_timestamp = external_timestamp - 5 * kStep; + uint32_t internal_timestamp = external_timestamp; + for (; external_timestamp != 5 * kStep; external_timestamp += kStep) { + // Scale to internal timestamp. + EXPECT_EQ(internal_timestamp, + scaler.ToInternal(external_timestamp, kRtpPayloadType)); + // Scale back. + EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp)); + // Internal timestamp should be incremented with twice the step. + internal_timestamp += 2 * kStep / 3; + } + + EXPECT_CALL(db, Die()); // Called when database object is deleted. +} + +TEST(TimestampScaler, TestIsacFbLargeStep) { + MockDecoderDatabase db; + DecoderDatabase::DecoderInfo info; + info.codec_type = kDecoderISACfb; // Uses a factor 2/3 scaling. + static const uint8_t kRtpPayloadType = 17; + EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) + .WillRepeatedly(Return(&info)); + + TimestampScaler scaler(db); + // Test both sides of the timestamp wrap-around. + static const uint32_t kStep = 960; + uint32_t external_timestamp = 0; + // |external_timestamp| will be a large positive value. + external_timestamp = external_timestamp - 5 * kStep; + uint32_t internal_timestamp = external_timestamp; + for (; external_timestamp != 5 * kStep; external_timestamp += kStep) { + // Scale to internal timestamp. + EXPECT_EQ(internal_timestamp, + scaler.ToInternal(external_timestamp, kRtpPayloadType)); + // Scale back. + EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp)); + // Internal timestamp should be incremented with twice the step. + internal_timestamp += 2 * kStep / 3; + } + + EXPECT_CALL(db, Die()); // Called when database object is deleted. +} + TEST(TimestampScaler, Failures) { static const uint8_t kRtpPayloadType = 17; MockDecoderDatabase db;