Home | History | Annotate | Download | only in phone
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    195 const std::vector<Session *> &Call::sessions() {
    196   return sessions_;
    197 }
    198 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    446 void Call::OnConnectionMonitor(VoiceChannel *channel,
    447                                const std::vector<ConnectionInfo> &infos) {
    448   SignalConnectionMonitor(this, infos);
    449 }
    450 
    451 void Call::OnMediaMonitor(VoiceChannel *channel, const VoiceMediaInfo& info) {
    452   SignalMediaMonitor(this, info);
    453 }
    454 
    455 void Call::OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info) {
    456   SignalAudioMonitor(this, info);
    457 }
    458 
    459 void Call::OnConnectionMonitor(VideoChannel *channel,
    460                                const std::vector<ConnectionInfo> &infos) {
    461   SignalVideoConnectionMonitor(this, infos);
    462 }
    463 
    464 void Call::OnMediaMonitor(VideoChannel *channel, const VideoMediaInfo& info) {
    465   SignalVideoMediaMonitor(this, info);
    466 }
    467 
    468 uint32 Call::id() {
    469   return id_;
    470 }
    471 
    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 
    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 
    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