Separating internal and external methods of RtpSender/RtpReceiver.

This moves the implementation specific methods to separate classes
(RtpSenderInternal/RtpReceiverInternal) so that the interface classes
represent the interface that external applications can rely on.

The reason this wasn't done earlier was that PeerConnection needed
to store proxy pointers, but also needed to access implementation-
specific methods on the underlying objects. This is now possible
by using "RtpSenderProxyWithInternal<RtpSenderInternal>", which is a proxy
that implements RtpSenderInterface but also provides direct access
to an RtpSenderInternal.

Review-Url: https://codereview.webrtc.org/2023373002
Cr-Commit-Position: refs/heads/master@{#13056}
diff --git a/webrtc/api/peerconnection.cc b/webrtc/api/peerconnection.cc
index 5f8acca..6b5cc69 100644
--- a/webrtc/api/peerconnection.cc
+++ b/webrtc/api/peerconnection.cc
@@ -45,7 +45,10 @@
 using webrtc::MediaConstraintsInterface;
 using webrtc::MediaStreamInterface;
 using webrtc::PeerConnectionInterface;
+using webrtc::RtpSenderInternal;
 using webrtc::RtpSenderInterface;
+using webrtc::RtpSenderProxy;
+using webrtc::RtpSenderProxyWithInternal;
 using webrtc::StreamCollection;
 
 static const char kDefaultStreamLabel[] = "default";
@@ -349,13 +352,14 @@
 // Add the stream and RTP data channel info to |session_options|.
 void AddSendStreams(
     cricket::MediaSessionOptions* session_options,
-    const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
+    const std::vector<rtc::scoped_refptr<
+        RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders,
     const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
         rtp_data_channels) {
   session_options->streams.clear();
   for (const auto& sender : senders) {
     session_options->AddSendStream(sender->media_type(), sender->id(),
-                                   sender->stream_id());
+                                   sender->internal()->stream_id());
   }
 
   // Check for data channels.
@@ -547,10 +551,10 @@
   // Need to detach RTP senders/receivers from WebRtcSession,
   // since it's about to be destroyed.
   for (const auto& sender : senders_) {
-    sender->Stop();
+    sender->internal()->Stop();
   }
   for (const auto& receiver : receivers_) {
-    receiver->Stop();
+    receiver->internal()->Stop();
   }
   // Destroy stats_ because it depends on session_.
   stats_.reset(nullptr);
@@ -702,32 +706,32 @@
   }
 
   // TODO(deadbeef): Support adding a track to multiple streams.
-  rtc::scoped_refptr<RtpSenderInterface> new_sender;
+  rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender;
   if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
-    new_sender = RtpSenderProxy::Create(
+    new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
         signaling_thread(),
         new AudioRtpSender(static_cast<AudioTrackInterface*>(track),
                            session_.get(), stats_.get()));
     if (!streams.empty()) {
-      new_sender->set_stream_id(streams[0]->label());
+      new_sender->internal()->set_stream_id(streams[0]->label());
     }
     const TrackInfo* track_info = FindTrackInfo(
-        local_audio_tracks_, new_sender->stream_id(), track->id());
+        local_audio_tracks_, new_sender->internal()->stream_id(), track->id());
     if (track_info) {
-      new_sender->SetSsrc(track_info->ssrc);
+      new_sender->internal()->SetSsrc(track_info->ssrc);
     }
   } else if (track->kind() == MediaStreamTrackInterface::kVideoKind) {
-    new_sender = RtpSenderProxy::Create(
+    new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
         signaling_thread(),
         new VideoRtpSender(static_cast<VideoTrackInterface*>(track),
                            session_.get()));
     if (!streams.empty()) {
-      new_sender->set_stream_id(streams[0]->label());
+      new_sender->internal()->set_stream_id(streams[0]->label());
     }
     const TrackInfo* track_info = FindTrackInfo(
-        local_video_tracks_, new_sender->stream_id(), track->id());
+        local_video_tracks_, new_sender->internal()->stream_id(), track->id());
     if (track_info) {
-      new_sender->SetSsrc(track_info->ssrc);
+      new_sender->internal()->SetSsrc(track_info->ssrc);
     }
   } else {
     LOG(LS_ERROR) << "CreateSender called with invalid kind: " << track->kind();
@@ -750,7 +754,7 @@
     LOG(LS_ERROR) << "Couldn't find sender " << sender->id() << " to remove.";
     return false;
   }
-  (*it)->Stop();
+  (*it)->internal()->Stop();
   senders_.erase(it);
 
   observer_->OnRenegotiationNeeded();
@@ -782,19 +786,19 @@
     const std::string& kind,
     const std::string& stream_id) {
   TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
-  rtc::scoped_refptr<RtpSenderInterface> new_sender;
+  rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender;
   if (kind == MediaStreamTrackInterface::kAudioKind) {
-    new_sender = RtpSenderProxy::Create(
+    new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
         signaling_thread(), new AudioRtpSender(session_.get(), stats_.get()));
   } else if (kind == MediaStreamTrackInterface::kVideoKind) {
-    new_sender = RtpSenderProxy::Create(signaling_thread(),
-                                        new VideoRtpSender(session_.get()));
+    new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
+        signaling_thread(), new VideoRtpSender(session_.get()));
   } else {
     LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
     return new_sender;
   }
   if (!stream_id.empty()) {
-    new_sender->set_stream_id(stream_id);
+    new_sender->internal()->set_stream_id(stream_id);
   }
   senders_.push_back(new_sender);
   return new_sender;
@@ -802,12 +806,20 @@
 
 std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
     const {
-  return senders_;
+  std::vector<rtc::scoped_refptr<RtpSenderInterface>> ret;
+  for (const auto& sender : senders_) {
+    ret.push_back(sender.get());
+  }
+  return ret;
 }
 
 std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
 PeerConnection::GetReceivers() const {
-  return receivers_;
+  std::vector<rtc::scoped_refptr<RtpReceiverInterface>> ret;
+  for (const auto& receiver : receivers_) {
+    ret.push_back(receiver.get());
+  }
+  return ret;
 }
 
 bool PeerConnection::GetStats(StatsObserver* observer,
@@ -1303,18 +1315,20 @@
 void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
                                          const std::string& track_id,
                                          uint32_t ssrc) {
-  receivers_.push_back(RtpReceiverProxy::Create(
-      signaling_thread(),
-      new AudioRtpReceiver(stream, track_id, ssrc, session_.get())));
+  receivers_.push_back(
+      RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
+          signaling_thread(),
+          new AudioRtpReceiver(stream, track_id, ssrc, session_.get())));
 }
 
 void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
                                          const std::string& track_id,
                                          uint32_t ssrc) {
-  receivers_.push_back(RtpReceiverProxy::Create(
-      signaling_thread(),
-      new VideoRtpReceiver(stream, track_id, factory_->worker_thread(), ssrc,
-                           session_.get())));
+  receivers_.push_back(
+      RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
+          signaling_thread(),
+          new VideoRtpReceiver(stream, track_id, factory_->worker_thread(),
+                               ssrc, session_.get())));
 }
 
 // TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
@@ -1325,7 +1339,7 @@
     LOG(LS_WARNING) << "RtpReceiver for track with id " << track_id
                     << " doesn't exist.";
   } else {
-    (*it)->Stop();
+    (*it)->internal()->Stop();
     receivers_.erase(it);
   }
 }
@@ -1338,7 +1352,7 @@
       LOG(LS_WARNING) << "RtpReceiver for track with id " << track_info.track_id
                       << " doesn't exist.";
     } else {
-      (*it)->Stop();
+      (*it)->internal()->Stop();
     }
   }
 }
@@ -1401,14 +1415,15 @@
   if (sender != senders_.end()) {
     // We already have a sender for this track, so just change the stream_id
     // so that it's correct in the next call to CreateOffer.
-    (*sender)->set_stream_id(stream->label());
+    (*sender)->internal()->set_stream_id(stream->label());
     return;
   }
 
   // Normal case; we've never seen this track before.
-  rtc::scoped_refptr<RtpSenderInterface> new_sender = RtpSenderProxy::Create(
-      signaling_thread(),
-      new AudioRtpSender(track, stream->label(), session_.get(), stats_.get()));
+  rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender =
+      RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
+          signaling_thread(), new AudioRtpSender(track, stream->label(),
+                                                 session_.get(), stats_.get()));
   senders_.push_back(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
@@ -1419,7 +1434,7 @@
   const TrackInfo* track_info =
       FindTrackInfo(local_audio_tracks_, stream->label(), track->id());
   if (track_info) {
-    new_sender->SetSsrc(track_info->ssrc);
+    new_sender->internal()->SetSsrc(track_info->ssrc);
   }
 }
 
@@ -1433,7 +1448,7 @@
                     << " doesn't exist.";
     return;
   }
-  (*sender)->Stop();
+  (*sender)->internal()->Stop();
   senders_.erase(sender);
 }
 
@@ -1443,19 +1458,20 @@
   if (sender != senders_.end()) {
     // We already have a sender for this track, so just change the stream_id
     // so that it's correct in the next call to CreateOffer.
-    (*sender)->set_stream_id(stream->label());
+    (*sender)->internal()->set_stream_id(stream->label());
     return;
   }
 
   // Normal case; we've never seen this track before.
-  rtc::scoped_refptr<RtpSenderInterface> new_sender = RtpSenderProxy::Create(
-      signaling_thread(),
-      new VideoRtpSender(track, stream->label(), session_.get()));
+  rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender =
+      RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
+          signaling_thread(),
+          new VideoRtpSender(track, stream->label(), session_.get()));
   senders_.push_back(new_sender);
   const TrackInfo* track_info =
       FindTrackInfo(local_video_tracks_, stream->label(), track->id());
   if (track_info) {
-    new_sender->SetSsrc(track_info->ssrc);
+    new_sender->internal()->SetSsrc(track_info->ssrc);
   }
 }
 
@@ -1467,7 +1483,7 @@
                     << " doesn't exist.";
     return;
   }
-  (*sender)->Stop();
+  (*sender)->internal()->Stop();
   senders_.erase(sender);
 }
 
@@ -1769,7 +1785,7 @@
                                       const std::string& track_id,
                                       uint32_t ssrc,
                                       cricket::MediaType media_type) {
-  RtpSenderInterface* sender = FindSenderById(track_id);
+  RtpSenderInternal* sender = FindSenderById(track_id);
   if (!sender) {
     LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
                     << " has been configured in the local description.";
@@ -1790,7 +1806,7 @@
                                          const std::string& track_id,
                                          uint32_t ssrc,
                                          cricket::MediaType media_type) {
-  RtpSenderInterface* sender = FindSenderById(track_id);
+  RtpSenderInternal* sender = FindSenderById(track_id);
   if (!sender) {
     // This is the normal case. I.e., RemoveStream has been called and the
     // SessionDescriptions has been renegotiated.
@@ -1894,7 +1910,8 @@
     return;
   }
   channel->SetReceiveSsrc(remote_ssrc);
-  auto proxy_channel = DataChannelProxy::Create(signaling_thread(), channel);
+  rtc::scoped_refptr<DataChannelInterface> proxy_channel =
+      DataChannelProxy::Create(signaling_thread(), channel);
   // Call both the raw pointer and scoped_refptr versions of the method
   // for compatibility.
   observer_->OnDataChannel(proxy_channel.get());
@@ -2028,36 +2045,42 @@
     return;
   }
 
-  auto proxy_channel = DataChannelProxy::Create(signaling_thread(), channel);
+  rtc::scoped_refptr<DataChannelInterface> proxy_channel =
+      DataChannelProxy::Create(signaling_thread(), channel);
   // Call both the raw pointer and scoped_refptr versions of the method
   // for compatibility.
   observer_->OnDataChannel(proxy_channel.get());
   observer_->OnDataChannel(std::move(proxy_channel));
 }
 
-RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
-  auto it =
-      std::find_if(senders_.begin(), senders_.end(),
-                   [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
-                     return sender->id() == id;
-                   });
-  return it != senders_.end() ? it->get() : nullptr;
+RtpSenderInternal* PeerConnection::FindSenderById(const std::string& id) {
+  auto it = std::find_if(
+      senders_.begin(), senders_.end(),
+      [id](const rtc::scoped_refptr<
+           RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) {
+        return sender->id() == id;
+      });
+  return it != senders_.end() ? (*it)->internal() : nullptr;
 }
 
-std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
+std::vector<
+    rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>::iterator
 PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
   return std::find_if(
       senders_.begin(), senders_.end(),
-      [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
+      [track](const rtc::scoped_refptr<
+              RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) {
         return sender->track() == track;
       });
 }
 
-std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
+std::vector<rtc::scoped_refptr<
+    RtpReceiverProxyWithInternal<RtpReceiverInternal>>>::iterator
 PeerConnection::FindReceiverForTrack(const std::string& track_id) {
   return std::find_if(
       receivers_.begin(), receivers_.end(),
-      [track_id](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
+      [track_id](const rtc::scoped_refptr<
+                 RtpReceiverProxyWithInternal<RtpReceiverInternal>>& receiver) {
         return receiver->id() == track_id;
       });
 }
diff --git a/webrtc/api/peerconnection.h b/webrtc/api/peerconnection.h
index a683e8d..aba595c 100644
--- a/webrtc/api/peerconnection.h
+++ b/webrtc/api/peerconnection.h
@@ -18,8 +18,8 @@
 
 #include "webrtc/api/peerconnectionfactory.h"
 #include "webrtc/api/peerconnectioninterface.h"
-#include "webrtc/api/rtpreceiverinterface.h"
-#include "webrtc/api/rtpsenderinterface.h"
+#include "webrtc/api/rtpreceiver.h"
+#include "webrtc/api/rtpsender.h"
 #include "webrtc/api/statscollector.h"
 #include "webrtc/api/streamcollection.h"
 #include "webrtc/api/webrtcsession.h"
@@ -334,11 +334,13 @@
   void OnDataChannelOpenMessage(const std::string& label,
                                 const InternalDataChannelInit& config);
 
-  RtpSenderInterface* FindSenderById(const std::string& id);
+  RtpSenderInternal* FindSenderById(const std::string& id);
 
-  std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
+  std::vector<rtc::scoped_refptr<
+      RtpSenderProxyWithInternal<RtpSenderInternal>>>::iterator
   FindSenderForTrack(MediaStreamTrackInterface* track);
-  std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
+  std::vector<rtc::scoped_refptr<
+      RtpReceiverProxyWithInternal<RtpReceiverInternal>>>::iterator
   FindReceiverForTrack(const std::string& track_id);
 
   TrackInfos* GetRemoteTracks(cricket::MediaType media_type);
@@ -400,8 +402,11 @@
 
   bool remote_peer_supports_msid_ = false;
 
-  std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders_;
-  std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers_;
+  std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
+      senders_;
+  std::vector<
+      rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
+      receivers_;
 
   std::unique_ptr<WebRtcSession> session_;
   std::unique_ptr<StatsCollector> stats_;
diff --git a/webrtc/api/peerconnectioninterface_unittest.cc b/webrtc/api/peerconnectioninterface_unittest.cc
index 7addbec..71233e0 100644
--- a/webrtc/api/peerconnectioninterface_unittest.cc
+++ b/webrtc/api/peerconnectioninterface_unittest.cc
@@ -333,7 +333,7 @@
     const std::string& id,
     const std::string& stream_id) {
   for (const auto& sender : senders) {
-    if (sender->id() == id && sender->stream_id() == stream_id) {
+    if (sender->id() == id && sender->stream_ids()[0] == stream_id) {
       return true;
     }
   }
@@ -1166,10 +1166,12 @@
       pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer())));
   auto audio_sender = pc_->AddTrack(audio_track, stream_list);
   auto video_sender = pc_->AddTrack(video_track, stream_list);
-  EXPECT_EQ(kStreamLabel1, audio_sender->stream_id());
+  EXPECT_EQ(1UL, audio_sender->stream_ids().size());
+  EXPECT_EQ(kStreamLabel1, audio_sender->stream_ids()[0]);
   EXPECT_EQ("audio_track", audio_sender->id());
   EXPECT_EQ(audio_track, audio_sender->track());
-  EXPECT_EQ(kStreamLabel1, video_sender->stream_id());
+  EXPECT_EQ(1UL, video_sender->stream_ids().size());
+  EXPECT_EQ(kStreamLabel1, video_sender->stream_ids()[0]);
   EXPECT_EQ("video_track", video_sender->id());
   EXPECT_EQ(video_track, video_sender->track());
 
@@ -1242,7 +1244,7 @@
   EXPECT_EQ(video_track, video_sender->track());
   // If the ID is truly a random GUID, it should be infinitely unlikely they
   // will be the same.
-  EXPECT_NE(video_sender->stream_id(), audio_sender->stream_id());
+  EXPECT_NE(video_sender->stream_ids(), audio_sender->stream_ids());
 }
 
 TEST_F(PeerConnectionInterfaceTest, CreateOfferReceiveAnswer) {
diff --git a/webrtc/api/proxy.h b/webrtc/api/proxy.h
index 2df85c4..20a5b49 100644
--- a/webrtc/api/proxy.h
+++ b/webrtc/api/proxy.h
@@ -306,43 +306,62 @@
   T5 a5_;
 };
 
-#define BEGIN_SIGNALING_PROXY_MAP(c)                                     \
-  class c##Proxy : public c##Interface {                                  \
-   protected:                                                             \
-    typedef c##Interface C;                                               \
-    c##Proxy(rtc::Thread* signaling_thread, C* c)                         \
-      : signaling_thread_(signaling_thread), c_(c) {}                     \
-    ~c##Proxy() {                                                         \
-      MethodCall0<c##Proxy, void> call(                                   \
-          this, &c##Proxy::Release_s);                                    \
-      call.Marshal(signaling_thread_);                                    \
-    }                                                                     \
-                                                                          \
-   public:                                                                \
-    static rtc::scoped_refptr<C> Create(rtc::Thread* signaling_thread, C* c) { \
-      return new rtc::RefCountedObject<c##Proxy>(                         \
-          signaling_thread, c);                                           \
-    }
+#define BEGIN_SIGNALING_PROXY_MAP(c)                                           \
+  template <class INTERNAL_CLASS>                                              \
+  class c##ProxyWithInternal;                                                  \
+  typedef c##ProxyWithInternal<c##Interface> c##Proxy;                         \
+  template <class INTERNAL_CLASS>                                              \
+  class c##ProxyWithInternal : public c##Interface {                           \
+   protected:                                                                  \
+    typedef c##Interface C;                                                    \
+    c##ProxyWithInternal(rtc::Thread* signaling_thread, INTERNAL_CLASS* c)     \
+        : signaling_thread_(signaling_thread), c_(c) {}                        \
+    ~c##ProxyWithInternal() {                                                  \
+      MethodCall0<c##ProxyWithInternal, void> call(                            \
+          this, &c##ProxyWithInternal::Release_s);                             \
+      call.Marshal(signaling_thread_);                                         \
+    }                                                                          \
+                                                                               \
+   public:                                                                     \
+    static rtc::scoped_refptr<c##ProxyWithInternal> Create(                    \
+        rtc::Thread* signaling_thread,                                         \
+        INTERNAL_CLASS* c) {                                                   \
+      return new rtc::RefCountedObject<c##ProxyWithInternal>(signaling_thread, \
+                                                             c);               \
+    }                                                                          \
+    const INTERNAL_CLASS* internal() const { return c_.get(); }                \
+    INTERNAL_CLASS* internal() { return c_.get(); }
 
-#define BEGIN_PROXY_MAP(c)                                              \
-  class c##Proxy : public c##Interface {                                \
-   protected:                                                           \
-    typedef c##Interface C;                                             \
-    c##Proxy(rtc::Thread* signaling_thread, rtc::Thread* worker_thread, C* c) \
-      : signaling_thread_(signaling_thread),                            \
-        worker_thread_(worker_thread),                                  \
-        c_(c) {}                                                        \
-    ~c##Proxy() {                                                       \
-      MethodCall0<c##Proxy, void> call(this, &c##Proxy::Release_s);     \
-      call.Marshal(signaling_thread_);                                  \
-    }                                                                   \
-                                                                        \
-   public:                                                              \
-    static rtc::scoped_refptr<C> Create(                                \
-        rtc::Thread* signaling_thread, rtc::Thread* worker_thread, C* c) { \
-      return new rtc::RefCountedObject<c##Proxy>(                       \
-          signaling_thread, worker_thread, c);                          \
-    }
+#define BEGIN_PROXY_MAP(c)                                      \
+  template <class INTERNAL_CLASS>                               \
+  class c##ProxyWithInternal;                                   \
+  typedef c##ProxyWithInternal<c##Interface> c##Proxy;          \
+  template <class INTERNAL_CLASS>                               \
+  class c##ProxyWithInternal : public c##Interface {            \
+   protected:                                                   \
+    typedef c##Interface C;                                     \
+    c##ProxyWithInternal(rtc::Thread* signaling_thread,         \
+                         rtc::Thread* worker_thread,            \
+                         INTERNAL_CLASS* c)                     \
+        : signaling_thread_(signaling_thread),                  \
+          worker_thread_(worker_thread),                        \
+          c_(c) {}                                              \
+    ~c##ProxyWithInternal() {                                   \
+      MethodCall0<c##ProxyWithInternal, void> call(             \
+          this, &c##ProxyWithInternal::Release_s);              \
+      call.Marshal(signaling_thread_);                          \
+    }                                                           \
+                                                                \
+   public:                                                      \
+    static rtc::scoped_refptr<c##ProxyWithInternal> Create(     \
+        rtc::Thread* signaling_thread,                          \
+        rtc::Thread* worker_thread,                             \
+        INTERNAL_CLASS* c) {                                    \
+      return new rtc::RefCountedObject<c##ProxyWithInternal>(   \
+          signaling_thread, worker_thread, c);                  \
+    }                                                           \
+    const INTERNAL_CLASS* internal() const { return c_.get(); } \
+    INTERNAL_CLASS* internal() { return c_.get(); }
 
 #define PROXY_METHOD0(r, method)                  \
   r method() override {                           \
@@ -407,24 +426,22 @@
     return call.Marshal(worker_thread_);                          \
   }
 
-#define END_SIGNALING_PROXY() \
-   private:\
-    void Release_s() {\
-      c_ = NULL;\
-    }\
-    mutable rtc::Thread* signaling_thread_;\
-    rtc::scoped_refptr<C> c_;\
-  };
+#define END_SIGNALING_PROXY()             \
+ private:                                 \
+  void Release_s() { c_ = NULL; }         \
+  mutable rtc::Thread* signaling_thread_; \
+  rtc::scoped_refptr<INTERNAL_CLASS> c_;  \
+  }                                       \
+  ;
 
-#define END_PROXY()                                  \
-   private:                                          \
-    void Release_s() {                               \
-      c_ = NULL;                                     \
-    }                                                \
-    mutable rtc::Thread* signaling_thread_;          \
-    mutable rtc::Thread* worker_thread_;             \
-    rtc::scoped_refptr<C> c_;                        \
-  };                                                 \
+#define END_PROXY()                       \
+ private:                                 \
+  void Release_s() { c_ = NULL; }         \
+  mutable rtc::Thread* signaling_thread_; \
+  mutable rtc::Thread* worker_thread_;    \
+  rtc::scoped_refptr<INTERNAL_CLASS> c_;  \
+  }                                       \
+  ;
 
 }  // namespace webrtc
 
diff --git a/webrtc/api/proxy_unittest.cc b/webrtc/api/proxy_unittest.cc
index 931ba28..005d062 100644
--- a/webrtc/api/proxy_unittest.cc
+++ b/webrtc/api/proxy_unittest.cc
@@ -73,6 +73,7 @@
 
 // Preprocessor hack to get a proxy class a name different than FakeProxy.
 #define FakeProxy FakeSignalingProxy
+#define FakeProxyWithInternal FakeSignalingProxyWithInternal
 BEGIN_SIGNALING_PROXY_MAP(Fake)
   PROXY_METHOD0(void, VoidMethod0)
   PROXY_METHOD0(std::string, Method0)
diff --git a/webrtc/api/rtpreceiver.cc b/webrtc/api/rtpreceiver.cc
index 1b52ce2..9df336e 100644
--- a/webrtc/api/rtpreceiver.cc
+++ b/webrtc/api/rtpreceiver.cc
@@ -58,15 +58,6 @@
     provider_->SetAudioPlayoutVolume(ssrc_, volume);
 }
 
-void AudioRtpReceiver::Stop() {
-  // TODO(deadbeef): Need to do more here to fully stop receiving packets.
-  if (!provider_) {
-    return;
-  }
-  provider_->SetAudioPlayout(ssrc_, false);
-  provider_ = nullptr;
-}
-
 RtpParameters AudioRtpReceiver::GetParameters() const {
   return provider_->GetAudioRtpReceiveParameters(ssrc_);
 }
@@ -76,6 +67,15 @@
   return provider_->SetAudioRtpReceiveParameters(ssrc_, parameters);
 }
 
+void AudioRtpReceiver::Stop() {
+  // TODO(deadbeef): Need to do more here to fully stop receiving packets.
+  if (!provider_) {
+    return;
+  }
+  provider_->SetAudioPlayout(ssrc_, false);
+  provider_ = nullptr;
+}
+
 void AudioRtpReceiver::Reconfigure() {
   if (!provider_) {
     return;
@@ -112,6 +112,15 @@
   Stop();
 }
 
+RtpParameters VideoRtpReceiver::GetParameters() const {
+  return provider_->GetVideoRtpReceiveParameters(ssrc_);
+}
+
+bool VideoRtpReceiver::SetParameters(const RtpParameters& parameters) {
+  TRACE_EVENT0("webrtc", "VideoRtpReceiver::SetParameters");
+  return provider_->SetVideoRtpReceiveParameters(ssrc_, parameters);
+}
+
 void VideoRtpReceiver::Stop() {
   // TODO(deadbeef): Need to do more here to fully stop receiving packets.
   if (!provider_) {
@@ -123,13 +132,4 @@
   provider_ = nullptr;
 }
 
-RtpParameters VideoRtpReceiver::GetParameters() const {
-  return provider_->GetVideoRtpReceiveParameters(ssrc_);
-}
-
-bool VideoRtpReceiver::SetParameters(const RtpParameters& parameters) {
-  TRACE_EVENT0("webrtc", "VideoRtpReceiver::SetParameters");
-  return provider_->SetVideoRtpReceiveParameters(ssrc_, parameters);
-}
-
 }  // namespace webrtc
diff --git a/webrtc/api/rtpreceiver.h b/webrtc/api/rtpreceiver.h
index 2e7339d..001264d 100644
--- a/webrtc/api/rtpreceiver.h
+++ b/webrtc/api/rtpreceiver.h
@@ -26,9 +26,15 @@
 
 namespace webrtc {
 
+// Internal class used by PeerConnection.
+class RtpReceiverInternal : public RtpReceiverInterface {
+ public:
+  virtual void Stop() = 0;
+};
+
 class AudioRtpReceiver : public ObserverInterface,
                          public AudioSourceInterface::AudioObserver,
-                         public rtc::RefCountedObject<RtpReceiverInterface> {
+                         public rtc::RefCountedObject<RtpReceiverInternal> {
  public:
   AudioRtpReceiver(MediaStreamInterface* stream,
                    const std::string& track_id,
@@ -54,11 +60,12 @@
 
   std::string id() const override { return id_; }
 
-  void Stop() override;
-
   RtpParameters GetParameters() const override;
   bool SetParameters(const RtpParameters& parameters) override;
 
+  // RtpReceiverInternal implementation.
+  void Stop() override;
+
  private:
   void Reconfigure();
 
@@ -69,7 +76,7 @@
   bool cached_track_enabled_;
 };
 
-class VideoRtpReceiver : public rtc::RefCountedObject<RtpReceiverInterface> {
+class VideoRtpReceiver : public rtc::RefCountedObject<RtpReceiverInternal> {
  public:
   VideoRtpReceiver(MediaStreamInterface* stream,
                    const std::string& track_id,
@@ -90,11 +97,12 @@
 
   std::string id() const override { return id_; }
 
-  void Stop() override;
-
   RtpParameters GetParameters() const override;
   bool SetParameters(const RtpParameters& parameters) override;
 
+  // RtpReceiverInternal implementation.
+  void Stop() override;
+
  private:
   std::string id_;
   uint32_t ssrc_;
diff --git a/webrtc/api/rtpreceiverinterface.h b/webrtc/api/rtpreceiverinterface.h
index ef4f0e1..4988838 100644
--- a/webrtc/api/rtpreceiverinterface.h
+++ b/webrtc/api/rtpreceiverinterface.h
@@ -31,8 +31,6 @@
   // to uniquely identify a receiver until we implement Unified Plan SDP.
   virtual std::string id() const = 0;
 
-  virtual void Stop() = 0;
-
   // The WebRTC specification only defines RTCRtpParameters in terms of senders,
   // but this API also applies them to receivers, similar to ORTC:
   // http://ortc.org/wp-content/uploads/2016/03/ortc.html#rtcrtpparameters*.
@@ -47,7 +45,6 @@
 BEGIN_SIGNALING_PROXY_MAP(RtpReceiver)
 PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
 PROXY_CONSTMETHOD0(std::string, id)
-PROXY_METHOD0(void, Stop)
 PROXY_CONSTMETHOD0(RtpParameters, GetParameters);
 PROXY_METHOD1(bool, SetParameters, const RtpParameters&)
 END_SIGNALING_PROXY()
diff --git a/webrtc/api/rtpsender.cc b/webrtc/api/rtpsender.cc
index 33d7ee3..f66e66b 100644
--- a/webrtc/api/rtpsender.cc
+++ b/webrtc/api/rtpsender.cc
@@ -145,6 +145,15 @@
   return true;
 }
 
+RtpParameters AudioRtpSender::GetParameters() const {
+  return provider_->GetAudioRtpSendParameters(ssrc_);
+}
+
+bool AudioRtpSender::SetParameters(const RtpParameters& parameters) {
+  TRACE_EVENT0("webrtc", "AudioRtpSender::SetParameters");
+  return provider_->SetAudioRtpSendParameters(ssrc_, parameters);
+}
+
 void AudioRtpSender::SetSsrc(uint32_t ssrc) {
   TRACE_EVENT0("webrtc", "AudioRtpSender::SetSsrc");
   if (stopped_ || ssrc == ssrc_) {
@@ -207,15 +216,6 @@
   provider_->SetAudioSend(ssrc_, track_->enabled(), options, source);
 }
 
-RtpParameters AudioRtpSender::GetParameters() const {
-  return provider_->GetAudioRtpSendParameters(ssrc_);
-}
-
-bool AudioRtpSender::SetParameters(const RtpParameters& parameters) {
-  TRACE_EVENT0("webrtc", "AudioRtpSender::SetParameters");
-  return provider_->SetAudioRtpSendParameters(ssrc_, parameters);
-}
-
 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track,
                                const std::string& stream_id,
                                VideoProviderInterface* provider)
@@ -297,6 +297,15 @@
   return true;
 }
 
+RtpParameters VideoRtpSender::GetParameters() const {
+  return provider_->GetVideoRtpSendParameters(ssrc_);
+}
+
+bool VideoRtpSender::SetParameters(const RtpParameters& parameters) {
+  TRACE_EVENT0("webrtc", "VideoRtpSender::SetParameters");
+  return provider_->SetVideoRtpSendParameters(ssrc_, parameters);
+}
+
 void VideoRtpSender::SetSsrc(uint32_t ssrc) {
   TRACE_EVENT0("webrtc", "VideoRtpSender::SetSsrc");
   if (stopped_ || ssrc == ssrc_) {
@@ -344,13 +353,4 @@
   provider_->SetVideoSend(ssrc_, false, nullptr, nullptr);
 }
 
-RtpParameters VideoRtpSender::GetParameters() const {
-  return provider_->GetVideoRtpSendParameters(ssrc_);
-}
-
-bool VideoRtpSender::SetParameters(const RtpParameters& parameters) {
-  TRACE_EVENT0("webrtc", "VideoRtpSender::SetParameters");
-  return provider_->SetVideoRtpSendParameters(ssrc_, parameters);
-}
-
 }  // namespace webrtc
diff --git a/webrtc/api/rtpsender.h b/webrtc/api/rtpsender.h
index c8a46a8..a0bcc94 100644
--- a/webrtc/api/rtpsender.h
+++ b/webrtc/api/rtpsender.h
@@ -27,6 +27,22 @@
 
 namespace webrtc {
 
+// Internal interface used by PeerConnection.
+class RtpSenderInternal : public RtpSenderInterface {
+ public:
+  // Used to set the SSRC of the sender, once a local description has been set.
+  // If |ssrc| is 0, this indiates that the sender should disconnect from the
+  // underlying transport (this occurs if the sender isn't seen in a local
+  // description).
+  virtual void SetSsrc(uint32_t ssrc) = 0;
+
+  // TODO(deadbeef): Support one sender having multiple stream ids.
+  virtual void set_stream_id(const std::string& stream_id) = 0;
+  virtual std::string stream_id() const = 0;
+
+  virtual void Stop() = 0;
+};
+
 // LocalAudioSinkAdapter receives data callback as a sink to the local
 // AudioTrack, and passes the data to the sink of AudioSource.
 class LocalAudioSinkAdapter : public AudioTrackSinkInterface,
@@ -52,7 +68,7 @@
 };
 
 class AudioRtpSender : public ObserverInterface,
-                       public rtc::RefCountedObject<RtpSenderInterface> {
+                       public rtc::RefCountedObject<RtpSenderInternal> {
  public:
   // StatsCollector provided so that Add/RemoveLocalAudioTrack can be called
   // at the appropriate times.
@@ -77,11 +93,9 @@
   // RtpSenderInterface implementation
   bool SetTrack(MediaStreamTrackInterface* track) override;
   rtc::scoped_refptr<MediaStreamTrackInterface> track() const override {
-    return track_.get();
+    return track_;
   }
 
-  void SetSsrc(uint32_t ssrc) override;
-
   uint32_t ssrc() const override { return ssrc_; }
 
   cricket::MediaType media_type() const override {
@@ -90,6 +104,17 @@
 
   std::string id() const override { return id_; }
 
+  std::vector<std::string> stream_ids() const override {
+    std::vector<std::string> ret = {stream_id_};
+    return ret;
+  }
+
+  RtpParameters GetParameters() const override;
+  bool SetParameters(const RtpParameters& parameters) override;
+
+  // RtpSenderInternal implementation.
+  void SetSsrc(uint32_t ssrc) override;
+
   void set_stream_id(const std::string& stream_id) override {
     stream_id_ = stream_id;
   }
@@ -97,9 +122,6 @@
 
   void Stop() override;
 
-  RtpParameters GetParameters() const override;
-  bool SetParameters(const RtpParameters& parameters) override;
-
  private:
   // TODO(nisse): Since SSRC == 0 is technically valid, figure out
   // some other way to test if we have a valid SSRC.
@@ -123,7 +145,7 @@
 };
 
 class VideoRtpSender : public ObserverInterface,
-                       public rtc::RefCountedObject<RtpSenderInterface> {
+                       public rtc::RefCountedObject<RtpSenderInternal> {
  public:
   VideoRtpSender(VideoTrackInterface* track,
                  const std::string& stream_id,
@@ -143,11 +165,9 @@
   // RtpSenderInterface implementation
   bool SetTrack(MediaStreamTrackInterface* track) override;
   rtc::scoped_refptr<MediaStreamTrackInterface> track() const override {
-    return track_.get();
+    return track_;
   }
 
-  void SetSsrc(uint32_t ssrc) override;
-
   uint32_t ssrc() const override { return ssrc_; }
 
   cricket::MediaType media_type() const override {
@@ -156,6 +176,17 @@
 
   std::string id() const override { return id_; }
 
+  std::vector<std::string> stream_ids() const override {
+    std::vector<std::string> ret = {stream_id_};
+    return ret;
+  }
+
+  RtpParameters GetParameters() const override;
+  bool SetParameters(const RtpParameters& parameters) override;
+
+  // RtpSenderInternal implementation.
+  void SetSsrc(uint32_t ssrc) override;
+
   void set_stream_id(const std::string& stream_id) override {
     stream_id_ = stream_id;
   }
@@ -163,9 +194,6 @@
 
   void Stop() override;
 
-  RtpParameters GetParameters() const override;
-  bool SetParameters(const RtpParameters& parameters) override;
-
  private:
   bool can_send_track() const { return track_ && ssrc_; }
   // Helper function to construct options for
diff --git a/webrtc/api/rtpsenderinterface.h b/webrtc/api/rtpsenderinterface.h
index 2291bb4..c940dc7 100644
--- a/webrtc/api/rtpsenderinterface.h
+++ b/webrtc/api/rtpsenderinterface.h
@@ -15,6 +15,7 @@
 #define WEBRTC_API_RTPSENDERINTERFACE_H_
 
 #include <string>
+#include <vector>
 
 #include "webrtc/api/mediastreaminterface.h"
 #include "webrtc/api/proxy.h"
@@ -32,11 +33,10 @@
   virtual bool SetTrack(MediaStreamTrackInterface* track) = 0;
   virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0;
 
-  // Used to set the SSRC of the sender, once a local description has been set.
-  // If |ssrc| is 0, this indiates that the sender should disconnect from the
-  // underlying transport (this occurs if the sender isn't seen in a local
-  // description).
-  virtual void SetSsrc(uint32_t ssrc) = 0;
+  // Returns primary SSRC used by this sender for sending media.
+  // Returns 0 if not yet determined.
+  // TODO(deadbeef): Change to rtc::Optional.
+  // TODO(deadbeef): Remove? With GetParameters this should be redundant.
   virtual uint32_t ssrc() const = 0;
 
   // Audio or video sender?
@@ -46,11 +46,7 @@
   // to uniquely identify a receiver until we implement Unified Plan SDP.
   virtual std::string id() const = 0;
 
-  // TODO(deadbeef): Support one sender having multiple stream ids.
-  virtual void set_stream_id(const std::string& stream_id) = 0;
-  virtual std::string stream_id() const = 0;
-
-  virtual void Stop() = 0;
+  virtual std::vector<std::string> stream_ids() const = 0;
 
   virtual RtpParameters GetParameters() const = 0;
   virtual bool SetParameters(const RtpParameters& parameters) = 0;
@@ -63,13 +59,10 @@
 BEGIN_SIGNALING_PROXY_MAP(RtpSender)
 PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*)
 PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
-PROXY_METHOD1(void, SetSsrc, uint32_t)
 PROXY_CONSTMETHOD0(uint32_t, ssrc)
 PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
 PROXY_CONSTMETHOD0(std::string, id)
-PROXY_METHOD1(void, set_stream_id, const std::string&)
-PROXY_CONSTMETHOD0(std::string, stream_id)
-PROXY_METHOD0(void, Stop)
+PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
 PROXY_CONSTMETHOD0(RtpParameters, GetParameters);
 PROXY_METHOD1(bool, SetParameters, const RtpParameters&)
 END_SIGNALING_PROXY()