Remove a dependency of BaseChannel on WebRtcSession by having WebRtcSession push down new media descriptions to BaseChannel rather than having BaseChannel listen to the description changes from WebRtcSession.

This is a part of the big BUNDLE implementation at https://webrtc-codereview.appspot.com/45519004/

R=tommi@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#8743}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8743 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index c2ce02c..1af0e19 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -874,6 +874,9 @@
     }
     SetState(source == cricket::CS_LOCAL ?
         STATE_SENTINITIATE : STATE_RECEIVEDINITIATE);
+    if (!PushdownMediaDescription(cricket::CA_OFFER, source, err_desc)) {
+      SetError(BaseSession::ERROR_CONTENT, *err_desc);
+    }
     if (error() != cricket::BaseSession::ERROR_NONE) {
       return BadOfferSdp(source, GetSessionErrorMsg(), err_desc);
     }
@@ -884,6 +887,9 @@
     EnableChannels();
     SetState(source == cricket::CS_LOCAL ?
         STATE_SENTPRACCEPT : STATE_RECEIVEDPRACCEPT);
+    if (!PushdownMediaDescription(cricket::CA_PRANSWER, source, err_desc)) {
+      SetError(BaseSession::ERROR_CONTENT, *err_desc);
+    }
     if (error() != cricket::BaseSession::ERROR_NONE) {
       return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc);
     }
@@ -895,6 +901,9 @@
     EnableChannels();
     SetState(source == cricket::CS_LOCAL ?
         STATE_SENTACCEPT : STATE_RECEIVEDACCEPT);
+    if (!PushdownMediaDescription(cricket::CA_ANSWER, source, err_desc)) {
+      SetError(BaseSession::ERROR_CONTENT, *err_desc);
+    }
     if (error() != cricket::BaseSession::ERROR_NONE) {
       return BadAnswerSdp(source, GetSessionErrorMsg(), err_desc);
     }
@@ -902,6 +911,27 @@
   return true;
 }
 
+bool WebRtcSession::PushdownMediaDescription(
+    cricket::ContentAction action,
+    cricket::ContentSource source,
+    std::string* err) {
+  auto set_content = [this, action, source, err](cricket::BaseChannel* ch) {
+    if (!ch) {
+      return true;
+    } else if (source == cricket::CS_LOCAL) {
+      return ch->PushdownLocalDescription(
+          base_local_description(), action, err);
+    } else {
+      return ch->PushdownRemoteDescription(
+          base_remote_description(), action, err);
+    }
+  };
+
+  return (set_content(voice_channel()) &&
+          set_content(video_channel()) &&
+          set_content(data_channel()));
+}
+
 WebRtcSession::Action WebRtcSession::GetAction(const std::string& type) {
   if (type == SessionDescriptionInterface::kOffer) {
     return WebRtcSession::kOffer;
@@ -986,17 +1016,15 @@
 }
 
 bool WebRtcSession::GetLocalTrackIdBySsrc(uint32 ssrc, std::string* track_id) {
-  if (!BaseSession::local_description())
+  if (!base_local_description())
     return false;
-  return webrtc::GetTrackIdBySsrc(
-      BaseSession::local_description(), ssrc, track_id);
+  return webrtc::GetTrackIdBySsrc(base_local_description(), ssrc, track_id);
 }
 
 bool WebRtcSession::GetRemoteTrackIdBySsrc(uint32 ssrc, std::string* track_id) {
-  if (!BaseSession::remote_description())
+  if (!base_remote_description())
     return false;
-  return webrtc::GetTrackIdBySsrc(
-      BaseSession::remote_description(), ssrc, track_id);
+  return webrtc::GetTrackIdBySsrc(base_remote_description(), ssrc, track_id);
 }
 
 std::string WebRtcSession::BadStateErrMsg(State state) {
@@ -1124,7 +1152,7 @@
   uint32 send_ssrc = 0;
   // The Dtmf is negotiated per channel not ssrc, so we only check if the ssrc
   // exists.
-  if (!GetAudioSsrcByTrackId(BaseSession::local_description(), track_id,
+  if (!GetAudioSsrcByTrackId(base_local_description(), track_id,
                              &send_ssrc)) {
     LOG(LS_ERROR) << "CanInsertDtmf: Track does not exist: " << track_id;
     return false;
@@ -1140,7 +1168,7 @@
     return false;
   }
   uint32 send_ssrc = 0;
-  if (!VERIFY(GetAudioSsrcByTrackId(BaseSession::local_description(),
+  if (!VERIFY(GetAudioSsrcByTrackId(base_local_description(),
                                     track_id, &send_ssrc))) {
     LOG(LS_ERROR) << "InsertDtmf: Track does not exist: " << track_id;
     return false;
@@ -1419,11 +1447,11 @@
 // Returns the media index for a local ice candidate given the content name.
 bool WebRtcSession::GetLocalCandidateMediaIndex(const std::string& content_name,
                                                 int* sdp_mline_index) {
-  if (!BaseSession::local_description() || !sdp_mline_index)
+  if (!base_local_description() || !sdp_mline_index)
     return false;
 
   bool content_found = false;
-  const ContentInfos& contents = BaseSession::local_description()->contents();
+  const ContentInfos& contents = base_local_description()->contents();
   for (size_t index = 0; index < contents.size(); ++index) {
     if (contents[index].name == content_name) {
       *sdp_mline_index = static_cast<int>(index);
@@ -1468,8 +1496,7 @@
     const IceCandidateInterface* candidate) {
 
   size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index());
-  size_t remote_content_size =
-      BaseSession::remote_description()->contents().size();
+  size_t remote_content_size = base_remote_description()->contents().size();
   if (mediacontent_index >= remote_content_size) {
     LOG(LS_ERROR)
         << "UseRemoteCandidateInSession: Invalid candidate media index.";
@@ -1477,7 +1504,7 @@
   }
 
   cricket::ContentInfo content =
-      BaseSession::remote_description()->contents()[mediacontent_index];
+      base_remote_description()->contents()[mediacontent_index];
   std::vector<cricket::Candidate> candidates;
   candidates.push_back(candidate->candidate());
   // Invoking BaseSession method to handle remote candidates.
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index 14e4414..ce0fb0c 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -175,6 +175,15 @@
   const SessionDescriptionInterface* remote_description() const {
     return remote_desc_.get();
   }
+  // TODO(pthatcher): Cleanup the distinction between
+  // SessionDescription and SessionDescriptionInterface and remove
+  // these if possible.
+  const cricket::SessionDescription* base_local_description() const {
+    return BaseSession::local_description();
+  }
+  const cricket::SessionDescription* base_remote_description() const {
+    return BaseSession::remote_description();
+  }
 
   // Get the id used as a media stream track's "id" field from ssrc.
   virtual bool GetLocalTrackIdBySsrc(uint32 ssrc, std::string* track_id);
@@ -244,6 +253,19 @@
     metrics_observer_ = metrics_observer;
   }
 
+ protected:
+  // Don't fire a new description.  The only thing it's used for is to
+  // push new media descriptions to the BaseChannels.  But in
+  // WebRtcSession, we just push to the BaseChannels directly, so we
+  // don't need this (and it would cause the descriptions to be pushed
+  // down twice).
+  // TODO(pthatcher): Remove this method and signal completely from
+  // BaseSession once all the subclasses of BaseSession push to
+  // BaseChannels directly rather than relying on the signal, or once
+  // BaseChannel no longer listens to the event and requires
+  // descriptions to be pushed down.
+  virtual void SignalNewDescription() override {}
+
  private:
   // Indicates the type of SessionDescription in a call to SetLocalDescription
   // and SetRemoteDescription.
@@ -259,6 +281,12 @@
   bool UpdateSessionState(Action action, cricket::ContentSource source,
                           std::string* err_desc);
   static Action GetAction(const std::string& type);
+  // Push the media parts of the local or remote session description
+  // down to all of the channels.
+  bool PushdownMediaDescription(cricket::ContentAction action,
+                                cricket::ContentSource source,
+                                std::string* error_desc);
+
 
   // Transport related callbacks, override from cricket::BaseSession.
   virtual void OnTransportRequestSignaling(cricket::Transport* transport);
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc
index 3c2c64f..eb06aef 100644
--- a/talk/session/media/channel.cc
+++ b/talk/session/media/channel.cc
@@ -688,30 +688,48 @@
 
 void BaseChannel::OnNewLocalDescription(
     BaseSession* session, ContentAction action) {
-  const ContentInfo* content_info =
-      GetFirstContent(session->local_description());
-  const MediaContentDescription* content_desc =
-      GetContentDescription(content_info);
   std::string error_desc;
-  if (content_desc && content_info && !content_info->rejected &&
-      !SetLocalContent(content_desc, action, &error_desc)) {
+  if (!PushdownLocalDescription(
+          session->local_description(), action, &error_desc))  {
     SetSessionError(session_, BaseSession::ERROR_CONTENT, error_desc);
-    LOG(LS_ERROR) << "Failure in SetLocalContent with action " << action;
   }
 }
 
 void BaseChannel::OnNewRemoteDescription(
     BaseSession* session, ContentAction action) {
-  const ContentInfo* content_info =
-      GetFirstContent(session->remote_description());
+  std::string error_desc;
+  if (!PushdownRemoteDescription(
+          session->remote_description(), action, &error_desc))  {
+    SetSessionError(session_, BaseSession::ERROR_CONTENT, error_desc);
+  }
+}
+
+bool BaseChannel::PushdownLocalDescription(
+    const SessionDescription* local_desc, ContentAction action,
+    std::string* error_desc) {
+  const ContentInfo* content_info = GetFirstContent(local_desc);
   const MediaContentDescription* content_desc =
       GetContentDescription(content_info);
-  std::string error_desc;
   if (content_desc && content_info && !content_info->rejected &&
-      !SetRemoteContent(content_desc, action, &error_desc)) {
-    SetSessionError(session_, BaseSession::ERROR_CONTENT, error_desc);
-    LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action;
+      !SetLocalContent(content_desc, action, error_desc)) {
+    LOG(LS_ERROR) << "Failure in SetLocalContent with action " << action;
+    return false;
   }
+  return true;
+}
+
+bool BaseChannel::PushdownRemoteDescription(
+    const SessionDescription* remote_desc, ContentAction action,
+    std::string* error_desc) {
+  const ContentInfo* content_info = GetFirstContent(remote_desc);
+  const MediaContentDescription* content_desc =
+      GetContentDescription(content_info);
+  if (content_desc && content_info && !content_info->rejected &&
+      !SetRemoteContent(content_desc, action, error_desc)) {
+    LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action;
+    return false;
+  }
+  return true;
 }
 
 void BaseChannel::EnableMedia_w() {
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h
index bc4b6f7..aebb41f 100644
--- a/talk/session/media/channel.h
+++ b/talk/session/media/channel.h
@@ -108,6 +108,12 @@
   bool writable() const { return writable_; }
   bool IsStreamMuted(uint32 ssrc);
 
+  bool PushdownLocalDescription(const SessionDescription* local_desc,
+                                ContentAction action,
+                                std::string* error_desc);
+  bool PushdownRemoteDescription(const SessionDescription* remote_desc,
+                                ContentAction action,
+                                std::string* error_desc);
   // Channel control
   bool SetLocalContent(const MediaContentDescription* content,
                        ContentAction action,
diff --git a/webrtc/p2p/base/session.h b/webrtc/p2p/base/session.h
index 8dffca7..cdee801 100644
--- a/webrtc/p2p/base/session.h
+++ b/webrtc/p2p/base/session.h
@@ -409,6 +409,9 @@
   Error error_;
   std::string error_desc_;
 
+  // Fires the new description signal according to the current state.
+  virtual void SignalNewDescription();
+
  private:
   // Helper methods to push local and remote transport descriptions.
   bool PushdownLocalTransportDescription(
@@ -435,9 +438,6 @@
                                       const std::string& content_name,
                                       TransportDescription* info);
 
-  // Fires the new description signal according to the current state.
-  void SignalNewDescription();
-
   // Gets the ContentAction and ContentSource according to the session state.
   bool GetContentAction(ContentAction* action, ContentSource* source);