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/remoteaudiosource.h"
     37 #include "talk/app/webrtc/remotevideocapturer.h"
     38 #include "talk/app/webrtc/sctputils.h"
     39 #include "talk/app/webrtc/videosource.h"
     40 #include "talk/app/webrtc/videotrack.h"
     41 #include "talk/base/bytebuffer.h"
     42 #include "talk/base/stringutils.h"
     43 #include "talk/media/sctp/sctpdataengine.h"
     44 
     45 static const char kDefaultStreamLabel[] = "default";
     46 static const char kDefaultAudioTrackLabel[] = "defaulta0";
     47 static const char kDefaultVideoTrackLabel[] = "defaultv0";
     48 
     49 namespace webrtc {
     50 
     51 using talk_base::scoped_ptr;
     52 using talk_base::scoped_refptr;
     53 
     54 static bool ParseConstraints(
     55     const MediaConstraintsInterface* constraints,
     56     cricket::MediaSessionOptions* options, bool is_answer) {
     57   bool value;
     58   size_t mandatory_constraints_satisfied = 0;
     59 
     60   if (FindConstraint(constraints,
     61                      MediaConstraintsInterface::kOfferToReceiveAudio,
     62                      &value, &mandatory_constraints_satisfied)) {
     63     // |options-|has_audio| can only change from false to
     64     // true, but never change from true to false. This is to make sure
     65     // CreateOffer / CreateAnswer doesn't remove a media content
     66     // description that has been created.
     67     options->has_audio |= value;
     68   } else {
     69     // kOfferToReceiveAudio defaults to true according to spec.
     70     options->has_audio = true;
     71   }
     72 
     73   if (FindConstraint(constraints,
     74                      MediaConstraintsInterface::kOfferToReceiveVideo,
     75                      &value, &mandatory_constraints_satisfied)) {
     76     // |options->has_video| can only change from false to
     77     // true, but never change from true to false. This is to make sure
     78     // CreateOffer / CreateAnswer doesn't remove a media content
     79     // description that has been created.
     80     options->has_video |= value;
     81   } else {
     82     // kOfferToReceiveVideo defaults to false according to spec. But
     83     // if it is an answer and video is offered, we should still accept video
     84     // per default.
     85     options->has_video |= is_answer;
     86   }
     87 
     88   if (FindConstraint(constraints,
     89                      MediaConstraintsInterface::kVoiceActivityDetection,
     90                      &value, &mandatory_constraints_satisfied)) {
     91     options->vad_enabled = value;
     92   }
     93 
     94   if (FindConstraint(constraints,
     95                      MediaConstraintsInterface::kUseRtpMux,
     96                      &value, &mandatory_constraints_satisfied)) {
     97     options->bundle_enabled = value;
     98   } else {
     99     // kUseRtpMux defaults to true according to spec.
    100     options->bundle_enabled = true;
    101   }
    102   if (FindConstraint(constraints,
    103                      MediaConstraintsInterface::kIceRestart,
    104                      &value, &mandatory_constraints_satisfied)) {
    105     options->transport_options.ice_restart = value;
    106   } else {
    107     // kIceRestart defaults to false according to spec.
    108     options->transport_options.ice_restart = false;
    109   }
    110 
    111   if (!constraints) {
    112     return true;
    113   }
    114   return mandatory_constraints_satisfied == constraints->GetMandatory().size();
    115 }
    116 
    117 // Returns true if if at least one media content is present and
    118 // |options.bundle_enabled| is true.
    119 // Bundle will be enabled  by default if at least one media content is present
    120 // and the constraint kUseRtpMux has not disabled bundle.
    121 static bool EvaluateNeedForBundle(const cricket::MediaSessionOptions& options) {
    122   return options.bundle_enabled &&
    123       (options.has_audio || options.has_video || options.has_data());
    124 }
    125 
    126 // Factory class for creating remote MediaStreams and MediaStreamTracks.
    127 class RemoteMediaStreamFactory {
    128  public:
    129   explicit RemoteMediaStreamFactory(talk_base::Thread* signaling_thread,
    130                                     cricket::ChannelManager* channel_manager)
    131       : signaling_thread_(signaling_thread),
    132         channel_manager_(channel_manager) {
    133   }
    134 
    135   talk_base::scoped_refptr<MediaStreamInterface> CreateMediaStream(
    136       const std::string& stream_label) {
    137     return MediaStreamProxy::Create(
    138         signaling_thread_, MediaStream::Create(stream_label));
    139   }
    140 
    141   AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
    142                                      const std::string& track_id) {
    143     return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
    144         stream, track_id, RemoteAudioSource::Create().get());
    145   }
    146 
    147   VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
    148                                      const std::string& track_id) {
    149     return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
    150         stream, track_id, VideoSource::Create(channel_manager_,
    151                                               new RemoteVideoCapturer(),
    152                                               NULL).get());
    153   }
    154 
    155  private:
    156   template <typename TI, typename T, typename TP, typename S>
    157   TI* AddTrack(MediaStreamInterface* stream, const std::string& track_id,
    158                S* source) {
    159     talk_base::scoped_refptr<TI> track(
    160         TP::Create(signaling_thread_, T::Create(track_id, source)));
    161     track->set_state(webrtc::MediaStreamTrackInterface::kLive);
    162     if (stream->AddTrack(track)) {
    163       return track;
    164     }
    165     return NULL;
    166   }
    167 
    168   talk_base::Thread* signaling_thread_;
    169   cricket::ChannelManager* channel_manager_;
    170 };
    171 
    172 MediaStreamSignaling::MediaStreamSignaling(
    173     talk_base::Thread* signaling_thread,
    174     MediaStreamSignalingObserver* stream_observer,
    175     cricket::ChannelManager* channel_manager)
    176     : signaling_thread_(signaling_thread),
    177       data_channel_factory_(NULL),
    178       stream_observer_(stream_observer),
    179       local_streams_(StreamCollection::Create()),
    180       remote_streams_(StreamCollection::Create()),
    181       remote_stream_factory_(new RemoteMediaStreamFactory(signaling_thread,
    182                                                           channel_manager)),
    183       last_allocated_sctp_even_sid_(-2),
    184       last_allocated_sctp_odd_sid_(-1) {
    185   options_.has_video = false;
    186   options_.has_audio = false;
    187 }
    188 
    189 MediaStreamSignaling::~MediaStreamSignaling() {
    190 }
    191 
    192 void MediaStreamSignaling::TearDown() {
    193   OnAudioChannelClose();
    194   OnVideoChannelClose();
    195   OnDataChannelClose();
    196 }
    197 
    198 bool MediaStreamSignaling::IsSctpSidAvailable(int sid) const {
    199   if (sid < 0 || sid > static_cast<int>(cricket::kMaxSctpSid))
    200     return false;
    201 
    202   return FindDataChannelBySid(sid) < 0;
    203 }
    204 
    205 // Gets the first unused odd/even id based on the DTLS role. If |role| is
    206 // SSL_CLIENT, the allocated id starts from 0 and takes even numbers; otherwise,
    207 // the id starts from 1 and takes odd numbers. Returns false if no id can be
    208 // allocated.
    209 bool MediaStreamSignaling::AllocateSctpSid(talk_base::SSLRole role, int* sid) {
    210   int& last_id = (role == talk_base::SSL_CLIENT) ?
    211       last_allocated_sctp_even_sid_ : last_allocated_sctp_odd_sid_;
    212 
    213   do {
    214     last_id += 2;
    215   } while (last_id <= static_cast<int>(cricket::kMaxSctpSid) &&
    216            !IsSctpSidAvailable(last_id));
    217 
    218   if (last_id > static_cast<int>(cricket::kMaxSctpSid)) {
    219     return false;
    220   }
    221 
    222   *sid = last_id;
    223   return true;
    224 }
    225 
    226 bool MediaStreamSignaling::HasDataChannels() const {
    227   return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
    228 }
    229 
    230 bool MediaStreamSignaling::AddDataChannel(DataChannel* data_channel) {
    231   ASSERT(data_channel != NULL);
    232   if (data_channel->data_channel_type() == cricket::DCT_RTP) {
    233     if (rtp_data_channels_.find(data_channel->label()) !=
    234         rtp_data_channels_.end()) {
    235       LOG(LS_ERROR) << "DataChannel with label " << data_channel->label()
    236                     << " already exists.";
    237       return false;
    238     }
    239     rtp_data_channels_[data_channel->label()] = data_channel;
    240   } else {
    241     ASSERT(data_channel->data_channel_type() == cricket::DCT_SCTP);
    242     sctp_data_channels_.push_back(data_channel);
    243   }
    244   return true;
    245 }
    246 
    247 bool MediaStreamSignaling::AddDataChannelFromOpenMessage(
    248     const cricket::ReceiveDataParams& params,
    249     const talk_base::Buffer& payload) {
    250   if (!data_channel_factory_) {
    251     LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
    252                     << "are not supported.";
    253     return false;
    254   }
    255 
    256   std::string label;
    257   InternalDataChannelInit config;
    258   config.id = params.ssrc;
    259   if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
    260     LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
    261                     << params.ssrc;
    262     return false;
    263   }
    264   config.open_handshake_role = InternalDataChannelInit::kAcker;
    265 
    266   scoped_refptr<DataChannel> channel(
    267       data_channel_factory_->CreateDataChannel(label, &config));
    268   if (!channel.get()) {
    269     LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
    270     return false;
    271   }
    272   sctp_data_channels_.push_back(channel);
    273   stream_observer_->OnAddDataChannel(channel);
    274   return true;
    275 }
    276 
    277 void MediaStreamSignaling::RemoveSctpDataChannel(int sid) {
    278   for (SctpDataChannels::iterator iter = sctp_data_channels_.begin();
    279        iter != sctp_data_channels_.end();
    280        ++iter) {
    281     if ((*iter)->id() == sid) {
    282       sctp_data_channels_.erase(iter);
    283 
    284       if (talk_base::IsEven(sid) && sid <= last_allocated_sctp_even_sid_) {
    285         last_allocated_sctp_even_sid_ = sid - 2;
    286       } else if (talk_base::IsOdd(sid) && sid <= last_allocated_sctp_odd_sid_) {
    287         last_allocated_sctp_odd_sid_ = sid - 2;
    288       }
    289       return;
    290     }
    291   }
    292 }
    293 
    294 bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
    295   if (local_streams_->find(local_stream->label()) != NULL) {
    296     LOG(LS_WARNING) << "MediaStream with label " << local_stream->label()
    297                     << "already exist.";
    298     return false;
    299   }
    300   local_streams_->AddStream(local_stream);
    301 
    302   // Find tracks that has already been configured in SDP. This can occur if a
    303   // local session description that contains the MSID of these tracks is set
    304   // before AddLocalStream is called. It can also occur if the local session
    305   // description is not changed and RemoveLocalStream
    306   // is called and later AddLocalStream is called again with the same stream.
    307   AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
    308   for (AudioTrackVector::const_iterator it = audio_tracks.begin();
    309        it != audio_tracks.end(); ++it) {
    310     const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
    311                                                 local_stream->label(),
    312                                                 (*it)->id());
    313     if (track_info) {
    314       OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
    315                        track_info->ssrc, cricket::MEDIA_TYPE_AUDIO);
    316     }
    317   }
    318 
    319   VideoTrackVector video_tracks = local_stream->GetVideoTracks();
    320   for (VideoTrackVector::const_iterator it = video_tracks.begin();
    321        it != video_tracks.end(); ++it) {
    322     const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
    323                                                 local_stream->label(),
    324                                                 (*it)->id());
    325     if (track_info) {
    326       OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
    327                        track_info->ssrc, cricket::MEDIA_TYPE_VIDEO);
    328     }
    329   }
    330   return true;
    331 }
    332 
    333 void MediaStreamSignaling::RemoveLocalStream(
    334     MediaStreamInterface* local_stream) {
    335   AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
    336   for (AudioTrackVector::const_iterator it = audio_tracks.begin();
    337        it != audio_tracks.end(); ++it) {
    338     const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
    339                                                 local_stream->label(),
    340                                                 (*it)->id());
    341     if (track_info) {
    342       stream_observer_->OnRemoveLocalAudioTrack(local_stream, *it,
    343                                                 track_info->ssrc);
    344     }
    345   }
    346   VideoTrackVector video_tracks = local_stream->GetVideoTracks();
    347   for (VideoTrackVector::const_iterator it = video_tracks.begin();
    348        it != video_tracks.end(); ++it) {
    349     const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
    350                                                 local_stream->label(),
    351                                                 (*it)->id());
    352     if (track_info) {
    353       stream_observer_->OnRemoveLocalVideoTrack(local_stream, *it);
    354     }
    355   }
    356 
    357   local_streams_->RemoveStream(local_stream);
    358   stream_observer_->OnRemoveLocalStream(local_stream);
    359 }
    360 
    361 bool MediaStreamSignaling::GetOptionsForOffer(
    362     const MediaConstraintsInterface* constraints,
    363     cricket::MediaSessionOptions* options) {
    364   UpdateSessionOptions();
    365   if (!ParseConstraints(constraints, &options_, false)) {
    366     return false;
    367   }
    368   options_.bundle_enabled = EvaluateNeedForBundle(options_);
    369   *options = options_;
    370   return true;
    371 }
    372 
    373 bool MediaStreamSignaling::GetOptionsForAnswer(
    374     const MediaConstraintsInterface* constraints,
    375     cricket::MediaSessionOptions* options) {
    376   UpdateSessionOptions();
    377 
    378   // Copy the |options_| to not let the flag MediaSessionOptions::has_audio and
    379   // MediaSessionOptions::has_video affect subsequent offers.
    380   cricket::MediaSessionOptions current_options = options_;
    381   if (!ParseConstraints(constraints, &current_options, true)) {
    382     return false;
    383   }
    384   current_options.bundle_enabled = EvaluateNeedForBundle(current_options);
    385   *options = current_options;
    386   return true;
    387 }
    388 
    389 // Updates or creates remote MediaStream objects given a
    390 // remote SessionDesription.
    391 // If the remote SessionDesription contains new remote MediaStreams
    392 // the observer OnAddStream method is called. If a remote MediaStream is missing
    393 // from the remote SessionDescription OnRemoveStream is called.
    394 void MediaStreamSignaling::OnRemoteDescriptionChanged(
    395     const SessionDescriptionInterface* desc) {
    396   const cricket::SessionDescription* remote_desc = desc->description();
    397   talk_base::scoped_refptr<StreamCollection> new_streams(
    398       StreamCollection::Create());
    399 
    400   // Find all audio rtp streams and create corresponding remote AudioTracks
    401   // and MediaStreams.
    402   const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
    403   if (audio_content) {
    404     const cricket::AudioContentDescription* desc =
    405         static_cast<const cricket::AudioContentDescription*>(
    406             audio_content->description);
    407     UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
    408     remote_info_.default_audio_track_needed =
    409         desc->direction() == cricket::MD_SENDRECV && desc->streams().empty();
    410   }
    411 
    412   // Find all video rtp streams and create corresponding remote VideoTracks
    413   // and MediaStreams.
    414   const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
    415   if (video_content) {
    416     const cricket::VideoContentDescription* desc =
    417         static_cast<const cricket::VideoContentDescription*>(
    418             video_content->description);
    419     UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
    420     remote_info_.default_video_track_needed =
    421         desc->direction() == cricket::MD_SENDRECV && desc->streams().empty();
    422   }
    423 
    424   // Update the DataChannels with the information from the remote peer.
    425   const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc);
    426   if (data_content) {
    427     const cricket::DataContentDescription* data_desc =
    428         static_cast<const cricket::DataContentDescription*>(
    429             data_content->description);
    430     if (talk_base::starts_with(
    431             data_desc->protocol().data(), cricket::kMediaProtocolRtpPrefix)) {
    432       UpdateRemoteRtpDataChannels(data_desc->streams());
    433     }
    434   }
    435 
    436   // Iterate new_streams and notify the observer about new MediaStreams.
    437   for (size_t i = 0; i < new_streams->count(); ++i) {
    438     MediaStreamInterface* new_stream = new_streams->at(i);
    439     stream_observer_->OnAddRemoteStream(new_stream);
    440   }
    441 
    442   // Find removed MediaStreams.
    443   if (remote_info_.IsDefaultMediaStreamNeeded() &&
    444       remote_streams_->find(kDefaultStreamLabel) != NULL) {
    445     // The default media stream already exists. No need to do anything.
    446   } else {
    447     UpdateEndedRemoteMediaStreams();
    448     remote_info_.msid_supported |= remote_streams_->count() > 0;
    449   }
    450   MaybeCreateDefaultStream();
    451 }
    452 
    453 void MediaStreamSignaling::OnLocalDescriptionChanged(
    454     const SessionDescriptionInterface* desc) {
    455   const cricket::ContentInfo* audio_content =
    456       GetFirstAudioContent(desc->description());
    457   if (audio_content) {
    458     if (audio_content->rejected) {
    459       RejectRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
    460     }
    461     const cricket::AudioContentDescription* audio_desc =
    462         static_cast<const cricket::AudioContentDescription*>(
    463             audio_content->description);
    464     UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
    465   }
    466 
    467   const cricket::ContentInfo* video_content =
    468       GetFirstVideoContent(desc->description());
    469   if (video_content) {
    470     if (video_content->rejected) {
    471       RejectRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
    472     }
    473     const cricket::VideoContentDescription* video_desc =
    474         static_cast<const cricket::VideoContentDescription*>(
    475             video_content->description);
    476     UpdateLocalTracks(video_desc->streams(), video_desc->type());
    477   }
    478 
    479   const cricket::ContentInfo* data_content =
    480       GetFirstDataContent(desc->description());
    481   if (data_content) {
    482     const cricket::DataContentDescription* data_desc =
    483         static_cast<const cricket::DataContentDescription*>(
    484             data_content->description);
    485     if (talk_base::starts_with(
    486             data_desc->protocol().data(), cricket::kMediaProtocolRtpPrefix)) {
    487       UpdateLocalRtpDataChannels(data_desc->streams());
    488     }
    489   }
    490 }
    491 
    492 void MediaStreamSignaling::OnAudioChannelClose() {
    493   RejectRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
    494 }
    495 
    496 void MediaStreamSignaling::OnVideoChannelClose() {
    497   RejectRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
    498 }
    499 
    500 void MediaStreamSignaling::OnDataChannelClose() {
    501   // Use a temporary copy of the RTP/SCTP DataChannel list because the
    502   // DataChannel may callback to us and try to modify the list.
    503   RtpDataChannels temp_rtp_dcs;
    504   temp_rtp_dcs.swap(rtp_data_channels_);
    505   RtpDataChannels::iterator it1 = temp_rtp_dcs.begin();
    506   for (; it1 != temp_rtp_dcs.end(); ++it1) {
    507     it1->second->OnDataEngineClose();
    508   }
    509 
    510   SctpDataChannels temp_sctp_dcs;
    511   temp_sctp_dcs.swap(sctp_data_channels_);
    512   SctpDataChannels::iterator it2 = temp_sctp_dcs.begin();
    513   for (; it2 != temp_sctp_dcs.end(); ++it2) {
    514     (*it2)->OnDataEngineClose();
    515   }
    516 }
    517 
    518 void MediaStreamSignaling::UpdateSessionOptions() {
    519   options_.streams.clear();
    520   if (local_streams_ != NULL) {
    521     for (size_t i = 0; i < local_streams_->count(); ++i) {
    522       MediaStreamInterface* stream = local_streams_->at(i);
    523 
    524       AudioTrackVector audio_tracks(stream->GetAudioTracks());
    525       if (!audio_tracks.empty()) {
    526         options_.has_audio = true;
    527       }
    528 
    529       // For each audio track in the stream, add it to the MediaSessionOptions.
    530       for (size_t j = 0; j < audio_tracks.size(); ++j) {
    531         scoped_refptr<MediaStreamTrackInterface> track(audio_tracks[j]);
    532         options_.AddStream(cricket::MEDIA_TYPE_AUDIO, track->id(),
    533                            stream->label());
    534       }
    535 
    536       VideoTrackVector video_tracks(stream->GetVideoTracks());
    537       if (!video_tracks.empty()) {
    538         options_.has_video = true;
    539       }
    540       // For each video track in the stream, add it to the MediaSessionOptions.
    541       for (size_t j = 0; j < video_tracks.size(); ++j) {
    542         scoped_refptr<MediaStreamTrackInterface> track(video_tracks[j]);
    543         options_.AddStream(cricket::MEDIA_TYPE_VIDEO, track->id(),
    544                            stream->label());
    545       }
    546     }
    547   }
    548 
    549   // Check for data channels.
    550   RtpDataChannels::const_iterator data_channel_it = rtp_data_channels_.begin();
    551   for (; data_channel_it != rtp_data_channels_.end(); ++data_channel_it) {
    552     const DataChannel* channel = data_channel_it->second;
    553     if (channel->state() == DataChannel::kConnecting ||
    554         channel->state() == DataChannel::kOpen) {
    555       // |streamid| and |sync_label| are both set to the DataChannel label
    556       // here so they can be signaled the same way as MediaStreams and Tracks.
    557       // For MediaStreams, the sync_label is the MediaStream label and the
    558       // track label is the same as |streamid|.
    559       const std::string& streamid = channel->label();
    560       const std::string& sync_label = channel->label();
    561       options_.AddStream(cricket::MEDIA_TYPE_DATA, streamid, sync_label);
    562     }
    563   }
    564 }
    565 
    566 void MediaStreamSignaling::UpdateRemoteStreamsList(
    567     const cricket::StreamParamsVec& streams,
    568     cricket::MediaType media_type,
    569     StreamCollection* new_streams) {
    570   TrackInfos* current_tracks = GetRemoteTracks(media_type);
    571 
    572   // Find removed tracks. Ie tracks where the track id or ssrc don't match the
    573   // new StreamParam.
    574   TrackInfos::iterator track_it = current_tracks->begin();
    575   while (track_it != current_tracks->end()) {
    576     const TrackInfo& info = *track_it;
    577     cricket::StreamParams params;
    578     if (!cricket::GetStreamBySsrc(streams, info.ssrc, &params) ||
    579         params.id != info.track_id) {
    580       OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
    581       track_it = current_tracks->erase(track_it);
    582     } else {
    583       ++track_it;
    584     }
    585   }
    586 
    587   // Find new and active tracks.
    588   for (cricket::StreamParamsVec::const_iterator it = streams.begin();
    589        it != streams.end(); ++it) {
    590     // The sync_label is the MediaStream label and the |stream.id| is the
    591     // track id.
    592     const std::string& stream_label = it->sync_label;
    593     const std::string& track_id = it->id;
    594     uint32 ssrc = it->first_ssrc();
    595 
    596     talk_base::scoped_refptr<MediaStreamInterface> stream =
    597         remote_streams_->find(stream_label);
    598     if (!stream) {
    599       // This is a new MediaStream. Create a new remote MediaStream.
    600       stream = remote_stream_factory_->CreateMediaStream(stream_label);
    601       remote_streams_->AddStream(stream);
    602       new_streams->AddStream(stream);
    603     }
    604 
    605     const TrackInfo* track_info = FindTrackInfo(*current_tracks, stream_label,
    606                                                 track_id);
    607     if (!track_info) {
    608       current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
    609       OnRemoteTrackSeen(stream_label, track_id, it->first_ssrc(), media_type);
    610     }
    611   }
    612 }
    613 
    614 void MediaStreamSignaling::OnRemoteTrackSeen(const std::string& stream_label,
    615                                              const std::string& track_id,
    616                                              uint32 ssrc,
    617                                              cricket::MediaType media_type) {
    618   MediaStreamInterface* stream = remote_streams_->find(stream_label);
    619 
    620   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    621     AudioTrackInterface* audio_track =
    622         remote_stream_factory_->AddAudioTrack(stream, track_id);
    623     stream_observer_->OnAddRemoteAudioTrack(stream, audio_track, ssrc);
    624   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    625     VideoTrackInterface* video_track =
    626         remote_stream_factory_->AddVideoTrack(stream, track_id);
    627     stream_observer_->OnAddRemoteVideoTrack(stream, video_track, ssrc);
    628   } else {
    629     ASSERT(false && "Invalid media type");
    630   }
    631 }
    632 
    633 void MediaStreamSignaling::OnRemoteTrackRemoved(
    634     const std::string& stream_label,
    635     const std::string& track_id,
    636     cricket::MediaType media_type) {
    637   MediaStreamInterface* stream = remote_streams_->find(stream_label);
    638 
    639   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    640     talk_base::scoped_refptr<AudioTrackInterface> audio_track =
    641         stream->FindAudioTrack(track_id);
    642     if (audio_track) {
    643       audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    644       stream->RemoveTrack(audio_track);
    645       stream_observer_->OnRemoveRemoteAudioTrack(stream, audio_track);
    646     }
    647   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    648     talk_base::scoped_refptr<VideoTrackInterface> video_track =
    649         stream->FindVideoTrack(track_id);
    650     if (video_track) {
    651       video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    652       stream->RemoveTrack(video_track);
    653       stream_observer_->OnRemoveRemoteVideoTrack(stream, video_track);
    654     }
    655   } else {
    656     ASSERT(false && "Invalid media type");
    657   }
    658 }
    659 
    660 void MediaStreamSignaling::RejectRemoteTracks(cricket::MediaType media_type) {
    661   TrackInfos* current_tracks = GetRemoteTracks(media_type);
    662   for (TrackInfos::iterator track_it = current_tracks->begin();
    663        track_it != current_tracks->end(); ++track_it) {
    664     const TrackInfo& info = *track_it;
    665     MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
    666     if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    667       AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
    668       // There's no guarantee the track is still available, e.g. the track may
    669       // have been removed from the stream by javascript.
    670       if (track) {
    671         track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    672       }
    673     }
    674     if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    675       VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
    676       // There's no guarantee the track is still available, e.g. the track may
    677       // have been removed from the stream by javascript.
    678       if (track) {
    679         track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
    680       }
    681     }
    682   }
    683 }
    684 
    685 void MediaStreamSignaling::UpdateEndedRemoteMediaStreams() {
    686   std::vector<scoped_refptr<MediaStreamInterface> > streams_to_remove;
    687   for (size_t i = 0; i < remote_streams_->count(); ++i) {
    688     MediaStreamInterface*stream = remote_streams_->at(i);
    689     if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
    690       streams_to_remove.push_back(stream);
    691     }
    692   }
    693 
    694   std::vector<scoped_refptr<MediaStreamInterface> >::const_iterator it;
    695   for (it = streams_to_remove.begin(); it != streams_to_remove.end(); ++it) {
    696     remote_streams_->RemoveStream(*it);
    697     stream_observer_->OnRemoveRemoteStream(*it);
    698   }
    699 }
    700 
    701 void MediaStreamSignaling::MaybeCreateDefaultStream() {
    702   if (!remote_info_.IsDefaultMediaStreamNeeded())
    703     return;
    704 
    705   bool default_created = false;
    706 
    707   scoped_refptr<MediaStreamInterface> default_remote_stream =
    708       remote_streams_->find(kDefaultStreamLabel);
    709   if (default_remote_stream == NULL) {
    710     default_created = true;
    711     default_remote_stream =
    712         remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
    713     remote_streams_->AddStream(default_remote_stream);
    714   }
    715   if (remote_info_.default_audio_track_needed &&
    716       default_remote_stream->GetAudioTracks().size() == 0) {
    717     remote_audio_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
    718                                              kDefaultAudioTrackLabel, 0));
    719 
    720     OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
    721                        cricket::MEDIA_TYPE_AUDIO);
    722   }
    723   if (remote_info_.default_video_track_needed &&
    724       default_remote_stream->GetVideoTracks().size() == 0) {
    725     remote_video_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
    726                                              kDefaultVideoTrackLabel, 0));
    727     OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
    728                        cricket::MEDIA_TYPE_VIDEO);
    729   }
    730   if (default_created) {
    731     stream_observer_->OnAddRemoteStream(default_remote_stream);
    732   }
    733 }
    734 
    735 MediaStreamSignaling::TrackInfos* MediaStreamSignaling::GetRemoteTracks(
    736     cricket::MediaType type) {
    737   if (type == cricket::MEDIA_TYPE_AUDIO)
    738     return &remote_audio_tracks_;
    739   else if (type == cricket::MEDIA_TYPE_VIDEO)
    740     return &remote_video_tracks_;
    741   ASSERT(false && "Unknown MediaType");
    742   return NULL;
    743 }
    744 
    745 MediaStreamSignaling::TrackInfos* MediaStreamSignaling::GetLocalTracks(
    746     cricket::MediaType media_type) {
    747   ASSERT(media_type == cricket::MEDIA_TYPE_AUDIO ||
    748          media_type == cricket::MEDIA_TYPE_VIDEO);
    749 
    750   return (media_type == cricket::MEDIA_TYPE_AUDIO) ?
    751       &local_audio_tracks_ : &local_video_tracks_;
    752 }
    753 
    754 void MediaStreamSignaling::UpdateLocalTracks(
    755     const std::vector<cricket::StreamParams>& streams,
    756     cricket::MediaType media_type) {
    757   TrackInfos* current_tracks = GetLocalTracks(media_type);
    758 
    759   // Find removed tracks. Ie tracks where the track id, stream label or ssrc
    760   // don't match the new StreamParam.
    761   TrackInfos::iterator track_it = current_tracks->begin();
    762   while (track_it != current_tracks->end()) {
    763     const TrackInfo& info = *track_it;
    764     cricket::StreamParams params;
    765     if (!cricket::GetStreamBySsrc(streams, info.ssrc, &params) ||
    766         params.id != info.track_id || params.sync_label != info.stream_label) {
    767       OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
    768                           media_type);
    769       track_it = current_tracks->erase(track_it);
    770     } else {
    771       ++track_it;
    772     }
    773   }
    774 
    775   // Find new and active tracks.
    776   for (cricket::StreamParamsVec::const_iterator it = streams.begin();
    777        it != streams.end(); ++it) {
    778     // The sync_label is the MediaStream label and the |stream.id| is the
    779     // track id.
    780     const std::string& stream_label = it->sync_label;
    781     const std::string& track_id = it->id;
    782     uint32 ssrc = it->first_ssrc();
    783     const TrackInfo* track_info = FindTrackInfo(*current_tracks,
    784                                                 stream_label,
    785                                                 track_id);
    786     if (!track_info) {
    787       current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
    788       OnLocalTrackSeen(stream_label, track_id, it->first_ssrc(),
    789                        media_type);
    790     }
    791   }
    792 }
    793 
    794 void MediaStreamSignaling::OnLocalTrackSeen(
    795     const std::string& stream_label,
    796     const std::string& track_id,
    797     uint32 ssrc,
    798     cricket::MediaType media_type) {
    799   MediaStreamInterface* stream = local_streams_->find(stream_label);
    800   if (!stream) {
    801     LOG(LS_WARNING) << "An unknown local MediaStream with label "
    802                     << stream_label <<  " has been configured.";
    803     return;
    804   }
    805 
    806   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    807     AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
    808     if (!audio_track) {
    809       LOG(LS_WARNING) << "An unknown local AudioTrack with id , "
    810                       << track_id <<  " has been configured.";
    811       return;
    812     }
    813     stream_observer_->OnAddLocalAudioTrack(stream, audio_track, ssrc);
    814   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    815     VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
    816     if (!video_track) {
    817       LOG(LS_WARNING) << "An unknown local VideoTrack with id , "
    818                       << track_id <<  " has been configured.";
    819       return;
    820     }
    821     stream_observer_->OnAddLocalVideoTrack(stream, video_track, ssrc);
    822   } else {
    823     ASSERT(false && "Invalid media type");
    824   }
    825 }
    826 
    827 void MediaStreamSignaling::OnLocalTrackRemoved(
    828     const std::string& stream_label,
    829     const std::string& track_id,
    830     uint32 ssrc,
    831     cricket::MediaType media_type) {
    832   MediaStreamInterface* stream = local_streams_->find(stream_label);
    833   if (!stream) {
    834     // This is the normal case. Ie RemoveLocalStream has been called and the
    835     // SessionDescriptions has been renegotiated.
    836     return;
    837   }
    838   // A track has been removed from the SessionDescription but the MediaStream
    839   // is still associated with MediaStreamSignaling. This only occurs if the SDP
    840   // doesn't match with the calls to AddLocalStream and RemoveLocalStream.
    841 
    842   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    843     AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
    844     if (!audio_track) {
    845       return;
    846     }
    847     stream_observer_->OnRemoveLocalAudioTrack(stream, audio_track, ssrc);
    848   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
    849     VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
    850     if (!video_track) {
    851       return;
    852     }
    853     stream_observer_->OnRemoveLocalVideoTrack(stream, video_track);
    854   } else {
    855     ASSERT(false && "Invalid media type.");
    856   }
    857 }
    858 
    859 void MediaStreamSignaling::UpdateLocalRtpDataChannels(
    860     const cricket::StreamParamsVec& streams) {
    861   std::vector<std::string> existing_channels;
    862 
    863   // Find new and active data channels.
    864   for (cricket::StreamParamsVec::const_iterator it =streams.begin();
    865        it != streams.end(); ++it) {
    866     // |it->sync_label| is actually the data channel label. The reason is that
    867     // we use the same naming of data channels as we do for
    868     // MediaStreams and Tracks.
    869     // For MediaStreams, the sync_label is the MediaStream label and the
    870     // track label is the same as |streamid|.
    871     const std::string& channel_label = it->sync_label;
    872     RtpDataChannels::iterator data_channel_it =
    873         rtp_data_channels_.find(channel_label);
    874     if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
    875       continue;
    876     }
    877     // Set the SSRC the data channel should use for sending.
    878     data_channel_it->second->SetSendSsrc(it->first_ssrc());
    879     existing_channels.push_back(data_channel_it->first);
    880   }
    881 
    882   UpdateClosingDataChannels(existing_channels, true);
    883 }
    884 
    885 void MediaStreamSignaling::UpdateRemoteRtpDataChannels(
    886     const cricket::StreamParamsVec& streams) {
    887   std::vector<std::string> existing_channels;
    888 
    889   // Find new and active data channels.
    890   for (cricket::StreamParamsVec::const_iterator it = streams.begin();
    891        it != streams.end(); ++it) {
    892     // The data channel label is either the mslabel or the SSRC if the mslabel
    893     // does not exist. Ex a=ssrc:444330170 mslabel:test1.
    894     std::string label = it->sync_label.empty() ?
    895         talk_base::ToString(it->first_ssrc()) : it->sync_label;
    896     RtpDataChannels::iterator data_channel_it =
    897         rtp_data_channels_.find(label);
    898     if (data_channel_it == rtp_data_channels_.end()) {
    899       // This is a new data channel.
    900       CreateRemoteDataChannel(label, it->first_ssrc());
    901     } else {
    902       data_channel_it->second->SetReceiveSsrc(it->first_ssrc());
    903     }
    904     existing_channels.push_back(label);
    905   }
    906 
    907   UpdateClosingDataChannels(existing_channels, false);
    908 }
    909 
    910 void MediaStreamSignaling::UpdateClosingDataChannels(
    911     const std::vector<std::string>& active_channels, bool is_local_update) {
    912   RtpDataChannels::iterator it = rtp_data_channels_.begin();
    913   while (it != rtp_data_channels_.end()) {
    914     DataChannel* data_channel = it->second;
    915     if (std::find(active_channels.begin(), active_channels.end(),
    916                   data_channel->label()) != active_channels.end()) {
    917       ++it;
    918       continue;
    919     }
    920 
    921     if (is_local_update)
    922       data_channel->SetSendSsrc(0);
    923     else
    924       data_channel->RemotePeerRequestClose();
    925 
    926     if (data_channel->state() == DataChannel::kClosed) {
    927       rtp_data_channels_.erase(it);
    928       it = rtp_data_channels_.begin();
    929     } else {
    930       ++it;
    931     }
    932   }
    933 }
    934 
    935 void MediaStreamSignaling::CreateRemoteDataChannel(const std::string& label,
    936                                                    uint32 remote_ssrc) {
    937   if (!data_channel_factory_) {
    938     LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
    939                     << "are not supported.";
    940     return;
    941   }
    942   scoped_refptr<DataChannel> channel(
    943       data_channel_factory_->CreateDataChannel(label, NULL));
    944   if (!channel.get()) {
    945     LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
    946                     << "CreateDataChannel failed.";
    947     return;
    948   }
    949   channel->SetReceiveSsrc(remote_ssrc);
    950   stream_observer_->OnAddDataChannel(channel);
    951 }
    952 
    953 void MediaStreamSignaling::OnDataTransportCreatedForSctp() {
    954   SctpDataChannels::iterator it = sctp_data_channels_.begin();
    955   for (; it != sctp_data_channels_.end(); ++it) {
    956     (*it)->OnTransportChannelCreated();
    957   }
    958 }
    959 
    960 void MediaStreamSignaling::OnDtlsRoleReadyForSctp(talk_base::SSLRole role) {
    961   SctpDataChannels::iterator it = sctp_data_channels_.begin();
    962   for (; it != sctp_data_channels_.end(); ++it) {
    963     if ((*it)->id() < 0) {
    964       int sid;
    965       if (!AllocateSctpSid(role, &sid)) {
    966         LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
    967         continue;
    968       }
    969       (*it)->SetSctpSid(sid);
    970     }
    971   }
    972 }
    973 
    974 
    975 void MediaStreamSignaling::OnRemoteSctpDataChannelClosed(uint32 sid) {
    976   int index = FindDataChannelBySid(sid);
    977   if (index < 0) {
    978     LOG(LS_WARNING) << "Unexpected sid " << sid
    979                     << " of the remotely closed DataChannel.";
    980     return;
    981   }
    982   sctp_data_channels_[index]->Close();
    983 }
    984 
    985 const MediaStreamSignaling::TrackInfo*
    986 MediaStreamSignaling::FindTrackInfo(
    987     const MediaStreamSignaling::TrackInfos& infos,
    988     const std::string& stream_label,
    989     const std::string track_id) const {
    990 
    991   for (TrackInfos::const_iterator it = infos.begin();
    992       it != infos.end(); ++it) {
    993     if (it->stream_label == stream_label && it->track_id == track_id)
    994       return &*it;
    995   }
    996   return NULL;
    997 }
    998 
    999 int MediaStreamSignaling::FindDataChannelBySid(int sid) const {
   1000   for (size_t i = 0; i < sctp_data_channels_.size(); ++i) {
   1001     if (sctp_data_channels_[i]->id() == sid) {
   1002       return static_cast<int>(i);
   1003     }
   1004   }
   1005   return -1;
   1006 }
   1007 
   1008 }  // namespace webrtc
   1009