OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2004 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 "webrtc/libjingle/session/media/call.h" | |
29 | |
30 #include <string> | |
31 | |
32 #include "talk/media/base/constants.h" | |
33 #include "talk/media/base/screencastid.h" | |
34 #include "talk/session/media/currentspeakermonitor.h" | |
35 #include "webrtc/base/helpers.h" | |
36 #include "webrtc/base/logging.h" | |
37 #include "webrtc/base/thread.h" | |
38 #include "webrtc/base/window.h" | |
39 #include "webrtc/libjingle/session/media/mediasessionclient.h" | |
40 #include "webrtc/libjingle/session/parsing.h" | |
41 | |
42 namespace cricket { | |
43 | |
44 const uint32 MSG_CHECKAUTODESTROY = 1; | |
45 const uint32 MSG_TERMINATECALL = 2; | |
46 const uint32 MSG_PLAYDTMF = 3; | |
47 | |
48 namespace { | |
49 const int kDTMFDelay = 300; // msec | |
50 const size_t kMaxDTMFDigits = 30; | |
51 const int kSendToVoicemailTimeout = 1000*20; | |
52 const int kNoVoicemailTimeout = 1000*180; | |
53 const int kMediaMonitorInterval = 1000*15; | |
54 // In order to be the same as the server-side switching, this must be 100. | |
55 const int kAudioMonitorPollPeriodMillis = 100; | |
56 | |
57 // V is a pointer type. | |
58 template<class K, class V> | |
59 V FindOrNull(const std::map<K, V>& map, | |
60 const K& key) { | |
61 typename std::map<K, V>::const_iterator it = map.find(key); | |
62 return (it != map.end()) ? it->second : NULL; | |
63 } | |
64 | |
65 | |
66 bool ContentContainsCrypto(const cricket::ContentInfo* content) { | |
67 if (content != NULL) { | |
68 const cricket::MediaContentDescription* desc = | |
69 static_cast<const cricket::MediaContentDescription*>( | |
70 content->description); | |
71 if (!desc || desc->cryptos().empty()) { | |
72 return false; | |
73 } | |
74 } | |
75 return true; | |
76 } | |
77 | |
78 } | |
79 | |
80 AudioSourceProxy::AudioSourceProxy(Call* call) | |
81 : call_(call) { | |
82 call_->SignalAudioMonitor.connect(this, &AudioSourceProxy::OnAudioMonitor); | |
83 call_->SignalMediaStreamsUpdate.connect( | |
84 this, &AudioSourceProxy::OnMediaStreamsUpdate); | |
85 } | |
86 | |
87 void AudioSourceProxy::OnAudioMonitor(Call* call, const AudioInfo& info) { | |
88 SignalAudioMonitor(this, info); | |
89 } | |
90 | |
91 void AudioSourceProxy::OnMediaStreamsUpdate(Call* call, Session* session, | |
92 const MediaStreams& added, const MediaStreams& removed) { | |
93 SignalMediaStreamsUpdate(this, session, added, removed); | |
94 } | |
95 | |
96 Call::Call(MediaSessionClient* session_client) | |
97 : id_(rtc::CreateRandomId()), | |
98 session_client_(session_client), | |
99 has_video_(false), | |
100 has_data_(false), | |
101 muted_(false), | |
102 video_muted_(false), | |
103 send_to_voicemail_(true), | |
104 playing_dtmf_(false) { | |
105 audio_source_proxy_.reset(new AudioSourceProxy(this)); | |
106 } | |
107 | |
108 Call::~Call() { | |
109 while (media_session_map_.begin() != media_session_map_.end()) { | |
110 Session* session = media_session_map_.begin()->second.session; | |
111 RemoveSession(session); | |
112 session_client_->session_manager()->DestroySession(session); | |
113 } | |
114 rtc::Thread::Current()->Clear(this); | |
115 } | |
116 | |
117 Session* Call::InitiateSession(const buzz::Jid& to, | |
118 const buzz::Jid& initiator, | |
119 const CallOptions& options) { | |
120 std::string id; | |
121 std::string initiator_name = initiator.Str(); | |
122 return InternalInitiateSession(id, to, initiator_name, options); | |
123 } | |
124 | |
125 Session *Call::InitiateSession(const std::string& id, | |
126 const buzz::Jid& to, | |
127 const CallOptions& options) { | |
128 std::string initiator_name; | |
129 return InternalInitiateSession(id, to, initiator_name, options); | |
130 } | |
131 | |
132 void Call::IncomingSession(Session* session, const SessionDescription* offer) { | |
133 AddSession(session, offer); | |
134 | |
135 // Make sure the session knows about the incoming ssrcs. This needs to be done | |
136 // prior to the SignalSessionState call, because that may trigger handling of | |
137 // these new SSRCs, so they need to be registered before then. | |
138 UpdateRemoteMediaStreams(session, offer->contents(), false); | |
139 | |
140 // Missed the first state, the initiate, which is needed by | |
141 // call_client. | |
142 SignalSessionState(this, session, Session::STATE_RECEIVEDINITIATE); | |
143 } | |
144 | |
145 void Call::AcceptSession(Session* session, | |
146 const cricket::CallOptions& options) { | |
147 MediaSessionMap::iterator it = media_session_map_.find(session->id()); | |
148 if (it != media_session_map_.end()) { | |
149 const SessionDescription* answer = session_client_->CreateAnswer( | |
150 session->remote_description(), options); | |
151 it->second.session->Accept(answer); | |
152 } | |
153 } | |
154 | |
155 void Call::RejectSession(Session* session) { | |
156 // Assume polite decline. | |
157 MediaSessionMap::iterator it = media_session_map_.find(session->id()); | |
158 if (it != media_session_map_.end()) | |
159 it->second.session->Reject(STR_TERMINATE_DECLINE); | |
160 } | |
161 | |
162 void Call::TerminateSession(Session* session) { | |
163 MediaSessionMap::iterator it = media_session_map_.find(session->id()); | |
164 if (it != media_session_map_.end()) { | |
165 // Assume polite terminations. | |
166 it->second.session->Terminate(); | |
167 } | |
168 } | |
169 | |
170 void Call::Terminate() { | |
171 // Copy the list so that we can iterate over it in a stable way | |
172 std::vector<Session*> sessions = this->sessions(); | |
173 | |
174 // There may be more than one session to terminate | |
175 std::vector<Session*>::iterator it; | |
176 for (it = sessions.begin(); it != sessions.end(); ++it) { | |
177 TerminateSession(*it); | |
178 } | |
179 } | |
180 | |
181 bool Call::SendViewRequest(Session* session, | |
182 const ViewRequest& view_request) { | |
183 StaticVideoViews::const_iterator it; | |
184 for (it = view_request.static_video_views.begin(); | |
185 it != view_request.static_video_views.end(); ++it) { | |
186 bool found = false; | |
187 MediaStreams* recv_streams = GetMediaStreams(session); | |
188 if (recv_streams) | |
189 found = recv_streams->GetVideoStream(it->selector, nullptr); | |
190 if (!found) { | |
191 LOG(LS_WARNING) << "Trying to send view request for (" | |
192 << it->selector.ssrc << ", '" | |
193 << it->selector.groupid << "', '" | |
194 << it->selector.streamid << "'" | |
195 << ") is not in the local streams."; | |
196 return false; | |
197 } | |
198 } | |
199 | |
200 XmlElements elems; | |
201 WriteError error; | |
202 if (!WriteJingleViewRequest(CN_VIDEO, view_request, &elems, &error)) { | |
203 LOG(LS_ERROR) << "Couldn't write out view request: " << error.text; | |
204 return false; | |
205 } | |
206 | |
207 return session->SendInfoMessage(elems, session->remote_name()); | |
208 } | |
209 | |
210 void Call::SetVideoRenderer(Session* session, uint32 ssrc, | |
211 VideoRenderer* renderer) { | |
212 VideoChannel* video_channel = GetVideoChannel(session); | |
213 if (video_channel) { | |
214 video_channel->SetRenderer(ssrc, renderer); | |
215 LOG(LS_INFO) << "Set renderer of ssrc " << ssrc | |
216 << " to " << renderer << "."; | |
217 } else { | |
218 LOG(LS_INFO) << "Failed to set renderer of ssrc " << ssrc << "."; | |
219 } | |
220 } | |
221 | |
222 void Call::OnMessage(rtc::Message* message) { | |
223 switch (message->message_id) { | |
224 case MSG_CHECKAUTODESTROY: | |
225 // If no more sessions for this call, delete it | |
226 if (media_session_map_.empty()) | |
227 session_client_->DestroyCall(this); | |
228 break; | |
229 case MSG_TERMINATECALL: | |
230 // Signal to the user that a timeout has happened and the call should | |
231 // be sent to voicemail. | |
232 if (send_to_voicemail_) { | |
233 SignalSetupToCallVoicemail(); | |
234 } | |
235 | |
236 // Callee didn't answer - terminate call | |
237 Terminate(); | |
238 break; | |
239 case MSG_PLAYDTMF: | |
240 ContinuePlayDTMF(); | |
241 } | |
242 } | |
243 | |
244 std::vector<Session*> Call::sessions() { | |
245 std::vector<Session*> sessions; | |
246 MediaSessionMap::iterator it; | |
247 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) | |
248 sessions.push_back(it->second.session); | |
249 | |
250 return sessions; | |
251 } | |
252 | |
253 bool Call::AddSession(Session* session, const SessionDescription* offer) { | |
254 bool succeeded = true; | |
255 MediaSession media_session; | |
256 media_session.session = session; | |
257 media_session.voice_channel = NULL; | |
258 media_session.video_channel = NULL; | |
259 media_session.data_channel = NULL; | |
260 media_session.recv_streams = NULL; | |
261 | |
262 const ContentInfo* audio_offer = GetFirstAudioContent(offer); | |
263 const ContentInfo* video_offer = GetFirstVideoContent(offer); | |
264 const ContentInfo* data_offer = GetFirstDataContent(offer); | |
265 has_video_ = (video_offer != NULL); | |
266 has_data_ = (data_offer != NULL); | |
267 | |
268 ASSERT(audio_offer != NULL); | |
269 // Create voice channel and start a media monitor. | |
270 media_session.voice_channel = | |
271 session_client_->channel_manager()->CreateVoiceChannel( | |
272 session, audio_offer->name, has_video_, AudioOptions()); | |
273 // voice_channel can be NULL in case of NullVoiceEngine. | |
274 if (media_session.voice_channel) { | |
275 media_session.voice_channel->SignalMediaMonitor.connect( | |
276 this, &Call::OnMediaMonitor); | |
277 media_session.voice_channel->StartMediaMonitor(kMediaMonitorInterval); | |
278 } else { | |
279 succeeded = false; | |
280 } | |
281 | |
282 // If desired, create video channel and start a media monitor. | |
283 if (has_video_ && succeeded) { | |
284 media_session.video_channel = | |
285 session_client_->channel_manager()->CreateVideoChannel( | |
286 session, | |
287 video_offer->name, | |
288 true, | |
289 VideoOptions(), | |
290 media_session.voice_channel); | |
291 // video_channel can be NULL in case of NullVideoEngine. | |
292 if (media_session.video_channel) { | |
293 media_session.video_channel->SignalMediaMonitor.connect( | |
294 this, &Call::OnMediaMonitor); | |
295 media_session.video_channel->StartMediaMonitor(kMediaMonitorInterval); | |
296 } else { | |
297 succeeded = false; | |
298 } | |
299 } | |
300 | |
301 // If desired, create data channel. | |
302 if (has_data_ && succeeded) { | |
303 const DataContentDescription* data = GetFirstDataContentDescription(offer); | |
304 if (data == NULL) { | |
305 succeeded = false; | |
306 } else { | |
307 DataChannelType data_channel_type = DCT_RTP; | |
308 if ((data->protocol() == kMediaProtocolSctp) || | |
309 (data->protocol() == kMediaProtocolDtlsSctp)) { | |
310 data_channel_type = DCT_SCTP; | |
311 } | |
312 | |
313 bool rtcp = false; | |
314 media_session.data_channel = | |
315 session_client_->channel_manager()->CreateDataChannel( | |
316 session, data_offer->name, rtcp, data_channel_type); | |
317 if (media_session.data_channel) { | |
318 media_session.data_channel->SignalDataReceived.connect( | |
319 this, &Call::OnDataReceived); | |
320 } else { | |
321 succeeded = false; | |
322 } | |
323 } | |
324 } | |
325 | |
326 if (succeeded) { | |
327 // Add session to list, create channels for this session. | |
328 media_session.recv_streams = new MediaStreams; | |
329 media_session_map_[session->id()] = media_session; | |
330 session->SignalState.connect(this, &Call::OnSessionState); | |
331 session->SignalError.connect(this, &Call::OnSessionError); | |
332 session->SignalInfoMessage.connect( | |
333 this, &Call::OnSessionInfoMessage); | |
334 session->SignalRemoteDescriptionUpdate.connect( | |
335 this, &Call::OnRemoteDescriptionUpdate); | |
336 session->SignalReceivedTerminateReason | |
337 .connect(this, &Call::OnReceivedTerminateReason); | |
338 | |
339 // If this call has the focus, enable this session's channels. | |
340 if (session_client_->GetFocus() == this) { | |
341 EnableSessionChannels(session, true); | |
342 } | |
343 | |
344 // Signal client. | |
345 SignalAddSession(this, session); | |
346 } | |
347 | |
348 return succeeded; | |
349 } | |
350 | |
351 void Call::RemoveSession(Session* session) { | |
352 MediaSessionMap::iterator it = media_session_map_.find(session->id()); | |
353 if (it == media_session_map_.end()) | |
354 return; | |
355 | |
356 // Remove all the screencasts, if they haven't been already. | |
357 while (!it->second.started_screencasts.empty()) { | |
358 uint32 ssrc = it->second.started_screencasts.begin()->first; | |
359 if (!StopScreencastWithoutSendingUpdate(it->second.session, ssrc)) { | |
360 LOG(LS_ERROR) << "Unable to stop screencast with ssrc " << ssrc; | |
361 ASSERT(false); | |
362 } | |
363 } | |
364 | |
365 // Destroy video channel | |
366 VideoChannel* video_channel = it->second.video_channel; | |
367 if (video_channel != NULL) | |
368 session_client_->channel_manager()->DestroyVideoChannel(video_channel); | |
369 | |
370 // Destroy voice channel | |
371 VoiceChannel* voice_channel = it->second.voice_channel; | |
372 if (voice_channel != NULL) | |
373 session_client_->channel_manager()->DestroyVoiceChannel(voice_channel); | |
374 | |
375 // Destroy data channel | |
376 DataChannel* data_channel = it->second.data_channel; | |
377 if (data_channel != NULL) | |
378 session_client_->channel_manager()->DestroyDataChannel(data_channel); | |
379 | |
380 delete it->second.recv_streams; | |
381 media_session_map_.erase(it); | |
382 | |
383 // Destroy speaker monitor | |
384 StopSpeakerMonitor(session); | |
385 | |
386 // Signal client | |
387 SignalRemoveSession(this, session); | |
388 | |
389 // The call auto destroys when the last session is removed | |
390 rtc::Thread::Current()->Post(this, MSG_CHECKAUTODESTROY); | |
391 } | |
392 | |
393 VoiceChannel* Call::GetVoiceChannel(Session* session) const { | |
394 MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); | |
395 return (it != media_session_map_.end()) ? it->second.voice_channel : NULL; | |
396 } | |
397 | |
398 VideoChannel* Call::GetVideoChannel(Session* session) const { | |
399 MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); | |
400 return (it != media_session_map_.end()) ? it->second.video_channel : NULL; | |
401 } | |
402 | |
403 DataChannel* Call::GetDataChannel(Session* session) const { | |
404 MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); | |
405 return (it != media_session_map_.end()) ? it->second.data_channel : NULL; | |
406 } | |
407 | |
408 MediaStreams* Call::GetMediaStreams(Session* session) const { | |
409 MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); | |
410 return (it != media_session_map_.end()) ? it->second.recv_streams : NULL; | |
411 } | |
412 | |
413 void Call::EnableChannels(bool enable) { | |
414 MediaSessionMap::iterator it; | |
415 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { | |
416 EnableSessionChannels(it->second.session, enable); | |
417 } | |
418 } | |
419 | |
420 void Call::EnableSessionChannels(Session* session, bool enable) { | |
421 MediaSessionMap::iterator it = media_session_map_.find(session->id()); | |
422 if (it == media_session_map_.end()) | |
423 return; | |
424 | |
425 VoiceChannel* voice_channel = it->second.voice_channel; | |
426 VideoChannel* video_channel = it->second.video_channel; | |
427 DataChannel* data_channel = it->second.data_channel; | |
428 if (voice_channel != NULL) | |
429 voice_channel->Enable(enable); | |
430 if (video_channel != NULL) | |
431 video_channel->Enable(enable); | |
432 if (data_channel != NULL) | |
433 data_channel->Enable(enable); | |
434 } | |
435 | |
436 void Call::Mute(bool mute) { | |
437 muted_ = mute; | |
438 MediaSessionMap::iterator it; | |
439 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { | |
440 if (it->second.voice_channel != NULL) | |
441 it->second.voice_channel->MuteStream(0, mute); | |
442 } | |
443 } | |
444 | |
445 void Call::MuteVideo(bool mute) { | |
446 video_muted_ = mute; | |
447 MediaSessionMap::iterator it; | |
448 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { | |
449 if (it->second.video_channel != NULL) | |
450 it->second.video_channel->MuteStream(0, mute); | |
451 } | |
452 } | |
453 | |
454 bool Call::SendData(Session* session, | |
455 const SendDataParams& params, | |
456 const rtc::Buffer& payload, | |
457 SendDataResult* result) { | |
458 DataChannel* data_channel = GetDataChannel(session); | |
459 if (!data_channel) { | |
460 LOG(LS_WARNING) << "Could not send data: no data channel."; | |
461 return false; | |
462 } | |
463 | |
464 return data_channel->SendData(params, payload, result); | |
465 } | |
466 | |
467 void Call::PressDTMF(int event) { | |
468 // Queue up this digit | |
469 if (queued_dtmf_.size() < kMaxDTMFDigits) { | |
470 LOG(LS_INFO) << "Call::PressDTMF(" << event << ")"; | |
471 | |
472 queued_dtmf_.push_back(event); | |
473 | |
474 if (!playing_dtmf_) { | |
475 ContinuePlayDTMF(); | |
476 } | |
477 } | |
478 } | |
479 | |
480 cricket::VideoFormat ScreencastFormatFromFps(int fps) { | |
481 // The capturer pretty much ignore this, but just in case we give it | |
482 // a resolution big enough to cover any expected desktop. In any | |
483 // case, it can't be 0x0, or the CaptureManager will fail to use it. | |
484 return cricket::VideoFormat( | |
485 1, 1, | |
486 cricket::VideoFormat::FpsToInterval(fps), | |
487 cricket::FOURCC_ANY); | |
488 } | |
489 | |
490 bool Call::StartScreencast(Session* session, | |
491 const std::string& streamid, uint32 ssrc, | |
492 const ScreencastId& screenid, int fps) { | |
493 MediaSessionMap::iterator it = media_session_map_.find(session->id()); | |
494 if (it == media_session_map_.end()) { | |
495 return false; | |
496 } | |
497 | |
498 VideoChannel *video_channel = GetVideoChannel(session); | |
499 if (!video_channel) { | |
500 LOG(LS_WARNING) << "Cannot add screencast" | |
501 << " because there is no video channel."; | |
502 return false; | |
503 } | |
504 | |
505 VideoCapturer* capturer = session_client_->channel_manager()-> | |
506 CreateScreenCapturer(screenid); | |
507 if (!capturer) { | |
508 LOG(LS_WARNING) << "Could not create screencast capturer."; | |
509 return false; | |
510 } | |
511 | |
512 if (!video_channel->AddScreencast(ssrc, capturer)) { | |
513 delete capturer; | |
514 LOG(LS_WARNING) << "Could not add screencast capturer."; | |
515 return false; | |
516 } | |
517 | |
518 VideoFormat format = ScreencastFormatFromFps(fps); | |
519 if (!session_client_->channel_manager()->StartVideoCapture( | |
520 capturer, format)) { | |
521 LOG(LS_WARNING) << "Could not start video capture."; | |
522 video_channel->RemoveScreencast(ssrc); | |
523 return false; | |
524 } | |
525 | |
526 if (!video_channel->SetCapturer(ssrc, capturer)) { | |
527 LOG(LS_WARNING) << "Could not start sending screencast."; | |
528 session_client_->channel_manager()->StopVideoCapture( | |
529 capturer, ScreencastFormatFromFps(fps)); | |
530 video_channel->RemoveScreencast(ssrc); | |
531 } | |
532 | |
533 // TODO(pthatcher): Once the CaptureManager has a nicer interface | |
534 // for removing captures (such as having StartCapture return a | |
535 // handle), remove this StartedCapture stuff. | |
536 it->second.started_screencasts.insert( | |
537 std::make_pair(ssrc, StartedCapture(capturer, format))); | |
538 | |
539 // TODO(pthatcher): Verify we aren't re-using an existing id or | |
540 // ssrc. | |
541 StreamParams stream; | |
542 stream.id = streamid; | |
543 stream.ssrcs.push_back(ssrc); | |
544 VideoContentDescription* video = CreateVideoStreamUpdate(stream); | |
545 | |
546 // TODO(pthatcher): Wait until view request before sending video. | |
547 video_channel->SetLocalContent(video, CA_UPDATE, NULL); | |
548 SendVideoStreamUpdate(session, video); | |
549 return true; | |
550 } | |
551 | |
552 bool Call::StopScreencast(Session* session, | |
553 const std::string& streamid, uint32 ssrc) { | |
554 if (!StopScreencastWithoutSendingUpdate(session, ssrc)) { | |
555 return false; | |
556 } | |
557 | |
558 VideoChannel *video_channel = GetVideoChannel(session); | |
559 if (!video_channel) { | |
560 LOG(LS_WARNING) << "Cannot add screencast" | |
561 << " because there is no video channel."; | |
562 return false; | |
563 } | |
564 | |
565 StreamParams stream; | |
566 stream.id = streamid; | |
567 // No ssrcs | |
568 VideoContentDescription* video = CreateVideoStreamUpdate(stream); | |
569 | |
570 video_channel->SetLocalContent(video, CA_UPDATE, NULL); | |
571 SendVideoStreamUpdate(session, video); | |
572 return true; | |
573 } | |
574 | |
575 bool Call::StopScreencastWithoutSendingUpdate( | |
576 Session* session, uint32 ssrc) { | |
577 MediaSessionMap::iterator it = media_session_map_.find(session->id()); | |
578 if (it == media_session_map_.end()) { | |
579 return false; | |
580 } | |
581 | |
582 VideoChannel *video_channel = GetVideoChannel(session); | |
583 if (!video_channel) { | |
584 LOG(LS_WARNING) << "Cannot remove screencast" | |
585 << " because there is no video channel."; | |
586 return false; | |
587 } | |
588 | |
589 StartedScreencastMap::const_iterator screencast_iter = | |
590 it->second.started_screencasts.find(ssrc); | |
591 if (screencast_iter == it->second.started_screencasts.end()) { | |
592 LOG(LS_WARNING) << "Could not stop screencast " << ssrc | |
593 << " because there is no capturer."; | |
594 return false; | |
595 } | |
596 | |
597 VideoCapturer* capturer = screencast_iter->second.capturer; | |
598 VideoFormat format = screencast_iter->second.format; | |
599 video_channel->SetCapturer(ssrc, NULL); | |
600 if (!session_client_->channel_manager()->StopVideoCapture( | |
601 capturer, format)) { | |
602 LOG(LS_WARNING) << "Could not stop screencast " << ssrc | |
603 << " because could not stop capture."; | |
604 return false; | |
605 } | |
606 video_channel->RemoveScreencast(ssrc); | |
607 it->second.started_screencasts.erase(ssrc); | |
608 return true; | |
609 } | |
610 | |
611 VideoContentDescription* Call::CreateVideoStreamUpdate( | |
612 const StreamParams& stream) { | |
613 VideoContentDescription* video = new VideoContentDescription(); | |
614 video->set_multistream(true); | |
615 video->set_partial(true); | |
616 video->AddStream(stream); | |
617 return video; | |
618 } | |
619 | |
620 void Call::SendVideoStreamUpdate( | |
621 Session* session, VideoContentDescription* video) { | |
622 // Takes the ownership of |video|. | |
623 rtc::scoped_ptr<VideoContentDescription> description(video); | |
624 const ContentInfo* video_info = | |
625 GetFirstVideoContent(session->local_description()); | |
626 if (video_info == NULL) { | |
627 LOG(LS_WARNING) << "Cannot send stream update for video."; | |
628 return; | |
629 } | |
630 | |
631 std::vector<ContentInfo> contents; | |
632 contents.push_back( | |
633 ContentInfo(video_info->name, video_info->type, description.get())); | |
634 | |
635 session->SendDescriptionInfoMessage(contents); | |
636 } | |
637 | |
638 void Call::ContinuePlayDTMF() { | |
639 playing_dtmf_ = false; | |
640 | |
641 // Check to see if we have a queued tone | |
642 if (queued_dtmf_.size() > 0) { | |
643 playing_dtmf_ = true; | |
644 | |
645 int tone = queued_dtmf_.front(); | |
646 queued_dtmf_.pop_front(); | |
647 | |
648 LOG(LS_INFO) << "Call::ContinuePlayDTMF(" << tone << ")"; | |
649 for (MediaSessionMap::iterator it = media_session_map_.begin(); | |
650 it != media_session_map_.end(); ++it) { | |
651 if (it->second.voice_channel != NULL) { | |
652 it->second.voice_channel->PressDTMF(tone, true); | |
653 } | |
654 } | |
655 | |
656 // Post a message to play the next tone or at least clear the playing_dtmf_ | |
657 // bit. | |
658 rtc::Thread::Current()->PostDelayed(kDTMFDelay, this, MSG_PLAYDTMF); | |
659 } | |
660 } | |
661 | |
662 void Call::Join(Call* call, bool enable) { | |
663 for (MediaSessionMap::iterator it = call->media_session_map_.begin(); | |
664 it != call->media_session_map_.end(); ++it) { | |
665 // Shouldn't already exist. | |
666 ASSERT(media_session_map_.find(it->first) == media_session_map_.end()); | |
667 media_session_map_[it->first] = it->second; | |
668 | |
669 it->second.session->SignalState.connect(this, &Call::OnSessionState); | |
670 it->second.session->SignalError.connect(this, &Call::OnSessionError); | |
671 it->second.session->SignalReceivedTerminateReason | |
672 .connect(this, &Call::OnReceivedTerminateReason); | |
673 | |
674 EnableSessionChannels(it->second.session, enable); | |
675 } | |
676 | |
677 // Moved all the sessions over, so the other call should no longer have any. | |
678 call->media_session_map_.clear(); | |
679 } | |
680 | |
681 void Call::StartConnectionMonitor(Session* session, int cms) { | |
682 VoiceChannel* voice_channel = GetVoiceChannel(session); | |
683 if (voice_channel) { | |
684 voice_channel->SignalConnectionMonitor.connect(this, | |
685 &Call::OnConnectionMonitor); | |
686 voice_channel->StartConnectionMonitor(cms); | |
687 } | |
688 | |
689 VideoChannel* video_channel = GetVideoChannel(session); | |
690 if (video_channel) { | |
691 video_channel->SignalConnectionMonitor.connect(this, | |
692 &Call::OnConnectionMonitor); | |
693 video_channel->StartConnectionMonitor(cms); | |
694 } | |
695 } | |
696 | |
697 void Call::StopConnectionMonitor(Session* session) { | |
698 VoiceChannel* voice_channel = GetVoiceChannel(session); | |
699 if (voice_channel) { | |
700 voice_channel->StopConnectionMonitor(); | |
701 voice_channel->SignalConnectionMonitor.disconnect(this); | |
702 } | |
703 | |
704 VideoChannel* video_channel = GetVideoChannel(session); | |
705 if (video_channel) { | |
706 video_channel->StopConnectionMonitor(); | |
707 video_channel->SignalConnectionMonitor.disconnect(this); | |
708 } | |
709 } | |
710 | |
711 void Call::StartAudioMonitor(Session* session, int cms) { | |
712 VoiceChannel* voice_channel = GetVoiceChannel(session); | |
713 if (voice_channel) { | |
714 voice_channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor); | |
715 voice_channel->StartAudioMonitor(cms); | |
716 } | |
717 } | |
718 | |
719 void Call::StopAudioMonitor(Session* session) { | |
720 VoiceChannel* voice_channel = GetVoiceChannel(session); | |
721 if (voice_channel) { | |
722 voice_channel->StopAudioMonitor(); | |
723 voice_channel->SignalAudioMonitor.disconnect(this); | |
724 } | |
725 } | |
726 | |
727 bool Call::IsAudioMonitorRunning(Session* session) { | |
728 VoiceChannel* voice_channel = GetVoiceChannel(session); | |
729 if (voice_channel) { | |
730 return voice_channel->IsAudioMonitorRunning(); | |
731 } else { | |
732 return false; | |
733 } | |
734 } | |
735 | |
736 void Call::StartSpeakerMonitor(Session* session) { | |
737 if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) { | |
738 if (!IsAudioMonitorRunning(session)) { | |
739 StartAudioMonitor(session, kAudioMonitorPollPeriodMillis); | |
740 } | |
741 CurrentSpeakerMonitor* speaker_monitor = | |
742 new cricket::CurrentSpeakerMonitor( | |
743 audio_source_proxy_.get(), session); | |
744 speaker_monitor->SignalUpdate.connect(this, &Call::OnSpeakerMonitor); | |
745 speaker_monitor->Start(); | |
746 speaker_monitor_map_[session->id()] = speaker_monitor; | |
747 } else { | |
748 LOG(LS_WARNING) << "Already started speaker monitor for session " | |
749 << session->id() << "."; | |
750 } | |
751 } | |
752 | |
753 void Call::StopSpeakerMonitor(Session* session) { | |
754 if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) { | |
755 LOG(LS_WARNING) << "Speaker monitor for session " | |
756 << session->id() << " already stopped."; | |
757 } else { | |
758 CurrentSpeakerMonitor* monitor = speaker_monitor_map_[session->id()]; | |
759 monitor->Stop(); | |
760 speaker_monitor_map_.erase(session->id()); | |
761 delete monitor; | |
762 } | |
763 } | |
764 | |
765 void Call::OnConnectionMonitor(VoiceChannel* channel, | |
766 const std::vector<ConnectionInfo> &infos) { | |
767 SignalConnectionMonitor(this, infos); | |
768 } | |
769 | |
770 void Call::OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info) { | |
771 last_voice_media_info_ = info; | |
772 SignalMediaMonitor(this, info); | |
773 } | |
774 | |
775 void Call::OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info) { | |
776 SignalAudioMonitor(this, info); | |
777 } | |
778 | |
779 void Call::OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc) { | |
780 Session* session = static_cast<Session*>(monitor->session()); | |
781 MediaStreams* recv_streams = GetMediaStreams(session); | |
782 if (recv_streams) { | |
783 StreamParams stream; | |
784 recv_streams->GetAudioStream(StreamSelector(ssrc), &stream); | |
785 SignalSpeakerMonitor(this, session, stream); | |
786 } | |
787 } | |
788 | |
789 void Call::OnConnectionMonitor(VideoChannel* channel, | |
790 const std::vector<ConnectionInfo> &infos) { | |
791 SignalVideoConnectionMonitor(this, infos); | |
792 } | |
793 | |
794 void Call::OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info) { | |
795 SignalVideoMediaMonitor(this, info); | |
796 } | |
797 | |
798 void Call::OnDataReceived(DataChannel* channel, | |
799 const ReceiveDataParams& params, | |
800 const rtc::Buffer& payload) { | |
801 SignalDataReceived(this, params, payload); | |
802 } | |
803 | |
804 uint32 Call::id() { | |
805 return id_; | |
806 } | |
807 | |
808 void Call::OnSessionState(BaseSession* base_session, BaseSession::State state) { | |
809 Session* session = static_cast<Session*>(base_session); | |
810 switch (state) { | |
811 case Session::STATE_RECEIVEDACCEPT: | |
812 UpdateRemoteMediaStreams(session, | |
813 session->remote_description()->contents(), false); | |
814 session_client_->session_manager()->signaling_thread()->Clear(this, | |
815 MSG_TERMINATECALL); | |
816 break; | |
817 case Session::STATE_RECEIVEDREJECT: | |
818 case Session::STATE_RECEIVEDTERMINATE: | |
819 session_client_->session_manager()->signaling_thread()->Clear(this, | |
820 MSG_TERMINATECALL); | |
821 break; | |
822 default: | |
823 break; | |
824 } | |
825 SignalSessionState(this, session, state); | |
826 } | |
827 | |
828 void Call::OnSessionError(BaseSession* base_session, Session::Error error) { | |
829 session_client_->session_manager()->signaling_thread()->Clear(this, | |
830 MSG_TERMINATECALL); | |
831 SignalSessionError(this, static_cast<Session*>(base_session), error); | |
832 } | |
833 | |
834 void Call::OnSessionInfoMessage(Session* session, | |
835 const buzz::XmlElement* action_elem) { | |
836 if (!IsJingleViewRequest(action_elem)) { | |
837 return; | |
838 } | |
839 | |
840 ViewRequest view_request; | |
841 ParseError error; | |
842 if (!ParseJingleViewRequest(action_elem, &view_request, &error)) { | |
843 LOG(LS_WARNING) << "Failed to parse view request: " << error.text; | |
844 return; | |
845 } | |
846 | |
847 VideoChannel* video_channel = GetVideoChannel(session); | |
848 if (video_channel == NULL) { | |
849 LOG(LS_WARNING) << "Ignore view request since we have no video channel."; | |
850 return; | |
851 } | |
852 | |
853 if (!video_channel->ApplyViewRequest(view_request)) { | |
854 LOG(LS_WARNING) << "Failed to ApplyViewRequest."; | |
855 } | |
856 } | |
857 | |
858 void Call::OnRemoteDescriptionUpdate(BaseSession* base_session, | |
859 const ContentInfos& updated_contents) { | |
860 Session* session = static_cast<Session*>(base_session); | |
861 | |
862 const ContentInfo* audio_content = GetFirstAudioContent(updated_contents); | |
863 if (audio_content) { | |
864 const AudioContentDescription* audio_update = | |
865 static_cast<const AudioContentDescription*>(audio_content->description); | |
866 if (!audio_update->codecs().empty()) { | |
867 UpdateVoiceChannelRemoteContent(session, audio_update); | |
868 } | |
869 } | |
870 | |
871 const ContentInfo* video_content = GetFirstVideoContent(updated_contents); | |
872 if (video_content) { | |
873 const VideoContentDescription* video_update = | |
874 static_cast<const VideoContentDescription*>(video_content->description); | |
875 if (!video_update->codecs().empty()) { | |
876 UpdateVideoChannelRemoteContent(session, video_update); | |
877 } | |
878 } | |
879 | |
880 const ContentInfo* data_content = GetFirstDataContent(updated_contents); | |
881 if (data_content) { | |
882 const DataContentDescription* data_update = | |
883 static_cast<const DataContentDescription*>(data_content->description); | |
884 if (!data_update->codecs().empty()) { | |
885 UpdateDataChannelRemoteContent(session, data_update); | |
886 } | |
887 } | |
888 | |
889 UpdateRemoteMediaStreams(session, updated_contents, true); | |
890 } | |
891 | |
892 bool Call::UpdateVoiceChannelRemoteContent( | |
893 Session* session, const AudioContentDescription* audio) { | |
894 VoiceChannel* voice_channel = GetVoiceChannel(session); | |
895 if (!voice_channel->SetRemoteContent(audio, CA_UPDATE, NULL)) { | |
896 const std::string error_desc = | |
897 "Failure in audio SetRemoteContent with CA_UPDATE"; | |
898 LOG(LS_ERROR) << error_desc; | |
899 session->SetError(BaseSession::ERROR_CONTENT, error_desc); | |
900 return false; | |
901 } | |
902 return true; | |
903 } | |
904 | |
905 bool Call::UpdateVideoChannelRemoteContent( | |
906 Session* session, const VideoContentDescription* video) { | |
907 VideoChannel* video_channel = GetVideoChannel(session); | |
908 if (!video_channel->SetRemoteContent(video, CA_UPDATE, NULL)) { | |
909 const std::string error_desc = | |
910 "Failure in video SetRemoteContent with CA_UPDATE"; | |
911 LOG(LS_ERROR) << error_desc; | |
912 session->SetError(BaseSession::ERROR_CONTENT, error_desc); | |
913 return false; | |
914 } | |
915 return true; | |
916 } | |
917 | |
918 bool Call::UpdateDataChannelRemoteContent( | |
919 Session* session, const DataContentDescription* data) { | |
920 DataChannel* data_channel = GetDataChannel(session); | |
921 if (!data_channel->SetRemoteContent(data, CA_UPDATE, NULL)) { | |
922 const std::string error_desc = | |
923 "Failure in data SetRemoteContent with CA_UPDATE"; | |
924 LOG(LS_ERROR) << error_desc; | |
925 session->SetError(BaseSession::ERROR_CONTENT, error_desc); | |
926 return false; | |
927 } | |
928 return true; | |
929 } | |
930 | |
931 void Call::UpdateRemoteMediaStreams(Session* session, | |
932 const ContentInfos& updated_contents, | |
933 bool update_channels) { | |
934 MediaStreams* recv_streams = GetMediaStreams(session); | |
935 if (!recv_streams) | |
936 return; | |
937 | |
938 cricket::MediaStreams added_streams; | |
939 cricket::MediaStreams removed_streams; | |
940 | |
941 const ContentInfo* audio_content = GetFirstAudioContent(updated_contents); | |
942 if (audio_content) { | |
943 const AudioContentDescription* audio_update = | |
944 static_cast<const AudioContentDescription*>(audio_content->description); | |
945 UpdateRecvStreams(audio_update->streams(), | |
946 update_channels ? GetVoiceChannel(session) : NULL, | |
947 recv_streams->mutable_audio(), | |
948 added_streams.mutable_audio(), | |
949 removed_streams.mutable_audio()); | |
950 } | |
951 | |
952 const ContentInfo* video_content = GetFirstVideoContent(updated_contents); | |
953 if (video_content) { | |
954 const VideoContentDescription* video_update = | |
955 static_cast<const VideoContentDescription*>(video_content->description); | |
956 UpdateRecvStreams(video_update->streams(), | |
957 update_channels ? GetVideoChannel(session) : NULL, | |
958 recv_streams->mutable_video(), | |
959 added_streams.mutable_video(), | |
960 removed_streams.mutable_video()); | |
961 } | |
962 | |
963 const ContentInfo* data_content = GetFirstDataContent(updated_contents); | |
964 if (data_content) { | |
965 const DataContentDescription* data_update = | |
966 static_cast<const DataContentDescription*>(data_content->description); | |
967 UpdateRecvStreams(data_update->streams(), | |
968 update_channels ? GetDataChannel(session) : NULL, | |
969 recv_streams->mutable_data(), | |
970 added_streams.mutable_data(), | |
971 removed_streams.mutable_data()); | |
972 } | |
973 | |
974 if (!added_streams.empty() || !removed_streams.empty()) { | |
975 SignalMediaStreamsUpdate(this, session, added_streams, removed_streams); | |
976 } | |
977 } | |
978 | |
979 void FindStreamChanges(const std::vector<StreamParams>& streams, | |
980 const std::vector<StreamParams>& updates, | |
981 std::vector<StreamParams>* added_streams, | |
982 std::vector<StreamParams>* removed_streams) { | |
983 for (std::vector<StreamParams>::const_iterator update = updates.begin(); | |
984 update != updates.end(); ++update) { | |
985 const StreamParams* stream = | |
986 GetStreamByIds(streams, update->groupid, update->id); | |
987 if (stream) { | |
988 if (!update->has_ssrcs()) { | |
989 removed_streams->push_back(*stream); | |
990 } | |
991 } else { | |
992 // There's a bug on reflector that will send <stream>s even | |
993 // though there is not ssrc (which means there isn't really a | |
994 // stream). To work around it, we simply ignore new <stream>s | |
995 // that don't have any ssrcs. | |
996 if (update->has_ssrcs()) { | |
997 added_streams->push_back(*update); | |
998 } | |
999 } | |
1000 } | |
1001 } | |
1002 | |
1003 void Call::UpdateRecvStreams(const std::vector<StreamParams>& update_streams, | |
1004 BaseChannel* channel, | |
1005 std::vector<StreamParams>* recv_streams, | |
1006 std::vector<StreamParams>* added_streams, | |
1007 std::vector<StreamParams>* removed_streams) { | |
1008 FindStreamChanges(*recv_streams, | |
1009 update_streams, added_streams, removed_streams); | |
1010 AddRecvStreams(*added_streams, | |
1011 channel, recv_streams); | |
1012 RemoveRecvStreams(*removed_streams, | |
1013 channel, recv_streams); | |
1014 } | |
1015 | |
1016 void Call::AddRecvStreams(const std::vector<StreamParams>& added_streams, | |
1017 BaseChannel* channel, | |
1018 std::vector<StreamParams>* recv_streams) { | |
1019 std::vector<StreamParams>::const_iterator stream; | |
1020 for (stream = added_streams.begin(); | |
1021 stream != added_streams.end(); | |
1022 ++stream) { | |
1023 AddRecvStream(*stream, channel, recv_streams); | |
1024 } | |
1025 } | |
1026 | |
1027 void Call::AddRecvStream(const StreamParams& stream, | |
1028 BaseChannel* channel, | |
1029 std::vector<StreamParams>* recv_streams) { | |
1030 if (channel && stream.has_ssrcs()) { | |
1031 channel->AddRecvStream(stream); | |
1032 } | |
1033 recv_streams->push_back(stream); | |
1034 } | |
1035 | |
1036 void Call::RemoveRecvStreams(const std::vector<StreamParams>& removed_streams, | |
1037 BaseChannel* channel, | |
1038 std::vector<StreamParams>* recv_streams) { | |
1039 std::vector<StreamParams>::const_iterator stream; | |
1040 for (stream = removed_streams.begin(); | |
1041 stream != removed_streams.end(); | |
1042 ++stream) { | |
1043 RemoveRecvStream(*stream, channel, recv_streams); | |
1044 } | |
1045 } | |
1046 | |
1047 void Call::RemoveRecvStream(const StreamParams& stream, | |
1048 BaseChannel* channel, | |
1049 std::vector<StreamParams>* recv_streams) { | |
1050 if (channel && stream.has_ssrcs()) { | |
1051 // TODO(pthatcher): Change RemoveRecvStream to take a stream argument. | |
1052 channel->RemoveRecvStream(stream.first_ssrc()); | |
1053 } | |
1054 RemoveStreamByIds(recv_streams, stream.groupid, stream.id); | |
1055 } | |
1056 | |
1057 void Call::OnReceivedTerminateReason(Session* session, | |
1058 const std::string& reason) { | |
1059 session_client_->session_manager()->signaling_thread()->Clear(this, | |
1060 MSG_TERMINATECALL); | |
1061 SignalReceivedTerminateReason(this, session, reason); | |
1062 } | |
1063 | |
1064 // TODO(mdodd): Get ride of this method since all Hangouts are using a secure | |
1065 // connection. | |
1066 bool Call::secure() const { | |
1067 if (session_client_->secure() == SEC_DISABLED) { | |
1068 return false; | |
1069 } | |
1070 | |
1071 bool ret = true; | |
1072 int i = 0; | |
1073 | |
1074 MediaSessionMap::const_iterator it; | |
1075 for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { | |
1076 LOG_F(LS_VERBOSE) << "session[" << i | |
1077 << "], check local and remote descriptions"; | |
1078 i++; | |
1079 | |
1080 if (!SessionDescriptionContainsCrypto( | |
1081 it->second.session->local_description()) || | |
1082 !SessionDescriptionContainsCrypto( | |
1083 it->second.session->remote_description())) { | |
1084 ret = false; | |
1085 break; | |
1086 } | |
1087 } | |
1088 | |
1089 LOG_F(LS_VERBOSE) << "secure=" << ret; | |
1090 return ret; | |
1091 } | |
1092 | |
1093 bool Call::SessionDescriptionContainsCrypto( | |
1094 const SessionDescription* sdesc) const { | |
1095 if (sdesc == NULL) { | |
1096 LOG_F(LS_VERBOSE) << "sessionDescription is NULL"; | |
1097 return false; | |
1098 } | |
1099 | |
1100 return ContentContainsCrypto(sdesc->GetContentByName(CN_AUDIO)) && | |
1101 ContentContainsCrypto(sdesc->GetContentByName(CN_VIDEO)); | |
1102 } | |
1103 | |
1104 Session* Call::InternalInitiateSession(const std::string& id, | |
1105 const buzz::Jid& to, | |
1106 const std::string& initiator_name, | |
1107 const CallOptions& options) { | |
1108 const SessionDescription* offer = session_client_->CreateOffer(options); | |
1109 | |
1110 Session* session = session_client_->CreateSession(id, this); | |
1111 // Only override the initiator_name if it was manually supplied. Otherwise, | |
1112 // session_client_ will supply the local jid as initiator in CreateOffer. | |
1113 if (!initiator_name.empty()) { | |
1114 session->set_initiator_name(initiator_name); | |
1115 } | |
1116 | |
1117 AddSession(session, offer); | |
1118 session->Initiate(to.Str(), offer); | |
1119 | |
1120 // After this timeout, terminate the call because the callee isn't | |
1121 // answering | |
1122 session_client_->session_manager()->signaling_thread()->Clear(this, | |
1123 MSG_TERMINATECALL); | |
1124 session_client_->session_manager()->signaling_thread()->PostDelayed( | |
1125 send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout, | |
1126 this, MSG_TERMINATECALL); | |
1127 return session; | |
1128 } | |
1129 | |
1130 AudioSourceProxy* Call::GetAudioSourceProxy() { | |
1131 return audio_source_proxy_.get(); | |
1132 } | |
1133 | |
1134 } // namespace cricket | |
OLD | NEW |