Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1196)

Side by Side Diff: talk/app/webrtc/mediastreamsignaling.cc

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

Powered by Google App Engine
This is Rietveld 408576698