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