Adding iSAC-fb support

Adding tests, too.

Review URL: https://webrtc-codereview.appspot.com/1070011

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3440 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/neteq4/audio_decoder.cc b/webrtc/modules/audio_coding/neteq4/audio_decoder.cc
index 3e9b464..5a745ff 100644
--- a/webrtc/modules/audio_coding/neteq4/audio_decoder.cc
+++ b/webrtc/modules/audio_coding/neteq4/audio_decoder.cc
@@ -30,6 +30,7 @@
 #endif
 #ifdef WEBRTC_CODEC_ISAC
     case kDecoderISACswb:
+    case kDecoderISACfb:
 #endif
 #ifdef WEBRTC_CODEC_PCM16
     case kDecoderPCM16B:
@@ -96,6 +97,7 @@
     }
 #ifdef WEBRTC_CODEC_ISAC
     case kDecoderISACswb:
+    case kDecoderISACfb:
 #endif
 #ifdef WEBRTC_CODEC_PCM16
     case kDecoderPCM16Bswb32kHz:
@@ -153,6 +155,8 @@
 #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 4ab7984..1d000ff 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 @@
   codec_type_ = kDecoderISACswb;
   WebRtcIsac_SetDecSampRate(static_cast<ISACStruct*>(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 1776a39..7aaa69a 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 @@
  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 b7e3286..f91438f 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 @@
   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 @@
   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 @@
   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 @@
   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 0b23c76..7668f33 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 @@
   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 65cc393..250ca0e 100644
--- a/webrtc/modules/audio_coding/neteq4/neteq_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq4/neteq_unittest.cc
@@ -235,6 +235,8 @@
   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 6bb22d5..d58d5dd 100644
--- a/webrtc/modules/audio_coding/neteq4/timestamp_scaler.cc
+++ b/webrtc/modules/audio_coding/neteq4/timestamp_scaler.cc
@@ -49,6 +49,7 @@
     }
     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 ecbed98..c676094 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 @@
   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;