Home | History | Annotate | Download | only in webrtc
      1 /*
      2  * libjingle
      3  * Copyright 2012, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/app/webrtc/mediastreamsignaling.h"
     29 
     30 #include <vector>
     31 
     32 #include "talk/app/webrtc/audiotrack.h"
     33 #include "talk/app/webrtc/mediastreamproxy.h"
     34 #include "talk/app/webrtc/mediaconstraintsinterface.h"
     35 #include "talk/app/webrtc/mediastreamtrackproxy.h"
     36 #include "talk/app/webrtc/videotrack.h"
     37 #include "talk/base/bytebuffer.h"
     38 
     39 static const char kDefaultStreamLabel[] = "default";
     40 static const char kDefaultAudioTrackLabel[] = "defaulta0";
     41 static const char kDefaultVideoTrackLabel[] = "defaultv0";
     42 
     43 namespace webrtc {
     44 
     45 using talk_base::scoped_ptr;
     46 using talk_base::scoped_refptr;
     47 
     48 // Supported MediaConstraints.
     49 const char MediaConstraintsInterface::kOfferToReceiveAudio[] =
     50     "OfferToReceiveAudio";
     51 const char MediaConstraintsInterface::kOfferToReceiveVideo[] =
     52     "OfferToReceiveVideo";
     53 const char MediaConstraintsInterface::kIceRestart[] =
     54     "IceRestart";
     55 const char MediaConstraintsInterface::kUseRtpMux[] =
     56     "googUseRtpMUX";
     57 const char MediaConstraintsInterface::kVoiceActivityDetection[] =
     58     "VoiceActivityDetection";
     59 
     60 static bool ParseConstraints(
     61     const MediaConstraintsInterface* constraints,
     62     cricket::MediaSessionOptions* options, bool is_answer) {
     63   bool value;
     64   size_t mandatory_constraints_satisfied = 0;
     65 
     66   if (FindConstraint(constraints,
     67                      MediaConstraintsInterface::kOfferToReceiveAudio,
     68                      &value, &mandatory_constraints_satisfied)) {
     69     // |options-|has_audio| can only change from false to
     70     // true, but never change from true to false. This is to make sure
     71     // CreateOffer / CreateAnswer doesn't remove a media content
     72     // description that has been created.
     73     options->has_audio |= value;
     74   } else {
     75     // kOfferToReceiveAudio defaults to true according to spec.
     76     options->has_audio = true;
     77   }
     78 
     79   if (FindConstraint(constraints,
     80                      MediaConstraintsInterface::kOfferToReceiveVideo,
     81                      &value, &mandatory_constraints_satisfied)) {
     82     // |options->has_video| can only change from false to
     83     // true, but never change from true to false. This is to make sure
     84     // CreateOffer / CreateAnswer doesn't remove a media content
     85     // description that has been created.
     86     options->has_video |= value;
     87   } else {
     88     // kOfferToReceiveVideo defaults to false according to spec. But
     89     // if it is an answer and video is offered, we should still accept video
     90     // per default.
     91     options->has_video |= is_answer;
     92   }
     93 
     94   if (FindConstraint(constraints,
     95                      MediaConstraintsInterface::kVoiceActivityDetection,
     96                      &value, &mandatory_constraints_satisfied)) {
     97     options->vad_enabled = value;
     98   }
     99 
    100   if (FindConstraint(constraints,
    101                      MediaConstraintsInterface::kUseRtpMux,
    102                      &value, &mandatory_constraints_satisfied)) {
    103     options->bundle_enabled = value;
    104   } else {
    105     // kUseRtpMux defaults to true according to spec.
    106     options->bundle_enabled = true;
    107   }
    108   if (FindConstraint(constraints,
    109                      MediaConstraintsInterface::kIceRestart,
    110                      &value, &mandatory_constraints_satisfied)) {
    111     options->transport_options.ice_restart = value;
    112   } else {
    113     // kIceRestart defaults to false according to spec.
    114     options->transport_options.ice_restart = false;
    115   }
    116 
    117   if (!constraints) {
    118     return true;
    119   }
    120   return mandatory_constraints_satisfied == constraints->GetMandatory().size();
    121 }
    122 
    123 // Returns true if if at least one media content is present and
    124 // |options.bundle_enabled| is true.
    125 // Bundle will be enabled  by default if at least one media content is present
    126 // and the constraint kUseRtpMux has not disabled bundle.
    127 static bool EvaluateNeedForBundle(const cricket::MediaSessionOptions& options) {
    128   return options.bundle_enabled &&
    129       (options.has_audio || options.has_video || options.has_data());
    130 }
    131 
    132 // Factory class for creating remote MediaStreams and MediaStreamTracks.
    133 class RemoteMediaStreamFactory {
    134  public:
    135   explicit RemoteMediaStreamFactory(talk_base::Thread* signaling_thread)
    136       : signaling_thread_(signaling_thread) {
    137   }
    138 
    139   talk_base::scoped_refptr<MediaStreamInterface> CreateMediaStream(
    140       const std::string& stream_label) {
    141     return MediaStreamProxy::Create(
    142         signaling_thread_, MediaStream::Create(stream_label));
    143   }
    144 
    145   AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
    146                                      const std::string& track_id) {
    147     return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(stream,
    148                                                                       track_id);
    149   }
    150 
    151   VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
    152                                      const std::string& track_id) {
    153     return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(stream,
    154                                                                       track_id);
    155   }
    156 
    157  private:
    158   template <typename TI, typename T, typename TP>
    159   TI* AddTrack(MediaStreamInterface* stream, const std::string& track_id) {
    160     talk_base::scoped_refptr<TI> track(
    161         TP::Create(signaling_thread_, T::Create(track_id, NULL)));
    162     track->set_state(webrtc::MediaStreamTrackInterface::kLive);
    163     if (stream->AddTrack(track)) {
    164       return track;
    165     }
    166     return NULL;
    167   }
    168 
    169   talk_base::Thread* signaling_thread_;
    170 };
    171 
    172 MediaStreamSignaling::MediaStreamSignaling(
    173     talk_base::Thread* signaling_thread,
    174     MediaStreamSignalingObserver* stream_observer)
    175     : signaling_thread_(signaling_thread),
    176       data_channel_factory_(NULL),
    177       stream_observer_(stream_observer),
    178       local_streams_(StreamCollection::Create()),
    179       remote_streams_(StreamCollection::Create()),
    180       remote_stream_factory_(new RemoteMediaStreamFactory(signaling_thread)),
    181       last_allocated_sctp_id_(0) {
    182   options_.has_video = false;
    183   options_.has_audio = false;
    184 }
    185 
    186 MediaStreamSignaling::~MediaStreamSignaling() {
    187 }
    188 
    189 void MediaStreamSignaling::TearDown() {
    190   OnAudioChannelClose();
    191   OnVideoChannelClose();
    192   OnDataChannelClose();
    193 }
    194 
    195 bool MediaStreamSignaling::IsSctpIdAvailable(int id) const {
    196   if (id < 0 || id > static_cast<int>(cricket::kMaxSctpSid))
    197     return false;
    198   for (DataChannels::const_iterator iter = data_channels_.begin();
    199        iter != data_channels_.end();
    200        ++iter) {
    201     if (iter->second->id() == id) {
    202       return false;
    203     }
    204   }
    205   return true;
    206 }
    207 
    208 // Gets the first id that has not been taken by existing data
    209 // channels. Starting from 1.
    210 // Returns false if no id can be allocated.
    211 // TODO(jiayl): Update to some kind of even/odd random number selection when the
    212 // rules are fully standardized.
    213 bool MediaStreamSignaling::AllocateSctpId(int* id) {
    214   do {
    215     last_allocated_sctp_id_++;
    216   } while (last_allocated_sctp_id_ <= static_cast<int>(cricket::kMaxSctpSid) &&
    217            !IsSctpIdAvailable(last_allocated_sctp_id_));
    218 
    219   if (last_allocated_sctp_id_ > static_cast<int>(cricket::kMaxSctpSid)) {
    220     last_allocated_sctp_id_ = cricket::kMaxSctpSid;
    221     return false;
    222   }
    223 
    224   *id = last_allocated_sctp_id_;
    225   return true;
    226 }
    227 
    228 bool MediaStreamSignaling::AddDataChannel(DataChannel* data_channel) {
    229   ASSERT(data_channel != NULL);
    230   if (data_channels_.find(data_channel->label()) != data_channels_.end()) {
    231     LOG(LS_ERROR) << "DataChannel with label " << data_channel->label()
    232                   << " already exists.";
    233     return false;
    234   }
    235   data_channels_[data_channel->label()] = data_channel;
    236   return true;
    237 }
    238 
    239 bool MediaStreamSignaling::AddDataChannelFromOpenMessage(
    240     const std::string& label,
    241     const DataChannelInit& config) {
    242   if (!data_channel_factory_) {
    243     LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
    244                     << "are not supported.";
    245     return false;
    246   }
    247 
    248   if (data_channels_.find(label) != data_channels_.end()) {
    249     LOG(LS_ERROR) << "DataChannel with label " << label
    250                   << " already exists.";
    251     return false;
    252   }
    253   scoped_refptr<DataChannel> channel(
    254       data_channel_factory_->CreateDataChannel(label, &config));
    255   data_channels_[label] = channel;
    256   stream_observer_->OnAddDataChannel(channel);
    257   // It's immediately ready to use.
    258   channel->OnChannelReady(true);
    259   return true;
    260 }
    261 
    262 bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
    263   if (local_streams_->find(local_stream->label()) != NULL) {
    264     LOG(LS_WARNING) << "MediaStream with label " << local_stream->label()
    265                     << "already exist.";
    266     return false;
    267   }
    268   local_streams_->AddStream(local_stream);
    269 
    270   // Find tracks that has already been configured in SDP. This can occur if a
    271   // local session description that contains the MSID of these tracks is set
    272   // before AddLocalStream is called. It can also occur if the local session
    273   // description is not changed and RemoveLocalStream
    274   // is called and later AddLocalStream is called again with the same stream.
    275   AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
    276   for (AudioTrackVector::const_iterator it = audio_tracks.begin();
    277        it != audio_tracks.end(); ++it) {
    278     TrackInfos::const_iterator track_info_it =
    279         local_audio_tracks_.find((*it)->id());
    280     if (track_info_it != local_audio_tracks_.end()) {
    281       const TrackInfo& info = track_info_it->second;
    282       OnLocalTrackSeen(info.stream_label, info.track_id, info.ssrc,
    283                        cricket::MEDIA_TYPE_AUDIO);
    284     }
    285   }
    286 
    287   VideoTrackVector video_tracks = local_stream->GetVideoTracks();
    288   for (VideoTrackVector::const_iterator it = video_tracks.begin();
    289        it != video_tracks.end(); ++it) {
    290     TrackInfos::const_iterator track_info_it =
    291         local_video_tracks_.find((*it)->id());
    292     if (track_info_it != local_video_tracks_.end()) {
    293       const TrackInfo& info = track_info_it->second;
    294       OnLocalTrackSeen(info.stream_label, info.track_id, info.ssrc,
    295                        cricket::MEDIA_TYPE_VIDEO);
    296     }
    297   }
    298   return true;
    299 }
    300 
    301 void MediaStreamSignaling::RemoveLocalStream(
    302     MediaStreamInterface* local_stream) {
    303   local_streams_->RemoveStream(local_stream);
    304   stream_observer_->OnRemoveLocalStream(local_stream);
    305 }
    306 
    307 bool MediaStreamSignaling::GetOptionsForOffer(
    308     const MediaConstraintsInterface* constraints,
    309     cricket::MediaSessionOptions* options) {
    310   UpdateSessionOptions();
    311   if (!ParseConstraints(constraints, &options_, false)) {
    312     return false;
    313   }
    314   options_.bundle_enabled = EvaluateNeedForBundle(options_);
    315   *options = options_;
    316   return true;
    317 }
    318 
    319 bool MediaStreamSignaling::GetOptionsForAnswer(
    320     const MediaConstraintsInterface* constraints,
    321     cricket::MediaSessionOptions* options) {
    322   UpdateSessionOptions();
    323 
    324   // Copy the |options_| to not let the flag MediaSessionOptions::has_audio and
    325   // MediaSessionOptions::has_video affect subsequent offers.
    326   cricket::MediaSessionOptions current_options = options_;
    327   if (!ParseConstraints(constraints, &current_options, true)) {
    328     return false;
    329   }
    330   current_options.bundle_enabled = EvaluateNeedForBundle(current_options);
    331   *options = current_options;
    332   return true;
    333 }
    334 
    335 // Updates or creates remote MediaStream objects given a
    336 // remote SessionDesription.
    337 // If the remote SessionDesription contains new remote MediaStreams
    338 // the observer OnAddStream method is called. If a remote MediaStream is missing
    339 // from the remote SessionDescription OnRemoveStream is called.
    340 void MediaStreamSignaling::OnRemoteDescriptionChanged(
    341     const SessionDescriptionInterface* desc) {
    342   const cricket::SessionDescription* remote_desc = desc->description();
    343   talk_base::scoped_refptr<StreamCollection> new_streams(
    344       StreamCollection::Create());
    345 
    346   // Find all audio rtp streams and create corresponding remote AudioTracks
    347   // and MediaStreams.
    348   const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
    349   if (audio_content) {
    350     const cricket::AudioContentDescription* desc =
    351         static_cast<const cricket::AudioContentDescription*>(
    352             audio_content->description);
    353     UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
    354     remote_info_.default_audio_track_needed =
    355         desc->direction() == cricket::MD_SENDRECV && desc->streams().empty();
    356   }
    357 
    358   // Find all video rtp streams and create corresponding remote VideoTracks
    359   // and MediaStreams.
    360   const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
    361   if (video_content) {
    362     const cricket::VideoContentDescription* desc =
    363         static_cast<const cricket::VideoContentDescription*>(
    364             video_content->description);
    365     UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
    366     remote_info_.default_video_track_needed =
    367         desc->direction() == cricket::MD_SENDRECV && desc->streams().empty();
    368   }
    369 
    370   // Update the DataChannels with the information from the remote peer.
    371   const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc);
    372   if (data_content) {
    373     const cricket::DataContentDescription* data_desc =
    374         static_cast<const cricket::DataContentDescription*>(
    375             data_content->description);
    376     if (data_desc->protocol() == cricket::kMediaProtocolDtlsSctp) {
    377       UpdateRemoteSctpDataChannels();
    378     } else {
    379       UpdateRemoteRtpDataChannels(data_desc->streams());
    380     }
    381   }
    382 
    383   // Iterate new_streams and notify the observer about new MediaStreams.
    384   for (size_t i = 0; i < new_streams->count(); ++i) {
    385     MediaStreamInterface* new_stream = new_streams->at(i);
    386     stream_observer_->OnAddRemoteStream(new_stream);
    387   }
    388 
    389   // Find removed MediaStreams.
    390   if (remote_info_.IsDefaultMediaStreamNeeded() &&
    391       remote_streams_->find(kDefaultStreamLabel) != NULL) {
    392     // The default media stream already exists. No need to do anything.
    393   } else {
    394     UpdateEndedRemoteMediaStreams();
    395     remote_info_.msid_supported |= remote_streams_->count() > 0;
    396   }
    397   MaybeCreateDefaultStream();
    398 }
    399 
    400 void MediaStreamSignaling::OnLocalDescriptionChanged(
    401     const SessionDescriptionInterface* desc) {
    402   const cricket::ContentInfo* audio_content =
    403       GetFirstAudioContent(desc->description());
    404   if (audio_content) {
    405     if (audio_content->rejected) {
    406       RejectRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
    407     }
    408     const cricket::AudioContentDescription* audio_desc =
    409         static_cast<const cricket::AudioContentDescription*>(
    410             audio_content->description);
    411     UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
    412   }
    413 
    414   const cricket::ContentInfo* video_content =
    415       GetFirstVideoContent(desc->description());
    416   if (video_content) {
    417     if (video_content->rejected) {
    418       RejectRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
    419     }
    420     const cricket::VideoContentDescription* video_desc =
    421         static_cast<const cricket::VideoContentDescription*>(
    422             video_content->description);
    423     UpdateLocalTracks(video_desc->streams(), video_desc->type());
    424   }
    425 
    426   const cricket::ContentInfo* data_content =
    427       GetFirstDataContent(desc->description());
    428   if (data_content) {
    429     const cricket::DataContentDescription* data_desc =
    430         static_cast<const cricket::DataContentDescription*>(
    431             data_content->description);
    432     if (data_desc->protocol() == cricket::kMediaProtocolDtlsSctp) {
    433       UpdateLocalSctpDataChannels();
    434     } else {
    435       UpdateLocalRtpDataChannels(data_desc->streams());
    436     }
    437   }
    438 }
    439 
    440 void MediaStreamSignaling::OnAudioChannelClose() {
    441   RejectRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
    442 }
    443 
    444 void MediaStreamSignaling::OnVideoChannelClose() {
    445   RejectRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
    446 }
    447 
    448 void MediaStreamSignaling::OnDataChannelClose() {
    449   DataChannels::iterator it = data_channels_.begin();
    450   for (; it != data_channels_.end(); ++it) {
    451     DataChannel* data_channel = it->second;
    452     data_channel->OnDataEngineClose();
    453   }
    454 }
    455 
    456 bool MediaStreamSignaling::GetRemoteAudioTrackSsrc(
    457     const std::string& track_id, uint32* ssrc) const {
    458   TrackInfos::const_iterator it = remote_audio_tracks_.find(track_id);
    459   if (it == remote_audio_tracks_.end()) {
    460     return false;
    461   }
    462 
    463   *ssrc = it->second.ssrc;
    464   return true;
    465 }
    466 
    467 bool MediaStreamSignaling::GetRemoteVideoTrackSsrc(
    468     const std::string& track_id, uint32* ssrc) const {
    469   TrackInfos::const_iterator it = remote_video_tracks_.find(track_id);
    470   if (it == remote_video_tracks_.end()) {
    471     return false;
    472   }
    473 
    474   *ssrc = it->second.ssrc;
    475   return true;
    476 }
    477 
    478 void MediaStreamSignaling::UpdateSessionOptions() {
    479   options_.streams.clear();
    480   if (local_streams_ != NULL) {
    481     for (size_t i = 0; i < local_streams_->count(); ++i) {
    482       MediaStreamInterface* stream = local_streams_->at(i);
    483 
    484       AudioTrackVector audio_tracks(stream->GetAudioTracks());
    485       if (!audio_tracks.empty()) {
    486         options_.has_audio = true;
    487       }
    488 
    489       // For each audio track in the stream, add it to the MediaSessionOptions.
    490       for (size_t j = 0; j < audio_tracks.size(); ++j) {
    491         scoped_refptr<MediaStreamTrackInterface> track(audio_tracks[j]);
    492         options_.AddStream(cricket::MEDIA_TYPE_AUDIO, track->id(),
    493                            stream->label());
    494       }
    495 
    496       VideoTrackVector video_tracks(stream->GetVideoTracks());
    497       if (!video_tracks.empty()) {
    498         options_.has_video = true;
    499       }
    500       // For each video track in the stream, add it to the MediaSessionOptions.
    501       for (size_t j = 0; j < video_tracks.size(); ++j) {
    502         scoped_refptr<MediaStreamTrackInterface> track(video_tracks[j]);
    503         options_.AddStream(cricket::MEDIA_TYPE_VIDEO, track->id(),
    504                            stream->label());
    505       }
    506     }
    507   }
    508 
    509   // Check for data channels.
    510   DataChannels::const_iterator data_channel_it = data_channels_.begin();
    511   for (; data_channel_it != data_channels_.end(); ++data_channel_it) {
    512     const DataChannel* channel = data_channel_it->second;
    513     if (channel->state() == DataChannel::kConnecting ||
    514         channel->state() == DataChannel::kOpen) {
    515       // |streamid| and |sync_label| are both set to the DataChannel label
    516       // here so they can be signaled the same way as MediaStreams and Tracks.
    517       // For MediaStreams, the sync_label is the MediaStream label and the
    518       // track label is the same as |streamid|.
    519       const std::string& streamid = channel->label();
    520       const std::string& sync_label = channel->label();
    521       options_.AddStream(cricket::MEDIA_TYPE_DATA, streamid, sync_label);
    522     }
    523   }
    524 }
    525 
    526 void MediaStreamSignaling::UpdateRemoteStreamsList(
    527     const cricket::StreamParamsVec& streams,
    528     cricket::MediaType media_type,
    529     StreamCollection* new_streams) {
    530   TrackInfos* current_tracks = GetRemoteTracks(media_type);
    531 
    532   // Find removed tracks. Ie tracks where the track id or ssrc don't match the
    533   // new StreamParam.
    534   TrackInfos::iterator track_it = current_tracks->begin();
    535   while (track_it != current_tracks->end()) {
    536     TrackInfo info = track_it->second;
    537     cricket::StreamParams params;
    538     if (!cricket::GetStreamBySsrc(streams, info.ssrc, &params) ||
    539         params.id != info.track_id) {
    540       OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
    541       current_tracks->erase(track_it++);
    542     } else {
    543       ++track_it;
    544     }
    545   }
    546 
    547   // Find new and active tracks.
    548   for (cricket::StreamParamsVec::const_iterator it = streams.begin();
    549        it != streams.end(); ++it) {
    550     // The sync_label is the MediaStream label and the |stream.id| is the
    551     // track id.
    552     const std::string& stream_label = it->sync_label;
    553     const std::string& track_id = it->id;
    554     uint32 ssrc = it->first_ssrc();
    555 
    556     talk_base::scoped_refptr<MediaStreamInterface> stream =
    557         remote_streams_->find(stream_label);
    558     if (!stream) {
    559       // This is a new MediaStream. Create a new remote MediaStream.
    560       stream = remote_stream_factory_->CreateMediaStream(stream_label);
    561       remote_streams_->AddStream(stream);
    562       new_streams->AddStream(stream);
    563     }
    564 
    565     TrackInfos::iterator track_it = current_tracks->find(track_id);
    566     if (track_it == current_tracks->end()) {
    567       (*current_tracks)[track_id] =
    568           TrackInfo(stream_label, track_id, ssrc);
    569       OnRemoteTrackSeen(stream_label, track_id, it->first_ssrc(), media_type);
    570     }
    571   }
    572 }
    573 
    574 void MediaStreamSignaling::OnRemoteTrackSeen(const std::string& stream_label,
    575                                              const std::string& track_id,
    576                                              uint32 ssrc,
    577                                              cricket::MediaType media_type) {
    578   MediaStreamInterface* stream = remote_streams_->find(stream_label);
    579 
    580   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    581     AudioTrackInterface* audio_track =
    582         remote_stream_factory_->AddAudioTrack(stream, track_id);
    583     stream_observer_->OnAddRemoteAudioTrack(stream, audio_track, ssrc);
    584   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    585     VideoTrackInterface* video_track =
    586         remote_stream_factory_->AddVideoTrack(stream, track_id);
    587     stream_observer_->OnAddRemoteVideoTrack(stream, video_track, ssrc);
    588   } else {
    589     ASSERT(false && "Invalid media type");
    590   }
    591 }
    592 
    593 void MediaStreamSignaling::OnRemoteTrackRemoved(
    594     const std::string& stream_label,
    595     const std::string& track_id,
    596     cricket::MediaType media_type) {
    597   MediaStreamInterface* stream = remote_streams_->find(stream_label);
    598 
    599   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    600     talk_base::scoped_refptr<AudioTrackInterface> audio_track =
    601         stream->FindAudioTrack(track_id);
    602     audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    603     stream->RemoveTrack(audio_track);
    604     stream_observer_->OnRemoveRemoteAudioTrack(stream, audio_track);
    605   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    606     talk_base::scoped_refptr<VideoTrackInterface> video_track =
    607         stream->FindVideoTrack(track_id);
    608     video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    609     stream->RemoveTrack(video_track);
    610     stream_observer_->OnRemoveRemoteVideoTrack(stream, video_track);
    611   } else {
    612     ASSERT(false && "Invalid media type");
    613   }
    614 }
    615 
    616 void MediaStreamSignaling::RejectRemoteTracks(cricket::MediaType media_type) {
    617   TrackInfos* current_tracks = GetRemoteTracks(media_type);
    618   for (TrackInfos::iterator track_it = current_tracks->begin();
    619        track_it != current_tracks->end(); ++track_it) {
    620     TrackInfo info = track_it->second;
    621     MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
    622     if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    623       AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
    624       track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    625     }
    626     if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    627       VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
    628       track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    629     }
    630   }
    631 }
    632 
    633 void MediaStreamSignaling::UpdateEndedRemoteMediaStreams() {
    634   std::vector<scoped_refptr<MediaStreamInterface> > streams_to_remove;
    635   for (size_t i = 0; i < remote_streams_->count(); ++i) {
    636     MediaStreamInterface*stream = remote_streams_->at(i);
    637     if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
    638       streams_to_remove.push_back(stream);
    639     }
    640   }
    641 
    642   std::vector<scoped_refptr<MediaStreamInterface> >::const_iterator it;
    643   for (it = streams_to_remove.begin(); it != streams_to_remove.end(); ++it) {
    644     remote_streams_->RemoveStream(*it);
    645     stream_observer_->OnRemoveRemoteStream(*it);
    646   }
    647 }
    648 
    649 void MediaStreamSignaling::MaybeCreateDefaultStream() {
    650   if (!remote_info_.IsDefaultMediaStreamNeeded())
    651     return;
    652 
    653   bool default_created = false;
    654 
    655   scoped_refptr<MediaStreamInterface> default_remote_stream =
    656       remote_streams_->find(kDefaultStreamLabel);
    657   if (default_remote_stream == NULL) {
    658     default_created = true;
    659     default_remote_stream =
    660         remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
    661     remote_streams_->AddStream(default_remote_stream);
    662   }
    663   if (remote_info_.default_audio_track_needed &&
    664       default_remote_stream->GetAudioTracks().size() == 0) {
    665     remote_audio_tracks_[kDefaultAudioTrackLabel] =
    666         TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0);
    667     OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
    668                        cricket::MEDIA_TYPE_AUDIO);
    669   }
    670   if (remote_info_.default_video_track_needed &&
    671       default_remote_stream->GetVideoTracks().size() == 0) {
    672     remote_video_tracks_[kDefaultVideoTrackLabel] =
    673         TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0);
    674     OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
    675                        cricket::MEDIA_TYPE_VIDEO);
    676   }
    677   if (default_created) {
    678     stream_observer_->OnAddRemoteStream(default_remote_stream);
    679   }
    680 }
    681 
    682 MediaStreamSignaling::TrackInfos* MediaStreamSignaling::GetRemoteTracks(
    683     cricket::MediaType type) {
    684   if (type == cricket::MEDIA_TYPE_AUDIO)
    685     return &remote_audio_tracks_;
    686   else if (type == cricket::MEDIA_TYPE_VIDEO)
    687     return &remote_video_tracks_;
    688   ASSERT(false && "Unknown MediaType");
    689   return NULL;
    690 }
    691 
    692 MediaStreamSignaling::TrackInfos* MediaStreamSignaling::GetLocalTracks(
    693     cricket::MediaType media_type) {
    694   ASSERT(media_type == cricket::MEDIA_TYPE_AUDIO ||
    695          media_type == cricket::MEDIA_TYPE_VIDEO);
    696 
    697   return (media_type == cricket::MEDIA_TYPE_AUDIO) ?
    698       &local_audio_tracks_ : &local_video_tracks_;
    699 }
    700 
    701 void MediaStreamSignaling::UpdateLocalTracks(
    702     const std::vector<cricket::StreamParams>& streams,
    703     cricket::MediaType media_type) {
    704   TrackInfos* current_tracks = GetLocalTracks(media_type);
    705 
    706   // Find removed tracks. Ie tracks where the track id or ssrc don't match the
    707   // new StreamParam.
    708   TrackInfos::iterator track_it = current_tracks->begin();
    709   while (track_it != current_tracks->end()) {
    710     TrackInfo info = track_it->second;
    711     cricket::StreamParams params;
    712     if (!cricket::GetStreamBySsrc(streams, info.ssrc, &params) ||
    713         params.id != info.track_id) {
    714       OnLocalTrackRemoved(info.stream_label, info.track_id, media_type);
    715       current_tracks->erase(track_it++);
    716     } else {
    717       ++track_it;
    718     }
    719   }
    720 
    721   // Find new and active tracks.
    722   for (cricket::StreamParamsVec::const_iterator it = streams.begin();
    723        it != streams.end(); ++it) {
    724     // The sync_label is the MediaStream label and the |stream.id| is the
    725     // track id.
    726     const std::string& stream_label = it->sync_label;
    727     const std::string& track_id = it->id;
    728     uint32 ssrc = it->first_ssrc();
    729     TrackInfos::iterator track_it =  current_tracks->find(track_id);
    730     if (track_it == current_tracks->end()) {
    731       (*current_tracks)[track_id] =
    732           TrackInfo(stream_label, track_id, ssrc);
    733       OnLocalTrackSeen(stream_label, track_id, it->first_ssrc(),
    734                        media_type);
    735     }
    736   }
    737 }
    738 
    739 void MediaStreamSignaling::OnLocalTrackSeen(
    740     const std::string& stream_label,
    741     const std::string& track_id,
    742     uint32 ssrc,
    743     cricket::MediaType media_type) {
    744   MediaStreamInterface* stream = local_streams_->find(stream_label);
    745   if (!stream) {
    746     LOG(LS_WARNING) << "An unknown local MediaStream with label "
    747                     << stream_label <<  " has been configured.";
    748     return;
    749   }
    750 
    751   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    752     AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
    753     if (!audio_track) {
    754       LOG(LS_WARNING) << "An unknown local AudioTrack with id , "
    755                       << track_id <<  " has been configured.";
    756       return;
    757     }
    758     stream_observer_->OnAddLocalAudioTrack(stream, audio_track, ssrc);
    759   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    760     VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
    761     if (!video_track) {
    762       LOG(LS_WARNING) << "An unknown local VideoTrack with id , "
    763                       << track_id <<  " has been configured.";
    764       return;
    765     }
    766     stream_observer_->OnAddLocalVideoTrack(stream, video_track, ssrc);
    767   } else {
    768     ASSERT(false && "Invalid media type");
    769   }
    770 }
    771 
    772 void MediaStreamSignaling::OnLocalTrackRemoved(
    773     const std::string& stream_label,
    774     const std::string& track_id,
    775     cricket::MediaType media_type) {
    776   MediaStreamInterface* stream = local_streams_->find(stream_label);
    777   if (!stream) {
    778     // This is the normal case. Ie RemoveLocalStream has been called and the
    779     // SessionDescriptions has been renegotiated.
    780     return;
    781   }
    782   // A track has been removed from the SessionDescription but the MediaStream
    783   // is still associated with MediaStreamSignaling. This only occurs if the SDP
    784   // doesn't match with the calls to AddLocalStream and RemoveLocalStream.
    785 
    786   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    787     AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
    788     if (!audio_track) {
    789       return;
    790     }
    791     stream_observer_->OnRemoveLocalAudioTrack(stream, audio_track);
    792   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    793     VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
    794     if (!video_track) {
    795       return;
    796     }
    797     stream_observer_->OnRemoveLocalVideoTrack(stream, video_track);
    798   } else {
    799     ASSERT(false && "Invalid media type.");
    800   }
    801 }
    802 
    803 void MediaStreamSignaling::UpdateLocalRtpDataChannels(
    804     const cricket::StreamParamsVec& streams) {
    805   std::vector<std::string> existing_channels;
    806 
    807   // Find new and active data channels.
    808   for (cricket::StreamParamsVec::const_iterator it =streams.begin();
    809        it != streams.end(); ++it) {
    810     // |it->sync_label| is actually the data channel label. The reason is that
    811     // we use the same naming of data channels as we do for
    812     // MediaStreams and Tracks.
    813     // For MediaStreams, the sync_label is the MediaStream label and the
    814     // track label is the same as |streamid|.
    815     const std::string& channel_label = it->sync_label;
    816     DataChannels::iterator data_channel_it = data_channels_.find(channel_label);
    817     if (!VERIFY(data_channel_it != data_channels_.end())) {
    818       continue;
    819     }
    820     // Set the SSRC the data channel should use for sending.
    821     data_channel_it->second->SetSendSsrc(it->first_ssrc());
    822     existing_channels.push_back(data_channel_it->first);
    823   }
    824 
    825   UpdateClosingDataChannels(existing_channels, true);
    826 }
    827 
    828 void MediaStreamSignaling::UpdateRemoteRtpDataChannels(
    829     const cricket::StreamParamsVec& streams) {
    830   std::vector<std::string> existing_channels;
    831 
    832   // Find new and active data channels.
    833   for (cricket::StreamParamsVec::const_iterator it = streams.begin();
    834        it != streams.end(); ++it) {
    835     // The data channel label is either the mslabel or the SSRC if the mslabel
    836     // does not exist. Ex a=ssrc:444330170 mslabel:test1.
    837     std::string label = it->sync_label.empty() ?
    838         talk_base::ToString(it->first_ssrc()) : it->sync_label;
    839     DataChannels::iterator data_channel_it =
    840         data_channels_.find(label);
    841     if (data_channel_it == data_channels_.end()) {
    842       // This is a new data channel.
    843       CreateRemoteDataChannel(label, it->first_ssrc());
    844     } else {
    845       data_channel_it->second->SetReceiveSsrc(it->first_ssrc());
    846     }
    847     existing_channels.push_back(label);
    848   }
    849 
    850   UpdateClosingDataChannels(existing_channels, false);
    851 }
    852 
    853 void MediaStreamSignaling::UpdateClosingDataChannels(
    854     const std::vector<std::string>& active_channels, bool is_local_update) {
    855   DataChannels::iterator it = data_channels_.begin();
    856   while (it != data_channels_.end()) {
    857     DataChannel* data_channel = it->second;
    858     if (std::find(active_channels.begin(), active_channels.end(),
    859                   data_channel->label()) != active_channels.end()) {
    860       ++it;
    861       continue;
    862     }
    863 
    864     if (is_local_update)
    865       data_channel->SetSendSsrc(0);
    866     else
    867       data_channel->RemotePeerRequestClose();
    868 
    869     if (data_channel->state() == DataChannel::kClosed) {
    870       data_channels_.erase(it);
    871       it = data_channels_.begin();
    872     } else {
    873       ++it;
    874     }
    875   }
    876 }
    877 
    878 void MediaStreamSignaling::CreateRemoteDataChannel(const std::string& label,
    879                                                    uint32 remote_ssrc) {
    880   if (!data_channel_factory_) {
    881     LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
    882                     << "are not supported.";
    883     return;
    884   }
    885   scoped_refptr<DataChannel> channel(
    886       data_channel_factory_->CreateDataChannel(label, NULL));
    887   channel->SetReceiveSsrc(remote_ssrc);
    888   stream_observer_->OnAddDataChannel(channel);
    889 }
    890 
    891 
    892 // Format defined at
    893 // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
    894 const uint8 DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03;
    895 
    896 enum DataChannelOpenMessageChannelType {
    897   DCOMCT_ORDERED_RELIABLE = 0x00,
    898   DCOMCT_ORDERED_PARTIAL_RTXS = 0x01,
    899   DCOMCT_ORDERED_PARTIAL_TIME = 0x02,
    900   DCOMCT_UNORDERED_RELIABLE = 0x80,
    901   DCOMCT_UNORDERED_PARTIAL_RTXS = 0x81,
    902   DCOMCT_UNORDERED_PARTIAL_TIME = 0x82,
    903 };
    904 
    905 bool MediaStreamSignaling::ParseDataChannelOpenMessage(
    906     const talk_base::Buffer& payload,
    907     std::string* label,
    908     DataChannelInit* config) {
    909   // Format defined at
    910   // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
    911 
    912   talk_base::ByteBuffer buffer(payload.data(), payload.length());
    913 
    914   uint8 message_type;
    915   if (!buffer.ReadUInt8(&message_type)) {
    916     LOG(LS_WARNING) << "Could not read OPEN message type.";
    917     return false;
    918   }
    919   if (message_type != DATA_CHANNEL_OPEN_MESSAGE_TYPE) {
    920     LOG(LS_WARNING) << "Data Channel OPEN message of unexpected type: "
    921                     << message_type;
    922     return false;
    923   }
    924 
    925   uint8 channel_type;
    926   if (!buffer.ReadUInt8(&channel_type)) {
    927     LOG(LS_WARNING) << "Could not read OPEN message channel type.";
    928     return false;
    929   }
    930   uint16 priority;
    931   if (!buffer.ReadUInt16(&priority)) {
    932     LOG(LS_WARNING) << "Could not read OPEN message reliabilility prioirty.";
    933     return false;
    934   }
    935   uint32 reliability_param;
    936   if (!buffer.ReadUInt32(&reliability_param)) {
    937     LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
    938     return false;
    939   }
    940   uint16 label_length;
    941   if (!buffer.ReadUInt16(&label_length)) {
    942     LOG(LS_WARNING) << "Could not read OPEN message label length.";
    943     return false;
    944   }
    945   uint16 protocol_length;
    946   if (!buffer.ReadUInt16(&protocol_length)) {
    947     LOG(LS_WARNING) << "Could not read OPEN message protocol length.";
    948     return false;
    949   }
    950   if (!buffer.ReadString(label, (size_t) label_length)) {
    951     LOG(LS_WARNING) << "Could not read OPEN message label";
    952     return false;
    953   }
    954   if (!buffer.ReadString(&config->protocol, protocol_length)) {
    955     LOG(LS_WARNING) << "Could not read OPEN message protocol.";
    956     return false;
    957   }
    958 
    959   config->ordered = true;
    960   switch (channel_type) {
    961     case DCOMCT_UNORDERED_RELIABLE:
    962     case DCOMCT_UNORDERED_PARTIAL_RTXS:
    963     case DCOMCT_UNORDERED_PARTIAL_TIME:
    964       config->ordered = false;
    965   }
    966 
    967   config->maxRetransmits = -1;
    968   config->maxRetransmitTime = -1;
    969   switch (channel_type) {
    970     case DCOMCT_ORDERED_PARTIAL_RTXS:
    971     case DCOMCT_UNORDERED_PARTIAL_RTXS:
    972       config->maxRetransmits = reliability_param;
    973 
    974     case DCOMCT_ORDERED_PARTIAL_TIME:
    975     case DCOMCT_UNORDERED_PARTIAL_TIME:
    976       config->maxRetransmitTime = reliability_param;
    977   }
    978 
    979   return true;
    980 }
    981 
    982 bool MediaStreamSignaling::WriteDataChannelOpenMessage(
    983     const std::string& label,
    984     const DataChannelInit& config,
    985     talk_base::Buffer* payload) {
    986   // Format defined at
    987   // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
    988   // TODO(pthatcher)
    989 
    990   uint8 channel_type = 0;
    991   uint32 reliability_param = 0;
    992   uint16 priority = 0;
    993   if (config.ordered) {
    994     if (config.maxRetransmits > -1) {
    995       channel_type = DCOMCT_ORDERED_PARTIAL_RTXS;
    996       reliability_param = config.maxRetransmits;
    997     } else if (config.maxRetransmitTime > -1) {
    998       channel_type = DCOMCT_ORDERED_PARTIAL_TIME;
    999       reliability_param = config.maxRetransmitTime;
   1000     } else {
   1001       channel_type = DCOMCT_ORDERED_RELIABLE;
   1002     }
   1003   } else {
   1004     if (config.maxRetransmits > -1) {
   1005       channel_type = DCOMCT_UNORDERED_PARTIAL_RTXS;
   1006       reliability_param = config.maxRetransmits;
   1007     } else if (config.maxRetransmitTime > -1) {
   1008       channel_type = DCOMCT_UNORDERED_PARTIAL_TIME;
   1009       reliability_param = config.maxRetransmitTime;
   1010     } else {
   1011       channel_type = DCOMCT_UNORDERED_RELIABLE;
   1012     }
   1013   }
   1014 
   1015   talk_base::ByteBuffer buffer(
   1016       NULL, 20 + label.length() + config.protocol.length(),
   1017       talk_base::ByteBuffer::ORDER_NETWORK);
   1018   buffer.WriteUInt8(DATA_CHANNEL_OPEN_MESSAGE_TYPE);
   1019   buffer.WriteUInt8(channel_type);
   1020   buffer.WriteUInt16(priority);
   1021   buffer.WriteUInt32(reliability_param);
   1022   buffer.WriteUInt16(static_cast<uint16>(label.length()));
   1023   buffer.WriteUInt16(static_cast<uint16>(config.protocol.length()));
   1024   buffer.WriteString(label);
   1025   buffer.WriteString(config.protocol);
   1026   payload->SetData(buffer.Data(), buffer.Length());
   1027   return true;
   1028 }
   1029 
   1030 void MediaStreamSignaling::UpdateLocalSctpDataChannels() {
   1031   DataChannels::iterator it = data_channels_.begin();
   1032   for (; it != data_channels_.end(); ++it) {
   1033     DataChannel* data_channel = it->second;
   1034     data_channel->SetSendSsrc(data_channel->id());
   1035   }
   1036 }
   1037 
   1038 void MediaStreamSignaling::UpdateRemoteSctpDataChannels() {
   1039   DataChannels::iterator it = data_channels_.begin();
   1040   for (; it != data_channels_.end(); ++it) {
   1041     DataChannel* data_channel = it->second;
   1042     data_channel->SetReceiveSsrc(data_channel->id());
   1043   }
   1044 }
   1045 
   1046 }  // namespace webrtc
   1047