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
35namespace cricket {
36
37const uint32 MSG_CHECKAUTODESTROY = 1;
38const uint32 MSG_TERMINATECALL = 2;
39const uint32 MSG_PLAYDTMF = 3;
40
41namespace {
42const int kDTMFDelay = 300;  // msec
43const size_t kMaxDTMFDigits = 30;
44const int kSendToVoicemailTimeout = 1000*20;
45const int kNoVoicemailTimeout = 1000*180;
46const int kMediaMonitorInterval = 1000*15;
47}
48
49Call::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
58Call::~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
67Session *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
85void 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
94void 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
105void 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
114void 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
124void 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
134void Call::SetLocalRenderer(VideoRenderer* renderer) {
135  local_renderer_ = renderer;
136  if (session_client_->GetFocus() == this) {
137    session_client_->channel_manager()->SetLocalRenderer(renderer);
138  }
139}
140
141void 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
149void 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
161void 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
173void 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
195const std::vector<Session *> &Call::sessions() {
196  return sessions_;
197}
198
199bool 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
260void 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
293VoiceChannel* 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
299VideoChannel* 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
305void 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
319void 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
329void 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
342void 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
367void 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
400void 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
416void 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
430void 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
438void 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
446void Call::OnConnectionMonitor(VoiceChannel *channel,
447                               const std::vector<ConnectionInfo> &infos) {
448  SignalConnectionMonitor(this, infos);
449}
450
451void Call::OnMediaMonitor(VoiceChannel *channel, const VoiceMediaInfo& info) {
452  SignalMediaMonitor(this, info);
453}
454
455void Call::OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info) {
456  SignalAudioMonitor(this, info);
457}
458
459void Call::OnConnectionMonitor(VideoChannel *channel,
460                               const std::vector<ConnectionInfo> &infos) {
461  SignalVideoConnectionMonitor(this, infos);
462}
463
464void Call::OnMediaMonitor(VideoChannel *channel, const VideoMediaInfo& info) {
465  SignalVideoMediaMonitor(this, info);
466}
467
468uint32 Call::id() {
469  return id_;
470}
471
472void 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
486void 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
492void 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