Apply the "shim" pattern for WebRtcVoiceEngine

This ensures that the MediaChannel interface is only implemented
through a send/receive shim, splitting channels also when kBoth is
used.

Bug: webrtc:13931
Change-Id: Ie97809597eaae7b4f504939339795432c34e56cb
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/307461
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40210}
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 80b39e6..795e2af 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -834,6 +834,7 @@
       defines = []
       deps = [
         ":codec",
+        ":media_channel_shim",
         ":media_constants",
         ":rtc_audio_video",
         ":rtc_internal_video_codecs",
diff --git a/media/base/media_channel_impl.h b/media/base/media_channel_impl.h
index d4d8182..411576a 100644
--- a/media/base/media_channel_impl.h
+++ b/media/base/media_channel_impl.h
@@ -338,11 +338,23 @@
     return nullptr;
   }
 
-  // Declared here to avoid "found in multiple base-class subobjects" error
+  // Declared here in order to avoid "found by multiple paths" compile error
+  bool AddSendStream(const StreamParams& sp) override = 0;
+  bool AddRecvStream(const StreamParams& sp) override = 0;
+  void OnPacketReceived(const webrtc::RtpPacketReceived& packet) override = 0;
+  void SetEncoderSelector(uint32_t ssrc,
+                          webrtc::VideoEncoderFactory::EncoderSelectorInterface*
+                              encoder_selector) override {}
   void ChooseReceiverReportSsrc(const std::set<uint32_t>& choices) override = 0;
   void SetSsrcListChangedCallback(
       absl::AnyInvocable<void(const std::set<uint32_t>&)> callback) override =
       0;
+  webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const override = 0;
+  webrtc::RTCError SetRtpSendParameters(
+      uint32_t ssrc,
+      const webrtc::RtpParameters& parameters,
+      webrtc::SetParametersCallback callback = nullptr) override = 0;
+
   void SetExtmapAllowMixed(bool mixed) override {
     MediaChannel::SetExtmapAllowMixed(mixed);
   }
@@ -360,18 +372,16 @@
   virtual bool GetSendStats(VoiceMediaSendInfo* info) = 0;
   virtual bool GetReceiveStats(VoiceMediaReceiveInfo* info,
                                bool get_and_clear_legacy_stats) = 0;
-
- private:
-  // Functions not implemented on this interface
   bool GetStats(VoiceMediaSendInfo* info) override {
-    RTC_CHECK_NOTREACHED();
-    return false;
+    return GetSendStats(info);
   }
   bool GetStats(VoiceMediaReceiveInfo* info,
                 bool get_and_clear_legacy_stats) override {
-    RTC_CHECK_NOTREACHED();
-    return false;
+    return GetReceiveStats(info, get_and_clear_legacy_stats);
   }
+
+ private:
+  // Functions not implemented on this interface
   MediaChannel* ImplForTesting() override {
     // This class and its subclasses are not interface classes.
     RTC_CHECK_NOTREACHED();
diff --git a/media/base/media_channel_shim.cc b/media/base/media_channel_shim.cc
index 432ea1c..adc749f 100644
--- a/media/base/media_channel_shim.cc
+++ b/media/base/media_channel_shim.cc
@@ -15,6 +15,25 @@
 // Note: The VideoMediaChannel default implementations are not used here, and
 // should be removed from that interface.
 // TODO(bugs.webrtc.org/13931): Remove them.
+VoiceMediaShimChannel::VoiceMediaShimChannel(
+    std::unique_ptr<VoiceMediaSendChannelInterface> send_impl,
+    std::unique_ptr<VoiceMediaReceiveChannelInterface> receive_impl)
+    : VoiceMediaChannel(MediaChannel::Role::kBoth, nullptr, false),
+      send_impl_(std::move(send_impl)),
+      receive_impl_(std::move(receive_impl)) {
+  if (send_impl_ && receive_impl_) {
+    send_impl_->SetSsrcListChangedCallback(
+        [this](const std::set<uint32_t>& choices) {
+          receive_impl_->ChooseReceiverReportSsrc(choices);
+        });
+    send_impl_->SetSendCodecChangedCallback([this]() {
+      receive_impl_->SetReceiveNackEnabled(send_impl_->SendCodecHasNack());
+      receive_impl_->SetReceiveNonSenderRttEnabled(
+          send_impl_->SenderNonSenderRttEnabled());
+    });
+  }
+}
+
 VideoMediaShimChannel::VideoMediaShimChannel(
     std::unique_ptr<VideoMediaSendChannelInterface> send_impl,
     std::unique_ptr<VideoMediaReceiveChannelInterface> receive_impl)
diff --git a/media/base/media_channel_shim.h b/media/base/media_channel_shim.h
index c50c5b1..679e15c 100644
--- a/media/base/media_channel_shim.h
+++ b/media/base/media_channel_shim.h
@@ -47,13 +47,261 @@
 #include "rtc_base/network/sent_packet.h"
 #include "rtc_base/network_route.h"
 
+namespace cricket {
+
+// The VideoMediaShimChannel is replacing the VideoMediaChannel
+// interface.
+// If called with both send_impl and receive_impl, it operates in kBoth
+// mode; if called with only one, it will shim that one and DCHECK if one
+// tries to do functions belonging to the other.
+class VoiceMediaShimChannel : public VoiceMediaChannel {
+ public:
+  VoiceMediaShimChannel(
+      std::unique_ptr<VoiceMediaSendChannelInterface> send_impl,
+      std::unique_ptr<VoiceMediaReceiveChannelInterface> receive_impl);
+
+  VoiceMediaSendChannelInterface* AsVoiceSendChannel() override { return this; }
+  VoiceMediaReceiveChannelInterface* AsVoiceReceiveChannel() override {
+    return this;
+  }
+  VideoMediaSendChannelInterface* AsVideoSendChannel() override {
+    RTC_CHECK_NOTREACHED();
+    return nullptr;
+  }
+  VideoMediaReceiveChannelInterface* AsVideoReceiveChannel() override {
+    RTC_CHECK_NOTREACHED();
+    return nullptr;
+  }
+
+  // SetInterface needs to run on both send and receive channels.
+  void SetInterface(MediaChannelNetworkInterface* iface) override {
+    if (send_impl_) {
+      send_impl()->SetInterface(iface);
+    }
+    if (receive_impl_) {
+      receive_impl()->SetInterface(iface);
+    }
+  }
+
+  // Not really valid for this mode
+  MediaChannel* ImplForTesting() override {
+    RTC_CHECK_NOTREACHED();
+    return nullptr;
+  }
+
+  // Implementation of MediaBaseChannelInterface
+  cricket::MediaType media_type() const override { return MEDIA_TYPE_VIDEO; }
+
+  // Implementation of MediaSendChannelInterface
+  void OnPacketSent(const rtc::SentPacket& sent_packet) override {
+    send_impl()->OnPacketSent(sent_packet);
+  }
+  void OnReadyToSend(bool ready) override { send_impl()->OnReadyToSend(ready); }
+  void OnNetworkRouteChanged(absl::string_view transport_name,
+                             const rtc::NetworkRoute& network_route) override {
+    send_impl()->OnNetworkRouteChanged(transport_name, network_route);
+  }
+  void SetExtmapAllowMixed(bool extmap_allow_mixed) override {
+    send_impl()->SetExtmapAllowMixed(extmap_allow_mixed);
+  }
+  bool HasNetworkInterface() const override {
+    return send_impl()->HasNetworkInterface();
+  }
+  bool ExtmapAllowMixed() const override {
+    return send_impl()->ExtmapAllowMixed();
+  }
+
+  bool AddSendStream(const StreamParams& sp) override {
+    return send_impl()->AddSendStream(sp);
+  }
+  bool RemoveSendStream(uint32_t ssrc) override {
+    return send_impl()->RemoveSendStream(ssrc);
+  }
+  void SetFrameEncryptor(uint32_t ssrc,
+                         rtc::scoped_refptr<webrtc::FrameEncryptorInterface>
+                             frame_encryptor) override {
+    send_impl()->SetFrameEncryptor(ssrc, frame_encryptor);
+  }
+  webrtc::RTCError SetRtpSendParameters(
+      uint32_t ssrc,
+      const webrtc::RtpParameters& parameters,
+      webrtc::SetParametersCallback callback = nullptr) override {
+    return send_impl()->SetRtpSendParameters(ssrc, parameters,
+                                             std::move(callback));
+  }
+
+  void SetEncoderToPacketizerFrameTransformer(
+      uint32_t ssrc,
+      rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer)
+      override {
+    return send_impl()->SetEncoderToPacketizerFrameTransformer(
+        ssrc, frame_transformer);
+  }
+  webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const override {
+    return send_impl()->GetRtpSendParameters(ssrc);
+  }
+  // Implementation of MediaReceiveChannelInterface
+  void OnPacketReceived(const webrtc::RtpPacketReceived& packet) override {
+    receive_impl()->OnPacketReceived(packet);
+  }
+  bool AddRecvStream(const StreamParams& sp) override {
+    return receive_impl()->AddRecvStream(sp);
+  }
+  bool RemoveRecvStream(uint32_t ssrc) override {
+    return receive_impl()->RemoveRecvStream(ssrc);
+  }
+  void ResetUnsignaledRecvStream() override {
+    return receive_impl()->ResetUnsignaledRecvStream();
+  }
+  absl::optional<uint32_t> GetUnsignaledSsrc() const override {
+    return receive_impl()->GetUnsignaledSsrc();
+  }
+  void ChooseReceiverReportSsrc(const std::set<uint32_t>& choices) override {
+    return receive_impl()->ChooseReceiverReportSsrc(choices);
+  }
+  void OnDemuxerCriteriaUpdatePending() override {
+    receive_impl()->OnDemuxerCriteriaUpdatePending();
+  }
+  void OnDemuxerCriteriaUpdateComplete() override {
+    receive_impl()->OnDemuxerCriteriaUpdateComplete();
+  }
+  void SetFrameDecryptor(uint32_t ssrc,
+                         rtc::scoped_refptr<webrtc::FrameDecryptorInterface>
+                             frame_decryptor) override {
+    receive_impl()->SetFrameDecryptor(ssrc, frame_decryptor);
+  }
+  void SetDepacketizerToDecoderFrameTransformer(
+      uint32_t ssrc,
+      rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer)
+      override {
+    receive_impl()->SetDepacketizerToDecoderFrameTransformer(ssrc,
+                                                             frame_transformer);
+  }
+  bool SendCodecHasNack() const override {
+    return send_impl()->SendCodecHasNack();
+  }
+  void SetSendCodecChangedCallback(
+      absl::AnyInvocable<void()> callback) override {
+    send_impl()->SetSendCodecChangedCallback(std::move(callback));
+  }
+  // Implementation of VoiceMediaSendChannel
+  bool SetSendParameters(const AudioSendParameters& params) override {
+    return send_impl()->SetSendParameters(params);
+  }
+  void SetSend(bool send) override { return send_impl()->SetSend(send); }
+  bool SetAudioSend(uint32_t ssrc,
+                    bool enable,
+                    const AudioOptions* options,
+                    AudioSource* source) override {
+    return send_impl()->SetAudioSend(ssrc, enable, options, source);
+  }
+  bool CanInsertDtmf() override { return send_impl()->CanInsertDtmf(); }
+  bool InsertDtmf(uint32_t ssrc, int event, int duration) override {
+    return send_impl()->InsertDtmf(ssrc, event, duration);
+  }
+  bool GetStats(VoiceMediaSendInfo* info) override {
+    return send_impl()->GetStats(info);
+  }
+  bool SenderNackEnabled() const override {
+    return send_impl()->SenderNackEnabled();
+  }
+  bool SenderNonSenderRttEnabled() const override {
+    return send_impl()->SenderNonSenderRttEnabled();
+  }
+  // Implementation of VoiceMediaReceiveChannelInterface
+  bool SetRecvParameters(const AudioRecvParameters& params) override {
+    return receive_impl()->SetRecvParameters(params);
+  }
+  webrtc::RtpParameters GetRtpReceiveParameters(uint32_t ssrc) const override {
+    return receive_impl()->GetRtpReceiveParameters(ssrc);
+  }
+  std::vector<webrtc::RtpSource> GetSources(uint32_t ssrc) const override {
+    return receive_impl()->GetSources(ssrc);
+  }
+  webrtc::RtpParameters GetDefaultRtpReceiveParameters() const override {
+    return receive_impl()->GetDefaultRtpReceiveParameters();
+  }
+  void SetPlayout(bool playout) override {
+    return receive_impl()->SetPlayout(playout);
+  }
+  bool SetOutputVolume(uint32_t ssrc, double volume) override {
+    return receive_impl()->SetOutputVolume(ssrc, volume);
+  }
+  bool SetDefaultOutputVolume(double volume) override {
+    return receive_impl()->SetDefaultOutputVolume(volume);
+  }
+  void SetRawAudioSink(
+      uint32_t ssrc,
+      std::unique_ptr<webrtc::AudioSinkInterface> sink) override {
+    return receive_impl()->SetRawAudioSink(ssrc, std::move(sink));
+  }
+  void SetDefaultRawAudioSink(
+      std::unique_ptr<webrtc::AudioSinkInterface> sink) override {
+    return receive_impl()->SetDefaultRawAudioSink(std::move(sink));
+  }
+  bool GetStats(VoiceMediaReceiveInfo* info, bool reset_legacy) override {
+    return receive_impl_->GetStats(info, reset_legacy);
+  }
+  void SetReceiveNackEnabled(bool enabled) override {
+    receive_impl_->SetReceiveNackEnabled(enabled);
+  }
+  void SetReceiveNonSenderRttEnabled(bool enabled) override {
+    receive_impl_->SetReceiveNonSenderRttEnabled(enabled);
+  }
+  void SetSsrcListChangedCallback(
+      absl::AnyInvocable<void(const std::set<uint32_t>&)> callback) override {
+    send_impl()->SetSsrcListChangedCallback(std::move(callback));
+  }
+  // Implementation of Delayable
+  bool SetBaseMinimumPlayoutDelayMs(uint32_t ssrc, int delay_ms) override {
+    return receive_impl()->SetBaseMinimumPlayoutDelayMs(ssrc, delay_ms);
+  }
+  absl::optional<int> GetBaseMinimumPlayoutDelayMs(
+      uint32_t ssrc) const override {
+    return receive_impl()->GetBaseMinimumPlayoutDelayMs(ssrc);
+  }
+  bool GetSendStats(VoiceMediaSendInfo* info) override {
+    return send_impl()->GetStats(info);
+  }
+  bool GetReceiveStats(VoiceMediaReceiveInfo* info,
+                       bool reset_legacy) override {
+    return receive_impl()->GetStats(info, reset_legacy);
+  }
+
+  // Only for testing of implementations - these will be used to static_cast the
+  // pointers to the implementations, so can only be safely used in conjunction
+  // with the corresponding create functions.
+  VoiceMediaSendChannelInterface* SendImplForTesting() {
+    return send_impl_.get();
+  }
+  VoiceMediaReceiveChannelInterface* ReceiveImplForTesting() {
+    return receive_impl_.get();
+  }
+
+ private:
+  VoiceMediaSendChannelInterface* send_impl() { return send_impl_.get(); }
+  VoiceMediaReceiveChannelInterface* receive_impl() {
+    RTC_DCHECK(receive_impl_);
+    return receive_impl_.get();
+  }
+  const VoiceMediaSendChannelInterface* send_impl() const {
+    RTC_DCHECK(send_impl_);
+    return send_impl_.get();
+  }
+  const VoiceMediaReceiveChannelInterface* receive_impl() const {
+    return receive_impl_.get();
+  }
+
+  std::unique_ptr<VoiceMediaSendChannelInterface> send_impl_;
+  std::unique_ptr<VoiceMediaReceiveChannelInterface> receive_impl_;
+};
+
 // The VideoMediaShimChannel is replacing the VideoMediaChannel
 // interface.
 // If called with both send_impl and receive_impl, it operates in kBoth
 // mode; if called with only one, it will shim that one and DCHECK if one
 // tries to do functions belonging to the other.
 
-namespace cricket {
 class VideoMediaShimChannel : public VideoMediaChannel {
  public:
   VideoMediaShimChannel(
diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc
index 1b240d6..86c56fc 100644
--- a/media/engine/webrtc_voice_engine.cc
+++ b/media/engine/webrtc_voice_engine.cc
@@ -441,8 +441,21 @@
     const webrtc::CryptoOptions& crypto_options,
     webrtc::AudioCodecPairId codec_pair_id) {
   RTC_DCHECK_RUN_ON(call->worker_thread());
-  return new WebRtcVoiceMediaChannel(role, this, config, options,
-                                     crypto_options, call, codec_pair_id);
+  std::unique_ptr<VoiceMediaSendChannelInterface> send_channel;
+  std::unique_ptr<VoiceMediaReceiveChannelInterface> receive_channel;
+  if (role == MediaChannel::Role::kSend || role == MediaChannel::Role::kBoth) {
+    send_channel = std::make_unique<WebRtcVoiceMediaChannel>(
+        MediaChannel::Role::kSend, this, config, options, crypto_options, call,
+        codec_pair_id);
+  }
+  if (role == MediaChannel::Role::kReceive ||
+      role == MediaChannel::Role::kBoth) {
+    receive_channel = std::make_unique<WebRtcVoiceMediaChannel>(
+        MediaChannel::Role::kReceive, this, config, options, crypto_options,
+        call, codec_pair_id);
+  }
+  return new VoiceMediaShimChannel(std::move(send_channel),
+                                   std::move(receive_channel));
 }
 
 void WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
diff --git a/media/engine/webrtc_voice_engine.h b/media/engine/webrtc_voice_engine.h
index 474acc4..4e398f4 100644
--- a/media/engine/webrtc_voice_engine.h
+++ b/media/engine/webrtc_voice_engine.h
@@ -53,6 +53,7 @@
 #include "media/base/codec.h"
 #include "media/base/media_channel.h"
 #include "media/base/media_channel_impl.h"
+#include "media/base/media_channel_shim.h"
 #include "media/base/media_config.h"
 #include "media/base/media_engine.h"
 #include "media/base/rtp_utils.h"
diff --git a/media/engine/webrtc_voice_engine_unittest.cc b/media/engine/webrtc_voice_engine_unittest.cc
index e993111..a5ffd53 100644
--- a/media/engine/webrtc_voice_engine_unittest.cc
+++ b/media/engine/webrtc_voice_engine_unittest.cc
@@ -26,6 +26,7 @@
 #include "media/base/fake_media_engine.h"
 #include "media/base/fake_network_interface.h"
 #include "media/base/fake_rtp.h"
+#include "media/base/media_channel_shim.h"
 #include "media/base/media_constants.h"
 #include "media/engine/fake_webrtc_call.h"
 #include "modules/audio_device/include/mock_audio_device.h"
@@ -803,6 +804,22 @@
     return apm_config_.high_pass_filter.enabled;
   }
 
+  cricket::WebRtcVoiceMediaChannel* SendImplFromPointer(
+      cricket::VoiceMediaChannel* channel) {
+    return static_cast<cricket::WebRtcVoiceMediaChannel*>(
+        static_cast<cricket::VoiceMediaShimChannel*>(channel)
+            ->SendImplForTesting());
+  }
+
+  cricket::WebRtcVoiceMediaChannel* SendImpl() {
+    return SendImplFromPointer(channel_);
+  }
+  cricket::WebRtcVoiceMediaChannel* ReceiveImpl() {
+    return static_cast<cricket::WebRtcVoiceMediaChannel*>(
+        static_cast<cricket::VoiceMediaShimChannel*>(channel_)
+            ->ReceiveImplForTesting());
+  }
+
  protected:
   rtc::AutoThread main_thread_;
   const bool use_null_apm_;
@@ -839,8 +856,7 @@
   EXPECT_EQ(kSsrcX, config.rtp.ssrc);
   EXPECT_EQ("", config.rtp.c_name);
   EXPECT_EQ(0u, config.rtp.extensions.size());
-  EXPECT_EQ(static_cast<cricket::WebRtcVoiceMediaChannel*>(channel_),
-            config.send_transport);
+  EXPECT_EQ(SendImpl(), config.send_transport);
 }
 
 // Test that we can add a receive stream and that it has the correct defaults.
@@ -851,8 +867,7 @@
       GetRecvStreamConfig(kSsrcX);
   EXPECT_EQ(kSsrcX, config.rtp.remote_ssrc);
   EXPECT_EQ(0xFA17FA17, config.rtp.local_ssrc);
-  EXPECT_EQ(static_cast<cricket::WebRtcVoiceMediaChannel*>(channel_),
-            config.rtcp_send_transport);
+  EXPECT_EQ(ReceiveImpl(), config.rtcp_send_transport);
   EXPECT_EQ("", config.sync_group);
 }
 
@@ -3073,18 +3088,16 @@
   EXPECT_CALL(*adm_, Recording()).Times(2).WillRepeatedly(Return(false));
   EXPECT_CALL(*adm_, InitRecording()).Times(2).WillRepeatedly(Return(0));
 
-  std::unique_ptr<cricket::WebRtcVoiceMediaChannel> channel1(
-      static_cast<cricket::WebRtcVoiceMediaChannel*>(
-          engine_->CreateMediaChannel(
-              cricket::MediaChannel::Role::kBoth, &call_,
-              cricket::MediaConfig(), cricket::AudioOptions(),
-              webrtc::CryptoOptions(), webrtc::AudioCodecPairId::Create())));
-  std::unique_ptr<cricket::WebRtcVoiceMediaChannel> channel2(
-      static_cast<cricket::WebRtcVoiceMediaChannel*>(
-          engine_->CreateMediaChannel(
-              cricket::MediaChannel::Role::kBoth, &call_,
-              cricket::MediaConfig(), cricket::AudioOptions(),
-              webrtc::CryptoOptions(), webrtc::AudioCodecPairId::Create())));
+  std::unique_ptr<cricket::VoiceMediaChannel> channel1(
+      engine_->CreateMediaChannel(
+          cricket::MediaChannel::Role::kBoth, &call_, cricket::MediaConfig(),
+          cricket::AudioOptions(), webrtc::CryptoOptions(),
+          webrtc::AudioCodecPairId::Create()));
+  std::unique_ptr<cricket::VoiceMediaChannel> channel2(
+      engine_->CreateMediaChannel(
+          cricket::MediaChannel::Role::kBoth, &call_, cricket::MediaConfig(),
+          cricket::AudioOptions(), webrtc::CryptoOptions(),
+          webrtc::AudioCodecPairId::Create()));
 
   // Have to add a stream to make SetSend work.
   cricket::StreamParams stream1;
@@ -3105,11 +3118,13 @@
     VerifyGainControlEnabledCorrectly();
     EXPECT_TRUE(apm_config_.noise_suppression.enabled);
     EXPECT_EQ(apm_config_.noise_suppression.level, kDefaultNsLevel);
-    EXPECT_EQ(parameters_options_all.options, channel1->options());
+    EXPECT_EQ(parameters_options_all.options,
+              SendImplFromPointer(channel1.get())->options());
     EXPECT_TRUE(channel2->SetSendParameters(parameters_options_all));
     VerifyEchoCancellationSettings(/*enabled=*/true);
     VerifyGainControlEnabledCorrectly();
-    EXPECT_EQ(parameters_options_all.options, channel2->options());
+    EXPECT_EQ(parameters_options_all.options,
+              SendImplFromPointer(channel2.get())->options());
   }
 
   // unset NS
@@ -3125,7 +3140,7 @@
     expected_options.echo_cancellation = true;
     expected_options.auto_gain_control = true;
     expected_options.noise_suppression = false;
-    EXPECT_EQ(expected_options, channel1->options());
+    EXPECT_EQ(expected_options, SendImplFromPointer(channel1.get())->options());
   }
 
   // unset AGC
@@ -3140,7 +3155,7 @@
     expected_options.echo_cancellation = true;
     expected_options.auto_gain_control = false;
     expected_options.noise_suppression = true;
-    EXPECT_EQ(expected_options, channel2->options());
+    EXPECT_EQ(expected_options, SendImplFromPointer(channel2.get())->options());
   }
 
   EXPECT_TRUE(channel_->SetSendParameters(parameters_options_all));
@@ -3181,7 +3196,7 @@
     expected_options.echo_cancellation = true;
     expected_options.auto_gain_control = false;
     expected_options.noise_suppression = false;
-    EXPECT_EQ(expected_options, channel2->options());
+    EXPECT_EQ(expected_options, SendImplFromPointer(channel2.get())->options());
   }
 }
 
@@ -3190,25 +3205,23 @@
   EXPECT_TRUE(SetupSendStream());
   cricket::FakeNetworkInterface network_interface;
   cricket::MediaConfig config;
-  std::unique_ptr<cricket::WebRtcVoiceMediaChannel> channel;
+  std::unique_ptr<cricket::VoiceMediaChannel> channel;
   webrtc::RtpParameters parameters;
 
-  channel.reset(static_cast<cricket::WebRtcVoiceMediaChannel*>(
-      engine_->CreateMediaChannel(cricket::MediaChannel::Role::kBoth, &call_,
-                                  config, cricket::AudioOptions(),
-                                  webrtc::CryptoOptions(),
-                                  webrtc::AudioCodecPairId::Create())));
+  channel.reset(engine_->CreateMediaChannel(
+      cricket::MediaChannel::Role::kBoth, &call_, config,
+      cricket::AudioOptions(), webrtc::CryptoOptions(),
+      webrtc::AudioCodecPairId::Create()));
   channel->SetInterface(&network_interface);
   // Default value when DSCP is disabled should be DSCP_DEFAULT.
   EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface.dscp());
   channel->SetInterface(nullptr);
 
   config.enable_dscp = true;
-  channel.reset(static_cast<cricket::WebRtcVoiceMediaChannel*>(
-      engine_->CreateMediaChannel(cricket::MediaChannel::Role::kBoth, &call_,
-                                  config, cricket::AudioOptions(),
-                                  webrtc::CryptoOptions(),
-                                  webrtc::AudioCodecPairId::Create())));
+  channel.reset(engine_->CreateMediaChannel(
+      cricket::MediaChannel::Role::kBoth, &call_, config,
+      cricket::AudioOptions(), webrtc::CryptoOptions(),
+      webrtc::AudioCodecPairId::Create()));
   channel->SetInterface(&network_interface);
   EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface.dscp());
 
@@ -3228,18 +3241,18 @@
 
   // Packets should also self-identify their dscp in PacketOptions.
   const uint8_t kData[10] = {0};
-  EXPECT_TRUE(channel->SendRtcp(kData, sizeof(kData)));
+  EXPECT_TRUE(
+      SendImplFromPointer(channel.get())->SendRtcp(kData, sizeof(kData)));
   EXPECT_EQ(rtc::DSCP_CS1, network_interface.options().dscp);
   channel->SetInterface(nullptr);
 
   // Verify that setting the option to false resets the
   // DiffServCodePoint.
   config.enable_dscp = false;
-  channel.reset(static_cast<cricket::WebRtcVoiceMediaChannel*>(
-      engine_->CreateMediaChannel(cricket::MediaChannel::Role::kBoth, &call_,
-                                  config, cricket::AudioOptions(),
-                                  webrtc::CryptoOptions(),
-                                  webrtc::AudioCodecPairId::Create())));
+  channel.reset(engine_->CreateMediaChannel(
+      cricket::MediaChannel::Role::kBoth, &call_, config,
+      cricket::AudioOptions(), webrtc::CryptoOptions(),
+      webrtc::AudioCodecPairId::Create()));
   channel->SetInterface(&network_interface);
   // Default value when DSCP is disabled should be DSCP_DEFAULT.
   EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface.dscp());
@@ -3444,8 +3457,7 @@
   rtc::CopyOnWriteBuffer kRtcpPacket(kRtcp, sizeof(kRtcp));
 
   EXPECT_TRUE(SetupSendStream());
-  cricket::WebRtcVoiceMediaChannel* media_channel =
-      static_cast<cricket::WebRtcVoiceMediaChannel*>(channel_);
+  cricket::VoiceMediaChannel* media_channel = ReceiveImpl();
   SetSendParameters(send_parameters_);
   EXPECT_TRUE(media_channel->AddRecvStream(
       cricket::StreamParams::CreateLegacy(kAudioSsrc)));
@@ -3617,8 +3629,7 @@
 TEST_P(WebRtcVoiceEngineTestFake, GetSourcesWithNonExistingSsrc) {
   // Setup an recv stream with `kSsrcX`.
   SetupRecvStream();
-  cricket::WebRtcVoiceMediaChannel* media_channel =
-      static_cast<cricket::WebRtcVoiceMediaChannel*>(channel_);
+  cricket::WebRtcVoiceMediaChannel* media_channel = ReceiveImpl();
   // Call GetSources with `kSsrcY` which doesn't exist.
   std::vector<webrtc::RtpSource> sources = media_channel->GetSources(kSsrcY);
   EXPECT_EQ(0u, sources.size());