Make AudioDecoder stateless

The channels_ member varable is removed from the base class, and the
associated accessor function is changed to Channels() which is a pure
virtual function.

R=jmarusic@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#8775}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8775 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.h b/webrtc/modules/audio_coding/codecs/audio_decoder.h
index 22e44a4..1ac02c5 100644
--- a/webrtc/modules/audio_coding/codecs/audio_decoder.h
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder.h
@@ -31,8 +31,8 @@
   // Used by PacketDuration below. Save the value -1 for errors.
   enum { kNotImplemented = -2 };
 
-  AudioDecoder() : channels_(1) {}
-  virtual ~AudioDecoder() {}
+  AudioDecoder() = default;
+  virtual ~AudioDecoder() = default;
 
   // Decodes |encode_len| bytes from |encoded| and writes the result in
   // |decoded|. The maximum bytes allowed to be written into |decoded| is
@@ -97,7 +97,7 @@
   // isn't a CNG decoder, don't call this method.
   virtual CNG_dec_inst* CngDecoderInstance();
 
-  size_t channels() const { return channels_; }
+  virtual size_t Channels() const = 0;
 
  protected:
   static SpeechType ConvertSpeechType(int16_t type);
@@ -114,8 +114,6 @@
                                       int16_t* decoded,
                                       SpeechType* speech_type);
 
-  size_t channels_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
 };
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
index 6b197bc..077568a 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -81,6 +81,7 @@
                      uint32_t rtp_timestamp,
                      uint32_t arrival_timestamp) override;
   int ErrorCode() override;
+  size_t Channels() const override { return 1; }
 
  protected:
   // AudioEncoder protected method.
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
index cf407db..2fc4306 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
@@ -121,7 +121,6 @@
 void AudioDecoderProxy::SetDecoder(AudioDecoder* decoder) {
   CriticalSectionScoped decoder_lock(decoder_lock_.get());
   decoder_ = decoder;
-  channels_ = decoder->channels();
   CHECK_EQ(decoder_->Init(), 0);
 }
 
@@ -205,6 +204,11 @@
   return decoder_->CngDecoderInstance();
 }
 
+size_t AudioDecoderProxy::Channels() const {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->Channels();
+}
+
 int16_t ACMGenericCodec::EncoderParams(WebRtcACMCodecParams* enc_params) {
   *enc_params = acm_codec_params_;
   return 0;
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
index 93fda43..cf07ea4 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
@@ -73,6 +73,7 @@
                               size_t encoded_len) const override;
   bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const override;
   CNG_dec_inst* CngDecoderInstance() override;
+  size_t Channels() const override;
 
  private:
   rtc::scoped_ptr<CriticalSectionWrapper> decoder_lock_;
diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc
index 8ffb761..ce24e4a 100644
--- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc
@@ -54,7 +54,7 @@
 int AudioDecoderPcmU::PacketDuration(const uint8_t* encoded,
                                      size_t encoded_len) const {
   // One encoded byte per sample per channel.
-  return static_cast<int>(encoded_len / channels_);
+  return static_cast<int>(encoded_len / Channels());
 }
 
 // PCMa
@@ -74,7 +74,7 @@
 int AudioDecoderPcmA::PacketDuration(const uint8_t* encoded,
                                      size_t encoded_len) const {
   // One encoded byte per sample per channel.
-  return static_cast<int>(encoded_len / channels_);
+  return static_cast<int>(encoded_len / Channels());
 }
 
 // PCM16B
@@ -98,12 +98,12 @@
 int AudioDecoderPcm16B::PacketDuration(const uint8_t* encoded,
                                        size_t encoded_len) const {
   // Two encoded byte per sample per channel.
-  return static_cast<int>(encoded_len / (2 * channels_));
+  return static_cast<int>(encoded_len / (2 * Channels()));
 }
 
-AudioDecoderPcm16BMultiCh::AudioDecoderPcm16BMultiCh(int num_channels) {
+AudioDecoderPcm16BMultiCh::AudioDecoderPcm16BMultiCh(int num_channels)
+    : channels_(num_channels) {
   DCHECK(num_channels > 0);
-  channels_ = num_channels;
 }
 #endif
 
@@ -171,11 +171,10 @@
 int AudioDecoderG722::PacketDuration(const uint8_t* encoded,
                                      size_t encoded_len) const {
   // 1/2 encoded byte per sample per channel.
-  return static_cast<int>(2 * encoded_len / channels_);
+  return static_cast<int>(2 * encoded_len / Channels());
 }
 
 AudioDecoderG722Stereo::AudioDecoderG722Stereo() {
-  channels_ = 2;
   WebRtcG722_CreateDecoder(&dec_state_left_);
   WebRtcG722_CreateDecoder(&dec_state_right_);
 }
@@ -260,9 +259,8 @@
 
 // Opus
 #ifdef WEBRTC_CODEC_OPUS
-AudioDecoderOpus::AudioDecoderOpus(int num_channels) {
+AudioDecoderOpus::AudioDecoderOpus(int num_channels) : channels_(num_channels) {
   DCHECK(num_channels == 1 || num_channels == 2);
-  channels_ = num_channels;
   WebRtcOpus_DecoderCreate(&dec_state_, static_cast<int>(channels_));
 }
 
diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h
index 2222b62..5f9c35b 100644
--- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h
+++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h
@@ -39,6 +39,7 @@
   AudioDecoderPcmU() {}
   virtual int Init() { return 0; }
   virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
+  size_t Channels() const override { return 1; }
 
  protected:
   int DecodeInternal(const uint8_t* encoded,
@@ -56,6 +57,7 @@
   AudioDecoderPcmA() {}
   virtual int Init() { return 0; }
   virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
+  size_t Channels() const override { return 1; }
 
  protected:
   int DecodeInternal(const uint8_t* encoded,
@@ -70,23 +72,27 @@
 
 class AudioDecoderPcmUMultiCh : public AudioDecoderPcmU {
  public:
-  explicit AudioDecoderPcmUMultiCh(size_t channels) : AudioDecoderPcmU() {
+  explicit AudioDecoderPcmUMultiCh(size_t channels)
+      : AudioDecoderPcmU(), channels_(channels) {
     assert(channels > 0);
-    channels_ = channels;
   }
+  size_t Channels() const override { return channels_; }
 
  private:
+  const size_t channels_;
   DISALLOW_COPY_AND_ASSIGN(AudioDecoderPcmUMultiCh);
 };
 
 class AudioDecoderPcmAMultiCh : public AudioDecoderPcmA {
  public:
-  explicit AudioDecoderPcmAMultiCh(size_t channels) : AudioDecoderPcmA() {
+  explicit AudioDecoderPcmAMultiCh(size_t channels)
+      : AudioDecoderPcmA(), channels_(channels) {
     assert(channels > 0);
-    channels_ = channels;
   }
+  size_t Channels() const override { return channels_; }
 
  private:
+  const size_t channels_;
   DISALLOW_COPY_AND_ASSIGN(AudioDecoderPcmAMultiCh);
 };
 
@@ -98,6 +104,7 @@
   AudioDecoderPcm16B();
   virtual int Init() { return 0; }
   virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
+  size_t Channels() const override { return 1; }
 
  protected:
   int DecodeInternal(const uint8_t* encoded,
@@ -116,8 +123,10 @@
 class AudioDecoderPcm16BMultiCh : public AudioDecoderPcm16B {
  public:
   explicit AudioDecoderPcm16BMultiCh(int num_channels);
+  size_t Channels() const override { return channels_; }
 
  private:
+  const size_t channels_;
   DISALLOW_COPY_AND_ASSIGN(AudioDecoderPcm16BMultiCh);
 };
 #endif
@@ -130,6 +139,7 @@
   virtual bool HasDecodePlc() const { return true; }
   virtual int DecodePlc(int num_frames, int16_t* decoded);
   virtual int Init();
+  size_t Channels() const override { return 1; }
 
  protected:
   int DecodeInternal(const uint8_t* encoded,
@@ -152,6 +162,7 @@
   virtual bool HasDecodePlc() const { return false; }
   virtual int Init();
   virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
+  size_t Channels() const override { return 1; }
 
  protected:
   int DecodeInternal(const uint8_t* encoded,
@@ -177,6 +188,7 @@
                      int sample_rate_hz,
                      int16_t* decoded,
                      SpeechType* speech_type) override;
+  size_t Channels() const override { return 2; }
 
  private:
   // Splits the stereo-interleaved payload in |encoded| into separate payloads
@@ -205,6 +217,7 @@
   virtual int PacketDurationRedundant(const uint8_t* encoded,
                                       size_t encoded_len) const;
   virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
+  size_t Channels() const override { return channels_; }
 
  protected:
   int DecodeInternal(const uint8_t* encoded,
@@ -220,6 +233,7 @@
 
  private:
   OpusDecInst* dec_state_;
+  const size_t channels_;
   DISALLOW_COPY_AND_ASSIGN(AudioDecoderOpus);
 };
 #endif
@@ -242,6 +256,7 @@
                              uint32_t arrival_timestamp) { return -1; }
 
   CNG_dec_inst* CngDecoderInstance() override { return dec_state_; }
+  size_t Channels() const override { return 1; }
 
  protected:
   int DecodeInternal(const uint8_t* encoded,
diff --git a/webrtc/modules/audio_coding/neteq/mock/mock_audio_decoder.h b/webrtc/modules/audio_coding/neteq/mock/mock_audio_decoder.h
index b113e4a..93261ab 100644
--- a/webrtc/modules/audio_coding/neteq/mock/mock_audio_decoder.h
+++ b/webrtc/modules/audio_coding/neteq/mock/mock_audio_decoder.h
@@ -31,6 +31,7 @@
   MOCK_METHOD5(IncomingPacket, int(const uint8_t*, size_t, uint16_t, uint32_t,
                                    uint32_t));
   MOCK_METHOD0(ErrorCode, int());
+  MOCK_CONST_METHOD0(Channels, size_t());
   MOCK_CONST_METHOD0(codec_type, NetEqDecoder());
   MOCK_METHOD1(CodecSupported, bool(NetEqDecoder));
 };
diff --git a/webrtc/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h b/webrtc/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
index beff6ae6..d8c8856 100644
--- a/webrtc/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
+++ b/webrtc/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
@@ -41,6 +41,7 @@
     *speech_type = ConvertSpeechType(1);
     return ret;
   }
+  size_t Channels() const override { return 1; }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ExternalPcm16B);
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
index fb9656b..32c6629 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -644,8 +644,8 @@
         decoder_database_->GetDecoderInfo(payload_type);
     assert(decoder_info);
     if (decoder_info->fs_hz != fs_hz_ ||
-        decoder->channels() != algorithm_buffer_->Channels())
-      SetSampleRateAndChannels(decoder_info->fs_hz, decoder->channels());
+        decoder->Channels() != algorithm_buffer_->Channels())
+      SetSampleRateAndChannels(decoder_info->fs_hz, decoder->Channels());
   }
 
   // TODO(hlundin): Move this code to DelayManager class.
@@ -1153,9 +1153,9 @@
         // If sampling rate or number of channels has changed, we need to make
         // a reset.
         if (decoder_info->fs_hz != fs_hz_ ||
-            decoder->channels() != algorithm_buffer_->Channels()) {
+            decoder->Channels() != algorithm_buffer_->Channels()) {
           // TODO(tlegrand): Add unittest to cover this event.
-          SetSampleRateAndChannels(decoder_info->fs_hz, decoder->channels());
+          SetSampleRateAndChannels(decoder_info->fs_hz, decoder->Channels());
         }
         sync_buffer_->set_end_timestamp(timestamp_);
         playout_timestamp_ = timestamp_;
@@ -1219,7 +1219,7 @@
     // since in this case, the we will increment the CNGplayedTS counter.
     // Increase with number of samples per channel.
     assert(*decoded_length == 0 ||
-           (decoder && decoder->channels() == sync_buffer_->Channels()));
+           (decoder && decoder->Channels() == sync_buffer_->Channels()));
     sync_buffer_->IncreaseEndTimestamp(
         *decoded_length / static_cast<int>(sync_buffer_->Channels()));
   }
@@ -1239,8 +1239,8 @@
     assert(decoder);  // At this point, we must have a decoder object.
     // The number of channels in the |sync_buffer_| should be the same as the
     // number decoder channels.
-    assert(sync_buffer_->Channels() == decoder->channels());
-    assert(decoded_buffer_length_ >= kMaxFrameSize * decoder->channels());
+    assert(sync_buffer_->Channels() == decoder->Channels());
+    assert(decoded_buffer_length_ >= kMaxFrameSize * decoder->Channels());
     assert(*operation == kNormal || *operation == kAccelerate ||
            *operation == kMerge || *operation == kPreemptiveExpand);
     packet_list->pop_front();
@@ -1254,8 +1254,9 @@
           ", pt=" << static_cast<int>(packet->header.payloadType) <<
           ", ssrc=" << packet->header.ssrc <<
           ", len=" << packet->payload_length;
-      memset(&decoded_buffer_[*decoded_length], 0, decoder_frame_length_ *
-             decoder->channels() * sizeof(decoded_buffer_[0]));
+      memset(&decoded_buffer_[*decoded_length], 0,
+             decoder_frame_length_ * decoder->Channels() *
+                 sizeof(decoded_buffer_[0]));
       decode_length = decoder_frame_length_;
     } else if (!packet->primary) {
       // This is a redundant payload; call the special decoder method.
@@ -1288,11 +1289,11 @@
     if (decode_length > 0) {
       *decoded_length += decode_length;
       // Update |decoder_frame_length_| with number of samples per channel.
-      decoder_frame_length_ = decode_length /
-          static_cast<int>(decoder->channels());
-      LOG(LS_VERBOSE) << "Decoded " << decode_length << " samples (" <<
-          decoder->channels() << " channel(s) -> " << decoder_frame_length_ <<
-          " samples per channel)";
+      decoder_frame_length_ =
+          decode_length / static_cast<int>(decoder->Channels());
+      LOG(LS_VERBOSE) << "Decoded " << decode_length << " samples ("
+                      << decoder->Channels() << " channel(s) -> "
+                      << decoder_frame_length_ << " samples per channel)";
     } else if (decode_length < 0) {
       // Error.
       LOG_FERR2(LS_WARNING, Decode, decode_length, payload_length);
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
index 0a5c6a4..3823d96 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -270,6 +270,7 @@
 
   // Create a mock decoder object.
   MockAudioDecoder mock_decoder;
+  EXPECT_CALL(mock_decoder, Channels()).WillRepeatedly(Return(1));
   // BWE update function called with first packet.
   EXPECT_CALL(mock_decoder, IncomingPacket(_,
                                            kPayloadLength,
@@ -447,6 +448,8 @@
       return 0;
     }
 
+    size_t Channels() const override { return 1; }
+
     uint16_t next_value() const { return next_value_; }
 
    private:
@@ -519,6 +522,7 @@
   // Create a mock decoder object.
   MockAudioDecoder mock_decoder;
   EXPECT_CALL(mock_decoder, Init()).WillRepeatedly(Return(0));
+  EXPECT_CALL(mock_decoder, Channels()).WillRepeatedly(Return(1));
   EXPECT_CALL(mock_decoder, IncomingPacket(_, kPayloadLengthBytes, _, _, _))
       .WillRepeatedly(Return(0));
   int16_t dummy_output[kPayloadLengthSamples] = {0};
@@ -682,6 +686,7 @@
   // Create a mock decoder object.
   MockAudioDecoder mock_decoder;
   EXPECT_CALL(mock_decoder, Init()).WillRepeatedly(Return(0));
+  EXPECT_CALL(mock_decoder, Channels()).WillRepeatedly(Return(1));
   EXPECT_CALL(mock_decoder, IncomingPacket(_, kPayloadLengthBytes, _, _, _))
       .WillRepeatedly(Return(0));
 
@@ -824,6 +829,7 @@
     MOCK_CONST_METHOD2(PacketDuration, int(const uint8_t*, size_t));
     MOCK_METHOD5(DecodeInternal, int(const uint8_t*, size_t, int, int16_t*,
                                      SpeechType*));
+    size_t Channels() const override { return 1; }
   } decoder_;
 
   const uint8_t kFirstPayloadValue = 1;
diff --git a/webrtc/modules/audio_coding/neteq/neteq_network_stats_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
index a49f957..e1a0f69 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
@@ -61,8 +61,8 @@
                      int16_t* decoded,
                      SpeechType* speech_type) override {
     *speech_type = kSpeech;
-    memset(decoded, 0, sizeof(int16_t) * kPacketDuration * channels_);
-    return kPacketDuration * channels_;
+    memset(decoded, 0, sizeof(int16_t) * kPacketDuration * Channels());
+    return kPacketDuration * Channels();
   }
 
   int DecodeRedundantInternal(const uint8_t* encoded,
diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
index 17391da..3eb4a29 100644
--- a/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
+++ b/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
@@ -21,7 +21,7 @@
     : codec_(codec),
       decoder_(decoder),
       sample_rate_hz_(CodecSampleRateHz(codec_)),
-      channels_(static_cast<int>(decoder_->channels())) {
+      channels_(static_cast<int>(decoder_->Channels())) {
   NetEq::Config config;
   config.sample_rate_hz = sample_rate_hz_;
   neteq_.reset(NetEq::Create(config));