• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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