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