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