Split audio and video channels into Send and Receive APIs.

The implementation here has a number of changes that force the callers
that called the "channel" functions into specific interfaces rather than
just letting C++ take care of it; this should go away once there stops
being a common implementation class for those interfaces.

Bug: webrtc:13931
Change-Id: Ic4e279528a341bc0a0e88d2e1e76c90bc43a1035
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/287640
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38888}
diff --git a/pc/audio_rtp_receiver.cc b/pc/audio_rtp_receiver.cc
index 09acfa8..7af460b 100644
--- a/pc/audio_rtp_receiver.cc
+++ b/pc/audio_rtp_receiver.cc
@@ -28,7 +28,7 @@
     std::string receiver_id,
     std::vector<std::string> stream_ids,
     bool is_unified_plan,
-    cricket::VoiceMediaChannel* voice_channel /*= nullptr*/)
+    cricket::VoiceMediaReceiveChannelInterface* voice_channel /*= nullptr*/)
     : AudioRtpReceiver(worker_thread,
                        receiver_id,
                        CreateStreamsFromIds(std::move(stream_ids)),
@@ -40,7 +40,7 @@
     const std::string& receiver_id,
     const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams,
     bool is_unified_plan,
-    cricket::VoiceMediaChannel* voice_channel /*= nullptr*/)
+    cricket::VoiceMediaReceiveChannelInterface* voice_channel /*= nullptr*/)
     : worker_thread_(worker_thread),
       id_(receiver_id),
       source_(rtc::make_ref_counted<RemoteAudioSource>(
@@ -324,7 +324,8 @@
 
   media_channel ? worker_thread_safety_->SetAlive()
                 : worker_thread_safety_->SetNotAlive();
-  media_channel_ = static_cast<cricket::VoiceMediaChannel*>(media_channel);
+  media_channel_ =
+      static_cast<cricket::VoiceMediaReceiveChannelInterface*>(media_channel);
 }
 
 void AudioRtpReceiver::NotifyFirstPacketReceived() {
diff --git a/pc/audio_rtp_receiver.h b/pc/audio_rtp_receiver.h
index cfebfe5..2e0f77c 100644
--- a/pc/audio_rtp_receiver.h
+++ b/pc/audio_rtp_receiver.h
@@ -50,18 +50,19 @@
   // However, when using that, the assumption is that right after construction,
   // a call to either `SetupUnsignaledMediaChannel` or `SetupMediaChannel`
   // will be made, which will internally start the source on the worker thread.
-  AudioRtpReceiver(rtc::Thread* worker_thread,
-                   std::string receiver_id,
-                   std::vector<std::string> stream_ids,
-                   bool is_unified_plan,
-                   cricket::VoiceMediaChannel* voice_channel = nullptr);
+  AudioRtpReceiver(
+      rtc::Thread* worker_thread,
+      std::string receiver_id,
+      std::vector<std::string> stream_ids,
+      bool is_unified_plan,
+      cricket::VoiceMediaReceiveChannelInterface* voice_channel = nullptr);
   // TODO(https://crbug.com/webrtc/9480): Remove this when streams() is removed.
   AudioRtpReceiver(
       rtc::Thread* worker_thread,
       const std::string& receiver_id,
       const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams,
       bool is_unified_plan,
-      cricket::VoiceMediaChannel* media_channel = nullptr);
+      cricket::VoiceMediaReceiveChannelInterface* media_channel = nullptr);
   virtual ~AudioRtpReceiver();
 
   // ObserverInterface implementation
@@ -135,8 +136,8 @@
   const std::string id_;
   const rtc::scoped_refptr<RemoteAudioSource> source_;
   const rtc::scoped_refptr<AudioTrackProxyWithInternal<AudioTrack>> track_;
-  cricket::VoiceMediaChannel* media_channel_ RTC_GUARDED_BY(worker_thread_) =
-      nullptr;
+  cricket::VoiceMediaReceiveChannelInterface* media_channel_
+      RTC_GUARDED_BY(worker_thread_) = nullptr;
   absl::optional<uint32_t> ssrc_ RTC_GUARDED_BY(worker_thread_);
   std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_
       RTC_GUARDED_BY(&signaling_thread_checker_);
diff --git a/pc/audio_rtp_receiver_unittest.cc b/pc/audio_rtp_receiver_unittest.cc
index bab6b74..eb77212 100644
--- a/pc/audio_rtp_receiver_unittest.cc
+++ b/pc/audio_rtp_receiver_unittest.cc
@@ -66,7 +66,7 @@
 
   receiver_->track();
   receiver_->track()->set_enabled(true);
-  receiver_->SetMediaChannel(&media_channel_);
+  receiver_->SetMediaChannel(media_channel_.AsVoiceReceiveChannel());
   EXPECT_CALL(media_channel_, SetDefaultRawAudioSink(_)).Times(0);
   receiver_->SetupMediaChannel(kSsrc);
 
@@ -86,7 +86,7 @@
   receiver_->OnSetVolume(kVolume);
 
   receiver_->track()->set_enabled(true);
-  receiver_->SetMediaChannel(&media_channel_);
+  receiver_->SetMediaChannel(media_channel_.AsVoiceReceiveChannel());
 
   // The previosly set initial volume should be propagated to the provided
   // media_channel_ as soon as SetupMediaChannel is called.
diff --git a/pc/channel.cc b/pc/channel.cc
index 3d17f24..4c078de 100644
--- a/pc/channel.cc
+++ b/pc/channel.cc
@@ -869,7 +869,7 @@
       webrtc::RtpTransceiverDirectionHasRecv(content->direction()),
       &recv_params);
 
-  if (!media_send_channel()->SetRecvParameters(recv_params)) {
+  if (!media_receive_channel()->SetRecvParameters(recv_params)) {
     error_desc = StringFormat(
         "Failed to set local audio description recv parameters for m-section "
         "with mid='%s'.",
@@ -1008,7 +1008,7 @@
     }
   }
 
-  if (!media_send_channel()->SetRecvParameters(recv_params)) {
+  if (!media_receive_channel()->SetRecvParameters(recv_params)) {
     error_desc = StringFormat(
         "Failed to set local video description recv parameters for m-section "
         "with mid='%s'.",
@@ -1103,7 +1103,7 @@
   last_send_params_ = send_params;
 
   if (needs_recv_params_update) {
-    if (!media_send_channel()->SetRecvParameters(recv_params)) {
+    if (!media_receive_channel()->SetRecvParameters(recv_params)) {
       error_desc = StringFormat(
           "Failed to set recv parameters for m-section with mid='%s'.",
           mid().c_str());
diff --git a/pc/channel.h b/pc/channel.h
index bc30993..08a6679 100644
--- a/pc/channel.h
+++ b/pc/channel.h
@@ -32,6 +32,7 @@
 #include "call/rtp_demuxer.h"
 #include "call/rtp_packet_sink_interface.h"
 #include "media/base/media_channel.h"
+#include "media/base/media_channel_impl.h"
 #include "media/base/stream_params.h"
 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "pc/channel_interface.h"
@@ -70,7 +71,7 @@
                     public sigslot::has_slots<>,
                     // TODO(tommi): Consider implementing these interfaces
                     // via composition.
-                    public MediaChannel::NetworkInterface,
+                    public MediaChannelNetworkInterface,
                     public webrtc::RtpPacketSinkInterface {
  public:
   // If `srtp_required` is true, the channel will not send or receive any
@@ -155,25 +156,29 @@
   // RtpPacketSinkInterface overrides.
   void OnRtpPacket(const webrtc::RtpPacketReceived& packet) override;
 
+  MediaChannel* media_channel() const override { return media_channel_.get(); }
+
   MediaSendChannelInterface* media_send_channel() const override {
-    return media_channel_.get();
+    return media_channel_->AsSendChannel();
   }
-  VideoMediaChannel* video_media_send_channel() const override {
+  VideoMediaSendChannelInterface* video_media_send_channel() const override {
     RTC_CHECK(false) << "Attempt to fetch video channel from non-video";
     return nullptr;
   }
-  VoiceMediaChannel* voice_media_send_channel() const override {
+  VoiceMediaSendChannelInterface* voice_media_send_channel() const override {
     RTC_CHECK(false) << "Attempt to fetch voice channel from non-voice";
     return nullptr;
   }
   MediaReceiveChannelInterface* media_receive_channel() const override {
-    return media_channel_.get();
+    return media_channel_->AsReceiveChannel();
   }
-  VideoMediaChannel* video_media_receive_channel() const override {
+  VideoMediaReceiveChannelInterface* video_media_receive_channel()
+      const override {
     RTC_CHECK(false) << "Attempt to fetch video channel from non-video";
     return nullptr;
   }
-  VoiceMediaChannel* voice_media_receive_channel() const override {
+  VoiceMediaReceiveChannelInterface* voice_media_receive_channel()
+      const override {
     RTC_CHECK(false) << "Attempt to fetch voice channel from non-voice";
     return nullptr;
   }
@@ -379,22 +384,22 @@
   ~VoiceChannel();
 
   // downcasts a MediaChannel
-  VoiceMediaChannel* media_send_channel() const override {
-    return static_cast<VoiceMediaChannel*>(BaseChannel::media_send_channel());
+  VoiceMediaSendChannelInterface* media_send_channel() const override {
+    return media_channel()->AsVoiceChannel()->AsVoiceSendChannel();
   }
 
-  VoiceMediaChannel* voice_media_send_channel() const override {
-    return static_cast<VoiceMediaChannel*>(media_send_channel());
+  VoiceMediaSendChannelInterface* voice_media_send_channel() const override {
+    return media_send_channel();
   }
 
   // downcasts a MediaChannel
-  VoiceMediaChannel* media_receive_channel() const override {
-    return static_cast<VoiceMediaChannel*>(
-        BaseChannel::media_receive_channel());
+  VoiceMediaReceiveChannelInterface* media_receive_channel() const override {
+    return media_channel()->AsVoiceChannel()->AsVoiceReceiveChannel();
   }
 
-  VoiceMediaChannel* voice_media_receive_channel() const override {
-    return static_cast<VoiceMediaChannel*>(media_receive_channel());
+  VoiceMediaReceiveChannelInterface* voice_media_receive_channel()
+      const override {
+    return media_receive_channel();
   }
 
   cricket::MediaType media_type() const override {
@@ -435,22 +440,22 @@
   ~VideoChannel();
 
   // downcasts a MediaChannel
-  VideoMediaChannel* media_send_channel() const override {
-    return static_cast<VideoMediaChannel*>(BaseChannel::media_send_channel());
+  VideoMediaSendChannelInterface* media_send_channel() const override {
+    return media_channel()->AsVideoChannel()->AsVideoSendChannel();
   }
 
-  VideoMediaChannel* video_media_send_channel() const override {
-    return static_cast<cricket::VideoMediaChannel*>(media_send_channel());
+  VideoMediaSendChannelInterface* video_media_send_channel() const override {
+    return media_send_channel();
   }
 
   // downcasts a MediaChannel
-  VideoMediaChannel* media_receive_channel() const override {
-    return static_cast<VideoMediaChannel*>(
-        BaseChannel::media_receive_channel());
+  VideoMediaReceiveChannelInterface* media_receive_channel() const override {
+    return media_channel()->AsVideoChannel()->AsVideoReceiveChannel();
   }
 
-  VideoMediaChannel* video_media_receive_channel() const override {
-    return static_cast<cricket::VideoMediaChannel*>(media_receive_channel());
+  VideoMediaReceiveChannelInterface* video_media_receive_channel()
+      const override {
+    return media_receive_channel();
   }
 
   cricket::MediaType media_type() const override {
diff --git a/pc/channel_interface.h b/pc/channel_interface.h
index 032bfad..445712b 100644
--- a/pc/channel_interface.h
+++ b/pc/channel_interface.h
@@ -28,6 +28,7 @@
 
 namespace cricket {
 
+class MediaChannel;
 class MediaContentDescription;
 struct MediaConfig;
 
@@ -47,16 +48,20 @@
   virtual ~ChannelInterface() = default;
   virtual cricket::MediaType media_type() const = 0;
 
+  // Temporary fix while MediaChannel is being reconstructed
+  virtual MediaChannel* media_channel() const = 0;
   virtual MediaSendChannelInterface* media_send_channel() const = 0;
   // Typecasts of media_channel(). Will cause an exception if the
   // channel is of the wrong type.
-  virtual VideoMediaChannel* video_media_send_channel() const = 0;
-  virtual VoiceMediaChannel* voice_media_send_channel() const = 0;
+  virtual VideoMediaSendChannelInterface* video_media_send_channel() const = 0;
+  virtual VoiceMediaSendChannelInterface* voice_media_send_channel() const = 0;
   virtual MediaReceiveChannelInterface* media_receive_channel() const = 0;
   // Typecasts of media_channel(). Will cause an exception if the
   // channel is of the wrong type.
-  virtual VideoMediaChannel* video_media_receive_channel() const = 0;
-  virtual VoiceMediaChannel* voice_media_receive_channel() const = 0;
+  virtual VideoMediaReceiveChannelInterface* video_media_receive_channel()
+      const = 0;
+  virtual VoiceMediaReceiveChannelInterface* voice_media_receive_channel()
+      const = 0;
 
   // Returns a string view for the transport name. Fetching the transport name
   // must be done on the network thread only and note that the lifetime of
diff --git a/pc/legacy_stats_collector.cc b/pc/legacy_stats_collector.cc
index 5941b8b..ad9f7ad 100644
--- a/pc/legacy_stats_collector.cc
+++ b/pc/legacy_stats_collector.cc
@@ -34,6 +34,7 @@
 #include "api/video/video_timing.h"
 #include "call/call.h"
 #include "media/base/media_channel.h"
+#include "media/base/media_channel_impl.h"
 #include "modules/audio_processing/include/audio_processing_statistics.h"
 #include "p2p/base/ice_transport_internal.h"
 #include "p2p/base/p2p_constants.h"
@@ -1042,7 +1043,8 @@
     }
     auto* video_channel = transceiver->internal()->channel();
     if (video_channel) {
-      video_media_channels.push_back(video_channel->video_media_send_channel());
+      video_media_channels.push_back(static_cast<cricket::VideoMediaChannel*>(
+          video_channel->video_media_send_channel()));
     }
   }
 
@@ -1150,15 +1152,15 @@
 };
 
 std::unique_ptr<MediaChannelStatsGatherer> CreateMediaChannelStatsGatherer(
-    cricket::MediaSendChannelInterface* channel) {
+    cricket::MediaChannel* channel) {
   RTC_DCHECK(channel);
   if (channel->media_type() == cricket::MEDIA_TYPE_AUDIO) {
     return std::make_unique<VoiceMediaChannelStatsGatherer>(
-        static_cast<cricket::VoiceMediaChannel*>(channel));
+        channel->AsVoiceChannel());
   } else {
     RTC_DCHECK_EQ(channel->media_type(), cricket::MEDIA_TYPE_VIDEO);
     return std::make_unique<VideoMediaChannelStatsGatherer>(
-        static_cast<cricket::VideoMediaChannel*>(channel));
+        channel->AsVideoChannel());
   }
 }
 
@@ -1179,7 +1181,7 @@
         continue;
       }
       std::unique_ptr<MediaChannelStatsGatherer> gatherer =
-          CreateMediaChannelStatsGatherer(channel->media_send_channel());
+          CreateMediaChannelStatsGatherer(channel->media_channel());
       gatherer->mid = channel->mid();
       gatherer->transport_name = transport_names_by_mid.at(gatherer->mid);
 
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 8f2015e..5de77fe 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -1174,14 +1174,14 @@
     auto audio_sender =
         AudioRtpSender::Create(worker_thread(), rtc::CreateRandomUuid(),
                                legacy_stats_.get(), rtp_manager());
-    audio_sender->SetMediaChannel(rtp_manager()->voice_media_channel());
+    audio_sender->SetMediaChannel(rtp_manager()->voice_media_send_channel());
     new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
         signaling_thread(), audio_sender);
     rtp_manager()->GetAudioTransceiver()->internal()->AddSender(new_sender);
   } else if (kind == MediaStreamTrackInterface::kVideoKind) {
     auto video_sender = VideoRtpSender::Create(
         worker_thread(), rtc::CreateRandomUuid(), rtp_manager());
-    video_sender->SetMediaChannel(rtp_manager()->video_media_channel());
+    video_sender->SetMediaChannel(rtp_manager()->video_media_send_channel());
     new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
         signaling_thread(), video_sender);
     rtp_manager()->GetVideoTransceiver()->internal()->AddSender(new_sender);
@@ -1629,15 +1629,16 @@
   }
 
   if (modified_config.allow_codec_switching.has_value()) {
-    std::vector<cricket::VideoMediaChannel*> channels;
+    std::vector<cricket::VideoMediaSendChannelInterface*> channels;
     for (const auto& transceiver : rtp_manager()->transceivers()->List()) {
       if (transceiver->media_type() != cricket::MEDIA_TYPE_VIDEO)
         continue;
 
       auto* video_channel = transceiver->internal()->channel();
       if (video_channel)
-        channels.push_back(static_cast<cricket::VideoMediaChannel*>(
-            video_channel->media_send_channel()));
+        channels.push_back(
+            static_cast<cricket::VideoMediaSendChannelInterface*>(
+                video_channel->media_send_channel()));
     }
 
     worker_thread()->BlockingCall(
diff --git a/pc/remote_audio_source.cc b/pc/remote_audio_source.cc
index 1058d1c..a516c57 100644
--- a/pc/remote_audio_source.cc
+++ b/pc/remote_audio_source.cc
@@ -70,8 +70,9 @@
   }
 }
 
-void RemoteAudioSource::Start(cricket::VoiceMediaChannel* media_channel,
-                              absl::optional<uint32_t> ssrc) {
+void RemoteAudioSource::Start(
+    cricket::VoiceMediaReceiveChannelInterface* media_channel,
+    absl::optional<uint32_t> ssrc) {
   RTC_DCHECK_RUN_ON(worker_thread_);
 
   // Register for callbacks immediately before AddSink so that we always get
@@ -84,8 +85,9 @@
              std::make_unique<AudioDataProxy>(this));
 }
 
-void RemoteAudioSource::Stop(cricket::VoiceMediaChannel* media_channel,
-                             absl::optional<uint32_t> ssrc) {
+void RemoteAudioSource::Stop(
+    cricket::VoiceMediaReceiveChannelInterface* media_channel,
+    absl::optional<uint32_t> ssrc) {
   RTC_DCHECK_RUN_ON(worker_thread_);
   RTC_DCHECK(media_channel);
   ssrc ? media_channel->SetRawAudioSink(*ssrc, nullptr)
diff --git a/pc/remote_audio_source.h b/pc/remote_audio_source.h
index d294a0f..0fac606 100644
--- a/pc/remote_audio_source.h
+++ b/pc/remote_audio_source.h
@@ -49,9 +49,9 @@
 
   // Register and unregister remote audio source with the underlying media
   // engine.
-  void Start(cricket::VoiceMediaChannel* media_channel,
+  void Start(cricket::VoiceMediaReceiveChannelInterface* media_channel,
              absl::optional<uint32_t> ssrc);
-  void Stop(cricket::VoiceMediaChannel* media_channel,
+  void Stop(cricket::VoiceMediaReceiveChannelInterface* media_channel,
             absl::optional<uint32_t> ssrc);
   void SetState(SourceState new_state);
 
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 374780e..d500a7b 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -36,6 +36,7 @@
 #include "api/video_codecs/scalability_mode.h"
 #include "common_video/include/quality_limitation_reason.h"
 #include "media/base/media_channel.h"
+#include "media/base/media_channel_impl.h"
 #include "modules/audio_processing/include/audio_processing_statistics.h"
 #include "modules/rtp_rtcp/include/report_block_data.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
@@ -2365,13 +2366,15 @@
 
       if (media_type == cricket::MEDIA_TYPE_AUDIO) {
         cricket::VoiceMediaChannel* voice_channel =
-            channel->voice_media_send_channel();
+            static_cast<cricket::VoiceMediaChannel*>(
+                channel->voice_media_send_channel());
         RTC_DCHECK(voice_stats.find(voice_channel) == voice_stats.end());
         voice_stats.insert(
             std::make_pair(voice_channel, cricket::VoiceMediaInfo()));
       } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
         cricket::VideoMediaChannel* video_channel =
-            channel->video_media_send_channel();
+            static_cast<cricket::VideoMediaChannel*>(
+                channel->video_media_send_channel());
         RTC_DCHECK(video_stats.find(video_channel) == video_stats.end());
         video_stats.insert(
             std::make_pair(video_channel, cricket::VideoMediaInfo()));
@@ -2410,12 +2413,14 @@
         cricket::MediaType media_type = transceiver->media_type();
         if (media_type == cricket::MEDIA_TYPE_AUDIO) {
           cricket::VoiceMediaChannel* voice_channel =
-              channel->voice_media_send_channel();
+              static_cast<cricket::VoiceMediaChannel*>(
+                  channel->voice_media_send_channel());
           RTC_DCHECK(voice_stats.find(voice_channel) != voice_stats.end());
           voice_media_info = std::move(voice_stats[voice_channel]);
         } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
           cricket::VideoMediaChannel* video_channel =
-              channel->video_media_send_channel();
+              static_cast<cricket::VideoMediaChannel*>(
+                  channel->video_media_send_channel());
           RTC_DCHECK(video_stats.find(video_channel) != video_stats.end());
           video_media_info = std::move(video_stats[video_channel]);
         }
diff --git a/pc/rtp_sender.h b/pc/rtp_sender.h
index 0a2348c..29e5f16 100644
--- a/pc/rtp_sender.h
+++ b/pc/rtp_sender.h
@@ -378,8 +378,8 @@
   void RemoveTrackFromStats() override;
 
  private:
-  cricket::VoiceMediaChannel* voice_media_channel() {
-    return static_cast<cricket::VoiceMediaChannel*>(media_channel_);
+  cricket::VoiceMediaSendChannelInterface* voice_media_channel() {
+    return media_channel_->AsVoiceSendChannel();
   }
   rtc::scoped_refptr<AudioTrackInterface> audio_track() const {
     return rtc::scoped_refptr<AudioTrackInterface>(
@@ -436,8 +436,8 @@
   void AttachTrack() override;
 
  private:
-  cricket::VideoMediaChannel* video_media_channel() {
-    return static_cast<cricket::VideoMediaChannel*>(media_channel_);
+  cricket::VideoMediaSendChannelInterface* video_media_channel() {
+    return media_channel_->AsVideoSendChannel();
   }
   rtc::scoped_refptr<VideoTrackInterface> video_track() const {
     return rtc::scoped_refptr<VideoTrackInterface>(
diff --git a/pc/rtp_sender_receiver_unittest.cc b/pc/rtp_sender_receiver_unittest.cc
index 42072de..a189e65 100644
--- a/pc/rtp_sender_receiver_unittest.cc
+++ b/pc/rtp_sender_receiver_unittest.cc
@@ -204,7 +204,7 @@
     ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_.get()));
     EXPECT_CALL(*set_streams_observer, OnSetStreams());
     audio_rtp_sender_->SetStreams({local_stream_->id()});
-    audio_rtp_sender_->SetMediaChannel(voice_media_channel());
+    audio_rtp_sender_->SetMediaChannel(voice_media_channel()->AsSendChannel());
     audio_rtp_sender_->SetSsrc(kAudioSsrc);
     VerifyVoiceChannelInput();
   }
@@ -212,7 +212,8 @@
   void CreateAudioRtpSenderWithNoTrack() {
     audio_rtp_sender_ =
         AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr, nullptr);
-    audio_rtp_sender_->SetMediaChannel(voice_media_channel());
+    audio_rtp_sender_->SetMediaChannel(
+        voice_media_channel()->AsVoiceSendChannel());
   }
 
   void CreateVideoRtpSender(uint32_t ssrc) {
@@ -264,14 +265,16 @@
     ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get()));
     EXPECT_CALL(*set_streams_observer, OnSetStreams());
     video_rtp_sender_->SetStreams({local_stream_->id()});
-    video_rtp_sender_->SetMediaChannel(video_media_channel());
+    video_rtp_sender_->SetMediaChannel(
+        video_media_channel()->AsVideoSendChannel());
     video_rtp_sender_->SetSsrc(ssrc);
     VerifyVideoChannelInput(ssrc);
   }
   void CreateVideoRtpSenderWithNoTrack() {
     video_rtp_sender_ =
         VideoRtpSender::Create(worker_thread_, /*id=*/"", nullptr);
-    video_rtp_sender_->SetMediaChannel(video_media_channel());
+    video_rtp_sender_->SetMediaChannel(
+        video_media_channel()->AsVideoSendChannel());
   }
 
   void DestroyAudioRtpSender() {
@@ -289,7 +292,8 @@
     audio_rtp_receiver_ = rtc::make_ref_counted<AudioRtpReceiver>(
         rtc::Thread::Current(), kAudioTrackId, streams,
         /*is_unified_plan=*/true);
-    audio_rtp_receiver_->SetMediaChannel(voice_media_channel());
+    audio_rtp_receiver_->SetMediaChannel(
+        voice_media_channel()->AsVoiceReceiveChannel());
     audio_rtp_receiver_->SetupMediaChannel(kAudioSsrc);
     audio_track_ = audio_rtp_receiver_->audio_track();
     VerifyVoiceChannelOutput();
@@ -299,7 +303,8 @@
       std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams = {}) {
     video_rtp_receiver_ = rtc::make_ref_counted<VideoRtpReceiver>(
         rtc::Thread::Current(), kVideoTrackId, streams);
-    video_rtp_receiver_->SetMediaChannel(video_media_channel());
+    video_rtp_receiver_->SetMediaChannel(
+        video_media_channel()->AsVideoReceiveChannel());
     video_rtp_receiver_->SetupMediaChannel(kVideoSsrc);
     video_track_ = video_rtp_receiver_->video_track();
     VerifyVideoChannelOutput();
@@ -319,7 +324,8 @@
 
     video_rtp_receiver_ = rtc::make_ref_counted<VideoRtpReceiver>(
         rtc::Thread::Current(), kVideoTrackId, streams);
-    video_rtp_receiver_->SetMediaChannel(video_media_channel());
+    video_rtp_receiver_->SetMediaChannel(
+        video_media_channel()->AsVideoReceiveChannel());
     video_rtp_receiver_->SetupMediaChannel(primary_ssrc);
     video_track_ = video_rtp_receiver_->video_track();
   }
@@ -689,15 +695,17 @@
 
 TEST_F(RtpSenderReceiverTest, AudioRtpReceiverDelay) {
   CreateAudioRtpReceiver();
-  VerifyRtpReceiverDelayBehaviour(voice_media_channel(),
-                                  audio_rtp_receiver_.get(), kAudioSsrc);
+  VerifyRtpReceiverDelayBehaviour(
+      voice_media_channel()->AsVoiceReceiveChannel(), audio_rtp_receiver_.get(),
+      kAudioSsrc);
   DestroyAudioRtpReceiver();
 }
 
 TEST_F(RtpSenderReceiverTest, VideoRtpReceiverDelay) {
   CreateVideoRtpReceiver();
-  VerifyRtpReceiverDelayBehaviour(video_media_channel(),
-                                  video_rtp_receiver_.get(), kVideoSsrc);
+  VerifyRtpReceiverDelayBehaviour(
+      video_media_channel()->AsVideoReceiveChannel(), video_rtp_receiver_.get(),
+      kVideoSsrc);
   DestroyVideoRtpReceiver();
 }
 
@@ -936,7 +944,8 @@
   cricket::StreamParams stream_params =
       cricket::CreateSimStreamParams("cname", ssrcs);
   voice_media_channel()->AddSendStream(stream_params);
-  audio_rtp_sender_->SetMediaChannel(voice_media_channel());
+  audio_rtp_sender_->SetMediaChannel(
+      voice_media_channel()->AsVoiceSendChannel());
   audio_rtp_sender_->SetSsrc(1);
 
   params = audio_rtp_sender_->GetParameters();
@@ -1189,7 +1198,8 @@
   cricket::StreamParams stream_params =
       cricket::CreateSimStreamParams("cname", ssrcs);
   video_media_channel()->AddSendStream(stream_params);
-  video_rtp_sender_->SetMediaChannel(video_media_channel());
+  video_rtp_sender_->SetMediaChannel(
+      video_media_channel()->AsVideoSendChannel());
   video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast);
 
   params = video_rtp_sender_->GetParameters();
@@ -1229,7 +1239,8 @@
   cricket::StreamParams stream_params =
       cricket::CreateSimStreamParams("cname", ssrcs);
   video_media_channel()->AddSendStream(stream_params);
-  video_rtp_sender_->SetMediaChannel(video_media_channel());
+  video_rtp_sender_->SetMediaChannel(
+      video_media_channel()->AsVideoSendChannel());
   video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast);
 
   params = video_rtp_sender_->GetParameters();
@@ -1272,7 +1283,8 @@
   cricket::StreamParams stream_params =
       cricket::StreamParams::CreateLegacy(kVideoSsrc);
   video_media_channel()->AddSendStream(stream_params);
-  video_rtp_sender_->SetMediaChannel(video_media_channel());
+  video_rtp_sender_->SetMediaChannel(
+      video_media_channel()->AsVideoSendChannel());
   EXPECT_DEATH(video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast), "");
 }
 #endif
@@ -1687,7 +1699,8 @@
   ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get()));
   EXPECT_CALL(*set_streams_observer, OnSetStreams());
   video_rtp_sender_->SetStreams({local_stream_->id()});
-  video_rtp_sender_->SetMediaChannel(video_media_channel());
+  video_rtp_sender_->SetMediaChannel(
+      video_media_channel()->AsVideoSendChannel());
   video_track_->set_enabled(true);
 
   // Sender is not ready to send (no SSRC) so no option should have been set.
diff --git a/pc/rtp_transmission_manager.cc b/pc/rtp_transmission_manager.cc
index 4fcb991..96b748b 100644
--- a/pc/rtp_transmission_manager.cc
+++ b/pc/rtp_transmission_manager.cc
@@ -72,8 +72,8 @@
   return observer_;
 }
 
-cricket::VoiceMediaChannel* RtpTransmissionManager::voice_media_channel()
-    const {
+cricket::VoiceMediaSendChannelInterface*
+RtpTransmissionManager::voice_media_send_channel() const {
   RTC_DCHECK_RUN_ON(signaling_thread());
   RTC_DCHECK(!IsUnifiedPlan());
   auto* voice_channel = GetAudioTransceiver()->internal()->channel();
@@ -84,8 +84,8 @@
   }
 }
 
-cricket::VideoMediaChannel* RtpTransmissionManager::video_media_channel()
-    const {
+cricket::VideoMediaSendChannelInterface*
+RtpTransmissionManager::video_media_send_channel() const {
   RTC_DCHECK_RUN_ON(signaling_thread());
   RTC_DCHECK(!IsUnifiedPlan());
   auto* video_channel = GetVideoTransceiver()->internal()->channel();
@@ -95,6 +95,29 @@
     return nullptr;
   }
 }
+cricket::VoiceMediaReceiveChannelInterface*
+RtpTransmissionManager::voice_media_receive_channel() const {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  RTC_DCHECK(!IsUnifiedPlan());
+  auto* voice_channel = GetAudioTransceiver()->internal()->channel();
+  if (voice_channel) {
+    return voice_channel->voice_media_receive_channel();
+  } else {
+    return nullptr;
+  }
+}
+
+cricket::VideoMediaReceiveChannelInterface*
+RtpTransmissionManager::video_media_receive_channel() const {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  RTC_DCHECK(!IsUnifiedPlan());
+  auto* video_channel = GetVideoTransceiver()->internal()->channel();
+  if (video_channel) {
+    return video_channel->video_media_receive_channel();
+  } else {
+    return nullptr;
+  }
+}
 
 RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
 RtpTransmissionManager::AddTrack(
@@ -132,7 +155,7 @@
                    init_send_encodings ? *init_send_encodings
                                        : std::vector<RtpEncodingParameters>());
   if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
-    new_sender->internal()->SetMediaChannel(voice_media_channel());
+    new_sender->internal()->SetMediaChannel(voice_media_send_channel());
     GetAudioTransceiver()->internal()->AddSender(new_sender);
     const RtpSenderInfo* sender_info =
         FindSenderInfo(local_audio_sender_infos_,
@@ -142,7 +165,7 @@
     }
   } else {
     RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
-    new_sender->internal()->SetMediaChannel(video_media_channel());
+    new_sender->internal()->SetMediaChannel(video_media_send_channel());
     GetVideoTransceiver()->internal()->AddSender(new_sender);
     const RtpSenderInfo* sender_info =
         FindSenderInfo(local_video_sender_infos_,
@@ -389,7 +412,7 @@
   auto new_sender = CreateSender(cricket::MEDIA_TYPE_AUDIO, track->id(),
                                  rtc::scoped_refptr<AudioTrackInterface>(track),
                                  {stream->id()}, {});
-  new_sender->internal()->SetMediaChannel(voice_media_channel());
+  new_sender->internal()->SetMediaChannel(voice_media_send_channel());
   GetAudioTransceiver()->internal()->AddSender(new_sender);
   // If the sender has already been configured in SDP, we call SetSsrc,
   // which will connect the sender to the underlying transport. This can
@@ -436,7 +459,7 @@
   auto new_sender = CreateSender(cricket::MEDIA_TYPE_VIDEO, track->id(),
                                  rtc::scoped_refptr<VideoTrackInterface>(track),
                                  {stream->id()}, {});
-  new_sender->internal()->SetMediaChannel(video_media_channel());
+  new_sender->internal()->SetMediaChannel(video_media_send_channel());
   GetVideoTransceiver()->internal()->AddSender(new_sender);
   const RtpSenderInfo* sender_info =
       FindSenderInfo(local_video_sender_infos_, stream->id(), track->id());
@@ -468,7 +491,7 @@
   // the constructor taking stream IDs instead.
   auto audio_receiver = rtc::make_ref_counted<AudioRtpReceiver>(
       worker_thread(), remote_sender_info.sender_id, streams, IsUnifiedPlan(),
-      voice_media_channel());
+      voice_media_receive_channel());
   if (remote_sender_info.sender_id == kDefaultAudioSenderId) {
     audio_receiver->SetupUnsignaledMediaChannel();
   } else {
@@ -497,7 +520,7 @@
       remote_sender_info.sender_id == kDefaultVideoSenderId
           ? absl::nullopt
           : absl::optional<uint32_t>(remote_sender_info.first_ssrc),
-      video_media_channel());
+      video_media_receive_channel());
 
   auto receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
       signaling_thread(), worker_thread(), std::move(video_receiver));
diff --git a/pc/rtp_transmission_manager.h b/pc/rtp_transmission_manager.h
index 06ce4fe..b41848c 100644
--- a/pc/rtp_transmission_manager.h
+++ b/pc/rtp_transmission_manager.h
@@ -204,8 +204,12 @@
 
   // Plan B helpers for getting the voice/video media channels for the single
   // audio/video transceiver, if it exists.
-  cricket::VoiceMediaChannel* voice_media_channel() const;
-  cricket::VideoMediaChannel* video_media_channel() const;
+  cricket::VoiceMediaSendChannelInterface* voice_media_send_channel() const;
+  cricket::VideoMediaSendChannelInterface* video_media_send_channel() const;
+  cricket::VoiceMediaReceiveChannelInterface* voice_media_receive_channel()
+      const;
+  cricket::VideoMediaReceiveChannelInterface* video_media_receive_channel()
+      const;
 
  private:
   rtc::Thread* signaling_thread() const { return context_->signaling_thread(); }
diff --git a/pc/test/mock_channel_interface.h b/pc/test/mock_channel_interface.h
index 6188a71..273e4a1 100644
--- a/pc/test/mock_channel_interface.h
+++ b/pc/test/mock_channel_interface.h
@@ -25,6 +25,7 @@
 class MockChannelInterface : public cricket::ChannelInterface {
  public:
   MOCK_METHOD(cricket::MediaType, media_type, (), (const, override));
+  MOCK_METHOD(MediaChannel*, media_channel, (), (const, override));
   MOCK_METHOD(MediaChannel*, media_send_channel, (), (const, override));
   MOCK_METHOD(VoiceMediaChannel*,
               voice_media_send_channel,
diff --git a/pc/test/mock_voice_media_channel.h b/pc/test/mock_voice_media_channel.h
index cd80ef8..5a9b880 100644
--- a/pc/test/mock_voice_media_channel.h
+++ b/pc/test/mock_voice_media_channel.h
@@ -16,6 +16,7 @@
 
 #include "api/call/audio_sink.h"
 #include "media/base/media_channel.h"
+#include "media/base/media_channel_impl.h"
 #include "rtc_base/gunit.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
@@ -29,7 +30,10 @@
   explicit MockVoiceMediaChannel(webrtc::TaskQueueBase* network_thread)
       : VoiceMediaChannel(network_thread) {}
 
-  MOCK_METHOD(void, SetInterface, (NetworkInterface * iface), (override));
+  MOCK_METHOD(void,
+              SetInterface,
+              (MediaChannelNetworkInterface * iface),
+              (override));
   MOCK_METHOD(void,
               OnPacketReceived,
               (rtc::CopyOnWriteBuffer packet, int64_t packet_time_us),
@@ -64,7 +68,6 @@
       (uint32_t ssrc,
        rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor),
       (override));
-  MOCK_METHOD(void, SetVideoCodecSwitchingEnabled, (bool enabled), (override));
   MOCK_METHOD(webrtc::RtpParameters,
               GetRtpSendParameters,
               (uint32_t ssrc),
diff --git a/pc/video_rtp_receiver.cc b/pc/video_rtp_receiver.cc
index 1a4964b..18dfc82 100644
--- a/pc/video_rtp_receiver.cc
+++ b/pc/video_rtp_receiver.cc
@@ -276,7 +276,11 @@
     SetEncodedSinkEnabled(false);
   }
 
-  media_channel_ = static_cast<cricket::VideoMediaChannel*>(media_channel);
+  if (media_channel) {
+    media_channel_ = media_channel->AsVideoReceiveChannel();
+  } else {
+    media_channel_ = nullptr;
+  }
 
   if (media_channel_) {
     if (saved_generate_keyframe_) {
diff --git a/pc/video_rtp_receiver.h b/pc/video_rtp_receiver.h
index f572853..086246d 100644
--- a/pc/video_rtp_receiver.h
+++ b/pc/video_rtp_receiver.h
@@ -149,8 +149,8 @@
   rtc::Thread* const worker_thread_;
 
   const std::string id_;
-  cricket::VideoMediaChannel* media_channel_ RTC_GUARDED_BY(worker_thread_) =
-      nullptr;
+  cricket::VideoMediaReceiveChannelInterface* media_channel_
+      RTC_GUARDED_BY(worker_thread_) = nullptr;
   absl::optional<uint32_t> ssrc_ RTC_GUARDED_BY(worker_thread_);
   // `source_` is held here to be able to change the state of the source when
   // the VideoRtpReceiver is stopped.