blob: 91fe146e95ad1f81db0f46be2b82c1e3f2383c9c [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 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 <string>
29#include "talk/base/helpers.h"
30#include "talk/base/logging.h"
31#include "talk/base/thread.h"
32#include "talk/base/window.h"
33#include "talk/media/base/constants.h"
34#include "talk/media/base/screencastid.h"
35#include "talk/p2p/base/parsing.h"
36#include "talk/session/media/call.h"
buildbot@webrtc.orgca272362014-05-08 23:10:23 +000037#include "talk/session/media/currentspeakermonitor.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038#include "talk/session/media/mediasessionclient.h"
39
40namespace cricket {
41
42const uint32 MSG_CHECKAUTODESTROY = 1;
43const uint32 MSG_TERMINATECALL = 2;
44const uint32 MSG_PLAYDTMF = 3;
45
46namespace {
47const int kDTMFDelay = 300; // msec
48const size_t kMaxDTMFDigits = 30;
49const int kSendToVoicemailTimeout = 1000*20;
50const int kNoVoicemailTimeout = 1000*180;
51const int kMediaMonitorInterval = 1000*15;
52// In order to be the same as the server-side switching, this must be 100.
53const int kAudioMonitorPollPeriodMillis = 100;
54
55// V is a pointer type.
56template<class K, class V>
57V FindOrNull(const std::map<K, V>& map,
58 const K& key) {
59 typename std::map<K, V>::const_iterator it = map.find(key);
60 return (it != map.end()) ? it->second : NULL;
61}
62
wu@webrtc.org9dba5252013-08-05 20:36:57 +000063
64bool ContentContainsCrypto(const cricket::ContentInfo* content) {
65 if (content != NULL) {
66 const cricket::MediaContentDescription* desc =
67 static_cast<const cricket::MediaContentDescription*>(
68 content->description);
69 if (!desc || desc->cryptos().empty()) {
70 return false;
71 }
72 }
73 return true;
74}
75
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076}
77
buildbot@webrtc.orgca272362014-05-08 23:10:23 +000078AudioSourceProxy::AudioSourceProxy(Call* call)
79 : call_(call) {
80 call_->SignalAudioMonitor.connect(this, &AudioSourceProxy::OnAudioMonitor);
81 call_->SignalMediaStreamsUpdate.connect(
82 this, &AudioSourceProxy::OnMediaStreamsUpdate);
83}
84
85void AudioSourceProxy::OnAudioMonitor(Call* call, const AudioInfo& info) {
86 SignalAudioMonitor(this, info);
87}
88
89void AudioSourceProxy::OnMediaStreamsUpdate(Call* call, Session* session,
90 const MediaStreams& added, const MediaStreams& removed) {
91 SignalMediaStreamsUpdate(this, session, added, removed);
92}
93
henrike@webrtc.org28e20752013-07-10 00:45:36 +000094Call::Call(MediaSessionClient* session_client)
95 : id_(talk_base::CreateRandomId()),
96 session_client_(session_client),
97 local_renderer_(NULL),
98 has_video_(false),
99 has_data_(false),
100 muted_(false),
101 video_muted_(false),
102 send_to_voicemail_(true),
103 playing_dtmf_(false) {
buildbot@webrtc.orgca272362014-05-08 23:10:23 +0000104 audio_source_proxy_.reset(new AudioSourceProxy(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105}
106
107Call::~Call() {
108 while (media_session_map_.begin() != media_session_map_.end()) {
109 Session* session = media_session_map_.begin()->second.session;
110 RemoveSession(session);
111 session_client_->session_manager()->DestroySession(session);
112 }
113 talk_base::Thread::Current()->Clear(this);
114}
115
116Session* Call::InitiateSession(const buzz::Jid& to,
117 const buzz::Jid& initiator,
118 const CallOptions& options) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000119 std::string id;
120 std::string initiator_name = initiator.Str();
121 return InternalInitiateSession(id, to, initiator_name, options);
122}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000124Session *Call::InitiateSession(const std::string& id,
125 const buzz::Jid& to,
126 const CallOptions& options) {
127 std::string initiator_name;
128 return InternalInitiateSession(id, to, initiator_name, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000129}
130
131void Call::IncomingSession(Session* session, const SessionDescription* offer) {
132 AddSession(session, offer);
133
134 // Make sure the session knows about the incoming ssrcs. This needs to be done
135 // prior to the SignalSessionState call, because that may trigger handling of
136 // these new SSRCs, so they need to be registered before then.
137 UpdateRemoteMediaStreams(session, offer->contents(), false);
138
139 // Missed the first state, the initiate, which is needed by
140 // call_client.
141 SignalSessionState(this, session, Session::STATE_RECEIVEDINITIATE);
142}
143
144void Call::AcceptSession(Session* session,
145 const cricket::CallOptions& options) {
146 MediaSessionMap::iterator it = media_session_map_.find(session->id());
147 if (it != media_session_map_.end()) {
148 const SessionDescription* answer = session_client_->CreateAnswer(
149 session->remote_description(), options);
150 it->second.session->Accept(answer);
151 }
152}
153
154void Call::RejectSession(Session* session) {
155 // Assume polite decline.
156 MediaSessionMap::iterator it = media_session_map_.find(session->id());
157 if (it != media_session_map_.end())
158 it->second.session->Reject(STR_TERMINATE_DECLINE);
159}
160
161void Call::TerminateSession(Session* session) {
162 MediaSessionMap::iterator it = media_session_map_.find(session->id());
163 if (it != media_session_map_.end()) {
164 // Assume polite terminations.
165 it->second.session->Terminate();
166 }
167}
168
169void Call::Terminate() {
170 // Copy the list so that we can iterate over it in a stable way
171 std::vector<Session*> sessions = this->sessions();
172
173 // There may be more than one session to terminate
174 std::vector<Session*>::iterator it;
175 for (it = sessions.begin(); it != sessions.end(); ++it) {
176 TerminateSession(*it);
177 }
178}
179
180bool Call::SendViewRequest(Session* session,
181 const ViewRequest& view_request) {
182 StaticVideoViews::const_iterator it;
183 for (it = view_request.static_video_views.begin();
184 it != view_request.static_video_views.end(); ++it) {
185 StreamParams found_stream;
186 bool found = false;
187 MediaStreams* recv_streams = GetMediaStreams(session);
188 if (recv_streams)
189 found = recv_streams->GetVideoStream(it->selector, &found_stream);
190 if (!found) {
191 LOG(LS_WARNING) << "Trying to send view request for ("
192 << it->selector.ssrc << ", '"
193 << it->selector.groupid << "', '"
194 << it->selector.streamid << "'"
195 << ") is not in the local streams.";
196 return false;
197 }
198 }
199
200 XmlElements elems;
201 WriteError error;
202 if (!WriteJingleViewRequest(CN_VIDEO, view_request, &elems, &error)) {
203 LOG(LS_ERROR) << "Couldn't write out view request: " << error.text;
204 return false;
205 }
206
wu@webrtc.org364f2042013-11-20 21:49:41 +0000207 return session->SendInfoMessage(elems, session->remote_name());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208}
209
210void Call::SetLocalRenderer(VideoRenderer* renderer) {
211 local_renderer_ = renderer;
212 if (session_client_->GetFocus() == this) {
213 session_client_->channel_manager()->SetLocalRenderer(renderer);
214 }
215}
216
217void Call::SetVideoRenderer(Session* session, uint32 ssrc,
218 VideoRenderer* renderer) {
219 VideoChannel* video_channel = GetVideoChannel(session);
220 if (video_channel) {
221 video_channel->SetRenderer(ssrc, renderer);
222 LOG(LS_INFO) << "Set renderer of ssrc " << ssrc
223 << " to " << renderer << ".";
224 } else {
225 LOG(LS_INFO) << "Failed to set renderer of ssrc " << ssrc << ".";
226 }
227}
228
229void Call::OnMessage(talk_base::Message* message) {
230 switch (message->message_id) {
231 case MSG_CHECKAUTODESTROY:
232 // If no more sessions for this call, delete it
233 if (media_session_map_.empty())
234 session_client_->DestroyCall(this);
235 break;
236 case MSG_TERMINATECALL:
237 // Signal to the user that a timeout has happened and the call should
238 // be sent to voicemail.
239 if (send_to_voicemail_) {
240 SignalSetupToCallVoicemail();
241 }
242
243 // Callee didn't answer - terminate call
244 Terminate();
245 break;
246 case MSG_PLAYDTMF:
247 ContinuePlayDTMF();
248 }
249}
250
251std::vector<Session*> Call::sessions() {
252 std::vector<Session*> sessions;
253 MediaSessionMap::iterator it;
254 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it)
255 sessions.push_back(it->second.session);
256
257 return sessions;
258}
259
260bool Call::AddSession(Session* session, const SessionDescription* offer) {
261 bool succeeded = true;
262 MediaSession media_session;
263 media_session.session = session;
264 media_session.voice_channel = NULL;
265 media_session.video_channel = NULL;
266 media_session.data_channel = NULL;
267 media_session.recv_streams = NULL;
268
269 const ContentInfo* audio_offer = GetFirstAudioContent(offer);
270 const ContentInfo* video_offer = GetFirstVideoContent(offer);
271 const ContentInfo* data_offer = GetFirstDataContent(offer);
272 has_video_ = (video_offer != NULL);
273 has_data_ = (data_offer != NULL);
274
275 ASSERT(audio_offer != NULL);
276 // Create voice channel and start a media monitor.
277 media_session.voice_channel =
278 session_client_->channel_manager()->CreateVoiceChannel(
279 session, audio_offer->name, has_video_);
280 // voice_channel can be NULL in case of NullVoiceEngine.
281 if (media_session.voice_channel) {
282 media_session.voice_channel->SignalMediaMonitor.connect(
283 this, &Call::OnMediaMonitor);
284 media_session.voice_channel->StartMediaMonitor(kMediaMonitorInterval);
285 } else {
286 succeeded = false;
287 }
288
289 // If desired, create video channel and start a media monitor.
290 if (has_video_ && succeeded) {
291 media_session.video_channel =
292 session_client_->channel_manager()->CreateVideoChannel(
293 session, video_offer->name, true, media_session.voice_channel);
294 // video_channel can be NULL in case of NullVideoEngine.
295 if (media_session.video_channel) {
296 media_session.video_channel->SignalMediaMonitor.connect(
297 this, &Call::OnMediaMonitor);
298 media_session.video_channel->StartMediaMonitor(kMediaMonitorInterval);
299 } else {
300 succeeded = false;
301 }
302 }
303
304 // If desired, create data channel.
305 if (has_data_ && succeeded) {
306 const DataContentDescription* data = GetFirstDataContentDescription(offer);
307 if (data == NULL) {
308 succeeded = false;
309 } else {
310 DataChannelType data_channel_type = DCT_RTP;
311 if ((data->protocol() == kMediaProtocolSctp) ||
312 (data->protocol() == kMediaProtocolDtlsSctp)) {
313 data_channel_type = DCT_SCTP;
314 }
315
316 bool rtcp = false;
317 media_session.data_channel =
318 session_client_->channel_manager()->CreateDataChannel(
319 session, data_offer->name, rtcp, data_channel_type);
320 if (media_session.data_channel) {
321 media_session.data_channel->SignalDataReceived.connect(
322 this, &Call::OnDataReceived);
323 } else {
324 succeeded = false;
325 }
326 }
327 }
328
329 if (succeeded) {
330 // Add session to list, create channels for this session.
331 media_session.recv_streams = new MediaStreams;
332 media_session_map_[session->id()] = media_session;
333 session->SignalState.connect(this, &Call::OnSessionState);
334 session->SignalError.connect(this, &Call::OnSessionError);
335 session->SignalInfoMessage.connect(
336 this, &Call::OnSessionInfoMessage);
337 session->SignalRemoteDescriptionUpdate.connect(
338 this, &Call::OnRemoteDescriptionUpdate);
339 session->SignalReceivedTerminateReason
340 .connect(this, &Call::OnReceivedTerminateReason);
341
342 // If this call has the focus, enable this session's channels.
343 if (session_client_->GetFocus() == this) {
344 EnableSessionChannels(session, true);
345 }
346
347 // Signal client.
348 SignalAddSession(this, session);
349 }
350
351 return succeeded;
352}
353
354void Call::RemoveSession(Session* session) {
355 MediaSessionMap::iterator it = media_session_map_.find(session->id());
356 if (it == media_session_map_.end())
357 return;
358
359 // Remove all the screencasts, if they haven't been already.
360 while (!it->second.started_screencasts.empty()) {
361 uint32 ssrc = it->second.started_screencasts.begin()->first;
362 if (!StopScreencastWithoutSendingUpdate(it->second.session, ssrc)) {
363 LOG(LS_ERROR) << "Unable to stop screencast with ssrc " << ssrc;
364 ASSERT(false);
365 }
366 }
367
368 // Destroy video channel
369 VideoChannel* video_channel = it->second.video_channel;
370 if (video_channel != NULL)
371 session_client_->channel_manager()->DestroyVideoChannel(video_channel);
372
373 // Destroy voice channel
374 VoiceChannel* voice_channel = it->second.voice_channel;
375 if (voice_channel != NULL)
376 session_client_->channel_manager()->DestroyVoiceChannel(voice_channel);
377
378 // Destroy data channel
379 DataChannel* data_channel = it->second.data_channel;
380 if (data_channel != NULL)
381 session_client_->channel_manager()->DestroyDataChannel(data_channel);
382
383 delete it->second.recv_streams;
384 media_session_map_.erase(it);
385
386 // Destroy speaker monitor
387 StopSpeakerMonitor(session);
388
389 // Signal client
390 SignalRemoveSession(this, session);
391
392 // The call auto destroys when the last session is removed
393 talk_base::Thread::Current()->Post(this, MSG_CHECKAUTODESTROY);
394}
395
396VoiceChannel* Call::GetVoiceChannel(Session* session) const {
397 MediaSessionMap::const_iterator it = media_session_map_.find(session->id());
398 return (it != media_session_map_.end()) ? it->second.voice_channel : NULL;
399}
400
401VideoChannel* Call::GetVideoChannel(Session* session) const {
402 MediaSessionMap::const_iterator it = media_session_map_.find(session->id());
403 return (it != media_session_map_.end()) ? it->second.video_channel : NULL;
404}
405
406DataChannel* Call::GetDataChannel(Session* session) const {
407 MediaSessionMap::const_iterator it = media_session_map_.find(session->id());
408 return (it != media_session_map_.end()) ? it->second.data_channel : NULL;
409}
410
411MediaStreams* Call::GetMediaStreams(Session* session) const {
412 MediaSessionMap::const_iterator it = media_session_map_.find(session->id());
413 return (it != media_session_map_.end()) ? it->second.recv_streams : NULL;
414}
415
416void Call::EnableChannels(bool enable) {
417 MediaSessionMap::iterator it;
418 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) {
419 EnableSessionChannels(it->second.session, enable);
420 }
421 session_client_->channel_manager()->SetLocalRenderer(
422 (enable) ? local_renderer_ : NULL);
423}
424
425void Call::EnableSessionChannels(Session* session, bool enable) {
426 MediaSessionMap::iterator it = media_session_map_.find(session->id());
427 if (it == media_session_map_.end())
428 return;
429
430 VoiceChannel* voice_channel = it->second.voice_channel;
431 VideoChannel* video_channel = it->second.video_channel;
432 DataChannel* data_channel = it->second.data_channel;
433 if (voice_channel != NULL)
434 voice_channel->Enable(enable);
435 if (video_channel != NULL)
436 video_channel->Enable(enable);
437 if (data_channel != NULL)
438 data_channel->Enable(enable);
439}
440
441void Call::Mute(bool mute) {
442 muted_ = mute;
443 MediaSessionMap::iterator it;
444 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) {
445 if (it->second.voice_channel != NULL)
446 it->second.voice_channel->MuteStream(0, mute);
447 }
448}
449
450void Call::MuteVideo(bool mute) {
451 video_muted_ = mute;
452 MediaSessionMap::iterator it;
453 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) {
454 if (it->second.video_channel != NULL)
455 it->second.video_channel->MuteStream(0, mute);
456 }
457}
458
459bool Call::SendData(Session* session,
460 const SendDataParams& params,
461 const talk_base::Buffer& payload,
462 SendDataResult* result) {
463 DataChannel* data_channel = GetDataChannel(session);
464 if (!data_channel) {
465 LOG(LS_WARNING) << "Could not send data: no data channel.";
466 return false;
467 }
468
469 return data_channel->SendData(params, payload, result);
470}
471
472void Call::PressDTMF(int event) {
473 // Queue up this digit
474 if (queued_dtmf_.size() < kMaxDTMFDigits) {
475 LOG(LS_INFO) << "Call::PressDTMF(" << event << ")";
476
477 queued_dtmf_.push_back(event);
478
479 if (!playing_dtmf_) {
480 ContinuePlayDTMF();
481 }
482 }
483}
484
485cricket::VideoFormat ScreencastFormatFromFps(int fps) {
486 // The capturer pretty much ignore this, but just in case we give it
487 // a resolution big enough to cover any expected desktop. In any
488 // case, it can't be 0x0, or the CaptureManager will fail to use it.
489 return cricket::VideoFormat(
490 1, 1,
491 cricket::VideoFormat::FpsToInterval(fps), cricket::FOURCC_ANY);
492}
493
494bool Call::StartScreencast(Session* session,
495 const std::string& streamid, uint32 ssrc,
496 const ScreencastId& screencastid, int fps) {
497 MediaSessionMap::iterator it = media_session_map_.find(session->id());
498 if (it == media_session_map_.end()) {
499 return false;
500 }
501
502 VideoChannel *video_channel = GetVideoChannel(session);
503 if (!video_channel) {
504 LOG(LS_WARNING) << "Cannot add screencast"
505 << " because there is no video channel.";
506 return false;
507 }
508
509 VideoCapturer *capturer = video_channel->AddScreencast(ssrc, screencastid);
510 if (capturer == NULL) {
511 LOG(LS_WARNING) << "Could not create screencast capturer.";
512 return false;
513 }
514
515 VideoFormat format = ScreencastFormatFromFps(fps);
516 if (!session_client_->channel_manager()->StartVideoCapture(
517 capturer, format)) {
518 LOG(LS_WARNING) << "Could not start video capture.";
519 video_channel->RemoveScreencast(ssrc);
520 return false;
521 }
522
523 if (!video_channel->SetCapturer(ssrc, capturer)) {
524 LOG(LS_WARNING) << "Could not start sending screencast.";
525 session_client_->channel_manager()->StopVideoCapture(
526 capturer, ScreencastFormatFromFps(fps));
527 video_channel->RemoveScreencast(ssrc);
528 }
529
530 // TODO(pthatcher): Once the CaptureManager has a nicer interface
531 // for removing captures (such as having StartCapture return a
532 // handle), remove this StartedCapture stuff.
533 it->second.started_screencasts.insert(
534 std::make_pair(ssrc, StartedCapture(capturer, format)));
535
536 // TODO(pthatcher): Verify we aren't re-using an existing id or
537 // ssrc.
538 StreamParams stream;
539 stream.id = streamid;
540 stream.ssrcs.push_back(ssrc);
541 VideoContentDescription* video = CreateVideoStreamUpdate(stream);
542
543 // TODO(pthatcher): Wait until view request before sending video.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000544 video_channel->SetLocalContent(video, CA_UPDATE, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 SendVideoStreamUpdate(session, video);
546 return true;
547}
548
549bool Call::StopScreencast(Session* session,
550 const std::string& streamid, uint32 ssrc) {
551 if (!StopScreencastWithoutSendingUpdate(session, ssrc)) {
552 return false;
553 }
554
555 VideoChannel *video_channel = GetVideoChannel(session);
556 if (!video_channel) {
557 LOG(LS_WARNING) << "Cannot add screencast"
558 << " because there is no video channel.";
559 return false;
560 }
561
562 StreamParams stream;
563 stream.id = streamid;
564 // No ssrcs
565 VideoContentDescription* video = CreateVideoStreamUpdate(stream);
566
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000567 video_channel->SetLocalContent(video, CA_UPDATE, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 SendVideoStreamUpdate(session, video);
569 return true;
570}
571
572bool Call::StopScreencastWithoutSendingUpdate(
573 Session* session, uint32 ssrc) {
574 MediaSessionMap::iterator it = media_session_map_.find(session->id());
575 if (it == media_session_map_.end()) {
576 return false;
577 }
578
579 VideoChannel *video_channel = GetVideoChannel(session);
580 if (!video_channel) {
581 LOG(LS_WARNING) << "Cannot remove screencast"
582 << " because there is no video channel.";
583 return false;
584 }
585
586 StartedScreencastMap::const_iterator screencast_iter =
587 it->second.started_screencasts.find(ssrc);
588 if (screencast_iter == it->second.started_screencasts.end()) {
589 LOG(LS_WARNING) << "Could not stop screencast " << ssrc
590 << " because there is no capturer.";
591 return false;
592 }
593
594 VideoCapturer* capturer = screencast_iter->second.capturer;
595 VideoFormat format = screencast_iter->second.format;
596 video_channel->SetCapturer(ssrc, NULL);
597 if (!session_client_->channel_manager()->StopVideoCapture(
598 capturer, format)) {
599 LOG(LS_WARNING) << "Could not stop screencast " << ssrc
600 << " because could not stop capture.";
601 return false;
602 }
603 video_channel->RemoveScreencast(ssrc);
604 it->second.started_screencasts.erase(ssrc);
605 return true;
606}
607
608VideoContentDescription* Call::CreateVideoStreamUpdate(
609 const StreamParams& stream) {
610 VideoContentDescription* video = new VideoContentDescription();
611 video->set_multistream(true);
612 video->set_partial(true);
613 video->AddStream(stream);
614 return video;
615}
616
617void Call::SendVideoStreamUpdate(
618 Session* session, VideoContentDescription* video) {
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000619 // Takes the ownership of |video|.
620 talk_base::scoped_ptr<VideoContentDescription> description(video);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621 const ContentInfo* video_info =
622 GetFirstVideoContent(session->local_description());
623 if (video_info == NULL) {
624 LOG(LS_WARNING) << "Cannot send stream update for video.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 return;
626 }
627
628 std::vector<ContentInfo> contents;
629 contents.push_back(
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000630 ContentInfo(video_info->name, video_info->type, description.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631
632 session->SendDescriptionInfoMessage(contents);
633}
634
635void Call::ContinuePlayDTMF() {
636 playing_dtmf_ = false;
637
638 // Check to see if we have a queued tone
639 if (queued_dtmf_.size() > 0) {
640 playing_dtmf_ = true;
641
642 int tone = queued_dtmf_.front();
643 queued_dtmf_.pop_front();
644
645 LOG(LS_INFO) << "Call::ContinuePlayDTMF(" << tone << ")";
646 for (MediaSessionMap::iterator it = media_session_map_.begin();
647 it != media_session_map_.end(); ++it) {
648 if (it->second.voice_channel != NULL) {
649 it->second.voice_channel->PressDTMF(tone, true);
650 }
651 }
652
653 // Post a message to play the next tone or at least clear the playing_dtmf_
654 // bit.
655 talk_base::Thread::Current()->PostDelayed(kDTMFDelay, this, MSG_PLAYDTMF);
656 }
657}
658
659void Call::Join(Call* call, bool enable) {
660 for (MediaSessionMap::iterator it = call->media_session_map_.begin();
661 it != call->media_session_map_.end(); ++it) {
662 // Shouldn't already exist.
663 ASSERT(media_session_map_.find(it->first) == media_session_map_.end());
664 media_session_map_[it->first] = it->second;
665
666 it->second.session->SignalState.connect(this, &Call::OnSessionState);
667 it->second.session->SignalError.connect(this, &Call::OnSessionError);
668 it->second.session->SignalReceivedTerminateReason
669 .connect(this, &Call::OnReceivedTerminateReason);
670
671 EnableSessionChannels(it->second.session, enable);
672 }
673
674 // Moved all the sessions over, so the other call should no longer have any.
675 call->media_session_map_.clear();
676}
677
678void Call::StartConnectionMonitor(Session* session, int cms) {
679 VoiceChannel* voice_channel = GetVoiceChannel(session);
680 if (voice_channel) {
681 voice_channel->SignalConnectionMonitor.connect(this,
682 &Call::OnConnectionMonitor);
683 voice_channel->StartConnectionMonitor(cms);
684 }
685
686 VideoChannel* video_channel = GetVideoChannel(session);
687 if (video_channel) {
688 video_channel->SignalConnectionMonitor.connect(this,
689 &Call::OnConnectionMonitor);
690 video_channel->StartConnectionMonitor(cms);
691 }
692}
693
694void Call::StopConnectionMonitor(Session* session) {
695 VoiceChannel* voice_channel = GetVoiceChannel(session);
696 if (voice_channel) {
697 voice_channel->StopConnectionMonitor();
698 voice_channel->SignalConnectionMonitor.disconnect(this);
699 }
700
701 VideoChannel* video_channel = GetVideoChannel(session);
702 if (video_channel) {
703 video_channel->StopConnectionMonitor();
704 video_channel->SignalConnectionMonitor.disconnect(this);
705 }
706}
707
708void Call::StartAudioMonitor(Session* session, int cms) {
709 VoiceChannel* voice_channel = GetVoiceChannel(session);
710 if (voice_channel) {
711 voice_channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor);
712 voice_channel->StartAudioMonitor(cms);
713 }
714}
715
716void Call::StopAudioMonitor(Session* session) {
717 VoiceChannel* voice_channel = GetVoiceChannel(session);
718 if (voice_channel) {
719 voice_channel->StopAudioMonitor();
720 voice_channel->SignalAudioMonitor.disconnect(this);
721 }
722}
723
724bool Call::IsAudioMonitorRunning(Session* session) {
725 VoiceChannel* voice_channel = GetVoiceChannel(session);
726 if (voice_channel) {
727 return voice_channel->IsAudioMonitorRunning();
728 } else {
729 return false;
730 }
731}
732
733void Call::StartSpeakerMonitor(Session* session) {
734 if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) {
735 if (!IsAudioMonitorRunning(session)) {
736 StartAudioMonitor(session, kAudioMonitorPollPeriodMillis);
737 }
738 CurrentSpeakerMonitor* speaker_monitor =
buildbot@webrtc.orgca272362014-05-08 23:10:23 +0000739 new cricket::CurrentSpeakerMonitor(
740 audio_source_proxy_.get(), session);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 speaker_monitor->SignalUpdate.connect(this, &Call::OnSpeakerMonitor);
742 speaker_monitor->Start();
743 speaker_monitor_map_[session->id()] = speaker_monitor;
744 } else {
745 LOG(LS_WARNING) << "Already started speaker monitor for session "
746 << session->id() << ".";
747 }
748}
749
750void Call::StopSpeakerMonitor(Session* session) {
751 if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) {
752 LOG(LS_WARNING) << "Speaker monitor for session "
753 << session->id() << " already stopped.";
754 } else {
755 CurrentSpeakerMonitor* monitor = speaker_monitor_map_[session->id()];
756 monitor->Stop();
757 speaker_monitor_map_.erase(session->id());
758 delete monitor;
759 }
760}
761
762void Call::OnConnectionMonitor(VoiceChannel* channel,
763 const std::vector<ConnectionInfo> &infos) {
764 SignalConnectionMonitor(this, infos);
765}
766
767void Call::OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info) {
768 last_voice_media_info_ = info;
769 SignalMediaMonitor(this, info);
770}
771
772void Call::OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info) {
773 SignalAudioMonitor(this, info);
774}
775
776void Call::OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc) {
777 Session* session = static_cast<Session*>(monitor->session());
778 MediaStreams* recv_streams = GetMediaStreams(session);
779 if (recv_streams) {
780 StreamParams stream;
781 recv_streams->GetAudioStream(StreamSelector(ssrc), &stream);
782 SignalSpeakerMonitor(this, session, stream);
783 }
784}
785
786void Call::OnConnectionMonitor(VideoChannel* channel,
787 const std::vector<ConnectionInfo> &infos) {
788 SignalVideoConnectionMonitor(this, infos);
789}
790
791void Call::OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info) {
792 SignalVideoMediaMonitor(this, info);
793}
794
795void Call::OnDataReceived(DataChannel* channel,
796 const ReceiveDataParams& params,
797 const talk_base::Buffer& payload) {
798 SignalDataReceived(this, params, payload);
799}
800
801uint32 Call::id() {
802 return id_;
803}
804
805void Call::OnSessionState(BaseSession* base_session, BaseSession::State state) {
806 Session* session = static_cast<Session*>(base_session);
807 switch (state) {
808 case Session::STATE_RECEIVEDACCEPT:
809 UpdateRemoteMediaStreams(session,
810 session->remote_description()->contents(), false);
811 session_client_->session_manager()->signaling_thread()->Clear(this,
812 MSG_TERMINATECALL);
813 break;
814 case Session::STATE_RECEIVEDREJECT:
815 case Session::STATE_RECEIVEDTERMINATE:
816 session_client_->session_manager()->signaling_thread()->Clear(this,
817 MSG_TERMINATECALL);
818 break;
819 default:
820 break;
821 }
822 SignalSessionState(this, session, state);
823}
824
825void Call::OnSessionError(BaseSession* base_session, Session::Error error) {
826 session_client_->session_manager()->signaling_thread()->Clear(this,
827 MSG_TERMINATECALL);
828 SignalSessionError(this, static_cast<Session*>(base_session), error);
829}
830
831void Call::OnSessionInfoMessage(Session* session,
832 const buzz::XmlElement* action_elem) {
833 if (!IsJingleViewRequest(action_elem)) {
834 return;
835 }
836
837 ViewRequest view_request;
838 ParseError error;
839 if (!ParseJingleViewRequest(action_elem, &view_request, &error)) {
840 LOG(LS_WARNING) << "Failed to parse view request: " << error.text;
841 return;
842 }
843
844 VideoChannel* video_channel = GetVideoChannel(session);
845 if (video_channel == NULL) {
846 LOG(LS_WARNING) << "Ignore view request since we have no video channel.";
847 return;
848 }
849
850 if (!video_channel->ApplyViewRequest(view_request)) {
851 LOG(LS_WARNING) << "Failed to ApplyViewRequest.";
852 }
853}
854
855void Call::OnRemoteDescriptionUpdate(BaseSession* base_session,
856 const ContentInfos& updated_contents) {
857 Session* session = static_cast<Session*>(base_session);
858
859 const ContentInfo* audio_content = GetFirstAudioContent(updated_contents);
860 if (audio_content) {
861 const AudioContentDescription* audio_update =
862 static_cast<const AudioContentDescription*>(audio_content->description);
863 if (!audio_update->codecs().empty()) {
864 UpdateVoiceChannelRemoteContent(session, audio_update);
865 }
866 }
867
868 const ContentInfo* video_content = GetFirstVideoContent(updated_contents);
869 if (video_content) {
870 const VideoContentDescription* video_update =
871 static_cast<const VideoContentDescription*>(video_content->description);
872 if (!video_update->codecs().empty()) {
873 UpdateVideoChannelRemoteContent(session, video_update);
874 }
875 }
876
877 const ContentInfo* data_content = GetFirstDataContent(updated_contents);
878 if (data_content) {
879 const DataContentDescription* data_update =
880 static_cast<const DataContentDescription*>(data_content->description);
881 if (!data_update->codecs().empty()) {
882 UpdateDataChannelRemoteContent(session, data_update);
883 }
884 }
885
886 UpdateRemoteMediaStreams(session, updated_contents, true);
887}
888
889bool Call::UpdateVoiceChannelRemoteContent(
890 Session* session, const AudioContentDescription* audio) {
891 VoiceChannel* voice_channel = GetVoiceChannel(session);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000892 if (!voice_channel->SetRemoteContent(audio, CA_UPDATE, NULL)) {
893 const std::string error_desc =
894 "Failure in audio SetRemoteContent with CA_UPDATE";
895 LOG(LS_ERROR) << error_desc;
896 session->SetError(BaseSession::ERROR_CONTENT, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 return false;
898 }
899 return true;
900}
901
902bool Call::UpdateVideoChannelRemoteContent(
903 Session* session, const VideoContentDescription* video) {
904 VideoChannel* video_channel = GetVideoChannel(session);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000905 if (!video_channel->SetRemoteContent(video, CA_UPDATE, NULL)) {
906 const std::string error_desc =
907 "Failure in video SetRemoteContent with CA_UPDATE";
908 LOG(LS_ERROR) << error_desc;
909 session->SetError(BaseSession::ERROR_CONTENT, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910 return false;
911 }
912 return true;
913}
914
915bool Call::UpdateDataChannelRemoteContent(
916 Session* session, const DataContentDescription* data) {
917 DataChannel* data_channel = GetDataChannel(session);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000918 if (!data_channel->SetRemoteContent(data, CA_UPDATE, NULL)) {
919 const std::string error_desc =
920 "Failure in data SetRemoteContent with CA_UPDATE";
921 LOG(LS_ERROR) << error_desc;
922 session->SetError(BaseSession::ERROR_CONTENT, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 return false;
924 }
925 return true;
926}
927
928void Call::UpdateRemoteMediaStreams(Session* session,
929 const ContentInfos& updated_contents,
930 bool update_channels) {
931 MediaStreams* recv_streams = GetMediaStreams(session);
932 if (!recv_streams)
933 return;
934
935 cricket::MediaStreams added_streams;
936 cricket::MediaStreams removed_streams;
937
938 const ContentInfo* audio_content = GetFirstAudioContent(updated_contents);
939 if (audio_content) {
940 const AudioContentDescription* audio_update =
941 static_cast<const AudioContentDescription*>(audio_content->description);
942 UpdateRecvStreams(audio_update->streams(),
943 update_channels ? GetVoiceChannel(session) : NULL,
944 recv_streams->mutable_audio(),
945 added_streams.mutable_audio(),
946 removed_streams.mutable_audio());
947 }
948
949 const ContentInfo* video_content = GetFirstVideoContent(updated_contents);
950 if (video_content) {
951 const VideoContentDescription* video_update =
952 static_cast<const VideoContentDescription*>(video_content->description);
953 UpdateRecvStreams(video_update->streams(),
954 update_channels ? GetVideoChannel(session) : NULL,
955 recv_streams->mutable_video(),
956 added_streams.mutable_video(),
957 removed_streams.mutable_video());
958 }
959
960 const ContentInfo* data_content = GetFirstDataContent(updated_contents);
961 if (data_content) {
962 const DataContentDescription* data_update =
963 static_cast<const DataContentDescription*>(data_content->description);
964 UpdateRecvStreams(data_update->streams(),
965 update_channels ? GetDataChannel(session) : NULL,
966 recv_streams->mutable_data(),
967 added_streams.mutable_data(),
968 removed_streams.mutable_data());
969 }
970
971 if (!added_streams.empty() || !removed_streams.empty()) {
972 SignalMediaStreamsUpdate(this, session, added_streams, removed_streams);
973 }
974}
975
976void FindStreamChanges(const std::vector<StreamParams>& streams,
977 const std::vector<StreamParams>& updates,
978 std::vector<StreamParams>* added_streams,
979 std::vector<StreamParams>* removed_streams) {
980 for (std::vector<StreamParams>::const_iterator update = updates.begin();
981 update != updates.end(); ++update) {
982 StreamParams stream;
983 if (GetStreamByIds(streams, update->groupid, update->id, &stream)) {
984 if (!update->has_ssrcs()) {
985 removed_streams->push_back(stream);
986 }
987 } else {
988 // There's a bug on reflector that will send <stream>s even
989 // though there is not ssrc (which means there isn't really a
990 // stream). To work around it, we simply ignore new <stream>s
991 // that don't have any ssrcs.
992 if (update->has_ssrcs()) {
993 added_streams->push_back(*update);
994 }
995 }
996 }
997}
998
999void Call::UpdateRecvStreams(const std::vector<StreamParams>& update_streams,
1000 BaseChannel* channel,
1001 std::vector<StreamParams>* recv_streams,
1002 std::vector<StreamParams>* added_streams,
1003 std::vector<StreamParams>* removed_streams) {
1004 FindStreamChanges(*recv_streams,
1005 update_streams, added_streams, removed_streams);
1006 AddRecvStreams(*added_streams,
1007 channel, recv_streams);
1008 RemoveRecvStreams(*removed_streams,
1009 channel, recv_streams);
1010}
1011
1012void Call::AddRecvStreams(const std::vector<StreamParams>& added_streams,
1013 BaseChannel* channel,
1014 std::vector<StreamParams>* recv_streams) {
1015 std::vector<StreamParams>::const_iterator stream;
1016 for (stream = added_streams.begin();
1017 stream != added_streams.end();
1018 ++stream) {
1019 AddRecvStream(*stream, channel, recv_streams);
1020 }
1021}
1022
1023void Call::AddRecvStream(const StreamParams& stream,
1024 BaseChannel* channel,
1025 std::vector<StreamParams>* recv_streams) {
1026 if (channel && stream.has_ssrcs()) {
1027 channel->AddRecvStream(stream);
1028 }
1029 recv_streams->push_back(stream);
1030}
1031
1032void Call::RemoveRecvStreams(const std::vector<StreamParams>& removed_streams,
1033 BaseChannel* channel,
1034 std::vector<StreamParams>* recv_streams) {
1035 std::vector<StreamParams>::const_iterator stream;
1036 for (stream = removed_streams.begin();
1037 stream != removed_streams.end();
1038 ++stream) {
1039 RemoveRecvStream(*stream, channel, recv_streams);
1040 }
1041}
1042
1043void Call::RemoveRecvStream(const StreamParams& stream,
1044 BaseChannel* channel,
1045 std::vector<StreamParams>* recv_streams) {
1046 if (channel && stream.has_ssrcs()) {
1047 // TODO(pthatcher): Change RemoveRecvStream to take a stream argument.
1048 channel->RemoveRecvStream(stream.first_ssrc());
1049 }
1050 RemoveStreamByIds(recv_streams, stream.groupid, stream.id);
1051}
1052
1053void Call::OnReceivedTerminateReason(Session* session,
1054 const std::string& reason) {
1055 session_client_->session_manager()->signaling_thread()->Clear(this,
1056 MSG_TERMINATECALL);
1057 SignalReceivedTerminateReason(this, session, reason);
1058}
1059
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001060// TODO(mdodd): Get ride of this method since all Hangouts are using a secure
1061// connection.
1062bool Call::secure() const {
1063 if (session_client_->secure() == SEC_DISABLED) {
1064 return false;
1065 }
1066
1067 bool ret = true;
1068 int i = 0;
1069
1070 MediaSessionMap::const_iterator it;
1071 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) {
1072 LOG_F(LS_VERBOSE) << "session[" << i
1073 << "], check local and remote descriptions";
1074 i++;
1075
1076 if (!SessionDescriptionContainsCrypto(
1077 it->second.session->local_description()) ||
1078 !SessionDescriptionContainsCrypto(
1079 it->second.session->remote_description())) {
1080 ret = false;
1081 break;
1082 }
1083 }
1084
1085 LOG_F(LS_VERBOSE) << "secure=" << ret;
1086 return ret;
1087}
1088
1089bool Call::SessionDescriptionContainsCrypto(
1090 const SessionDescription* sdesc) const {
1091 if (sdesc == NULL) {
1092 LOG_F(LS_VERBOSE) << "sessionDescription is NULL";
1093 return false;
1094 }
1095
1096 return ContentContainsCrypto(sdesc->GetContentByName(CN_AUDIO)) &&
1097 ContentContainsCrypto(sdesc->GetContentByName(CN_VIDEO));
1098}
1099
1100Session* Call::InternalInitiateSession(const std::string& id,
1101 const buzz::Jid& to,
1102 const std::string& initiator_name,
1103 const CallOptions& options) {
1104 const SessionDescription* offer = session_client_->CreateOffer(options);
1105
1106 Session* session = session_client_->CreateSession(id, this);
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +00001107 // Only override the initiator_name if it was manually supplied. Otherwise,
1108 // session_client_ will supply the local jid as initiator in CreateOffer.
1109 if (!initiator_name.empty()) {
1110 session->set_initiator_name(initiator_name);
1111 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001112
1113 AddSession(session, offer);
1114 session->Initiate(to.Str(), offer);
1115
1116 // After this timeout, terminate the call because the callee isn't
1117 // answering
1118 session_client_->session_manager()->signaling_thread()->Clear(this,
1119 MSG_TERMINATECALL);
1120 session_client_->session_manager()->signaling_thread()->PostDelayed(
1121 send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout,
1122 this, MSG_TERMINATECALL);
1123 return session;
1124}
1125
buildbot@webrtc.orgca272362014-05-08 23:10:23 +00001126AudioSourceProxy* Call::GetAudioSourceProxy() {
1127 return audio_source_proxy_.get();
1128}
1129
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130} // namespace cricket