1 /*
2 * libjingle
3 * Copyright 2004--2007, 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/session/phone/call.h"
33 #include "talk/session/phone/mediasessionclient.h"
34
35 namespace cricket {
36
37 const uint32 MSG_CHECKAUTODESTROY = 1;
38 const uint32 MSG_TERMINATECALL = 2;
39 const uint32 MSG_PLAYDTMF = 3;
40
41 namespace {
42 const int kDTMFDelay = 300; // msec
43 const size_t kMaxDTMFDigits = 30;
44 const int kSendToVoicemailTimeout = 1000*20;
45 const int kNoVoicemailTimeout = 1000*180;
46 const int kMediaMonitorInterval = 1000*15;
47 }
48
Call(MediaSessionClient * session_client)49 Call::Call(MediaSessionClient* session_client)
50 : id_(talk_base::CreateRandomId()),
51 session_client_(session_client),
52 local_renderer_(NULL),
53 muted_(false),
54 send_to_voicemail_(true),
55 playing_dtmf_(false) {
56 }
57
~Call()58 Call::~Call() {
59 while (sessions_.begin() != sessions_.end()) {
60 Session *session = sessions_[0];
61 RemoveSession(session);
62 session_client_->session_manager()->DestroySession(session);
63 }
64 talk_base::Thread::Current()->Clear(this);
65 }
66
InitiateSession(const buzz::Jid & jid,const CallOptions & options)67 Session *Call::InitiateSession(const buzz::Jid &jid,
68 const CallOptions& options) {
69 const SessionDescription* offer = session_client_->CreateOffer(options);
70
71 Session *session = session_client_->CreateSession(this);
72 AddSession(session, offer);
73 session->Initiate(jid.Str(), offer);
74
75 // After this timeout, terminate the call because the callee isn't
76 // answering
77 session_client_->session_manager()->signaling_thread()->Clear(this,
78 MSG_TERMINATECALL);
79 session_client_->session_manager()->signaling_thread()->PostDelayed(
80 send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout,
81 this, MSG_TERMINATECALL);
82 return session;
83 }
84
IncomingSession(Session * session,const SessionDescription * offer)85 void Call::IncomingSession(
86 Session* session, const SessionDescription* offer) {
87 AddSession(session, offer);
88
89 // Missed the first state, the initiate, which is needed by
90 // call_client.
91 SignalSessionState(this, session, Session::STATE_RECEIVEDINITIATE);
92 }
93
AcceptSession(BaseSession * session,const cricket::CallOptions & options)94 void Call::AcceptSession(BaseSession* session,
95 const cricket::CallOptions& options) {
96 std::vector<Session *>::iterator it;
97 it = std::find(sessions_.begin(), sessions_.end(), session);
98 ASSERT(it != sessions_.end());
99 if (it != sessions_.end()) {
100 session->Accept(
101 session_client_->CreateAnswer(session->remote_description(), options));
102 }
103 }
104
RejectSession(BaseSession * session)105 void Call::RejectSession(BaseSession *session) {
106 std::vector<Session *>::iterator it;
107 it = std::find(sessions_.begin(), sessions_.end(), session);
108 ASSERT(it != sessions_.end());
109 // Assume polite decline.
110 if (it != sessions_.end())
111 session->Reject(STR_TERMINATE_DECLINE);
112 }
113
TerminateSession(BaseSession * session)114 void Call::TerminateSession(BaseSession *session) {
115 ASSERT(std::find(sessions_.begin(), sessions_.end(), session)
116 != sessions_.end());
117 std::vector<Session *>::iterator it;
118 it = std::find(sessions_.begin(), sessions_.end(), session);
119 // Assume polite terminations.
120 if (it != sessions_.end())
121 (*it)->Terminate();
122 }
123
Terminate()124 void Call::Terminate() {
125 // Copy the list so that we can iterate over it in a stable way
126 std::vector<Session *> sessions = sessions_;
127
128 // There may be more than one session to terminate
129 std::vector<Session *>::iterator it;
130 for (it = sessions.begin(); it != sessions.end(); it++)
131 TerminateSession(*it);
132 }
133
SetLocalRenderer(VideoRenderer * renderer)134 void Call::SetLocalRenderer(VideoRenderer* renderer) {
135 local_renderer_ = renderer;
136 if (session_client_->GetFocus() == this) {
137 session_client_->channel_manager()->SetLocalRenderer(renderer);
138 }
139 }
140
SetVideoRenderer(BaseSession * session,uint32 ssrc,VideoRenderer * renderer)141 void Call::SetVideoRenderer(BaseSession *session, uint32 ssrc,
142 VideoRenderer* renderer) {
143 VideoChannel *video_channel = GetVideoChannel(session);
144 if (video_channel) {
145 video_channel->SetRenderer(ssrc, renderer);
146 }
147 }
148
AddStream(BaseSession * session,uint32 voice_ssrc,uint32 video_ssrc)149 void Call::AddStream(BaseSession *session,
150 uint32 voice_ssrc, uint32 video_ssrc) {
151 VoiceChannel *voice_channel = GetVoiceChannel(session);
152 VideoChannel *video_channel = GetVideoChannel(session);
153 if (voice_channel && voice_ssrc) {
154 voice_channel->AddStream(voice_ssrc);
155 }
156 if (video_channel && video_ssrc) {
157 video_channel->AddStream(video_ssrc, voice_ssrc);
158 }
159 }
160
RemoveStream(BaseSession * session,uint32 voice_ssrc,uint32 video_ssrc)161 void Call::RemoveStream(BaseSession *session,
162 uint32 voice_ssrc, uint32 video_ssrc) {
163 VoiceChannel *voice_channel = GetVoiceChannel(session);
164 VideoChannel *video_channel = GetVideoChannel(session);
165 if (voice_channel && voice_ssrc) {
166 voice_channel->RemoveStream(voice_ssrc);
167 }
168 if (video_channel && video_ssrc) {
169 video_channel->RemoveStream(video_ssrc);
170 }
171 }
172
OnMessage(talk_base::Message * message)173 void Call::OnMessage(talk_base::Message *message) {
174 switch (message->message_id) {
175 case MSG_CHECKAUTODESTROY:
176 // If no more sessions for this call, delete it
177 if (sessions_.size() == 0)
178 session_client_->DestroyCall(this);
179 break;
180 case MSG_TERMINATECALL:
181 // Signal to the user that a timeout has happened and the call should
182 // be sent to voicemail.
183 if (send_to_voicemail_) {
184 SignalSetupToCallVoicemail();
185 }
186
187 // Callee didn't answer - terminate call
188 Terminate();
189 break;
190 case MSG_PLAYDTMF:
191 ContinuePlayDTMF();
192 }
193 }
194
sessions()195 const std::vector<Session *> &Call::sessions() {
196 return sessions_;
197 }
198
AddSession(Session * session,const SessionDescription * offer)199 bool Call::AddSession(Session *session, const SessionDescription* offer) {
200 bool succeeded = true;
201 VoiceChannel *voice_channel = NULL;
202 VideoChannel *video_channel = NULL;
203
204 const ContentInfo* audio_offer = GetFirstAudioContent(offer);
205 const ContentInfo* video_offer = GetFirstVideoContent(offer);
206 video_ = (video_offer != NULL);
207
208 ASSERT(audio_offer != NULL);
209 // Create voice channel and start a media monitor
210 voice_channel = session_client_->channel_manager()->CreateVoiceChannel(
211 session, audio_offer->name, video_);
212 // voice_channel can be NULL in case of NullVoiceEngine.
213 if (voice_channel) {
214 voice_channel_map_[session->id()] = voice_channel;
215
216 voice_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
217 voice_channel->StartMediaMonitor(kMediaMonitorInterval);
218 } else {
219 succeeded = false;
220 }
221
222 // If desired, create video channel and start a media monitor
223 if (video_ && succeeded) {
224 video_channel = session_client_->channel_manager()->CreateVideoChannel(
225 session, video_offer->name, true, voice_channel);
226 // video_channel can be NULL in case of NullVideoEngine.
227 if (video_channel) {
228 video_channel_map_[session->id()] = video_channel;
229
230 video_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
231 video_channel->StartMediaMonitor(kMediaMonitorInterval);
232 } else {
233 succeeded = false;
234 }
235 }
236
237 if (succeeded) {
238 // Add session to list, create channels for this session
239 sessions_.push_back(session);
240 session->SignalState.connect(this, &Call::OnSessionState);
241 session->SignalError.connect(this, &Call::OnSessionError);
242 session->SignalReceivedTerminateReason
243 .connect(this, &Call::OnReceivedTerminateReason);
244
245 // If this call has the focus, enable this channel
246 if (session_client_->GetFocus() == this) {
247 voice_channel->Enable(true);
248 if (video_channel) {
249 video_channel->Enable(true);
250 }
251 }
252
253 // Signal client
254 SignalAddSession(this, session);
255 }
256
257 return succeeded;
258 }
259
RemoveSession(Session * session)260 void Call::RemoveSession(Session *session) {
261 // Remove session from list
262 std::vector<Session *>::iterator it_session;
263 it_session = std::find(sessions_.begin(), sessions_.end(), session);
264 if (it_session == sessions_.end())
265 return;
266 sessions_.erase(it_session);
267
268 // Destroy video channel
269 std::map<std::string, VideoChannel *>::iterator it_vchannel;
270 it_vchannel = video_channel_map_.find(session->id());
271 if (it_vchannel != video_channel_map_.end()) {
272 VideoChannel *video_channel = it_vchannel->second;
273 video_channel_map_.erase(it_vchannel);
274 session_client_->channel_manager()->DestroyVideoChannel(video_channel);
275 }
276
277 // Destroy voice channel
278 std::map<std::string, VoiceChannel *>::iterator it_channel;
279 it_channel = voice_channel_map_.find(session->id());
280 if (it_channel != voice_channel_map_.end()) {
281 VoiceChannel *voice_channel = it_channel->second;
282 voice_channel_map_.erase(it_channel);
283 session_client_->channel_manager()->DestroyVoiceChannel(voice_channel);
284 }
285
286 // Signal client
287 SignalRemoveSession(this, session);
288
289 // The call auto destroys when the last session is removed
290 talk_base::Thread::Current()->Post(this, MSG_CHECKAUTODESTROY);
291 }
292
GetVoiceChannel(BaseSession * session)293 VoiceChannel* Call::GetVoiceChannel(BaseSession* session) {
294 std::map<std::string, VoiceChannel *>::iterator it
295 = voice_channel_map_.find(session->id());
296 return (it != voice_channel_map_.end()) ? it->second : NULL;
297 }
298
GetVideoChannel(BaseSession * session)299 VideoChannel* Call::GetVideoChannel(BaseSession* session) {
300 std::map<std::string, VideoChannel *>::iterator it
301 = video_channel_map_.find(session->id());
302 return (it != video_channel_map_.end()) ? it->second : NULL;
303 }
304
EnableChannels(bool enable)305 void Call::EnableChannels(bool enable) {
306 std::vector<Session *>::iterator it;
307 for (it = sessions_.begin(); it != sessions_.end(); it++) {
308 VoiceChannel *voice_channel = GetVoiceChannel(*it);
309 VideoChannel *video_channel = GetVideoChannel(*it);
310 if (voice_channel != NULL)
311 voice_channel->Enable(enable);
312 if (video_channel != NULL)
313 video_channel->Enable(enable);
314 }
315 session_client_->channel_manager()->SetLocalRenderer(
316 (enable) ? local_renderer_ : NULL);
317 }
318
Mute(bool mute)319 void Call::Mute(bool mute) {
320 muted_ = mute;
321 std::vector<Session *>::iterator it;
322 for (it = sessions_.begin(); it != sessions_.end(); it++) {
323 VoiceChannel *voice_channel = voice_channel_map_[(*it)->id()];
324 if (voice_channel != NULL)
325 voice_channel->Mute(mute);
326 }
327 }
328
PressDTMF(int event)329 void Call::PressDTMF(int event) {
330 // Queue up this digit
331 if (queued_dtmf_.size() < kMaxDTMFDigits) {
332 LOG(LS_INFO) << "Call::PressDTMF(" << event << ")";
333
334 queued_dtmf_.push_back(event);
335
336 if (!playing_dtmf_) {
337 ContinuePlayDTMF();
338 }
339 }
340 }
341
ContinuePlayDTMF()342 void Call::ContinuePlayDTMF() {
343 playing_dtmf_ = false;
344
345 // Check to see if we have a queued tone
346 if (queued_dtmf_.size() > 0) {
347 playing_dtmf_ = true;
348
349 int tone = queued_dtmf_.front();
350 queued_dtmf_.pop_front();
351
352 LOG(LS_INFO) << "Call::ContinuePlayDTMF(" << tone << ")";
353 std::vector<Session *>::iterator it;
354 for (it = sessions_.begin(); it != sessions_.end(); it++) {
355 VoiceChannel *voice_channel = voice_channel_map_[(*it)->id()];
356 if (voice_channel != NULL) {
357 voice_channel->PressDTMF(tone, true);
358 }
359 }
360
361 // Post a message to play the next tone or at least clear the playing_dtmf_
362 // bit.
363 talk_base::Thread::Current()->PostDelayed(kDTMFDelay, this, MSG_PLAYDTMF);
364 }
365 }
366
Join(Call * call,bool enable)367 void Call::Join(Call *call, bool enable) {
368 while (call->sessions_.size() != 0) {
369 // Move session
370 Session *session = call->sessions_[0];
371 call->sessions_.erase(call->sessions_.begin());
372 sessions_.push_back(session);
373 session->SignalState.connect(this, &Call::OnSessionState);
374 session->SignalError.connect(this, &Call::OnSessionError);
375 session->SignalReceivedTerminateReason
376 .connect(this, &Call::OnReceivedTerminateReason);
377
378 // Move voice channel
379 std::map<std::string, VoiceChannel *>::iterator it_channel;
380 it_channel = call->voice_channel_map_.find(session->id());
381 if (it_channel != call->voice_channel_map_.end()) {
382 VoiceChannel *voice_channel = (*it_channel).second;
383 call->voice_channel_map_.erase(it_channel);
384 voice_channel_map_[session->id()] = voice_channel;
385 voice_channel->Enable(enable);
386 }
387
388 // Move video channel
389 std::map<std::string, VideoChannel *>::iterator it_vchannel;
390 it_vchannel = call->video_channel_map_.find(session->id());
391 if (it_vchannel != call->video_channel_map_.end()) {
392 VideoChannel *video_channel = (*it_vchannel).second;
393 call->video_channel_map_.erase(it_vchannel);
394 video_channel_map_[session->id()] = video_channel;
395 video_channel->Enable(enable);
396 }
397 }
398 }
399
StartConnectionMonitor(BaseSession * session,int cms)400 void Call::StartConnectionMonitor(BaseSession *session, int cms) {
401 VoiceChannel *voice_channel = GetVoiceChannel(session);
402 if (voice_channel) {
403 voice_channel->SignalConnectionMonitor.connect(this,
404 &Call::OnConnectionMonitor);
405 voice_channel->StartConnectionMonitor(cms);
406 }
407
408 VideoChannel *video_channel = GetVideoChannel(session);
409 if (video_channel) {
410 video_channel->SignalConnectionMonitor.connect(this,
411 &Call::OnConnectionMonitor);
412 video_channel->StartConnectionMonitor(cms);
413 }
414 }
415
StopConnectionMonitor(BaseSession * session)416 void Call::StopConnectionMonitor(BaseSession *session) {
417 VoiceChannel *voice_channel = GetVoiceChannel(session);
418 if (voice_channel) {
419 voice_channel->StopConnectionMonitor();
420 voice_channel->SignalConnectionMonitor.disconnect(this);
421 }
422
423 VideoChannel *video_channel = GetVideoChannel(session);
424 if (video_channel) {
425 video_channel->StopConnectionMonitor();
426 video_channel->SignalConnectionMonitor.disconnect(this);
427 }
428 }
429
StartAudioMonitor(BaseSession * session,int cms)430 void Call::StartAudioMonitor(BaseSession *session, int cms) {
431 VoiceChannel *voice_channel = GetVoiceChannel(session);
432 if (voice_channel) {
433 voice_channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor);
434 voice_channel->StartAudioMonitor(cms);
435 }
436 }
437
StopAudioMonitor(BaseSession * session)438 void Call::StopAudioMonitor(BaseSession *session) {
439 VoiceChannel *voice_channel = GetVoiceChannel(session);
440 if (voice_channel) {
441 voice_channel->StopAudioMonitor();
442 voice_channel->SignalAudioMonitor.disconnect(this);
443 }
444 }
445
OnConnectionMonitor(VoiceChannel * channel,const std::vector<ConnectionInfo> & infos)446 void Call::OnConnectionMonitor(VoiceChannel *channel,
447 const std::vector<ConnectionInfo> &infos) {
448 SignalConnectionMonitor(this, infos);
449 }
450
OnMediaMonitor(VoiceChannel * channel,const VoiceMediaInfo & info)451 void Call::OnMediaMonitor(VoiceChannel *channel, const VoiceMediaInfo& info) {
452 SignalMediaMonitor(this, info);
453 }
454
OnAudioMonitor(VoiceChannel * channel,const AudioInfo & info)455 void Call::OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info) {
456 SignalAudioMonitor(this, info);
457 }
458
OnConnectionMonitor(VideoChannel * channel,const std::vector<ConnectionInfo> & infos)459 void Call::OnConnectionMonitor(VideoChannel *channel,
460 const std::vector<ConnectionInfo> &infos) {
461 SignalVideoConnectionMonitor(this, infos);
462 }
463
OnMediaMonitor(VideoChannel * channel,const VideoMediaInfo & info)464 void Call::OnMediaMonitor(VideoChannel *channel, const VideoMediaInfo& info) {
465 SignalVideoMediaMonitor(this, info);
466 }
467
id()468 uint32 Call::id() {
469 return id_;
470 }
471
OnSessionState(BaseSession * session,BaseSession::State state)472 void Call::OnSessionState(BaseSession *session, BaseSession::State state) {
473 switch (state) {
474 case Session::STATE_RECEIVEDACCEPT:
475 case Session::STATE_RECEIVEDREJECT:
476 case Session::STATE_RECEIVEDTERMINATE:
477 session_client_->session_manager()->signaling_thread()->Clear(this,
478 MSG_TERMINATECALL);
479 break;
480 default:
481 break;
482 }
483 SignalSessionState(this, session, state);
484 }
485
OnSessionError(BaseSession * session,Session::Error error)486 void Call::OnSessionError(BaseSession *session, Session::Error error) {
487 session_client_->session_manager()->signaling_thread()->Clear(this,
488 MSG_TERMINATECALL);
489 SignalSessionError(this, session, error);
490 }
491
OnReceivedTerminateReason(Session * session,const std::string & reason)492 void Call::OnReceivedTerminateReason(Session *session,
493 const std::string &reason) {
494 session_client_->session_manager()->signaling_thread()->Clear(this,
495 MSG_TERMINATECALL);
496 SignalReceivedTerminateReason(this, session, reason);
497 }
498
499 } // namespace cricket
500