3
* Copyright 2004--2007, Google Inc.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
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.
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.
29
#include "talk/base/helpers.h"
30
#include "talk/base/logging.h"
31
#include "talk/base/thread.h"
32
#include "talk/p2p/base/parsing.h"
33
#include "talk/session/phone/call.h"
34
#include "talk/session/phone/mediasessionclient.h"
38
const uint32 MSG_CHECKAUTODESTROY = 1;
39
const uint32 MSG_TERMINATECALL = 2;
40
const uint32 MSG_PLAYDTMF = 3;
43
const int kDTMFDelay = 300; // msec
44
const size_t kMaxDTMFDigits = 30;
45
const int kSendToVoicemailTimeout = 1000*20;
46
const int kNoVoicemailTimeout = 1000*180;
47
const int kMediaMonitorInterval = 1000*15;
48
// In order to be the same as the server-side switching, this must be 100.
49
const int kAudioMonitorPollPeriodMillis = 100;
51
// V is a pointer type.
52
template<class K, class V>
53
V FindOrNull(const std::map<K, V>& map,
55
typename std::map<K, V>::const_iterator it = map.find(key);
56
return (it != map.end()) ? it->second : NULL;
61
Call::Call(MediaSessionClient* session_client)
62
: id_(talk_base::CreateRandomId()),
63
session_client_(session_client),
64
local_renderer_(NULL),
69
send_to_voicemail_(true),
70
playing_dtmf_(false) {
74
while (sessions_.begin() != sessions_.end()) {
75
Session* session = sessions_[0];
76
RemoveSession(session);
77
session_client_->session_manager()->DestroySession(session);
79
talk_base::Thread::Current()->Clear(this);
82
Session* Call::InitiateSession(const buzz::Jid &jid,
83
const CallOptions& options) {
84
const SessionDescription* offer = session_client_->CreateOffer(options);
86
Session* session = session_client_->CreateSession(this);
87
AddSession(session, offer);
88
session->Initiate(jid.Str(), offer);
90
// After this timeout, terminate the call because the callee isn't
92
session_client_->session_manager()->signaling_thread()->Clear(this,
94
session_client_->session_manager()->signaling_thread()->PostDelayed(
95
send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout,
96
this, MSG_TERMINATECALL);
100
void Call::IncomingSession(
101
Session* session, const SessionDescription* offer) {
102
AddSession(session, offer);
104
// Missed the first state, the initiate, which is needed by
106
SignalSessionState(this, session, Session::STATE_RECEIVEDINITIATE);
109
void Call::AcceptSession(Session* session,
110
const cricket::CallOptions& options) {
111
std::vector<Session*>::iterator it;
112
it = std::find(sessions_.begin(), sessions_.end(), session);
113
ASSERT(it != sessions_.end());
114
if (it != sessions_.end()) {
116
session_client_->CreateAnswer(session->remote_description(), options));
120
void Call::RejectSession(Session* session) {
121
std::vector<Session*>::iterator it;
122
it = std::find(sessions_.begin(), sessions_.end(), session);
123
ASSERT(it != sessions_.end());
124
// Assume polite decline.
125
if (it != sessions_.end())
126
session->Reject(STR_TERMINATE_DECLINE);
129
void Call::TerminateSession(Session* session) {
130
ASSERT(std::find(sessions_.begin(), sessions_.end(), session)
132
std::vector<Session*>::iterator it;
133
it = std::find(sessions_.begin(), sessions_.end(), session);
134
// Assume polite terminations.
135
if (it != sessions_.end())
139
void Call::Terminate() {
140
// Copy the list so that we can iterate over it in a stable way
141
std::vector<Session*> sessions = sessions_;
143
// There may be more than one session to terminate
144
std::vector<Session*>::iterator it;
145
for (it = sessions.begin(); it != sessions.end(); it++)
146
TerminateSession(*it);
149
bool Call::SendViewRequest(Session* session,
150
const ViewRequest& view_request) {
151
StaticVideoViews::const_iterator it;
152
for (it = view_request.static_video_views.begin();
153
it != view_request.static_video_views.end(); ++it) {
154
StreamParams found_stream;
155
bool found = recv_streams_.GetVideoStreamBySsrc(it->ssrc, &found_stream);
158
"Tried sending view request for bad ssrc: " << it->ssrc;
165
if (!WriteJingleViewRequest(CN_VIDEO, view_request, &elems, &error)) {
166
LOG(LS_ERROR) << "Couldn't write out view request: " << error.text;
170
return session->SendInfoMessage(elems);
173
void Call::SetLocalRenderer(VideoRenderer* renderer) {
174
local_renderer_ = renderer;
175
if (session_client_->GetFocus() == this) {
176
session_client_->channel_manager()->SetLocalRenderer(renderer);
180
void Call::SetVideoRenderer(Session* session, uint32 ssrc,
181
VideoRenderer* renderer) {
182
VideoChannel* video_channel = GetVideoChannel(session);
184
video_channel->SetRenderer(ssrc, renderer);
185
LOG(LS_INFO) << "Set renderer of ssrc " << ssrc
186
<< " to " << renderer << ".";
188
LOG(LS_INFO) << "Failed to set renderer of ssrc " << ssrc << ".";
192
void Call::OnMessage(talk_base::Message* message) {
193
switch (message->message_id) {
194
case MSG_CHECKAUTODESTROY:
195
// If no more sessions for this call, delete it
196
if (sessions_.size() == 0)
197
session_client_->DestroyCall(this);
199
case MSG_TERMINATECALL:
200
// Signal to the user that a timeout has happened and the call should
201
// be sent to voicemail.
202
if (send_to_voicemail_) {
203
SignalSetupToCallVoicemail();
206
// Callee didn't answer - terminate call
214
const std::vector<Session*> &Call::sessions() {
218
bool Call::AddSession(Session* session, const SessionDescription* offer) {
219
bool succeeded = true;
220
VoiceChannel* voice_channel = NULL;
221
VideoChannel* video_channel = NULL;
222
DataChannel* data_channel = NULL;
224
const ContentInfo* audio_offer = GetFirstAudioContent(offer);
225
const ContentInfo* video_offer = GetFirstVideoContent(offer);
226
const ContentInfo* data_offer = GetFirstDataContent(offer);
227
has_video_ = (video_offer != NULL);
228
has_data_ = (data_offer != NULL);
230
ASSERT(audio_offer != NULL);
231
// Create voice channel and start a media monitor.
232
voice_channel = session_client_->channel_manager()->CreateVoiceChannel(
233
session, audio_offer->name, has_video_);
234
// voice_channel can be NULL in case of NullVoiceEngine.
236
voice_channel_map_[session->id()] = voice_channel;
237
voice_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
238
voice_channel->StartMediaMonitor(kMediaMonitorInterval);
243
// If desired, create video channel and start a media monitor.
244
if (has_video_ && succeeded) {
245
video_channel = session_client_->channel_manager()->CreateVideoChannel(
246
session, video_offer->name, true, voice_channel);
247
// video_channel can be NULL in case of NullVideoEngine.
249
video_channel_map_[session->id()] = video_channel;
250
video_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
251
video_channel->StartMediaMonitor(kMediaMonitorInterval);
257
// If desired, create data channel
258
if (has_data_ && succeeded) {
260
data_channel = session_client_->channel_manager()->CreateDataChannel(
261
session, data_offer->name, rtcp);
263
data_channel_map_[session->id()] = data_channel;
264
data_channel->SignalDataReceived.connect(this, &Call::OnDataReceived);
271
// Add session to list, create channels for this session.
272
sessions_.push_back(session);
273
session->SignalState.connect(this, &Call::OnSessionState);
274
session->SignalError.connect(this, &Call::OnSessionError);
275
session->SignalInfoMessage.connect(
276
this, &Call::OnSessionInfoMessage);
277
session->SignalRemoteDescriptionUpdate.connect(
278
this, &Call::OnRemoteDescriptionUpdate);
279
session->SignalReceivedTerminateReason
280
.connect(this, &Call::OnReceivedTerminateReason);
282
// If this call has the focus, enable this channel.
283
if (session_client_->GetFocus() == this) {
284
voice_channel->Enable(true);
286
video_channel->Enable(true);
291
SignalAddSession(this, session);
297
void Call::RemoveSession(Session* session) {
298
// Remove session from list
299
std::vector<Session*>::iterator it_session;
300
it_session = std::find(sessions_.begin(), sessions_.end(), session);
301
if (it_session == sessions_.end())
303
sessions_.erase(it_session);
305
// Destroy video channel
306
std::map<std::string, VideoChannel*>::iterator it_vchannel;
307
it_vchannel = video_channel_map_.find(session->id());
308
if (it_vchannel != video_channel_map_.end()) {
309
VideoChannel* video_channel = it_vchannel->second;
310
video_channel_map_.erase(it_vchannel);
311
session_client_->channel_manager()->DestroyVideoChannel(video_channel);
314
// Destroy voice channel
315
std::map<std::string, VoiceChannel*>::iterator it_channel;
316
it_channel = voice_channel_map_.find(session->id());
317
if (it_channel != voice_channel_map_.end()) {
318
VoiceChannel* voice_channel = it_channel->second;
319
voice_channel_map_.erase(it_channel);
320
session_client_->channel_manager()->DestroyVoiceChannel(voice_channel);
323
// Destroy data channel
324
std::map<std::string, DataChannel*>::iterator it_dchannel;
325
it_dchannel = data_channel_map_.find(session->id());
326
if (it_dchannel != data_channel_map_.end()) {
327
DataChannel* data_channel = it_dchannel->second;
328
data_channel_map_.erase(it_dchannel);
329
session_client_->channel_manager()->DestroyDataChannel(data_channel);
332
// Destroy speaker monitor
333
StopSpeakerMonitor(session);
336
SignalRemoveSession(this, session);
338
// The call auto destroys when the last session is removed
339
talk_base::Thread::Current()->Post(this, MSG_CHECKAUTODESTROY);
342
VoiceChannel* Call::GetVoiceChannel(Session* session) {
343
std::map<std::string, VoiceChannel*>::iterator it
344
= voice_channel_map_.find(session->id());
345
return (it != voice_channel_map_.end()) ? it->second : NULL;
348
VideoChannel* Call::GetVideoChannel(Session* session) {
349
std::map<std::string, VideoChannel*>::iterator it
350
= video_channel_map_.find(session->id());
351
return (it != video_channel_map_.end()) ? it->second : NULL;
354
DataChannel* Call::GetDataChannel(Session* session) {
355
std::map<std::string, DataChannel*>::iterator it =
356
data_channel_map_.find(session->id());
357
return (it != data_channel_map_.end()) ? it->second : NULL;
360
void Call::EnableChannels(bool enable) {
361
std::vector<Session*>::iterator it;
362
for (it = sessions_.begin(); it != sessions_.end(); it++) {
363
VoiceChannel* voice_channel = GetVoiceChannel(*it);
364
VideoChannel* video_channel = GetVideoChannel(*it);
365
DataChannel* data_channel = GetDataChannel(*it);
366
if (voice_channel != NULL)
367
voice_channel->Enable(enable);
368
if (video_channel != NULL)
369
video_channel->Enable(enable);
370
if (data_channel != NULL)
371
data_channel->Enable(enable);
373
session_client_->channel_manager()->SetLocalRenderer(
374
(enable) ? local_renderer_ : NULL);
377
void Call::Mute(bool mute) {
379
std::vector<Session*>::iterator it;
380
for (it = sessions_.begin(); it != sessions_.end(); it++) {
381
VoiceChannel* voice_channel = voice_channel_map_[(*it)->id()];
382
if (voice_channel != NULL)
383
voice_channel->Mute(mute);
387
void Call::MuteVideo(bool mute) {
389
std::vector<Session*>::iterator it;
390
for (it = sessions_.begin(); it != sessions_.end(); it++) {
391
VideoChannel* video_channel = video_channel_map_[(*it)->id()];
392
if (video_channel != NULL)
393
video_channel->Mute(mute);
397
void Call::SendData(Session* session,
398
const DataMediaChannel::SendDataParams& params,
399
const std::string& data) {
400
DataChannel* data_channel = GetDataChannel(session);
402
LOG(LS_WARNING) << "Could not send data: no data channel.";
406
data_channel->SendData(params, data);
409
void Call::PressDTMF(int event) {
410
// Queue up this digit
411
if (queued_dtmf_.size() < kMaxDTMFDigits) {
412
LOG(LS_INFO) << "Call::PressDTMF(" << event << ")";
414
queued_dtmf_.push_back(event);
416
if (!playing_dtmf_) {
422
void Call::ContinuePlayDTMF() {
423
playing_dtmf_ = false;
425
// Check to see if we have a queued tone
426
if (queued_dtmf_.size() > 0) {
427
playing_dtmf_ = true;
429
int tone = queued_dtmf_.front();
430
queued_dtmf_.pop_front();
432
LOG(LS_INFO) << "Call::ContinuePlayDTMF(" << tone << ")";
433
std::vector<Session*>::iterator it;
434
for (it = sessions_.begin(); it != sessions_.end(); it++) {
435
VoiceChannel* voice_channel = voice_channel_map_[(*it)->id()];
436
if (voice_channel != NULL) {
437
voice_channel->PressDTMF(tone, true);
441
// Post a message to play the next tone or at least clear the playing_dtmf_
443
talk_base::Thread::Current()->PostDelayed(kDTMFDelay, this, MSG_PLAYDTMF);
447
void Call::Join(Call* call, bool enable) {
448
while (call->sessions_.size() != 0) {
450
Session* session = call->sessions_[0];
451
call->sessions_.erase(call->sessions_.begin());
452
sessions_.push_back(session);
453
session->SignalState.connect(this, &Call::OnSessionState);
454
session->SignalError.connect(this, &Call::OnSessionError);
455
session->SignalReceivedTerminateReason
456
.connect(this, &Call::OnReceivedTerminateReason);
458
// Move voice channel
459
std::map<std::string, VoiceChannel*>::iterator it_channel;
460
it_channel = call->voice_channel_map_.find(session->id());
461
if (it_channel != call->voice_channel_map_.end()) {
462
VoiceChannel* voice_channel = (*it_channel).second;
463
call->voice_channel_map_.erase(it_channel);
464
voice_channel_map_[session->id()] = voice_channel;
465
voice_channel->Enable(enable);
468
// Move video channel
469
std::map<std::string, VideoChannel*>::iterator it_vchannel;
470
it_vchannel = call->video_channel_map_.find(session->id());
471
if (it_vchannel != call->video_channel_map_.end()) {
472
VideoChannel* video_channel = (*it_vchannel).second;
473
call->video_channel_map_.erase(it_vchannel);
474
video_channel_map_[session->id()] = video_channel;
475
video_channel->Enable(enable);
478
// TODO: Move data channel?
482
void Call::StartConnectionMonitor(Session* session, int cms) {
483
VoiceChannel* voice_channel = GetVoiceChannel(session);
485
voice_channel->SignalConnectionMonitor.connect(this,
486
&Call::OnConnectionMonitor);
487
voice_channel->StartConnectionMonitor(cms);
490
VideoChannel* video_channel = GetVideoChannel(session);
492
video_channel->SignalConnectionMonitor.connect(this,
493
&Call::OnConnectionMonitor);
494
video_channel->StartConnectionMonitor(cms);
498
void Call::StopConnectionMonitor(Session* session) {
499
VoiceChannel* voice_channel = GetVoiceChannel(session);
501
voice_channel->StopConnectionMonitor();
502
voice_channel->SignalConnectionMonitor.disconnect(this);
505
VideoChannel* video_channel = GetVideoChannel(session);
507
video_channel->StopConnectionMonitor();
508
video_channel->SignalConnectionMonitor.disconnect(this);
512
void Call::StartAudioMonitor(Session* session, int cms) {
513
VoiceChannel* voice_channel = GetVoiceChannel(session);
515
voice_channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor);
516
voice_channel->StartAudioMonitor(cms);
520
void Call::StopAudioMonitor(Session* session) {
521
VoiceChannel* voice_channel = GetVoiceChannel(session);
523
voice_channel->StopAudioMonitor();
524
voice_channel->SignalAudioMonitor.disconnect(this);
528
bool Call::IsAudioMonitorRunning(Session* session) {
529
VoiceChannel* voice_channel = GetVoiceChannel(session);
531
return voice_channel->IsAudioMonitorRunning();
537
void Call::StartSpeakerMonitor(Session* session) {
538
if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) {
539
if (!IsAudioMonitorRunning(session)) {
540
StartAudioMonitor(session, kAudioMonitorPollPeriodMillis);
542
CurrentSpeakerMonitor* speaker_monitor =
543
new cricket::CurrentSpeakerMonitor(this, session);
544
speaker_monitor->SignalUpdate.connect(this, &Call::OnSpeakerMonitor);
545
speaker_monitor->Start();
546
speaker_monitor_map_[session->id()] = speaker_monitor;
548
LOG(LS_WARNING) << "Already started speaker monitor for session "
549
<< session->id() << ".";
553
void Call::StopSpeakerMonitor(Session* session) {
554
if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) {
555
LOG(LS_WARNING) << "Speaker monitor for session "
556
<< session->id() << " already stopped.";
558
CurrentSpeakerMonitor* monitor = speaker_monitor_map_[session->id()];
560
speaker_monitor_map_.erase(session->id());
565
void Call::OnConnectionMonitor(VoiceChannel* channel,
566
const std::vector<ConnectionInfo> &infos) {
567
SignalConnectionMonitor(this, infos);
570
void Call::OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info) {
571
SignalMediaMonitor(this, info);
574
void Call::OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info) {
575
SignalAudioMonitor(this, info);
578
void Call::OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc) {
580
recv_streams_.GetAudioStreamBySsrc(ssrc, &stream);
581
SignalSpeakerMonitor(this, static_cast<Session*>(monitor->session()),
585
void Call::OnConnectionMonitor(VideoChannel* channel,
586
const std::vector<ConnectionInfo> &infos) {
587
SignalVideoConnectionMonitor(this, infos);
590
void Call::OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info) {
591
SignalVideoMediaMonitor(this, info);
594
void Call::OnDataReceived(DataChannel* channel,
595
const ReceiveDataParams& params,
596
const std::string& data) {
597
SignalDataReceived(this, params, data);
604
void Call::OnSessionState(BaseSession* session, BaseSession::State state) {
606
case Session::STATE_RECEIVEDACCEPT:
607
case Session::STATE_RECEIVEDREJECT:
608
case Session::STATE_RECEIVEDTERMINATE:
609
session_client_->session_manager()->signaling_thread()->Clear(this,
615
SignalSessionState(this, static_cast<Session*>(session), state);
618
void Call::OnSessionError(BaseSession* session, Session::Error error) {
619
session_client_->session_manager()->signaling_thread()->Clear(this,
621
SignalSessionError(this, static_cast<Session*>(session), error);
624
void Call::OnSessionInfoMessage(Session* session,
625
const buzz::XmlElement* action_elem) {
626
if (!IsJingleViewRequest(action_elem)) {
630
ViewRequest view_request;
632
if (!ParseJingleViewRequest(action_elem, &view_request, &error)) {
633
LOG(LS_WARNING) << "Failed to parse view request: " << error.text;
637
VideoChannel* video_channel = GetVideoChannel(session);
638
if (video_channel == NULL) {
639
LOG(LS_WARNING) << "Ignore view request since we have no video channel.";
643
if (!video_channel->ApplyViewRequest(view_request)) {
644
LOG(LS_WARNING) << "Failed to ApplyViewRequest.";
648
void FindStreamChanges(const std::vector<StreamParams>& streams,
649
const std::vector<StreamParams>& updates,
650
std::vector<StreamParams>* added_streams,
651
std::vector<StreamParams>* removed_streams) {
652
for (std::vector<StreamParams>::const_iterator update = updates.begin();
653
update != updates.end(); ++update) {
655
if (GetStreamByNickAndName(streams, update->nick, update->name, &stream)) {
656
if (!update->has_ssrcs()) {
657
removed_streams->push_back(stream);
660
// There's a bug on reflector that will send <stream>s even
661
// though there is not ssrc (which means there isn't really a
662
// stream). To work around it, we simply ignore new <stream>s
663
// that don't have any ssrcs.
664
if (update->has_ssrcs()) {
665
added_streams->push_back(*update);
671
void Call::UpdateRecvStreams(const std::vector<StreamParams>& update_streams,
672
BaseChannel* channel,
673
std::vector<StreamParams>* recv_streams,
674
std::vector<StreamParams>* added_streams,
675
std::vector<StreamParams>* removed_streams) {
676
FindStreamChanges(*recv_streams,
677
update_streams, added_streams, removed_streams);
678
AddRecvStreams(*added_streams,
679
channel, recv_streams);
680
RemoveRecvStreams(*removed_streams,
681
channel, recv_streams);
684
void Call::AddRecvStreams(const std::vector<StreamParams>& added_streams,
685
BaseChannel* channel,
686
std::vector<StreamParams>* recv_streams) {
687
std::vector<StreamParams>::const_iterator stream;
688
for (stream = added_streams.begin();
689
stream != added_streams.end();
691
AddRecvStream(*stream, channel, recv_streams);
695
void Call::AddRecvStream(const StreamParams& stream,
696
BaseChannel* channel,
697
std::vector<StreamParams>* recv_streams) {
698
if (channel && stream.has_ssrcs()) {
699
channel->AddRecvStream(stream);
701
recv_streams->push_back(stream);
704
void Call::RemoveRecvStreams(const std::vector<StreamParams>& removed_streams,
705
BaseChannel* channel,
706
std::vector<StreamParams>* recv_streams) {
707
std::vector<StreamParams>::const_iterator stream;
708
for (stream = removed_streams.begin();
709
stream != removed_streams.end();
711
RemoveRecvStream(*stream, channel, recv_streams);
715
void Call::RemoveRecvStream(const StreamParams& stream,
716
BaseChannel* channel,
717
std::vector<StreamParams>* recv_streams) {
718
if (channel && stream.has_ssrcs()) {
719
// TODO: Change RemoveRecvStream to take a stream argument.
720
channel->RemoveRecvStream(stream.first_ssrc());
722
RemoveStreamByNickAndName(recv_streams, stream.nick, stream.name);
725
void Call::OnRemoteDescriptionUpdate(BaseSession* base_session,
726
const ContentInfos& updated_contents) {
727
Session* session = static_cast<Session*>(base_session);
729
cricket::MediaStreams added_streams;
730
cricket::MediaStreams removed_streams;
731
std::vector<StreamParams>::const_iterator stream;
733
const ContentInfo* audio_content = GetFirstAudioContent(updated_contents);
735
const AudioContentDescription* audio_update =
736
static_cast<const AudioContentDescription*>(audio_content->description);
737
if (!audio_update->codecs().empty()) {
738
UpdateVoiceChannelRemoteContent(session, audio_update);
740
UpdateRecvStreams(audio_update->streams(),
741
GetVoiceChannel(session),
742
recv_streams_.mutable_audio(),
743
added_streams.mutable_audio(),
744
removed_streams.mutable_audio());
747
const ContentInfo* video_content = GetFirstVideoContent(updated_contents);
749
const VideoContentDescription* video_update =
750
static_cast<const VideoContentDescription*>(video_content->description);
751
if (!video_update->codecs().empty()) {
752
UpdateVideoChannelRemoteContent(session, video_update);
754
UpdateRecvStreams(video_update->streams(),
755
GetVideoChannel(session),
756
recv_streams_.mutable_video(),
757
added_streams.mutable_video(),
758
removed_streams.mutable_video());
761
const ContentInfo* data_content = GetFirstDataContent(updated_contents);
763
const DataContentDescription* data_update =
764
static_cast<const DataContentDescription*>(data_content->description);
765
if (!data_update->codecs().empty()) {
766
UpdateDataChannelRemoteContent(session, data_update);
768
UpdateRecvStreams(data_update->streams(),
769
GetDataChannel(session),
770
recv_streams_.mutable_data(),
771
added_streams.mutable_data(),
772
removed_streams.mutable_data());
775
if (!added_streams.empty() || !removed_streams.empty()) {
776
SignalMediaStreamsUpdate(this, session, added_streams, removed_streams);
780
bool Call::UpdateVoiceChannelRemoteContent(
781
Session* session, const AudioContentDescription* audio) {
782
VoiceChannel* voice_channel = GetVoiceChannel(session);
783
if (!voice_channel->SetRemoteContent(audio, CA_UPDATE)) {
784
LOG(LS_ERROR) << "Failure in audio SetRemoteContent with CA_UPDATE";
785
session->SetError(BaseSession::ERROR_CONTENT);
791
bool Call::UpdateVideoChannelRemoteContent(
792
Session* session, const VideoContentDescription* video) {
793
VideoChannel* video_channel = GetVideoChannel(session);
794
if (!video_channel->SetRemoteContent(video, CA_UPDATE)) {
795
LOG(LS_ERROR) << "Failure in video SetRemoteContent with CA_UPDATE";
796
session->SetError(BaseSession::ERROR_CONTENT);
802
bool Call::UpdateDataChannelRemoteContent(
803
Session* session, const DataContentDescription* data) {
804
DataChannel* data_channel = GetDataChannel(session);
805
if (!data_channel->SetRemoteContent(data, CA_UPDATE)) {
806
LOG(LS_ERROR) << "Failure in data SetRemoteContent with CA_UPDATE";
807
session->SetError(BaseSession::ERROR_CONTENT);
813
void Call::OnReceivedTerminateReason(Session* session,
814
const std::string& reason) {
815
session_client_->session_manager()->signaling_thread()->Clear(this,
817
SignalReceivedTerminateReason(this, session, reason);
820
} // namespace cricket