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