Add AudioReceiveStream::SetGain() method and use that in WVoMC::SetOutputVolume().

Removes the need to use VoEVolume::SetChannelOutputVolumeScaling().

BUG=webrtc:4690

Review-Url: https://codereview.webrtc.org/2062193002
Cr-Commit-Position: refs/heads/master@{#13194}
diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc
index 15e4f61..c933f78 100644
--- a/webrtc/audio/audio_receive_stream.cc
+++ b/webrtc/audio/audio_receive_stream.cc
@@ -210,6 +210,11 @@
   channel_proxy_->SetSink(std::move(sink));
 }
 
+void AudioReceiveStream::SetGain(float gain) {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  channel_proxy_->SetChannelOutputVolumeScaling(gain);
+}
+
 const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   return config_;
diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h
index d99956c..284f98e 100644
--- a/webrtc/audio/audio_receive_stream.h
+++ b/webrtc/audio/audio_receive_stream.h
@@ -41,6 +41,7 @@
   void Stop() override;
   webrtc::AudioReceiveStream::Stats GetStats() const override;
   void SetSink(std::unique_ptr<AudioSinkInterface> sink) override;
+  void SetGain(float gain) override;
 
   void SignalNetworkState(NetworkState state);
   bool DeliverRtcp(const uint8_t* packet, size_t length);
diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc
index 2e789f9..8e26dd9 100644
--- a/webrtc/audio/audio_receive_stream_unittest.cc
+++ b/webrtc/audio/audio_receive_stream_unittest.cc
@@ -30,6 +30,7 @@
 namespace {
 
 using testing::_;
+using testing::FloatEq;
 using testing::Return;
 using testing::ReturnRef;
 
@@ -92,12 +93,12 @@
           EXPECT_CALL(*channel_proxy_,
               SetReceiveAudioLevelIndicationStatus(true, kAudioLevelId))
                   .Times(1);
-          EXPECT_CALL(*channel_proxy_, EnableReceiveTransportSequenceNumber(
-                                           kTransportSequenceNumberId))
-              .Times(1);
           EXPECT_CALL(*channel_proxy_,
-                      RegisterReceiverCongestionControlObjects(&packet_router_))
-              .Times(1);
+              EnableReceiveTransportSequenceNumber(kTransportSequenceNumberId))
+                  .Times(1);
+          EXPECT_CALL(*channel_proxy_,
+              RegisterReceiverCongestionControlObjects(&packet_router_))
+                  .Times(1);
           EXPECT_CALL(congestion_controller_, packet_router())
               .WillOnce(Return(&packet_router_));
           EXPECT_CALL(*channel_proxy_, ResetCongestionControlObjects())
@@ -303,7 +304,6 @@
   EXPECT_TRUE(recv_stream.DeliverRtcp(&rtcp_packet[0], rtcp_packet.size()));
 }
 
-
 TEST(AudioReceiveStreamTest, GetStats) {
   ConfigHelper helper;
   internal::AudioReceiveStream recv_stream(
@@ -345,5 +345,14 @@
   EXPECT_EQ(kCallStats.capture_start_ntp_time_ms_,
             stats.capture_start_ntp_time_ms);
 }
+
+TEST(AudioReceiveStreamTest, SetGain) {
+  ConfigHelper helper;
+  internal::AudioReceiveStream recv_stream(
+      helper.congestion_controller(), helper.config(), helper.audio_state());
+  EXPECT_CALL(*helper.channel_proxy(),
+      SetChannelOutputVolumeScaling(FloatEq(0.765f)));
+  recv_stream.SetGain(0.765f);
+}
 }  // namespace test
 }  // namespace webrtc
diff --git a/webrtc/audio_receive_stream.h b/webrtc/audio_receive_stream.h
index 16ed769..e0e9536 100644
--- a/webrtc/audio_receive_stream.h
+++ b/webrtc/audio_receive_stream.h
@@ -127,6 +127,10 @@
   // of feeding to the AEC.
   virtual void SetSink(std::unique_ptr<AudioSinkInterface> sink) = 0;
 
+  // Sets playback gain of the stream, applied when mixing, and thus after it
+  // is potentially forwarded to any attached AudioSinkInterface implementation.
+  virtual void SetGain(float gain) = 0;
+
  protected:
   virtual ~AudioReceiveStream() {}
 };
diff --git a/webrtc/media/engine/fakewebrtccall.cc b/webrtc/media/engine/fakewebrtccall.cc
index fd020d4..914a403 100644
--- a/webrtc/media/engine/fakewebrtccall.cc
+++ b/webrtc/media/engine/fakewebrtccall.cc
@@ -57,7 +57,7 @@
 
 FakeAudioReceiveStream::FakeAudioReceiveStream(
     const webrtc::AudioReceiveStream::Config& config)
-    : config_(config), received_packets_(0) {
+    : config_(config) {
   RTC_DCHECK(config.voe_channel_id != -1);
 }
 
@@ -93,6 +93,10 @@
   sink_ = std::move(sink);
 }
 
+void FakeAudioReceiveStream::SetGain(float gain) {
+  gain_ = gain;
+}
+
 FakeVideoSendStream::FakeVideoSendStream(
     const webrtc::VideoSendStream::Config& config,
     const webrtc::VideoEncoderConfig& encoder_config)
diff --git a/webrtc/media/engine/fakewebrtccall.h b/webrtc/media/engine/fakewebrtccall.h
index 4a0e41c..f703b15 100644
--- a/webrtc/media/engine/fakewebrtccall.h
+++ b/webrtc/media/engine/fakewebrtccall.h
@@ -75,6 +75,7 @@
   int received_packets() const { return received_packets_; }
   bool VerifyLastPacket(const uint8_t* data, size_t length) const;
   const webrtc::AudioSinkInterface* sink() const { return sink_.get(); }
+  float gain() const { return gain_; }
   bool DeliverRtp(const uint8_t* packet,
                   size_t length,
                   const webrtc::PacketTime& packet_time);
@@ -86,11 +87,13 @@
 
   webrtc::AudioReceiveStream::Stats GetStats() const override;
   void SetSink(std::unique_ptr<webrtc::AudioSinkInterface> sink) override;
+  void SetGain(float gain) override;
 
   webrtc::AudioReceiveStream::Config config_;
   webrtc::AudioReceiveStream::Stats stats_;
-  int received_packets_;
+  int received_packets_ = 0;
   std::unique_ptr<webrtc::AudioSinkInterface> sink_;
+  float gain_ = 1.0f;
   rtc::Buffer last_packet_;
 };
 
diff --git a/webrtc/media/engine/fakewebrtcvoiceengine.h b/webrtc/media/engine/fakewebrtcvoiceengine.h
index 8d15f52..4e3ced6 100644
--- a/webrtc/media/engine/fakewebrtcvoiceengine.h
+++ b/webrtc/media/engine/fakewebrtcvoiceengine.h
@@ -129,7 +129,6 @@
       memset(&send_codec, 0, sizeof(send_codec));
     }
     bool playout = false;
-    float volume_scale = 1.0f;
     bool vad = false;
     bool codec_fec = false;
     int max_encoding_bandwidth = 0;
@@ -441,16 +440,8 @@
   WEBRTC_STUB(GetSpeechOutputLevel, (int, unsigned int&));
   WEBRTC_STUB(GetSpeechInputLevelFullRange, (unsigned int&));
   WEBRTC_STUB(GetSpeechOutputLevelFullRange, (int, unsigned int&));
-  WEBRTC_FUNC(SetChannelOutputVolumeScaling, (int channel, float scale)) {
-    WEBRTC_CHECK_CHANNEL(channel);
-    channels_[channel]->volume_scale= scale;
-    return 0;
-  }
-  WEBRTC_FUNC(GetChannelOutputVolumeScaling, (int channel, float& scale)) {
-    WEBRTC_CHECK_CHANNEL(channel);
-    scale = channels_[channel]->volume_scale;
-    return 0;
-  }
+  WEBRTC_STUB(SetChannelOutputVolumeScaling, (int channel, float scale));
+  WEBRTC_STUB(GetChannelOutputVolumeScaling, (int channel, float& scale));
   WEBRTC_STUB(SetOutputVolumePan, (int channel, float left, float right));
   WEBRTC_STUB(GetOutputVolumePan, (int channel, float& left, float& right));
 
diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc
index eb9b4bb..2ddf67d 100644
--- a/webrtc/media/engine/webrtcvoiceengine.cc
+++ b/webrtc/media/engine/webrtcvoiceengine.cc
@@ -1341,6 +1341,11 @@
     stream_->SetSink(std::move(sink));
   }
 
+  void SetOutputVolume(double volume) {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    stream_->SetGain(volume);
+  }
+
  private:
   void RecreateAudioReceiveStream(
       uint32_t local_ssrc,
@@ -2270,19 +2275,14 @@
     }
     ssrc = static_cast<uint32_t>(default_recv_ssrc_);
   }
-  int ch_id = GetReceiveChannelId(ssrc);
-  if (ch_id < 0) {
-    LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc;
+  const auto it = recv_streams_.find(ssrc);
+  if (it == recv_streams_.end()) {
+    LOG(LS_WARNING) << "SetOutputVolume: no recv stream" << ssrc;
     return false;
   }
-
-  if (-1 == engine()->voe()->volume()->SetChannelOutputVolumeScaling(ch_id,
-                                                                     volume)) {
-    LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume);
-    return false;
-  }
-  LOG(LS_INFO) << "SetOutputVolume to " << volume
-               << " for channel " << ch_id << " and ssrc " << ssrc;
+  it->second->SetOutputVolume(volume);
+  LOG(LS_INFO) << "SetOutputVolume() to " << volume
+               << " for recv stream with ssrc " << ssrc;
   return true;
 }
 
diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
index 167ec89..2db70d1 100644
--- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc
+++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
@@ -3130,24 +3130,20 @@
   cricket::StreamParams stream;
   stream.ssrcs.push_back(kSsrc2);
   EXPECT_TRUE(channel_->AddRecvStream(stream));
-  int channel_id = voe_.GetLastChannel();
+  EXPECT_DOUBLE_EQ(1, GetRecvStream(kSsrc2).gain());
   EXPECT_TRUE(channel_->SetOutputVolume(kSsrc2, 3));
-  float scale = 0;
-  EXPECT_EQ(0, voe_.GetChannelOutputVolumeScaling(channel_id, scale));
-  EXPECT_DOUBLE_EQ(3, scale);
+  EXPECT_DOUBLE_EQ(3, GetRecvStream(kSsrc2).gain());
 }
 
 TEST_F(WebRtcVoiceEngineTestFake, SetOutputVolumeDefaultRecvStream) {
   EXPECT_TRUE(SetupChannel());
   EXPECT_TRUE(channel_->SetOutputVolume(0, 2));
   DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
-  int channel_id = voe_.GetLastChannel();
-  float scale = 0;
-  EXPECT_EQ(0, voe_.GetChannelOutputVolumeScaling(channel_id, scale));
-  EXPECT_DOUBLE_EQ(2, scale);
+  EXPECT_DOUBLE_EQ(2, GetRecvStream(1).gain());
   EXPECT_TRUE(channel_->SetOutputVolume(0, 3));
-  EXPECT_EQ(0, voe_.GetChannelOutputVolumeScaling(channel_id, scale));
-  EXPECT_DOUBLE_EQ(3, scale);
+  EXPECT_DOUBLE_EQ(3, GetRecvStream(1).gain());
+  EXPECT_TRUE(channel_->SetOutputVolume(1, 4));
+  EXPECT_DOUBLE_EQ(4, GetRecvStream(1).gain());
 }
 
 TEST_F(WebRtcVoiceEngineTestFake, SetsSyncGroupFromSyncLabel) {
diff --git a/webrtc/test/mock_voe_channel_proxy.h b/webrtc/test/mock_voe_channel_proxy.h
index da215d6..dc2a961 100644
--- a/webrtc/test/mock_voe_channel_proxy.h
+++ b/webrtc/test/mock_voe_channel_proxy.h
@@ -46,7 +46,8 @@
   MOCK_METHOD1(SetSendTelephoneEventPayloadType, bool(int payload_type));
   MOCK_METHOD2(SendTelephoneEventOutband, bool(int event, int duration_ms));
   MOCK_METHOD1(SetInputMute, void(bool muted));
-
+  // TODO(solenberg): Talk the compiler into accepting this mock method:
+  // MOCK_METHOD1(SetSink, void(std::unique_ptr<AudioSinkInterface> sink));
   MOCK_METHOD1(RegisterExternalTransport, void(Transport* transport));
   MOCK_METHOD0(DeRegisterExternalTransport, void());
   MOCK_METHOD3(ReceivedRTPPacket, bool(const uint8_t* packet,
@@ -55,6 +56,7 @@
   MOCK_METHOD2(ReceivedRTCPPacket, bool(const uint8_t* packet, size_t length));
   MOCK_CONST_METHOD0(GetAudioDecoderFactory,
                      const rtc::scoped_refptr<AudioDecoderFactory>&());
+  MOCK_METHOD1(SetChannelOutputVolumeScaling, void(float scaling));
 };
 }  // namespace test
 }  // namespace webrtc
diff --git a/webrtc/voice_engine/channel_proxy.cc b/webrtc/voice_engine/channel_proxy.cc
index 46288e9..f60728a 100644
--- a/webrtc/voice_engine/channel_proxy.cc
+++ b/webrtc/voice_engine/channel_proxy.cc
@@ -193,10 +193,17 @@
 }
 
 const rtc::scoped_refptr<AudioDecoderFactory>&
-ChannelProxy::GetAudioDecoderFactory() const {
+    ChannelProxy::GetAudioDecoderFactory() const {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
   return channel()->GetAudioDecoderFactory();
 }
 
+void ChannelProxy::SetChannelOutputVolumeScaling(float scaling) {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  int error = channel()->SetChannelOutputVolumeScaling(scaling);
+  RTC_DCHECK_EQ(0, error);
+}
+
 Channel* ChannelProxy::channel() const {
   RTC_DCHECK(channel_owner_.channel());
   return channel_owner_.channel();
diff --git a/webrtc/voice_engine/channel_proxy.h b/webrtc/voice_engine/channel_proxy.h
index 93b8a58..39eed67 100644
--- a/webrtc/voice_engine/channel_proxy.h
+++ b/webrtc/voice_engine/channel_proxy.h
@@ -83,7 +83,9 @@
   virtual bool ReceivedRTCPPacket(const uint8_t* packet, size_t length);
 
   virtual const rtc::scoped_refptr<AudioDecoderFactory>&
-  GetAudioDecoderFactory() const;
+      GetAudioDecoderFactory() const;
+
+  virtual void SetChannelOutputVolumeScaling(float scaling);
 
  private:
   Channel* channel() const;