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 #ifdef HAVE_CONFIG_H 29 #include <config.h> 30 #endif 31 32 #ifdef HAVE_WEBRTC_VOICE 33 34 #include "talk/media/webrtc/webrtcvoiceengine.h" 35 36 #include <algorithm> 37 #include <cstdio> 38 #include <string> 39 #include <vector> 40 41 #include "talk/media/base/audiorenderer.h" 42 #include "talk/media/base/constants.h" 43 #include "talk/media/base/streamparams.h" 44 #include "talk/media/base/voiceprocessor.h" 45 #include "talk/media/webrtc/webrtcvoe.h" 46 #include "webrtc/base/base64.h" 47 #include "webrtc/base/byteorder.h" 48 #include "webrtc/base/common.h" 49 #include "webrtc/base/helpers.h" 50 #include "webrtc/base/logging.h" 51 #include "webrtc/base/stringencode.h" 52 #include "webrtc/base/stringutils.h" 53 #include "webrtc/common.h" 54 #include "webrtc/modules/audio_processing/include/audio_processing.h" 55 #include "webrtc/video_engine/include/vie_network.h" 56 57 #ifdef WIN32 58 #include <objbase.h> // NOLINT 59 #endif 60 61 namespace cricket { 62 63 struct CodecPref { 64 const char* name; 65 int clockrate; 66 int channels; 67 int payload_type; 68 bool is_multi_rate; 69 }; 70 71 static const CodecPref kCodecPrefs[] = { 72 { "OPUS", 48000, 2, 111, true }, 73 { "ISAC", 16000, 1, 103, true }, 74 { "ISAC", 32000, 1, 104, true }, 75 { "CELT", 32000, 1, 109, true }, 76 { "CELT", 32000, 2, 110, true }, 77 { "G722", 16000, 1, 9, false }, 78 { "ILBC", 8000, 1, 102, false }, 79 { "PCMU", 8000, 1, 0, false }, 80 { "PCMA", 8000, 1, 8, false }, 81 { "CN", 48000, 1, 107, false }, 82 { "CN", 32000, 1, 106, false }, 83 { "CN", 16000, 1, 105, false }, 84 { "CN", 8000, 1, 13, false }, 85 { "red", 8000, 1, 127, false }, 86 { "telephone-event", 8000, 1, 126, false }, 87 }; 88 89 // For Linux/Mac, using the default device is done by specifying index 0 for 90 // VoE 4.0 and not -1 (which was the case for VoE 3.5). 91 // 92 // On Windows Vista and newer, Microsoft introduced the concept of "Default 93 // Communications Device". This means that there are two types of default 94 // devices (old Wave Audio style default and Default Communications Device). 95 // 96 // On Windows systems which only support Wave Audio style default, uses either 97 // -1 or 0 to select the default device. 98 // 99 // On Windows systems which support both "Default Communication Device" and 100 // old Wave Audio style default, use -1 for Default Communications Device and 101 // -2 for Wave Audio style default, which is what we want to use for clips. 102 // It's not clear yet whether the -2 index is handled properly on other OSes. 103 104 #ifdef WIN32 105 static const int kDefaultAudioDeviceId = -1; 106 static const int kDefaultSoundclipDeviceId = -2; 107 #else 108 static const int kDefaultAudioDeviceId = 0; 109 #endif 110 111 static const char kIsacCodecName[] = "ISAC"; 112 static const char kL16CodecName[] = "L16"; 113 // Codec parameters for Opus. 114 static const int kOpusMonoBitrate = 32000; 115 // Parameter used for NACK. 116 // This value is equivalent to 5 seconds of audio data at 20 ms per packet. 117 static const int kNackMaxPackets = 250; 118 static const int kOpusStereoBitrate = 64000; 119 // draft-spittka-payload-rtp-opus-03 120 // Opus bitrate should be in the range between 6000 and 510000. 121 static const int kOpusMinBitrate = 6000; 122 static const int kOpusMaxBitrate = 510000; 123 124 // Default audio dscp value. 125 // See http://tools.ietf.org/html/rfc2474 for details. 126 // See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00 127 static const rtc::DiffServCodePoint kAudioDscpValue = rtc::DSCP_EF; 128 129 // Ensure we open the file in a writeable path on ChromeOS and Android. This 130 // workaround can be removed when it's possible to specify a filename for audio 131 // option based AEC dumps. 132 // 133 // TODO(grunell): Use a string in the options instead of hardcoding it here 134 // and let the embedder choose the filename (crbug.com/264223). 135 // 136 // NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified 137 // below. 138 #if defined(CHROMEOS) 139 static const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump"; 140 #elif defined(ANDROID) 141 static const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; 142 #else 143 static const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; 144 #endif 145 146 // Dumps an AudioCodec in RFC 2327-ish format. 147 static std::string ToString(const AudioCodec& codec) { 148 std::stringstream ss; 149 ss << codec.name << "/" << codec.clockrate << "/" << codec.channels 150 << " (" << codec.id << ")"; 151 return ss.str(); 152 } 153 static std::string ToString(const webrtc::CodecInst& codec) { 154 std::stringstream ss; 155 ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels 156 << " (" << codec.pltype << ")"; 157 return ss.str(); 158 } 159 160 static void LogMultiline(rtc::LoggingSeverity sev, char* text) { 161 const char* delim = "\r\n"; 162 for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) { 163 LOG_V(sev) << tok; 164 } 165 } 166 167 // Severity is an integer because it comes is assumed to be from command line. 168 static int SeverityToFilter(int severity) { 169 int filter = webrtc::kTraceNone; 170 switch (severity) { 171 case rtc::LS_VERBOSE: 172 filter |= webrtc::kTraceAll; 173 case rtc::LS_INFO: 174 filter |= (webrtc::kTraceStateInfo | webrtc::kTraceInfo); 175 case rtc::LS_WARNING: 176 filter |= (webrtc::kTraceTerseInfo | webrtc::kTraceWarning); 177 case rtc::LS_ERROR: 178 filter |= (webrtc::kTraceError | webrtc::kTraceCritical); 179 } 180 return filter; 181 } 182 183 static bool IsCodecMultiRate(const webrtc::CodecInst& codec) { 184 for (size_t i = 0; i < ARRAY_SIZE(kCodecPrefs); ++i) { 185 if (_stricmp(kCodecPrefs[i].name, codec.plname) == 0 && 186 kCodecPrefs[i].clockrate == codec.plfreq) { 187 return kCodecPrefs[i].is_multi_rate; 188 } 189 } 190 return false; 191 } 192 193 static bool IsTelephoneEventCodec(const std::string& name) { 194 return _stricmp(name.c_str(), "telephone-event") == 0; 195 } 196 197 static bool IsCNCodec(const std::string& name) { 198 return _stricmp(name.c_str(), "CN") == 0; 199 } 200 201 static bool IsRedCodec(const std::string& name) { 202 return _stricmp(name.c_str(), "red") == 0; 203 } 204 205 static bool FindCodec(const std::vector<AudioCodec>& codecs, 206 const AudioCodec& codec, 207 AudioCodec* found_codec) { 208 for (std::vector<AudioCodec>::const_iterator it = codecs.begin(); 209 it != codecs.end(); ++it) { 210 if (it->Matches(codec)) { 211 if (found_codec != NULL) { 212 *found_codec = *it; 213 } 214 return true; 215 } 216 } 217 return false; 218 } 219 220 static bool IsNackEnabled(const AudioCodec& codec) { 221 return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack, 222 kParamValueEmpty)); 223 } 224 225 // Gets the default set of options applied to the engine. Historically, these 226 // were supplied as a combination of flags from the channel manager (ec, agc, 227 // ns, and highpass) and the rest hardcoded in InitInternal. 228 static AudioOptions GetDefaultEngineOptions() { 229 AudioOptions options; 230 options.echo_cancellation.Set(true); 231 options.auto_gain_control.Set(true); 232 options.noise_suppression.Set(true); 233 options.highpass_filter.Set(true); 234 options.stereo_swapping.Set(false); 235 options.typing_detection.Set(true); 236 options.conference_mode.Set(false); 237 options.adjust_agc_delta.Set(0); 238 options.experimental_agc.Set(false); 239 options.experimental_aec.Set(false); 240 options.experimental_ns.Set(false); 241 options.aec_dump.Set(false); 242 return options; 243 } 244 245 class WebRtcSoundclipMedia : public SoundclipMedia { 246 public: 247 explicit WebRtcSoundclipMedia(WebRtcVoiceEngine *engine) 248 : engine_(engine), webrtc_channel_(-1) { 249 engine_->RegisterSoundclip(this); 250 } 251 252 virtual ~WebRtcSoundclipMedia() { 253 engine_->UnregisterSoundclip(this); 254 if (webrtc_channel_ != -1) { 255 // We shouldn't have to call Disable() here. DeleteChannel() should call 256 // StopPlayout() while deleting the channel. We should fix the bug 257 // inside WebRTC and remove the Disable() call bellow. This work is 258 // tracked by bug http://b/issue?id=5382855. 259 PlaySound(NULL, 0, 0); 260 Disable(); 261 if (engine_->voe_sc()->base()->DeleteChannel(webrtc_channel_) 262 == -1) { 263 LOG_RTCERR1(DeleteChannel, webrtc_channel_); 264 } 265 } 266 } 267 268 bool Init() { 269 if (!engine_->voe_sc()) { 270 return false; 271 } 272 webrtc_channel_ = engine_->CreateSoundclipVoiceChannel(); 273 if (webrtc_channel_ == -1) { 274 LOG_RTCERR0(CreateChannel); 275 return false; 276 } 277 return true; 278 } 279 280 bool Enable() { 281 if (engine_->voe_sc()->base()->StartPlayout(webrtc_channel_) == -1) { 282 LOG_RTCERR1(StartPlayout, webrtc_channel_); 283 return false; 284 } 285 return true; 286 } 287 288 bool Disable() { 289 if (engine_->voe_sc()->base()->StopPlayout(webrtc_channel_) == -1) { 290 LOG_RTCERR1(StopPlayout, webrtc_channel_); 291 return false; 292 } 293 return true; 294 } 295 296 virtual bool PlaySound(const char *buf, int len, int flags) { 297 // The voe file api is not available in chrome. 298 if (!engine_->voe_sc()->file()) { 299 return false; 300 } 301 // Must stop playing the current sound (if any), because we are about to 302 // modify the stream. 303 if (engine_->voe_sc()->file()->StopPlayingFileLocally(webrtc_channel_) 304 == -1) { 305 LOG_RTCERR1(StopPlayingFileLocally, webrtc_channel_); 306 return false; 307 } 308 309 if (buf) { 310 stream_.reset(new WebRtcSoundclipStream(buf, len)); 311 stream_->set_loop((flags & SF_LOOP) != 0); 312 stream_->Rewind(); 313 314 // Play it. 315 if (engine_->voe_sc()->file()->StartPlayingFileLocally( 316 webrtc_channel_, stream_.get()) == -1) { 317 LOG_RTCERR2(StartPlayingFileLocally, webrtc_channel_, stream_.get()); 318 LOG(LS_ERROR) << "Unable to start soundclip"; 319 return false; 320 } 321 } else { 322 stream_.reset(); 323 } 324 return true; 325 } 326 327 int GetLastEngineError() const { return engine_->voe_sc()->error(); } 328 329 private: 330 WebRtcVoiceEngine *engine_; 331 int webrtc_channel_; 332 rtc::scoped_ptr<WebRtcSoundclipStream> stream_; 333 }; 334 335 WebRtcVoiceEngine::WebRtcVoiceEngine() 336 : voe_wrapper_(new VoEWrapper()), 337 voe_wrapper_sc_(new VoEWrapper()), 338 voe_wrapper_sc_initialized_(false), 339 tracing_(new VoETraceWrapper()), 340 adm_(NULL), 341 adm_sc_(NULL), 342 log_filter_(SeverityToFilter(kDefaultLogSeverity)), 343 is_dumping_aec_(false), 344 desired_local_monitor_enable_(false), 345 tx_processor_ssrc_(0), 346 rx_processor_ssrc_(0) { 347 Construct(); 348 } 349 350 WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper, 351 VoEWrapper* voe_wrapper_sc, 352 VoETraceWrapper* tracing) 353 : voe_wrapper_(voe_wrapper), 354 voe_wrapper_sc_(voe_wrapper_sc), 355 voe_wrapper_sc_initialized_(false), 356 tracing_(tracing), 357 adm_(NULL), 358 adm_sc_(NULL), 359 log_filter_(SeverityToFilter(kDefaultLogSeverity)), 360 is_dumping_aec_(false), 361 desired_local_monitor_enable_(false), 362 tx_processor_ssrc_(0), 363 rx_processor_ssrc_(0) { 364 Construct(); 365 } 366 367 void WebRtcVoiceEngine::Construct() { 368 SetTraceFilter(log_filter_); 369 initialized_ = false; 370 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; 371 SetTraceOptions(""); 372 if (tracing_->SetTraceCallback(this) == -1) { 373 LOG_RTCERR0(SetTraceCallback); 374 } 375 if (voe_wrapper_->base()->RegisterVoiceEngineObserver(*this) == -1) { 376 LOG_RTCERR0(RegisterVoiceEngineObserver); 377 } 378 // Clear the default agc state. 379 memset(&default_agc_config_, 0, sizeof(default_agc_config_)); 380 381 // Load our audio codec list. 382 ConstructCodecs(); 383 384 // Load our RTP Header extensions. 385 rtp_header_extensions_.push_back( 386 RtpHeaderExtension(kRtpAudioLevelHeaderExtension, 387 kRtpAudioLevelHeaderExtensionDefaultId)); 388 rtp_header_extensions_.push_back( 389 RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, 390 kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); 391 options_ = GetDefaultEngineOptions(); 392 } 393 394 static bool IsOpus(const AudioCodec& codec) { 395 return (_stricmp(codec.name.c_str(), kOpusCodecName) == 0); 396 } 397 398 static bool IsIsac(const AudioCodec& codec) { 399 return (_stricmp(codec.name.c_str(), kIsacCodecName) == 0); 400 } 401 402 // True if params["stereo"] == "1" 403 static bool IsOpusStereoEnabled(const AudioCodec& codec) { 404 int value; 405 return codec.GetParam(kCodecParamStereo, &value) && value == 1; 406 } 407 408 // TODO(minyue): Clamp bitrate when invalid. 409 static bool IsValidOpusBitrate(int bitrate) { 410 return (bitrate >= kOpusMinBitrate && bitrate <= kOpusMaxBitrate); 411 } 412 413 // Returns 0 if params[kCodecParamMaxAverageBitrate] is not defined or invalid. 414 // Returns the value of params[kCodecParamMaxAverageBitrate] otherwise. 415 static int GetOpusBitrateFromParams(const AudioCodec& codec) { 416 int bitrate = 0; 417 if (!codec.GetParam(kCodecParamMaxAverageBitrate, &bitrate)) { 418 return 0; 419 } 420 if (!IsValidOpusBitrate(bitrate)) { 421 LOG(LS_WARNING) << "Codec parameter \"maxaveragebitrate\" has an " 422 << "invalid value: " << bitrate; 423 return 0; 424 } 425 return bitrate; 426 } 427 428 // Return true if params[kCodecParamUseInbandFec] == "1", false 429 // otherwise. 430 static bool IsOpusFecEnabled(const AudioCodec& codec) { 431 int value; 432 return codec.GetParam(kCodecParamUseInbandFec, &value) && value == 1; 433 } 434 435 // Returns kOpusDefaultPlaybackRate if params[kCodecParamMaxPlaybackRate] is not 436 // defined. Returns the value of params[kCodecParamMaxPlaybackRate] otherwise. 437 static int GetOpusMaxPlaybackRate(const AudioCodec& codec) { 438 int value; 439 if (codec.GetParam(kCodecParamMaxPlaybackRate, &value)) { 440 return value; 441 } 442 return kOpusDefaultMaxPlaybackRate; 443 } 444 445 static void GetOpusConfig(const AudioCodec& codec, webrtc::CodecInst* voe_codec, 446 bool* enable_codec_fec, int* max_playback_rate) { 447 *enable_codec_fec = IsOpusFecEnabled(codec); 448 *max_playback_rate = GetOpusMaxPlaybackRate(codec); 449 450 // If OPUS, change what we send according to the "stereo" codec 451 // parameter, and not the "channels" parameter. We set 452 // voe_codec.channels to 2 if "stereo=1" and 1 otherwise. If 453 // the bitrate is not specified, i.e. is zero, we set it to the 454 // appropriate default value for mono or stereo Opus. 455 456 // TODO(minyue): The determination of bit rate might take the maximum playback 457 // rate into account. 458 459 if (IsOpusStereoEnabled(codec)) { 460 voe_codec->channels = 2; 461 if (!IsValidOpusBitrate(codec.bitrate)) { 462 if (codec.bitrate != 0) { 463 LOG(LS_WARNING) << "Overrides the invalid supplied bitrate(" 464 << codec.bitrate 465 << ") with default opus stereo bitrate: " 466 << kOpusStereoBitrate; 467 } 468 voe_codec->rate = kOpusStereoBitrate; 469 } 470 } else { 471 voe_codec->channels = 1; 472 if (!IsValidOpusBitrate(codec.bitrate)) { 473 if (codec.bitrate != 0) { 474 LOG(LS_WARNING) << "Overrides the invalid supplied bitrate(" 475 << codec.bitrate 476 << ") with default opus mono bitrate: " 477 << kOpusMonoBitrate; 478 } 479 voe_codec->rate = kOpusMonoBitrate; 480 } 481 } 482 int bitrate_from_params = GetOpusBitrateFromParams(codec); 483 if (bitrate_from_params != 0) { 484 voe_codec->rate = bitrate_from_params; 485 } 486 } 487 488 void WebRtcVoiceEngine::ConstructCodecs() { 489 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; 490 int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); 491 for (int i = 0; i < ncodecs; ++i) { 492 webrtc::CodecInst voe_codec; 493 if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { 494 // Skip uncompressed formats. 495 if (_stricmp(voe_codec.plname, kL16CodecName) == 0) { 496 continue; 497 } 498 499 const CodecPref* pref = NULL; 500 for (size_t j = 0; j < ARRAY_SIZE(kCodecPrefs); ++j) { 501 if (_stricmp(kCodecPrefs[j].name, voe_codec.plname) == 0 && 502 kCodecPrefs[j].clockrate == voe_codec.plfreq && 503 kCodecPrefs[j].channels == voe_codec.channels) { 504 pref = &kCodecPrefs[j]; 505 break; 506 } 507 } 508 509 if (pref) { 510 // Use the payload type that we've configured in our pref table; 511 // use the offset in our pref table to determine the sort order. 512 AudioCodec codec(pref->payload_type, voe_codec.plname, voe_codec.plfreq, 513 voe_codec.rate, voe_codec.channels, 514 ARRAY_SIZE(kCodecPrefs) - (pref - kCodecPrefs)); 515 LOG(LS_INFO) << ToString(codec); 516 if (IsIsac(codec)) { 517 // Indicate auto-bandwidth in signaling. 518 codec.bitrate = 0; 519 } 520 if (IsOpus(codec)) { 521 // Only add fmtp parameters that differ from the spec. 522 if (kPreferredMinPTime != kOpusDefaultMinPTime) { 523 codec.params[kCodecParamMinPTime] = 524 rtc::ToString(kPreferredMinPTime); 525 } 526 if (kPreferredMaxPTime != kOpusDefaultMaxPTime) { 527 codec.params[kCodecParamMaxPTime] = 528 rtc::ToString(kPreferredMaxPTime); 529 } 530 // TODO(hellner): Add ptime, sprop-stereo, stereo and useinbandfec 531 // when they can be set to values other than the default. 532 } 533 codecs_.push_back(codec); 534 } else { 535 LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec); 536 } 537 } 538 } 539 // Make sure they are in local preference order. 540 std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable); 541 } 542 543 WebRtcVoiceEngine::~WebRtcVoiceEngine() { 544 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; 545 if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) { 546 LOG_RTCERR0(DeRegisterVoiceEngineObserver); 547 } 548 if (adm_) { 549 voe_wrapper_.reset(); 550 adm_->Release(); 551 adm_ = NULL; 552 } 553 if (adm_sc_) { 554 voe_wrapper_sc_.reset(); 555 adm_sc_->Release(); 556 adm_sc_ = NULL; 557 } 558 559 // Test to see if the media processor was deregistered properly 560 ASSERT(SignalRxMediaFrame.is_empty()); 561 ASSERT(SignalTxMediaFrame.is_empty()); 562 563 tracing_->SetTraceCallback(NULL); 564 } 565 566 bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) { 567 LOG(LS_INFO) << "WebRtcVoiceEngine::Init"; 568 bool res = InitInternal(); 569 if (res) { 570 LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!"; 571 } else { 572 LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed"; 573 Terminate(); 574 } 575 return res; 576 } 577 578 bool WebRtcVoiceEngine::InitInternal() { 579 // Temporarily turn logging level up for the Init call 580 int old_filter = log_filter_; 581 int extended_filter = log_filter_ | SeverityToFilter(rtc::LS_INFO); 582 SetTraceFilter(extended_filter); 583 SetTraceOptions(""); 584 585 // Init WebRtc VoiceEngine. 586 if (voe_wrapper_->base()->Init(adm_) == -1) { 587 LOG_RTCERR0_EX(Init, voe_wrapper_->error()); 588 SetTraceFilter(old_filter); 589 return false; 590 } 591 592 SetTraceFilter(old_filter); 593 SetTraceOptions(log_options_); 594 595 // Log the VoiceEngine version info 596 char buffer[1024] = ""; 597 voe_wrapper_->base()->GetVersion(buffer); 598 LOG(LS_INFO) << "WebRtc VoiceEngine Version:"; 599 LogMultiline(rtc::LS_INFO, buffer); 600 601 // Save the default AGC configuration settings. This must happen before 602 // calling SetOptions or the default will be overwritten. 603 if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) { 604 LOG_RTCERR0(GetAgcConfig); 605 return false; 606 } 607 608 // Set defaults for options, so that ApplyOptions applies them explicitly 609 // when we clear option (channel) overrides. External clients can still 610 // modify the defaults via SetOptions (on the media engine). 611 if (!SetOptions(GetDefaultEngineOptions())) { 612 return false; 613 } 614 615 // Print our codec list again for the call diagnostic log 616 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; 617 for (std::vector<AudioCodec>::const_iterator it = codecs_.begin(); 618 it != codecs_.end(); ++it) { 619 LOG(LS_INFO) << ToString(*it); 620 } 621 622 // Disable the DTMF playout when a tone is sent. 623 // PlayDtmfTone will be used if local playout is needed. 624 if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) { 625 LOG_RTCERR1(SetDtmfFeedbackStatus, false); 626 } 627 628 initialized_ = true; 629 return true; 630 } 631 632 bool WebRtcVoiceEngine::EnsureSoundclipEngineInit() { 633 if (voe_wrapper_sc_initialized_) { 634 return true; 635 } 636 // Note that, if initialization fails, voe_wrapper_sc_initialized_ will still 637 // be false, so subsequent calls to EnsureSoundclipEngineInit will 638 // probably just fail again. That's acceptable behavior. 639 #if defined(LINUX) && !defined(HAVE_LIBPULSE) 640 voe_wrapper_sc_->hw()->SetAudioDeviceLayer(webrtc::kAudioLinuxAlsa); 641 #endif 642 643 // Initialize the VoiceEngine instance that we'll use to play out sound clips. 644 if (voe_wrapper_sc_->base()->Init(adm_sc_) == -1) { 645 LOG_RTCERR0_EX(Init, voe_wrapper_sc_->error()); 646 return false; 647 } 648 649 // On Windows, tell it to use the default sound (not communication) devices. 650 // First check whether there is a valid sound device for playback. 651 // TODO(juberti): Clean this up when we support setting the soundclip device. 652 #ifdef WIN32 653 // The SetPlayoutDevice may not be implemented in the case of external ADM. 654 // TODO(ronghuawu): We should only check the adm_sc_ here, but current 655 // PeerConnection interface never set the adm_sc_, so need to check both 656 // in order to determine if the external adm is used. 657 if (!adm_ && !adm_sc_) { 658 int num_of_devices = 0; 659 if (voe_wrapper_sc_->hw()->GetNumOfPlayoutDevices(num_of_devices) != -1 && 660 num_of_devices > 0) { 661 if (voe_wrapper_sc_->hw()->SetPlayoutDevice(kDefaultSoundclipDeviceId) 662 == -1) { 663 LOG_RTCERR1_EX(SetPlayoutDevice, kDefaultSoundclipDeviceId, 664 voe_wrapper_sc_->error()); 665 return false; 666 } 667 } else { 668 LOG(LS_WARNING) << "No valid sound playout device found."; 669 } 670 } 671 #endif 672 voe_wrapper_sc_initialized_ = true; 673 LOG(LS_INFO) << "Initialized WebRtc soundclip engine."; 674 return true; 675 } 676 677 void WebRtcVoiceEngine::Terminate() { 678 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; 679 initialized_ = false; 680 681 StopAecDump(); 682 683 if (voe_wrapper_sc_) { 684 voe_wrapper_sc_initialized_ = false; 685 voe_wrapper_sc_->base()->Terminate(); 686 } 687 voe_wrapper_->base()->Terminate(); 688 desired_local_monitor_enable_ = false; 689 } 690 691 int WebRtcVoiceEngine::GetCapabilities() { 692 return AUDIO_SEND | AUDIO_RECV; 693 } 694 695 VoiceMediaChannel *WebRtcVoiceEngine::CreateChannel() { 696 WebRtcVoiceMediaChannel* ch = new WebRtcVoiceMediaChannel(this); 697 if (!ch->valid()) { 698 delete ch; 699 ch = NULL; 700 } 701 return ch; 702 } 703 704 SoundclipMedia *WebRtcVoiceEngine::CreateSoundclip() { 705 if (!EnsureSoundclipEngineInit()) { 706 LOG(LS_ERROR) << "Unable to create soundclip: soundclip engine failed to " 707 << "initialize."; 708 return NULL; 709 } 710 WebRtcSoundclipMedia *soundclip = new WebRtcSoundclipMedia(this); 711 if (!soundclip->Init() || !soundclip->Enable()) { 712 delete soundclip; 713 return NULL; 714 } 715 return soundclip; 716 } 717 718 bool WebRtcVoiceEngine::SetOptions(const AudioOptions& options) { 719 if (!ApplyOptions(options)) { 720 return false; 721 } 722 options_ = options; 723 return true; 724 } 725 726 bool WebRtcVoiceEngine::SetOptionOverrides(const AudioOptions& overrides) { 727 LOG(LS_INFO) << "Setting option overrides: " << overrides.ToString(); 728 if (!ApplyOptions(overrides)) { 729 return false; 730 } 731 option_overrides_ = overrides; 732 return true; 733 } 734 735 bool WebRtcVoiceEngine::ClearOptionOverrides() { 736 LOG(LS_INFO) << "Clearing option overrides."; 737 AudioOptions options = options_; 738 // Only call ApplyOptions if |options_overrides_| contains overrided options. 739 // ApplyOptions affects NS, AGC other options that is shared between 740 // all WebRtcVoiceEngineChannels. 741 if (option_overrides_ == AudioOptions()) { 742 return true; 743 } 744 745 if (!ApplyOptions(options)) { 746 return false; 747 } 748 option_overrides_ = AudioOptions(); 749 return true; 750 } 751 752 // AudioOptions defaults are set in InitInternal (for options with corresponding 753 // MediaEngineInterface flags) and in SetOptions(int) for flagless options. 754 bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { 755 AudioOptions options = options_in; // The options are modified below. 756 // kEcConference is AEC with high suppression. 757 webrtc::EcModes ec_mode = webrtc::kEcConference; 758 webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone; 759 webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog; 760 webrtc::NsModes ns_mode = webrtc::kNsHighSuppression; 761 bool aecm_comfort_noise = false; 762 if (options.aecm_generate_comfort_noise.Get(&aecm_comfort_noise)) { 763 LOG(LS_VERBOSE) << "Comfort noise explicitly set to " 764 << aecm_comfort_noise << " (default is false)."; 765 } 766 767 #if defined(IOS) 768 // On iOS, VPIO provides built-in EC and AGC. 769 options.echo_cancellation.Set(false); 770 options.auto_gain_control.Set(false); 771 #elif defined(ANDROID) 772 ec_mode = webrtc::kEcAecm; 773 #endif 774 775 #if defined(IOS) || defined(ANDROID) 776 // Set the AGC mode for iOS as well despite disabling it above, to avoid 777 // unsupported configuration errors from webrtc. 778 agc_mode = webrtc::kAgcFixedDigital; 779 options.typing_detection.Set(false); 780 options.experimental_agc.Set(false); 781 options.experimental_aec.Set(false); 782 options.experimental_ns.Set(false); 783 #endif 784 785 LOG(LS_INFO) << "Applying audio options: " << options.ToString(); 786 787 webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing(); 788 789 bool echo_cancellation; 790 if (options.echo_cancellation.Get(&echo_cancellation)) { 791 if (voep->SetEcStatus(echo_cancellation, ec_mode) == -1) { 792 LOG_RTCERR2(SetEcStatus, echo_cancellation, ec_mode); 793 return false; 794 } else { 795 LOG(LS_VERBOSE) << "Echo control set to " << echo_cancellation 796 << " with mode " << ec_mode; 797 } 798 #if !defined(ANDROID) 799 // TODO(ajm): Remove the error return on Android from webrtc. 800 if (voep->SetEcMetricsStatus(echo_cancellation) == -1) { 801 LOG_RTCERR1(SetEcMetricsStatus, echo_cancellation); 802 return false; 803 } 804 #endif 805 if (ec_mode == webrtc::kEcAecm) { 806 if (voep->SetAecmMode(aecm_mode, aecm_comfort_noise) != 0) { 807 LOG_RTCERR2(SetAecmMode, aecm_mode, aecm_comfort_noise); 808 return false; 809 } 810 } 811 } 812 813 bool auto_gain_control; 814 if (options.auto_gain_control.Get(&auto_gain_control)) { 815 if (voep->SetAgcStatus(auto_gain_control, agc_mode) == -1) { 816 LOG_RTCERR2(SetAgcStatus, auto_gain_control, agc_mode); 817 return false; 818 } else { 819 LOG(LS_VERBOSE) << "Auto gain set to " << auto_gain_control 820 << " with mode " << agc_mode; 821 } 822 } 823 824 if (options.tx_agc_target_dbov.IsSet() || 825 options.tx_agc_digital_compression_gain.IsSet() || 826 options.tx_agc_limiter.IsSet()) { 827 // Override default_agc_config_. Generally, an unset option means "leave 828 // the VoE bits alone" in this function, so we want whatever is set to be 829 // stored as the new "default". If we didn't, then setting e.g. 830 // tx_agc_target_dbov would reset digital compression gain and limiter 831 // settings. 832 // Also, if we don't update default_agc_config_, then adjust_agc_delta 833 // would be an offset from the original values, and not whatever was set 834 // explicitly. 835 default_agc_config_.targetLeveldBOv = 836 options.tx_agc_target_dbov.GetWithDefaultIfUnset( 837 default_agc_config_.targetLeveldBOv); 838 default_agc_config_.digitalCompressionGaindB = 839 options.tx_agc_digital_compression_gain.GetWithDefaultIfUnset( 840 default_agc_config_.digitalCompressionGaindB); 841 default_agc_config_.limiterEnable = 842 options.tx_agc_limiter.GetWithDefaultIfUnset( 843 default_agc_config_.limiterEnable); 844 if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) { 845 LOG_RTCERR3(SetAgcConfig, 846 default_agc_config_.targetLeveldBOv, 847 default_agc_config_.digitalCompressionGaindB, 848 default_agc_config_.limiterEnable); 849 return false; 850 } 851 } 852 853 bool noise_suppression; 854 if (options.noise_suppression.Get(&noise_suppression)) { 855 if (voep->SetNsStatus(noise_suppression, ns_mode) == -1) { 856 LOG_RTCERR2(SetNsStatus, noise_suppression, ns_mode); 857 return false; 858 } else { 859 LOG(LS_VERBOSE) << "Noise suppression set to " << noise_suppression 860 << " with mode " << ns_mode; 861 } 862 } 863 864 bool highpass_filter; 865 if (options.highpass_filter.Get(&highpass_filter)) { 866 LOG(LS_INFO) << "High pass filter enabled? " << highpass_filter; 867 if (voep->EnableHighPassFilter(highpass_filter) == -1) { 868 LOG_RTCERR1(SetHighpassFilterStatus, highpass_filter); 869 return false; 870 } 871 } 872 873 bool stereo_swapping; 874 if (options.stereo_swapping.Get(&stereo_swapping)) { 875 LOG(LS_INFO) << "Stereo swapping enabled? " << stereo_swapping; 876 voep->EnableStereoChannelSwapping(stereo_swapping); 877 if (voep->IsStereoChannelSwappingEnabled() != stereo_swapping) { 878 LOG_RTCERR1(EnableStereoChannelSwapping, stereo_swapping); 879 return false; 880 } 881 } 882 883 bool typing_detection; 884 if (options.typing_detection.Get(&typing_detection)) { 885 LOG(LS_INFO) << "Typing detection is enabled? " << typing_detection; 886 if (voep->SetTypingDetectionStatus(typing_detection) == -1) { 887 // In case of error, log the info and continue 888 LOG_RTCERR1(SetTypingDetectionStatus, typing_detection); 889 } 890 } 891 892 int adjust_agc_delta; 893 if (options.adjust_agc_delta.Get(&adjust_agc_delta)) { 894 LOG(LS_INFO) << "Adjust agc delta is " << adjust_agc_delta; 895 if (!AdjustAgcLevel(adjust_agc_delta)) { 896 return false; 897 } 898 } 899 900 bool aec_dump; 901 if (options.aec_dump.Get(&aec_dump)) { 902 LOG(LS_INFO) << "Aec dump is enabled? " << aec_dump; 903 if (aec_dump) 904 StartAecDump(kAecDumpByAudioOptionFilename); 905 else 906 StopAecDump(); 907 } 908 909 webrtc::Config config; 910 911 experimental_aec_.SetFrom(options.experimental_aec); 912 bool experimental_aec; 913 if (experimental_aec_.Get(&experimental_aec)) { 914 LOG(LS_INFO) << "Experimental aec is enabled? " << experimental_aec; 915 config.Set<webrtc::DelayCorrection>( 916 new webrtc::DelayCorrection(experimental_aec)); 917 } 918 919 #ifdef USE_WEBRTC_DEV_BRANCH 920 experimental_ns_.SetFrom(options.experimental_ns); 921 bool experimental_ns; 922 if (experimental_ns_.Get(&experimental_ns)) { 923 LOG(LS_INFO) << "Experimental ns is enabled? " << experimental_ns; 924 config.Set<webrtc::ExperimentalNs>( 925 new webrtc::ExperimentalNs(experimental_ns)); 926 } 927 #endif 928 929 // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine 930 // returns NULL on audio_processing(). 931 webrtc::AudioProcessing* audioproc = voe_wrapper_->base()->audio_processing(); 932 if (audioproc) { 933 audioproc->SetExtraOptions(config); 934 } 935 936 #ifndef USE_WEBRTC_DEV_BRANCH 937 bool experimental_ns; 938 if (options.experimental_ns.Get(&experimental_ns)) { 939 LOG(LS_INFO) << "Experimental ns is enabled? " << experimental_ns; 940 // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine 941 // returns NULL on audio_processing(). 942 if (audioproc) { 943 if (audioproc->EnableExperimentalNs(experimental_ns) == -1) { 944 LOG_RTCERR1(EnableExperimentalNs, experimental_ns); 945 return false; 946 } 947 } else { 948 LOG(LS_VERBOSE) << "Experimental noise suppression set to " 949 << experimental_ns; 950 } 951 } 952 #endif 953 954 uint32 recording_sample_rate; 955 if (options.recording_sample_rate.Get(&recording_sample_rate)) { 956 LOG(LS_INFO) << "Recording sample rate is " << recording_sample_rate; 957 if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) { 958 LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate); 959 } 960 } 961 962 uint32 playout_sample_rate; 963 if (options.playout_sample_rate.Get(&playout_sample_rate)) { 964 LOG(LS_INFO) << "Playout sample rate is " << playout_sample_rate; 965 if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) { 966 LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate); 967 } 968 } 969 970 return true; 971 } 972 973 bool WebRtcVoiceEngine::SetDelayOffset(int offset) { 974 voe_wrapper_->processing()->SetDelayOffsetMs(offset); 975 if (voe_wrapper_->processing()->DelayOffsetMs() != offset) { 976 LOG_RTCERR1(SetDelayOffsetMs, offset); 977 return false; 978 } 979 980 return true; 981 } 982 983 struct ResumeEntry { 984 ResumeEntry(WebRtcVoiceMediaChannel *c, bool p, SendFlags s) 985 : channel(c), 986 playout(p), 987 send(s) { 988 } 989 990 WebRtcVoiceMediaChannel *channel; 991 bool playout; 992 SendFlags send; 993 }; 994 995 // TODO(juberti): Refactor this so that the core logic can be used to set the 996 // soundclip device. At that time, reinstate the soundclip pause/resume code. 997 bool WebRtcVoiceEngine::SetDevices(const Device* in_device, 998 const Device* out_device) { 999 #if !defined(IOS) 1000 int in_id = in_device ? rtc::FromString<int>(in_device->id) : 1001 kDefaultAudioDeviceId; 1002 int out_id = out_device ? rtc::FromString<int>(out_device->id) : 1003 kDefaultAudioDeviceId; 1004 // The device manager uses -1 as the default device, which was the case for 1005 // VoE 3.5. VoE 4.0, however, uses 0 as the default in Linux and Mac. 1006 #ifndef WIN32 1007 if (-1 == in_id) { 1008 in_id = kDefaultAudioDeviceId; 1009 } 1010 if (-1 == out_id) { 1011 out_id = kDefaultAudioDeviceId; 1012 } 1013 #endif 1014 1015 std::string in_name = (in_id != kDefaultAudioDeviceId) ? 1016 in_device->name : "Default device"; 1017 std::string out_name = (out_id != kDefaultAudioDeviceId) ? 1018 out_device->name : "Default device"; 1019 LOG(LS_INFO) << "Setting microphone to (id=" << in_id << ", name=" << in_name 1020 << ") and speaker to (id=" << out_id << ", name=" << out_name 1021 << ")"; 1022 1023 // If we're running the local monitor, we need to stop it first. 1024 bool ret = true; 1025 if (!PauseLocalMonitor()) { 1026 LOG(LS_WARNING) << "Failed to pause local monitor"; 1027 ret = false; 1028 } 1029 1030 // Must also pause all audio playback and capture. 1031 for (ChannelList::const_iterator i = channels_.begin(); 1032 i != channels_.end(); ++i) { 1033 WebRtcVoiceMediaChannel *channel = *i; 1034 if (!channel->PausePlayout()) { 1035 LOG(LS_WARNING) << "Failed to pause playout"; 1036 ret = false; 1037 } 1038 if (!channel->PauseSend()) { 1039 LOG(LS_WARNING) << "Failed to pause send"; 1040 ret = false; 1041 } 1042 } 1043 1044 // Find the recording device id in VoiceEngine and set recording device. 1045 if (!FindWebRtcAudioDeviceId(true, in_name, in_id, &in_id)) { 1046 ret = false; 1047 } 1048 if (ret) { 1049 if (voe_wrapper_->hw()->SetRecordingDevice(in_id) == -1) { 1050 LOG_RTCERR2(SetRecordingDevice, in_name, in_id); 1051 ret = false; 1052 } 1053 webrtc::AudioProcessing* ap = voe()->base()->audio_processing(); 1054 if (ap) 1055 ap->Initialize(); 1056 } 1057 1058 // Find the playout device id in VoiceEngine and set playout device. 1059 if (!FindWebRtcAudioDeviceId(false, out_name, out_id, &out_id)) { 1060 LOG(LS_WARNING) << "Failed to find VoiceEngine device id for " << out_name; 1061 ret = false; 1062 } 1063 if (ret) { 1064 if (voe_wrapper_->hw()->SetPlayoutDevice(out_id) == -1) { 1065 LOG_RTCERR2(SetPlayoutDevice, out_name, out_id); 1066 ret = false; 1067 } 1068 } 1069 1070 // Resume all audio playback and capture. 1071 for (ChannelList::const_iterator i = channels_.begin(); 1072 i != channels_.end(); ++i) { 1073 WebRtcVoiceMediaChannel *channel = *i; 1074 if (!channel->ResumePlayout()) { 1075 LOG(LS_WARNING) << "Failed to resume playout"; 1076 ret = false; 1077 } 1078 if (!channel->ResumeSend()) { 1079 LOG(LS_WARNING) << "Failed to resume send"; 1080 ret = false; 1081 } 1082 } 1083 1084 // Resume local monitor. 1085 if (!ResumeLocalMonitor()) { 1086 LOG(LS_WARNING) << "Failed to resume local monitor"; 1087 ret = false; 1088 } 1089 1090 if (ret) { 1091 LOG(LS_INFO) << "Set microphone to (id=" << in_id <<" name=" << in_name 1092 << ") and speaker to (id="<< out_id << " name=" << out_name 1093 << ")"; 1094 } 1095 1096 return ret; 1097 #else 1098 return true; 1099 #endif // !IOS 1100 } 1101 1102 bool WebRtcVoiceEngine::FindWebRtcAudioDeviceId( 1103 bool is_input, const std::string& dev_name, int dev_id, int* rtc_id) { 1104 // In Linux, VoiceEngine uses the same device dev_id as the device manager. 1105 #if defined(LINUX) || defined(ANDROID) 1106 *rtc_id = dev_id; 1107 return true; 1108 #else 1109 // In Windows and Mac, we need to find the VoiceEngine device id by name 1110 // unless the input dev_id is the default device id. 1111 if (kDefaultAudioDeviceId == dev_id) { 1112 *rtc_id = dev_id; 1113 return true; 1114 } 1115 1116 // Get the number of VoiceEngine audio devices. 1117 int count = 0; 1118 if (is_input) { 1119 if (-1 == voe_wrapper_->hw()->GetNumOfRecordingDevices(count)) { 1120 LOG_RTCERR0(GetNumOfRecordingDevices); 1121 return false; 1122 } 1123 } else { 1124 if (-1 == voe_wrapper_->hw()->GetNumOfPlayoutDevices(count)) { 1125 LOG_RTCERR0(GetNumOfPlayoutDevices); 1126 return false; 1127 } 1128 } 1129 1130 for (int i = 0; i < count; ++i) { 1131 char name[128]; 1132 char guid[128]; 1133 if (is_input) { 1134 voe_wrapper_->hw()->GetRecordingDeviceName(i, name, guid); 1135 LOG(LS_VERBOSE) << "VoiceEngine microphone " << i << ": " << name; 1136 } else { 1137 voe_wrapper_->hw()->GetPlayoutDeviceName(i, name, guid); 1138 LOG(LS_VERBOSE) << "VoiceEngine speaker " << i << ": " << name; 1139 } 1140 1141 std::string webrtc_name(name); 1142 if (dev_name.compare(0, webrtc_name.size(), webrtc_name) == 0) { 1143 *rtc_id = i; 1144 return true; 1145 } 1146 } 1147 LOG(LS_WARNING) << "VoiceEngine cannot find device: " << dev_name; 1148 return false; 1149 #endif 1150 } 1151 1152 bool WebRtcVoiceEngine::GetOutputVolume(int* level) { 1153 unsigned int ulevel; 1154 if (voe_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) { 1155 LOG_RTCERR1(GetSpeakerVolume, level); 1156 return false; 1157 } 1158 *level = ulevel; 1159 return true; 1160 } 1161 1162 bool WebRtcVoiceEngine::SetOutputVolume(int level) { 1163 ASSERT(level >= 0 && level <= 255); 1164 if (voe_wrapper_->volume()->SetSpeakerVolume(level) == -1) { 1165 LOG_RTCERR1(SetSpeakerVolume, level); 1166 return false; 1167 } 1168 return true; 1169 } 1170 1171 int WebRtcVoiceEngine::GetInputLevel() { 1172 unsigned int ulevel; 1173 return (voe_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ? 1174 static_cast<int>(ulevel) : -1; 1175 } 1176 1177 bool WebRtcVoiceEngine::SetLocalMonitor(bool enable) { 1178 desired_local_monitor_enable_ = enable; 1179 return ChangeLocalMonitor(desired_local_monitor_enable_); 1180 } 1181 1182 bool WebRtcVoiceEngine::ChangeLocalMonitor(bool enable) { 1183 // The voe file api is not available in chrome. 1184 if (!voe_wrapper_->file()) { 1185 return false; 1186 } 1187 if (enable && !monitor_) { 1188 monitor_.reset(new WebRtcMonitorStream); 1189 if (voe_wrapper_->file()->StartRecordingMicrophone(monitor_.get()) == -1) { 1190 LOG_RTCERR1(StartRecordingMicrophone, monitor_.get()); 1191 // Must call Stop() because there are some cases where Start will report 1192 // failure but still change the state, and if we leave VE in the on state 1193 // then it could crash later when trying to invoke methods on our monitor. 1194 voe_wrapper_->file()->StopRecordingMicrophone(); 1195 monitor_.reset(); 1196 return false; 1197 } 1198 } else if (!enable && monitor_) { 1199 voe_wrapper_->file()->StopRecordingMicrophone(); 1200 monitor_.reset(); 1201 } 1202 return true; 1203 } 1204 1205 bool WebRtcVoiceEngine::PauseLocalMonitor() { 1206 return ChangeLocalMonitor(false); 1207 } 1208 1209 bool WebRtcVoiceEngine::ResumeLocalMonitor() { 1210 return ChangeLocalMonitor(desired_local_monitor_enable_); 1211 } 1212 1213 const std::vector<AudioCodec>& WebRtcVoiceEngine::codecs() { 1214 return codecs_; 1215 } 1216 1217 bool WebRtcVoiceEngine::FindCodec(const AudioCodec& in) { 1218 return FindWebRtcCodec(in, NULL); 1219 } 1220 1221 // Get the VoiceEngine codec that matches |in|, with the supplied settings. 1222 bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, 1223 webrtc::CodecInst* out) { 1224 int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); 1225 for (int i = 0; i < ncodecs; ++i) { 1226 webrtc::CodecInst voe_codec; 1227 if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { 1228 AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq, 1229 voe_codec.rate, voe_codec.channels, 0); 1230 bool multi_rate = IsCodecMultiRate(voe_codec); 1231 // Allow arbitrary rates for ISAC to be specified. 1232 if (multi_rate) { 1233 // Set codec.bitrate to 0 so the check for codec.Matches() passes. 1234 codec.bitrate = 0; 1235 } 1236 if (codec.Matches(in)) { 1237 if (out) { 1238 // Fixup the payload type. 1239 voe_codec.pltype = in.id; 1240 1241 // Set bitrate if specified. 1242 if (multi_rate && in.bitrate != 0) { 1243 voe_codec.rate = in.bitrate; 1244 } 1245 1246 // Apply codec-specific settings. 1247 if (IsIsac(codec)) { 1248 // If ISAC and an explicit bitrate is not specified, 1249 // enable auto bandwidth adjustment. 1250 voe_codec.rate = (in.bitrate > 0) ? in.bitrate : -1; 1251 } 1252 *out = voe_codec; 1253 } 1254 return true; 1255 } 1256 } 1257 } 1258 return false; 1259 } 1260 const std::vector<RtpHeaderExtension>& 1261 WebRtcVoiceEngine::rtp_header_extensions() const { 1262 return rtp_header_extensions_; 1263 } 1264 1265 void WebRtcVoiceEngine::SetLogging(int min_sev, const char* filter) { 1266 // if min_sev == -1, we keep the current log level. 1267 if (min_sev >= 0) { 1268 SetTraceFilter(SeverityToFilter(min_sev)); 1269 } 1270 log_options_ = filter; 1271 SetTraceOptions(initialized_ ? log_options_ : ""); 1272 } 1273 1274 int WebRtcVoiceEngine::GetLastEngineError() { 1275 return voe_wrapper_->error(); 1276 } 1277 1278 void WebRtcVoiceEngine::SetTraceFilter(int filter) { 1279 log_filter_ = filter; 1280 tracing_->SetTraceFilter(filter); 1281 } 1282 1283 // We suppport three different logging settings for VoiceEngine: 1284 // 1. Observer callback that goes into talk diagnostic logfile. 1285 // Use --logfile and --loglevel 1286 // 1287 // 2. Encrypted VoiceEngine log for debugging VoiceEngine. 1288 // Use --voice_loglevel --voice_logfilter "tracefile file_name" 1289 // 1290 // 3. EC log and dump for debugging QualityEngine. 1291 // Use --voice_loglevel --voice_logfilter "recordEC file_name" 1292 // 1293 // For more details see: "https://sites.google.com/a/google.com/wavelet/Home/ 1294 // Magic-Flute--RTC-Engine-/Magic-Flute-Command-Line-Parameters" 1295 void WebRtcVoiceEngine::SetTraceOptions(const std::string& options) { 1296 // Set encrypted trace file. 1297 std::vector<std::string> opts; 1298 rtc::tokenize(options, ' ', '"', '"', &opts); 1299 std::vector<std::string>::iterator tracefile = 1300 std::find(opts.begin(), opts.end(), "tracefile"); 1301 if (tracefile != opts.end() && ++tracefile != opts.end()) { 1302 // Write encrypted debug output (at same loglevel) to file 1303 // EncryptedTraceFile no longer supported. 1304 if (tracing_->SetTraceFile(tracefile->c_str()) == -1) { 1305 LOG_RTCERR1(SetTraceFile, *tracefile); 1306 } 1307 } 1308 1309 // Allow trace options to override the trace filter. We default 1310 // it to log_filter_ (as a translation of libjingle log levels) 1311 // elsewhere, but this allows clients to explicitly set webrtc 1312 // log levels. 1313 std::vector<std::string>::iterator tracefilter = 1314 std::find(opts.begin(), opts.end(), "tracefilter"); 1315 if (tracefilter != opts.end() && ++tracefilter != opts.end()) { 1316 if (!tracing_->SetTraceFilter(rtc::FromString<int>(*tracefilter))) { 1317 LOG_RTCERR1(SetTraceFilter, *tracefilter); 1318 } 1319 } 1320 1321 // Set AEC dump file 1322 std::vector<std::string>::iterator recordEC = 1323 std::find(opts.begin(), opts.end(), "recordEC"); 1324 if (recordEC != opts.end()) { 1325 ++recordEC; 1326 if (recordEC != opts.end()) 1327 StartAecDump(recordEC->c_str()); 1328 else 1329 StopAecDump(); 1330 } 1331 } 1332 1333 // Ignore spammy trace messages, mostly from the stats API when we haven't 1334 // gotten RTCP info yet from the remote side. 1335 bool WebRtcVoiceEngine::ShouldIgnoreTrace(const std::string& trace) { 1336 static const char* kTracesToIgnore[] = { 1337 "\tfailed to GetReportBlockInformation", 1338 "GetRecCodec() failed to get received codec", 1339 "GetReceivedRtcpStatistics: Could not get received RTP statistics", 1340 "GetRemoteRTCPData() failed to measure statistics due to lack of received RTP and/or RTCP packets", // NOLINT 1341 "GetRemoteRTCPData() failed to retrieve sender info for remote side", 1342 "GetRTPStatistics() failed to measure RTT since no RTP packets have been received yet", // NOLINT 1343 "GetRTPStatistics() failed to read RTP statistics from the RTP/RTCP module", 1344 "GetRTPStatistics() failed to retrieve RTT from the RTP/RTCP module", 1345 "SenderInfoReceived No received SR", 1346 "StatisticsRTP() no statistics available", 1347 "TransmitMixer::TypingDetection() VE_TYPING_NOISE_WARNING message has been posted", // NOLINT 1348 "TransmitMixer::TypingDetection() pending noise-saturation warning exists", // NOLINT 1349 "GetRecPayloadType() failed to retrieve RX payload type (error=10026)", // NOLINT 1350 "StopPlayingFileAsMicrophone() isnot playing (error=8088)", 1351 NULL 1352 }; 1353 for (const char* const* p = kTracesToIgnore; *p; ++p) { 1354 if (trace.find(*p) != std::string::npos) { 1355 return true; 1356 } 1357 } 1358 return false; 1359 } 1360 1361 void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace, 1362 int length) { 1363 rtc::LoggingSeverity sev = rtc::LS_VERBOSE; 1364 if (level == webrtc::kTraceError || level == webrtc::kTraceCritical) 1365 sev = rtc::LS_ERROR; 1366 else if (level == webrtc::kTraceWarning) 1367 sev = rtc::LS_WARNING; 1368 else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo) 1369 sev = rtc::LS_INFO; 1370 else if (level == webrtc::kTraceTerseInfo) 1371 sev = rtc::LS_INFO; 1372 1373 // Skip past boilerplate prefix text 1374 if (length < 72) { 1375 std::string msg(trace, length); 1376 LOG(LS_ERROR) << "Malformed webrtc log message: "; 1377 LOG_V(sev) << msg; 1378 } else { 1379 std::string msg(trace + 71, length - 72); 1380 if (!ShouldIgnoreTrace(msg)) { 1381 LOG_V(sev) << "webrtc: " << msg; 1382 } 1383 } 1384 } 1385 1386 void WebRtcVoiceEngine::CallbackOnError(int channel_num, int err_code) { 1387 rtc::CritScope lock(&channels_cs_); 1388 WebRtcVoiceMediaChannel* channel = NULL; 1389 uint32 ssrc = 0; 1390 LOG(LS_WARNING) << "VoiceEngine error " << err_code << " reported on channel " 1391 << channel_num << "."; 1392 if (FindChannelAndSsrc(channel_num, &channel, &ssrc)) { 1393 ASSERT(channel != NULL); 1394 channel->OnError(ssrc, err_code); 1395 } else { 1396 LOG(LS_ERROR) << "VoiceEngine channel " << channel_num 1397 << " could not be found in channel list when error reported."; 1398 } 1399 } 1400 1401 bool WebRtcVoiceEngine::FindChannelAndSsrc( 1402 int channel_num, WebRtcVoiceMediaChannel** channel, uint32* ssrc) const { 1403 ASSERT(channel != NULL && ssrc != NULL); 1404 1405 *channel = NULL; 1406 *ssrc = 0; 1407 // Find corresponding channel and ssrc 1408 for (ChannelList::const_iterator it = channels_.begin(); 1409 it != channels_.end(); ++it) { 1410 ASSERT(*it != NULL); 1411 if ((*it)->FindSsrc(channel_num, ssrc)) { 1412 *channel = *it; 1413 return true; 1414 } 1415 } 1416 1417 return false; 1418 } 1419 1420 // This method will search through the WebRtcVoiceMediaChannels and 1421 // obtain the voice engine's channel number. 1422 bool WebRtcVoiceEngine::FindChannelNumFromSsrc( 1423 uint32 ssrc, MediaProcessorDirection direction, int* channel_num) { 1424 ASSERT(channel_num != NULL); 1425 ASSERT(direction == MPD_RX || direction == MPD_TX); 1426 1427 *channel_num = -1; 1428 // Find corresponding channel for ssrc. 1429 for (ChannelList::const_iterator it = channels_.begin(); 1430 it != channels_.end(); ++it) { 1431 ASSERT(*it != NULL); 1432 if (direction & MPD_RX) { 1433 *channel_num = (*it)->GetReceiveChannelNum(ssrc); 1434 } 1435 if (*channel_num == -1 && (direction & MPD_TX)) { 1436 *channel_num = (*it)->GetSendChannelNum(ssrc); 1437 } 1438 if (*channel_num != -1) { 1439 return true; 1440 } 1441 } 1442 LOG(LS_WARNING) << "FindChannelFromSsrc. No Channel Found for Ssrc: " << ssrc; 1443 return false; 1444 } 1445 1446 void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel *channel) { 1447 rtc::CritScope lock(&channels_cs_); 1448 channels_.push_back(channel); 1449 } 1450 1451 void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel *channel) { 1452 rtc::CritScope lock(&channels_cs_); 1453 ChannelList::iterator i = std::find(channels_.begin(), 1454 channels_.end(), 1455 channel); 1456 if (i != channels_.end()) { 1457 channels_.erase(i); 1458 } 1459 } 1460 1461 void WebRtcVoiceEngine::RegisterSoundclip(WebRtcSoundclipMedia *soundclip) { 1462 soundclips_.push_back(soundclip); 1463 } 1464 1465 void WebRtcVoiceEngine::UnregisterSoundclip(WebRtcSoundclipMedia *soundclip) { 1466 SoundclipList::iterator i = std::find(soundclips_.begin(), 1467 soundclips_.end(), 1468 soundclip); 1469 if (i != soundclips_.end()) { 1470 soundclips_.erase(i); 1471 } 1472 } 1473 1474 // Adjusts the default AGC target level by the specified delta. 1475 // NB: If we start messing with other config fields, we'll want 1476 // to save the current webrtc::AgcConfig as well. 1477 bool WebRtcVoiceEngine::AdjustAgcLevel(int delta) { 1478 webrtc::AgcConfig config = default_agc_config_; 1479 config.targetLeveldBOv -= delta; 1480 1481 LOG(LS_INFO) << "Adjusting AGC level from default -" 1482 << default_agc_config_.targetLeveldBOv << "dB to -" 1483 << config.targetLeveldBOv << "dB"; 1484 1485 if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) { 1486 LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv); 1487 return false; 1488 } 1489 return true; 1490 } 1491 1492 bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm, 1493 webrtc::AudioDeviceModule* adm_sc) { 1494 if (initialized_) { 1495 LOG(LS_WARNING) << "SetAudioDeviceModule can not be called after Init."; 1496 return false; 1497 } 1498 if (adm_) { 1499 adm_->Release(); 1500 adm_ = NULL; 1501 } 1502 if (adm) { 1503 adm_ = adm; 1504 adm_->AddRef(); 1505 } 1506 1507 if (adm_sc_) { 1508 adm_sc_->Release(); 1509 adm_sc_ = NULL; 1510 } 1511 if (adm_sc) { 1512 adm_sc_ = adm_sc; 1513 adm_sc_->AddRef(); 1514 } 1515 return true; 1516 } 1517 1518 bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file) { 1519 FILE* aec_dump_file_stream = rtc::FdopenPlatformFileForWriting(file); 1520 if (!aec_dump_file_stream) { 1521 LOG(LS_ERROR) << "Could not open AEC dump file stream."; 1522 if (!rtc::ClosePlatformFile(file)) 1523 LOG(LS_WARNING) << "Could not close file."; 1524 return false; 1525 } 1526 StopAecDump(); 1527 if (voe_wrapper_->processing()->StartDebugRecording(aec_dump_file_stream) != 1528 webrtc::AudioProcessing::kNoError) { 1529 LOG_RTCERR0(StartDebugRecording); 1530 fclose(aec_dump_file_stream); 1531 return false; 1532 } 1533 is_dumping_aec_ = true; 1534 return true; 1535 } 1536 1537 bool WebRtcVoiceEngine::RegisterProcessor( 1538 uint32 ssrc, 1539 VoiceProcessor* voice_processor, 1540 MediaProcessorDirection direction) { 1541 bool register_with_webrtc = false; 1542 int channel_id = -1; 1543 bool success = false; 1544 uint32* processor_ssrc = NULL; 1545 bool found_channel = FindChannelNumFromSsrc(ssrc, direction, &channel_id); 1546 if (voice_processor == NULL || !found_channel) { 1547 LOG(LS_WARNING) << "Media Processing Registration Failed. ssrc: " << ssrc 1548 << " foundChannel: " << found_channel; 1549 return false; 1550 } 1551 1552 webrtc::ProcessingTypes processing_type; 1553 { 1554 rtc::CritScope cs(&signal_media_critical_); 1555 if (direction == MPD_RX) { 1556 processing_type = webrtc::kPlaybackAllChannelsMixed; 1557 if (SignalRxMediaFrame.is_empty()) { 1558 register_with_webrtc = true; 1559 processor_ssrc = &rx_processor_ssrc_; 1560 } 1561 SignalRxMediaFrame.connect(voice_processor, 1562 &VoiceProcessor::OnFrame); 1563 } else { 1564 processing_type = webrtc::kRecordingPerChannel; 1565 if (SignalTxMediaFrame.is_empty()) { 1566 register_with_webrtc = true; 1567 processor_ssrc = &tx_processor_ssrc_; 1568 } 1569 SignalTxMediaFrame.connect(voice_processor, 1570 &VoiceProcessor::OnFrame); 1571 } 1572 } 1573 if (register_with_webrtc) { 1574 // TODO(janahan): when registering consider instantiating a 1575 // a VoeMediaProcess object and not make the engine extend the interface. 1576 if (voe()->media() && voe()->media()-> 1577 RegisterExternalMediaProcessing(channel_id, 1578 processing_type, 1579 *this) != -1) { 1580 LOG(LS_INFO) << "Media Processing Registration Succeeded. channel:" 1581 << channel_id; 1582 *processor_ssrc = ssrc; 1583 success = true; 1584 } else { 1585 LOG_RTCERR2(RegisterExternalMediaProcessing, 1586 channel_id, 1587 processing_type); 1588 success = false; 1589 } 1590 } else { 1591 // If we don't have to register with the engine, we just needed to 1592 // connect a new processor, set success to true; 1593 success = true; 1594 } 1595 return success; 1596 } 1597 1598 bool WebRtcVoiceEngine::UnregisterProcessorChannel( 1599 MediaProcessorDirection channel_direction, 1600 uint32 ssrc, 1601 VoiceProcessor* voice_processor, 1602 MediaProcessorDirection processor_direction) { 1603 bool success = true; 1604 FrameSignal* signal; 1605 webrtc::ProcessingTypes processing_type; 1606 uint32* processor_ssrc = NULL; 1607 if (channel_direction == MPD_RX) { 1608 signal = &SignalRxMediaFrame; 1609 processing_type = webrtc::kPlaybackAllChannelsMixed; 1610 processor_ssrc = &rx_processor_ssrc_; 1611 } else { 1612 signal = &SignalTxMediaFrame; 1613 processing_type = webrtc::kRecordingPerChannel; 1614 processor_ssrc = &tx_processor_ssrc_; 1615 } 1616 1617 int deregister_id = -1; 1618 { 1619 rtc::CritScope cs(&signal_media_critical_); 1620 if ((processor_direction & channel_direction) != 0 && !signal->is_empty()) { 1621 signal->disconnect(voice_processor); 1622 int channel_id = -1; 1623 bool found_channel = FindChannelNumFromSsrc(ssrc, 1624 channel_direction, 1625 &channel_id); 1626 if (signal->is_empty() && found_channel) { 1627 deregister_id = channel_id; 1628 } 1629 } 1630 } 1631 if (deregister_id != -1) { 1632 if (voe()->media() && 1633 voe()->media()->DeRegisterExternalMediaProcessing(deregister_id, 1634 processing_type) != -1) { 1635 *processor_ssrc = 0; 1636 LOG(LS_INFO) << "Media Processing DeRegistration Succeeded. channel:" 1637 << deregister_id; 1638 } else { 1639 LOG_RTCERR2(DeRegisterExternalMediaProcessing, 1640 deregister_id, 1641 processing_type); 1642 success = false; 1643 } 1644 } 1645 return success; 1646 } 1647 1648 bool WebRtcVoiceEngine::UnregisterProcessor( 1649 uint32 ssrc, 1650 VoiceProcessor* voice_processor, 1651 MediaProcessorDirection direction) { 1652 bool success = true; 1653 if (voice_processor == NULL) { 1654 LOG(LS_WARNING) << "Media Processing Deregistration Failed. ssrc: " 1655 << ssrc; 1656 return false; 1657 } 1658 if (!UnregisterProcessorChannel(MPD_RX, ssrc, voice_processor, direction)) { 1659 success = false; 1660 } 1661 if (!UnregisterProcessorChannel(MPD_TX, ssrc, voice_processor, direction)) { 1662 success = false; 1663 } 1664 return success; 1665 } 1666 1667 // Implementing method from WebRtc VoEMediaProcess interface 1668 // Do not lock mux_channel_cs_ in this callback. 1669 void WebRtcVoiceEngine::Process(int channel, 1670 webrtc::ProcessingTypes type, 1671 int16_t audio10ms[], 1672 int length, 1673 int sampling_freq, 1674 bool is_stereo) { 1675 rtc::CritScope cs(&signal_media_critical_); 1676 AudioFrame frame(audio10ms, length, sampling_freq, is_stereo); 1677 if (type == webrtc::kPlaybackAllChannelsMixed) { 1678 SignalRxMediaFrame(rx_processor_ssrc_, MPD_RX, &frame); 1679 } else if (type == webrtc::kRecordingPerChannel) { 1680 SignalTxMediaFrame(tx_processor_ssrc_, MPD_TX, &frame); 1681 } else { 1682 LOG(LS_WARNING) << "Media Processing invoked unexpectedly." 1683 << " channel: " << channel << " type: " << type 1684 << " tx_ssrc: " << tx_processor_ssrc_ 1685 << " rx_ssrc: " << rx_processor_ssrc_; 1686 } 1687 } 1688 1689 void WebRtcVoiceEngine::StartAecDump(const std::string& filename) { 1690 if (!is_dumping_aec_) { 1691 // Start dumping AEC when we are not dumping. 1692 if (voe_wrapper_->processing()->StartDebugRecording( 1693 filename.c_str()) != webrtc::AudioProcessing::kNoError) { 1694 LOG_RTCERR1(StartDebugRecording, filename.c_str()); 1695 } else { 1696 is_dumping_aec_ = true; 1697 } 1698 } 1699 } 1700 1701 void WebRtcVoiceEngine::StopAecDump() { 1702 if (is_dumping_aec_) { 1703 // Stop dumping AEC when we are dumping. 1704 if (voe_wrapper_->processing()->StopDebugRecording() != 1705 webrtc::AudioProcessing::kNoError) { 1706 LOG_RTCERR0(StopDebugRecording); 1707 } 1708 is_dumping_aec_ = false; 1709 } 1710 } 1711 1712 int WebRtcVoiceEngine::CreateVoiceChannel(VoEWrapper* voice_engine_wrapper) { 1713 return voice_engine_wrapper->base()->CreateChannel(voe_config_); 1714 } 1715 1716 int WebRtcVoiceEngine::CreateMediaVoiceChannel() { 1717 return CreateVoiceChannel(voe_wrapper_.get()); 1718 } 1719 1720 int WebRtcVoiceEngine::CreateSoundclipVoiceChannel() { 1721 return CreateVoiceChannel(voe_wrapper_sc_.get()); 1722 } 1723 1724 class WebRtcVoiceMediaChannel::WebRtcVoiceChannelRenderer 1725 : public AudioRenderer::Sink { 1726 public: 1727 WebRtcVoiceChannelRenderer(int ch, 1728 webrtc::AudioTransport* voe_audio_transport) 1729 : channel_(ch), 1730 voe_audio_transport_(voe_audio_transport), 1731 renderer_(NULL) { 1732 } 1733 virtual ~WebRtcVoiceChannelRenderer() { 1734 Stop(); 1735 } 1736 1737 // Starts the rendering by setting a sink to the renderer to get data 1738 // callback. 1739 // This method is called on the libjingle worker thread. 1740 // TODO(xians): Make sure Start() is called only once. 1741 void Start(AudioRenderer* renderer) { 1742 rtc::CritScope lock(&lock_); 1743 ASSERT(renderer != NULL); 1744 if (renderer_ != NULL) { 1745 ASSERT(renderer_ == renderer); 1746 return; 1747 } 1748 1749 // TODO(xians): Remove AddChannel() call after Chrome turns on APM 1750 // in getUserMedia by default. 1751 renderer->AddChannel(channel_); 1752 renderer->SetSink(this); 1753 renderer_ = renderer; 1754 } 1755 1756 // Stops rendering by setting the sink of the renderer to NULL. No data 1757 // callback will be received after this method. 1758 // This method is called on the libjingle worker thread. 1759 void Stop() { 1760 rtc::CritScope lock(&lock_); 1761 if (renderer_ == NULL) 1762 return; 1763 1764 renderer_->RemoveChannel(channel_); 1765 renderer_->SetSink(NULL); 1766 renderer_ = NULL; 1767 } 1768 1769 // AudioRenderer::Sink implementation. 1770 // This method is called on the audio thread. 1771 virtual void OnData(const void* audio_data, 1772 int bits_per_sample, 1773 int sample_rate, 1774 int number_of_channels, 1775 int number_of_frames) OVERRIDE { 1776 voe_audio_transport_->OnData(channel_, 1777 audio_data, 1778 bits_per_sample, 1779 sample_rate, 1780 number_of_channels, 1781 number_of_frames); 1782 } 1783 1784 // Callback from the |renderer_| when it is going away. In case Start() has 1785 // never been called, this callback won't be triggered. 1786 virtual void OnClose() OVERRIDE { 1787 rtc::CritScope lock(&lock_); 1788 // Set |renderer_| to NULL to make sure no more callback will get into 1789 // the renderer. 1790 renderer_ = NULL; 1791 } 1792 1793 // Accessor to the VoE channel ID. 1794 int channel() const { return channel_; } 1795 1796 private: 1797 const int channel_; 1798 webrtc::AudioTransport* const voe_audio_transport_; 1799 1800 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. 1801 // PeerConnection will make sure invalidating the pointer before the object 1802 // goes away. 1803 AudioRenderer* renderer_; 1804 1805 // Protects |renderer_| in Start(), Stop() and OnClose(). 1806 rtc::CriticalSection lock_; 1807 }; 1808 1809 // WebRtcVoiceMediaChannel 1810 WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine *engine) 1811 : WebRtcMediaChannel<VoiceMediaChannel, WebRtcVoiceEngine>( 1812 engine, 1813 engine->CreateMediaVoiceChannel()), 1814 send_bw_setting_(false), 1815 send_bw_bps_(0), 1816 options_(), 1817 dtmf_allowed_(false), 1818 desired_playout_(false), 1819 nack_enabled_(false), 1820 playout_(false), 1821 typing_noise_detected_(false), 1822 desired_send_(SEND_NOTHING), 1823 send_(SEND_NOTHING), 1824 shared_bwe_vie_(NULL), 1825 shared_bwe_vie_channel_(-1), 1826 default_receive_ssrc_(0) { 1827 engine->RegisterChannel(this); 1828 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel " 1829 << voe_channel(); 1830 1831 ConfigureSendChannel(voe_channel()); 1832 } 1833 1834 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { 1835 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel " 1836 << voe_channel(); 1837 SetupSharedBandwidthEstimation(NULL, -1); 1838 1839 // Remove any remaining send streams, the default channel will be deleted 1840 // later. 1841 while (!send_channels_.empty()) 1842 RemoveSendStream(send_channels_.begin()->first); 1843 1844 // Unregister ourselves from the engine. 1845 engine()->UnregisterChannel(this); 1846 // Remove any remaining streams. 1847 while (!receive_channels_.empty()) { 1848 RemoveRecvStream(receive_channels_.begin()->first); 1849 } 1850 1851 // Delete the default channel. 1852 DeleteChannel(voe_channel()); 1853 } 1854 1855 bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { 1856 LOG(LS_INFO) << "Setting voice channel options: " 1857 << options.ToString(); 1858 1859 // Check if DSCP value is changed from previous. 1860 bool dscp_option_changed = (options_.dscp != options.dscp); 1861 1862 // TODO(xians): Add support to set different options for different send 1863 // streams after we support multiple APMs. 1864 1865 // We retain all of the existing options, and apply the given ones 1866 // on top. This means there is no way to "clear" options such that 1867 // they go back to the engine default. 1868 options_.SetAll(options); 1869 1870 if (send_ != SEND_NOTHING) { 1871 if (!engine()->SetOptionOverrides(options_)) { 1872 LOG(LS_WARNING) << 1873 "Failed to engine SetOptionOverrides during channel SetOptions."; 1874 return false; 1875 } 1876 } else { 1877 // Will be interpreted when appropriate. 1878 } 1879 1880 // Receiver-side auto gain control happens per channel, so set it here from 1881 // options. Note that, like conference mode, setting it on the engine won't 1882 // have the desired effect, since voice channels don't inherit options from 1883 // the media engine when those options are applied per-channel. 1884 bool rx_auto_gain_control; 1885 if (options.rx_auto_gain_control.Get(&rx_auto_gain_control)) { 1886 if (engine()->voe()->processing()->SetRxAgcStatus( 1887 voe_channel(), rx_auto_gain_control, 1888 webrtc::kAgcFixedDigital) == -1) { 1889 LOG_RTCERR1(SetRxAgcStatus, rx_auto_gain_control); 1890 return false; 1891 } else { 1892 LOG(LS_VERBOSE) << "Rx auto gain set to " << rx_auto_gain_control 1893 << " with mode " << webrtc::kAgcFixedDigital; 1894 } 1895 } 1896 if (options.rx_agc_target_dbov.IsSet() || 1897 options.rx_agc_digital_compression_gain.IsSet() || 1898 options.rx_agc_limiter.IsSet()) { 1899 webrtc::AgcConfig config; 1900 // If only some of the options are being overridden, get the current 1901 // settings for the channel and bail if they aren't available. 1902 if (!options.rx_agc_target_dbov.IsSet() || 1903 !options.rx_agc_digital_compression_gain.IsSet() || 1904 !options.rx_agc_limiter.IsSet()) { 1905 if (engine()->voe()->processing()->GetRxAgcConfig( 1906 voe_channel(), config) != 0) { 1907 LOG(LS_ERROR) << "Failed to get default rx agc configuration for " 1908 << "channel " << voe_channel() << ". Since not all rx " 1909 << "agc options are specified, unable to safely set rx " 1910 << "agc options."; 1911 return false; 1912 } 1913 } 1914 config.targetLeveldBOv = 1915 options.rx_agc_target_dbov.GetWithDefaultIfUnset( 1916 config.targetLeveldBOv); 1917 config.digitalCompressionGaindB = 1918 options.rx_agc_digital_compression_gain.GetWithDefaultIfUnset( 1919 config.digitalCompressionGaindB); 1920 config.limiterEnable = options.rx_agc_limiter.GetWithDefaultIfUnset( 1921 config.limiterEnable); 1922 if (engine()->voe()->processing()->SetRxAgcConfig( 1923 voe_channel(), config) == -1) { 1924 LOG_RTCERR4(SetRxAgcConfig, voe_channel(), config.targetLeveldBOv, 1925 config.digitalCompressionGaindB, config.limiterEnable); 1926 return false; 1927 } 1928 } 1929 if (dscp_option_changed) { 1930 rtc::DiffServCodePoint dscp = rtc::DSCP_DEFAULT; 1931 if (options_.dscp.GetWithDefaultIfUnset(false)) 1932 dscp = kAudioDscpValue; 1933 if (MediaChannel::SetDscp(dscp) != 0) { 1934 LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel"; 1935 } 1936 } 1937 1938 // Force update of Video Engine BWE forwarding to reflect experiment setting. 1939 if (!SetupSharedBandwidthEstimation(shared_bwe_vie_, 1940 shared_bwe_vie_channel_)) { 1941 return false; 1942 } 1943 1944 LOG(LS_INFO) << "Set voice channel options. Current options: " 1945 << options_.ToString(); 1946 return true; 1947 } 1948 1949 bool WebRtcVoiceMediaChannel::SetRecvCodecs( 1950 const std::vector<AudioCodec>& codecs) { 1951 // Set the payload types to be used for incoming media. 1952 LOG(LS_INFO) << "Setting receive voice codecs:"; 1953 1954 std::vector<AudioCodec> new_codecs; 1955 // Find all new codecs. We allow adding new codecs but don't allow changing 1956 // the payload type of codecs that is already configured since we might 1957 // already be receiving packets with that payload type. 1958 for (std::vector<AudioCodec>::const_iterator it = codecs.begin(); 1959 it != codecs.end(); ++it) { 1960 AudioCodec old_codec; 1961 if (FindCodec(recv_codecs_, *it, &old_codec)) { 1962 if (old_codec.id != it->id) { 1963 LOG(LS_ERROR) << it->name << " payload type changed."; 1964 return false; 1965 } 1966 } else { 1967 new_codecs.push_back(*it); 1968 } 1969 } 1970 if (new_codecs.empty()) { 1971 // There are no new codecs to configure. Already configured codecs are 1972 // never removed. 1973 return true; 1974 } 1975 1976 if (playout_) { 1977 // Receive codecs can not be changed while playing. So we temporarily 1978 // pause playout. 1979 PausePlayout(); 1980 } 1981 1982 bool ret = true; 1983 for (std::vector<AudioCodec>::const_iterator it = new_codecs.begin(); 1984 it != new_codecs.end() && ret; ++it) { 1985 webrtc::CodecInst voe_codec; 1986 if (engine()->FindWebRtcCodec(*it, &voe_codec)) { 1987 LOG(LS_INFO) << ToString(*it); 1988 voe_codec.pltype = it->id; 1989 if (default_receive_ssrc_ == 0) { 1990 // Set the receive codecs on the default channel explicitly if the 1991 // default channel is not used by |receive_channels_|, this happens in 1992 // conference mode or in non-conference mode when there is no playout 1993 // channel. 1994 // TODO(xians): Figure out how we use the default channel in conference 1995 // mode. 1996 if (engine()->voe()->codec()->SetRecPayloadType( 1997 voe_channel(), voe_codec) == -1) { 1998 LOG_RTCERR2(SetRecPayloadType, voe_channel(), ToString(voe_codec)); 1999 ret = false; 2000 } 2001 } 2002 2003 // Set the receive codecs on all receiving channels. 2004 for (ChannelMap::iterator it = receive_channels_.begin(); 2005 it != receive_channels_.end() && ret; ++it) { 2006 if (engine()->voe()->codec()->SetRecPayloadType( 2007 it->second->channel(), voe_codec) == -1) { 2008 LOG_RTCERR2(SetRecPayloadType, it->second->channel(), 2009 ToString(voe_codec)); 2010 ret = false; 2011 } 2012 } 2013 } else { 2014 LOG(LS_WARNING) << "Unknown codec " << ToString(*it); 2015 ret = false; 2016 } 2017 } 2018 if (ret) { 2019 recv_codecs_ = codecs; 2020 } 2021 2022 if (desired_playout_ && !playout_) { 2023 ResumePlayout(); 2024 } 2025 return ret; 2026 } 2027 2028 bool WebRtcVoiceMediaChannel::SetSendCodecs( 2029 int channel, const std::vector<AudioCodec>& codecs) { 2030 // Disable VAD, FEC, and RED unless we know the other side wants them. 2031 engine()->voe()->codec()->SetVADStatus(channel, false); 2032 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); 2033 #ifdef USE_WEBRTC_DEV_BRANCH 2034 engine()->voe()->rtp()->SetREDStatus(channel, false); 2035 engine()->voe()->codec()->SetFECStatus(channel, false); 2036 #else 2037 // TODO(minyue): Remove code under #else case after new WebRTC roll. 2038 engine()->voe()->rtp()->SetFECStatus(channel, false); 2039 #endif // USE_WEBRTC_DEV_BRANCH 2040 2041 // Scan through the list to figure out the codec to use for sending, along 2042 // with the proper configuration for VAD and DTMF. 2043 bool found_send_codec = false; 2044 webrtc::CodecInst send_codec; 2045 memset(&send_codec, 0, sizeof(send_codec)); 2046 2047 bool nack_enabled = nack_enabled_; 2048 bool enable_codec_fec = false; 2049 2050 // max_playback_rate <= 0 will not trigger setting of maximum encoding 2051 // bandwidth. 2052 int max_playback_rate = 0; 2053 2054 // Set send codec (the first non-telephone-event/CN codec) 2055 for (std::vector<AudioCodec>::const_iterator it = codecs.begin(); 2056 it != codecs.end(); ++it) { 2057 // Ignore codecs we don't know about. The negotiation step should prevent 2058 // this, but double-check to be sure. 2059 webrtc::CodecInst voe_codec; 2060 if (!engine()->FindWebRtcCodec(*it, &voe_codec)) { 2061 LOG(LS_WARNING) << "Unknown codec " << ToString(*it); 2062 continue; 2063 } 2064 2065 if (IsTelephoneEventCodec(it->name) || IsCNCodec(it->name)) { 2066 // Skip telephone-event/CN codec, which will be handled later. 2067 continue; 2068 } 2069 2070 2071 // We'll use the first codec in the list to actually send audio data. 2072 // Be sure to use the payload type requested by the remote side. 2073 // "red", for RED audio, is a special case where the actual codec to be 2074 // used is specified in params. 2075 if (IsRedCodec(it->name)) { 2076 // Parse out the RED parameters. If we fail, just ignore RED; 2077 // we don't support all possible params/usage scenarios. 2078 if (!GetRedSendCodec(*it, codecs, &send_codec)) { 2079 continue; 2080 } 2081 2082 // Enable redundant encoding of the specified codec. Treat any 2083 // failure as a fatal internal error. 2084 #ifdef USE_WEBRTC_DEV_BRANCH 2085 LOG(LS_INFO) << "Enabling RED on channel " << channel; 2086 if (engine()->voe()->rtp()->SetREDStatus(channel, true, it->id) == -1) { 2087 LOG_RTCERR3(SetREDStatus, channel, true, it->id); 2088 #else 2089 // TODO(minyue): Remove code under #else case after new WebRTC roll. 2090 LOG(LS_INFO) << "Enabling FEC"; 2091 if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) { 2092 LOG_RTCERR3(SetFECStatus, channel, true, it->id); 2093 #endif // USE_WEBRTC_DEV_BRANCH 2094 return false; 2095 } 2096 } else { 2097 send_codec = voe_codec; 2098 nack_enabled = IsNackEnabled(*it); 2099 // For Opus as the send codec, we are to enable inband FEC if requested 2100 // and set maximum playback rate. 2101 if (IsOpus(*it)) { 2102 GetOpusConfig(*it, &send_codec, &enable_codec_fec, &max_playback_rate); 2103 } 2104 } 2105 found_send_codec = true; 2106 break; 2107 } 2108 2109 if (nack_enabled_ != nack_enabled) { 2110 SetNack(channel, nack_enabled); 2111 nack_enabled_ = nack_enabled; 2112 } 2113 2114 if (!found_send_codec) { 2115 LOG(LS_WARNING) << "Received empty list of codecs."; 2116 return false; 2117 } 2118 2119 // Set the codec immediately, since SetVADStatus() depends on whether 2120 // the current codec is mono or stereo. 2121 if (!SetSendCodec(channel, send_codec)) 2122 return false; 2123 2124 // FEC should be enabled after SetSendCodec. 2125 if (enable_codec_fec) { 2126 LOG(LS_INFO) << "Attempt to enable codec internal FEC on channel " 2127 << channel; 2128 #ifdef USE_WEBRTC_DEV_BRANCH 2129 if (engine()->voe()->codec()->SetFECStatus(channel, true) == -1) { 2130 // Enable codec internal FEC. Treat any failure as fatal internal error. 2131 LOG_RTCERR2(SetFECStatus, channel, true); 2132 return false; 2133 } 2134 #endif // USE_WEBRTC_DEV_BRANCH 2135 } 2136 2137 // maxplaybackrate should be set after SetSendCodec. 2138 if (max_playback_rate > 0) { 2139 LOG(LS_INFO) << "Attempt to set maximum playback rate to " 2140 << max_playback_rate 2141 << " Hz on channel " 2142 << channel; 2143 #ifdef USE_WEBRTC_DEV_BRANCH 2144 // (max_playback_rate + 1) >> 1 is to obtain ceil(max_playback_rate / 2.0). 2145 if (engine()->voe()->codec()->SetOpusMaxPlaybackRate( 2146 channel, max_playback_rate) == -1) { 2147 LOG(LS_WARNING) << "Could not set maximum playback rate."; 2148 } 2149 #endif 2150 } 2151 2152 // Always update the |send_codec_| to the currently set send codec. 2153 send_codec_.reset(new webrtc::CodecInst(send_codec)); 2154 2155 if (send_bw_setting_) { 2156 SetSendBandwidthInternal(send_bw_bps_); 2157 } 2158 2159 // Loop through the codecs list again to config the telephone-event/CN codec. 2160 for (std::vector<AudioCodec>::const_iterator it = codecs.begin(); 2161 it != codecs.end(); ++it) { 2162 // Ignore codecs we don't know about. The negotiation step should prevent 2163 // this, but double-check to be sure. 2164 webrtc::CodecInst voe_codec; 2165 if (!engine()->FindWebRtcCodec(*it, &voe_codec)) { 2166 LOG(LS_WARNING) << "Unknown codec " << ToString(*it); 2167 continue; 2168 } 2169 2170 // Find the DTMF telephone event "codec" and tell VoiceEngine channels 2171 // about it. 2172 if (IsTelephoneEventCodec(it->name)) { 2173 if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType( 2174 channel, it->id) == -1) { 2175 LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, it->id); 2176 return false; 2177 } 2178 } else if (IsCNCodec(it->name)) { 2179 // Turn voice activity detection/comfort noise on if supported. 2180 // Set the wideband CN payload type appropriately. 2181 // (narrowband always uses the static payload type 13). 2182 webrtc::PayloadFrequencies cn_freq; 2183 switch (it->clockrate) { 2184 case 8000: 2185 cn_freq = webrtc::kFreq8000Hz; 2186 break; 2187 case 16000: 2188 cn_freq = webrtc::kFreq16000Hz; 2189 break; 2190 case 32000: 2191 cn_freq = webrtc::kFreq32000Hz; 2192 break; 2193 default: 2194 LOG(LS_WARNING) << "CN frequency " << it->clockrate 2195 << " not supported."; 2196 continue; 2197 } 2198 // Set the CN payloadtype and the VAD status. 2199 // The CN payload type for 8000 Hz clockrate is fixed at 13. 2200 if (cn_freq != webrtc::kFreq8000Hz) { 2201 if (engine()->voe()->codec()->SetSendCNPayloadType( 2202 channel, it->id, cn_freq) == -1) { 2203 LOG_RTCERR3(SetSendCNPayloadType, channel, it->id, cn_freq); 2204 // TODO(ajm): This failure condition will be removed from VoE. 2205 // Restore the return here when we update to a new enough webrtc. 2206 // 2207 // Not returning false because the SetSendCNPayloadType will fail if 2208 // the channel is already sending. 2209 // This can happen if the remote description is applied twice, for 2210 // example in the case of ROAP on top of JSEP, where both side will 2211 // send the offer. 2212 } 2213 } 2214 // Only turn on VAD if we have a CN payload type that matches the 2215 // clockrate for the codec we are going to use. 2216 if (it->clockrate == send_codec.plfreq) { 2217 LOG(LS_INFO) << "Enabling VAD"; 2218 if (engine()->voe()->codec()->SetVADStatus(channel, true) == -1) { 2219 LOG_RTCERR2(SetVADStatus, channel, true); 2220 return false; 2221 } 2222 } 2223 } 2224 } 2225 return true; 2226 } 2227 2228 bool WebRtcVoiceMediaChannel::SetSendCodecs( 2229 const std::vector<AudioCodec>& codecs) { 2230 dtmf_allowed_ = false; 2231 for (std::vector<AudioCodec>::const_iterator it = codecs.begin(); 2232 it != codecs.end(); ++it) { 2233 // Find the DTMF telephone event "codec". 2234 if (_stricmp(it->name.c_str(), "telephone-event") == 0 || 2235 _stricmp(it->name.c_str(), "audio/telephone-event") == 0) { 2236 dtmf_allowed_ = true; 2237 } 2238 } 2239 2240 // Cache the codecs in order to configure the channel created later. 2241 send_codecs_ = codecs; 2242 for (ChannelMap::iterator iter = send_channels_.begin(); 2243 iter != send_channels_.end(); ++iter) { 2244 if (!SetSendCodecs(iter->second->channel(), codecs)) { 2245 return false; 2246 } 2247 } 2248 2249 // Set nack status on receive channels and update |nack_enabled_|. 2250 SetNack(receive_channels_, nack_enabled_); 2251 return true; 2252 } 2253 2254 void WebRtcVoiceMediaChannel::SetNack(const ChannelMap& channels, 2255 bool nack_enabled) { 2256 for (ChannelMap::const_iterator it = channels.begin(); 2257 it != channels.end(); ++it) { 2258 SetNack(it->second->channel(), nack_enabled); 2259 } 2260 } 2261 2262 void WebRtcVoiceMediaChannel::SetNack(int channel, bool nack_enabled) { 2263 if (nack_enabled) { 2264 LOG(LS_INFO) << "Enabling NACK for channel " << channel; 2265 engine()->voe()->rtp()->SetNACKStatus(channel, true, kNackMaxPackets); 2266 } else { 2267 LOG(LS_INFO) << "Disabling NACK for channel " << channel; 2268 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); 2269 } 2270 } 2271 2272 bool WebRtcVoiceMediaChannel::SetSendCodec( 2273 const webrtc::CodecInst& send_codec) { 2274 LOG(LS_INFO) << "Selected voice codec " << ToString(send_codec) 2275 << ", bitrate=" << send_codec.rate; 2276 for (ChannelMap::iterator iter = send_channels_.begin(); 2277 iter != send_channels_.end(); ++iter) { 2278 if (!SetSendCodec(iter->second->channel(), send_codec)) 2279 return false; 2280 } 2281 2282 return true; 2283 } 2284 2285 bool WebRtcVoiceMediaChannel::SetSendCodec( 2286 int channel, const webrtc::CodecInst& send_codec) { 2287 LOG(LS_INFO) << "Send channel " << channel << " selected voice codec " 2288 << ToString(send_codec) << ", bitrate=" << send_codec.rate; 2289 2290 webrtc::CodecInst current_codec; 2291 if (engine()->voe()->codec()->GetSendCodec(channel, current_codec) == 0 && 2292 (send_codec == current_codec)) { 2293 // Codec is already configured, we can return without setting it again. 2294 return true; 2295 } 2296 2297 if (engine()->voe()->codec()->SetSendCodec(channel, send_codec) == -1) { 2298 LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec)); 2299 return false; 2300 } 2301 return true; 2302 } 2303 2304 bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions( 2305 const std::vector<RtpHeaderExtension>& extensions) { 2306 if (receive_extensions_ == extensions) { 2307 return true; 2308 } 2309 2310 // The default channel may or may not be in |receive_channels_|. Set the rtp 2311 // header extensions for default channel regardless. 2312 if (!SetChannelRecvRtpHeaderExtensions(voe_channel(), extensions)) { 2313 return false; 2314 } 2315 2316 // Loop through all receive channels and enable/disable the extensions. 2317 for (ChannelMap::const_iterator channel_it = receive_channels_.begin(); 2318 channel_it != receive_channels_.end(); ++channel_it) { 2319 if (!SetChannelRecvRtpHeaderExtensions(channel_it->second->channel(), 2320 extensions)) { 2321 return false; 2322 } 2323 } 2324 2325 receive_extensions_ = extensions; 2326 return true; 2327 } 2328 2329 bool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions( 2330 int channel_id, const std::vector<RtpHeaderExtension>& extensions) { 2331 const RtpHeaderExtension* audio_level_extension = 2332 FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); 2333 if (!SetHeaderExtension( 2334 &webrtc::VoERTP_RTCP::SetReceiveAudioLevelIndicationStatus, channel_id, 2335 audio_level_extension)) { 2336 return false; 2337 } 2338 2339 const RtpHeaderExtension* send_time_extension = 2340 FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); 2341 if (!SetHeaderExtension( 2342 &webrtc::VoERTP_RTCP::SetReceiveAbsoluteSenderTimeStatus, channel_id, 2343 send_time_extension)) { 2344 return false; 2345 } 2346 return true; 2347 } 2348 2349 bool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions( 2350 const std::vector<RtpHeaderExtension>& extensions) { 2351 if (send_extensions_ == extensions) { 2352 return true; 2353 } 2354 2355 // The default channel may or may not be in |send_channels_|. Set the rtp 2356 // header extensions for default channel regardless. 2357 2358 if (!SetChannelSendRtpHeaderExtensions(voe_channel(), extensions)) { 2359 return false; 2360 } 2361 2362 // Loop through all send channels and enable/disable the extensions. 2363 for (ChannelMap::const_iterator channel_it = send_channels_.begin(); 2364 channel_it != send_channels_.end(); ++channel_it) { 2365 if (!SetChannelSendRtpHeaderExtensions(channel_it->second->channel(), 2366 extensions)) { 2367 return false; 2368 } 2369 } 2370 2371 send_extensions_ = extensions; 2372 return true; 2373 } 2374 2375 bool WebRtcVoiceMediaChannel::SetChannelSendRtpHeaderExtensions( 2376 int channel_id, const std::vector<RtpHeaderExtension>& extensions) { 2377 const RtpHeaderExtension* audio_level_extension = 2378 FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); 2379 2380 if (!SetHeaderExtension( 2381 &webrtc::VoERTP_RTCP::SetSendAudioLevelIndicationStatus, channel_id, 2382 audio_level_extension)) { 2383 return false; 2384 } 2385 2386 const RtpHeaderExtension* send_time_extension = 2387 FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); 2388 if (!SetHeaderExtension( 2389 &webrtc::VoERTP_RTCP::SetSendAbsoluteSenderTimeStatus, channel_id, 2390 send_time_extension)) { 2391 return false; 2392 } 2393 2394 return true; 2395 } 2396 2397 bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) { 2398 desired_playout_ = playout; 2399 return ChangePlayout(desired_playout_); 2400 } 2401 2402 bool WebRtcVoiceMediaChannel::PausePlayout() { 2403 return ChangePlayout(false); 2404 } 2405 2406 bool WebRtcVoiceMediaChannel::ResumePlayout() { 2407 return ChangePlayout(desired_playout_); 2408 } 2409 2410 bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) { 2411 if (playout_ == playout) { 2412 return true; 2413 } 2414 2415 // Change the playout of all channels to the new state. 2416 bool result = true; 2417 if (receive_channels_.empty()) { 2418 // Only toggle the default channel if we don't have any other channels. 2419 result = SetPlayout(voe_channel(), playout); 2420 } 2421 for (ChannelMap::iterator it = receive_channels_.begin(); 2422 it != receive_channels_.end() && result; ++it) { 2423 if (!SetPlayout(it->second->channel(), playout)) { 2424 LOG(LS_ERROR) << "SetPlayout " << playout << " on channel " 2425 << it->second->channel() << " failed"; 2426 result = false; 2427 } 2428 } 2429 2430 if (result) { 2431 playout_ = playout; 2432 } 2433 return result; 2434 } 2435 2436 bool WebRtcVoiceMediaChannel::SetSend(SendFlags send) { 2437 desired_send_ = send; 2438 if (!send_channels_.empty()) 2439 return ChangeSend(desired_send_); 2440 return true; 2441 } 2442 2443 bool WebRtcVoiceMediaChannel::PauseSend() { 2444 return ChangeSend(SEND_NOTHING); 2445 } 2446 2447 bool WebRtcVoiceMediaChannel::ResumeSend() { 2448 return ChangeSend(desired_send_); 2449 } 2450 2451 bool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) { 2452 if (send_ == send) { 2453 return true; 2454 } 2455 2456 // Change the settings on each send channel. 2457 if (send == SEND_MICROPHONE) 2458 engine()->SetOptionOverrides(options_); 2459 2460 // Change the settings on each send channel. 2461 for (ChannelMap::iterator iter = send_channels_.begin(); 2462 iter != send_channels_.end(); ++iter) { 2463 if (!ChangeSend(iter->second->channel(), send)) 2464 return false; 2465 } 2466 2467 // Clear up the options after stopping sending. 2468 if (send == SEND_NOTHING) 2469 engine()->ClearOptionOverrides(); 2470 2471 send_ = send; 2472 return true; 2473 } 2474 2475 bool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) { 2476 if (send == SEND_MICROPHONE) { 2477 if (engine()->voe()->base()->StartSend(channel) == -1) { 2478 LOG_RTCERR1(StartSend, channel); 2479 return false; 2480 } 2481 if (engine()->voe()->file() && 2482 engine()->voe()->file()->StopPlayingFileAsMicrophone(channel) == -1) { 2483 LOG_RTCERR1(StopPlayingFileAsMicrophone, channel); 2484 return false; 2485 } 2486 } else { // SEND_NOTHING 2487 ASSERT(send == SEND_NOTHING); 2488 if (engine()->voe()->base()->StopSend(channel) == -1) { 2489 LOG_RTCERR1(StopSend, channel); 2490 return false; 2491 } 2492 } 2493 2494 return true; 2495 } 2496 2497 // TODO(ronghuawu): Change this method to return bool. 2498 void WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) { 2499 if (engine()->voe()->network()->RegisterExternalTransport( 2500 channel, *this) == -1) { 2501 LOG_RTCERR2(RegisterExternalTransport, channel, this); 2502 } 2503 2504 // Enable RTCP (for quality stats and feedback messages) 2505 EnableRtcp(channel); 2506 2507 // Reset all recv codecs; they will be enabled via SetRecvCodecs. 2508 ResetRecvCodecs(channel); 2509 2510 // Set RTP header extension for the new channel. 2511 SetChannelSendRtpHeaderExtensions(channel, send_extensions_); 2512 } 2513 2514 bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) { 2515 if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) { 2516 LOG_RTCERR1(DeRegisterExternalTransport, channel); 2517 } 2518 2519 if (engine()->voe()->base()->DeleteChannel(channel) == -1) { 2520 LOG_RTCERR1(DeleteChannel, channel); 2521 return false; 2522 } 2523 2524 return true; 2525 } 2526 2527 bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) { 2528 // If the default channel is already used for sending create a new channel 2529 // otherwise use the default channel for sending. 2530 int channel = GetSendChannelNum(sp.first_ssrc()); 2531 if (channel != -1) { 2532 LOG(LS_ERROR) << "Stream already exists with ssrc " << sp.first_ssrc(); 2533 return false; 2534 } 2535 2536 bool default_channel_is_available = true; 2537 for (ChannelMap::const_iterator iter = send_channels_.begin(); 2538 iter != send_channels_.end(); ++iter) { 2539 if (IsDefaultChannel(iter->second->channel())) { 2540 default_channel_is_available = false; 2541 break; 2542 } 2543 } 2544 if (default_channel_is_available) { 2545 channel = voe_channel(); 2546 } else { 2547 // Create a new channel for sending audio data. 2548 channel = engine()->CreateMediaVoiceChannel(); 2549 if (channel == -1) { 2550 LOG_RTCERR0(CreateChannel); 2551 return false; 2552 } 2553 2554 ConfigureSendChannel(channel); 2555 } 2556 2557 // Save the channel to send_channels_, so that RemoveSendStream() can still 2558 // delete the channel in case failure happens below. 2559 webrtc::AudioTransport* audio_transport = 2560 engine()->voe()->base()->audio_transport(); 2561 send_channels_.insert(std::make_pair( 2562 sp.first_ssrc(), 2563 new WebRtcVoiceChannelRenderer(channel, audio_transport))); 2564 2565 // Set the send (local) SSRC. 2566 // If there are multiple send SSRCs, we can only set the first one here, and 2567 // the rest of the SSRC(s) need to be set after SetSendCodec has been called 2568 // (with a codec requires multiple SSRC(s)). 2569 if (engine()->voe()->rtp()->SetLocalSSRC(channel, sp.first_ssrc()) == -1) { 2570 LOG_RTCERR2(SetSendSSRC, channel, sp.first_ssrc()); 2571 return false; 2572 } 2573 2574 // At this point the channel's local SSRC has been updated. If the channel is 2575 // the default channel make sure that all the receive channels are updated as 2576 // well. Receive channels have to have the same SSRC as the default channel in 2577 // order to send receiver reports with this SSRC. 2578 if (IsDefaultChannel(channel)) { 2579 for (ChannelMap::const_iterator it = receive_channels_.begin(); 2580 it != receive_channels_.end(); ++it) { 2581 // Only update the SSRC for non-default channels. 2582 if (!IsDefaultChannel(it->second->channel())) { 2583 if (engine()->voe()->rtp()->SetLocalSSRC(it->second->channel(), 2584 sp.first_ssrc()) != 0) { 2585 LOG_RTCERR2(SetLocalSSRC, it->second->channel(), sp.first_ssrc()); 2586 return false; 2587 } 2588 } 2589 } 2590 } 2591 2592 if (engine()->voe()->rtp()->SetRTCP_CNAME(channel, sp.cname.c_str()) == -1) { 2593 LOG_RTCERR2(SetRTCP_CNAME, channel, sp.cname); 2594 return false; 2595 } 2596 2597 // Set the current codecs to be used for the new channel. 2598 if (!send_codecs_.empty() && !SetSendCodecs(channel, send_codecs_)) 2599 return false; 2600 2601 return ChangeSend(channel, desired_send_); 2602 } 2603 2604 bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) { 2605 ChannelMap::iterator it = send_channels_.find(ssrc); 2606 if (it == send_channels_.end()) { 2607 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc 2608 << " which doesn't exist."; 2609 return false; 2610 } 2611 2612 int channel = it->second->channel(); 2613 ChangeSend(channel, SEND_NOTHING); 2614 2615 // Delete the WebRtcVoiceChannelRenderer object connected to the channel, 2616 // this will disconnect the audio renderer with the send channel. 2617 delete it->second; 2618 send_channels_.erase(it); 2619 2620 if (IsDefaultChannel(channel)) { 2621 // Do not delete the default channel since the receive channels depend on 2622 // the default channel, recycle it instead. 2623 ChangeSend(channel, SEND_NOTHING); 2624 } else { 2625 // Clean up and delete the send channel. 2626 LOG(LS_INFO) << "Removing audio send stream " << ssrc 2627 << " with VoiceEngine channel #" << channel << "."; 2628 if (!DeleteChannel(channel)) 2629 return false; 2630 } 2631 2632 if (send_channels_.empty()) 2633 ChangeSend(SEND_NOTHING); 2634 2635 return true; 2636 } 2637 2638 bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { 2639 rtc::CritScope lock(&receive_channels_cs_); 2640 2641 if (!VERIFY(sp.ssrcs.size() == 1)) 2642 return false; 2643 uint32 ssrc = sp.first_ssrc(); 2644 2645 if (ssrc == 0) { 2646 LOG(LS_WARNING) << "AddRecvStream with 0 ssrc is not supported."; 2647 return false; 2648 } 2649 2650 if (receive_channels_.find(ssrc) != receive_channels_.end()) { 2651 LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc; 2652 return false; 2653 } 2654 2655 // Reuse default channel for recv stream in non-conference mode call 2656 // when the default channel is not being used. 2657 webrtc::AudioTransport* audio_transport = 2658 engine()->voe()->base()->audio_transport(); 2659 if (!InConferenceMode() && default_receive_ssrc_ == 0) { 2660 LOG(LS_INFO) << "Recv stream " << sp.first_ssrc() 2661 << " reuse default channel"; 2662 default_receive_ssrc_ = sp.first_ssrc(); 2663 receive_channels_.insert(std::make_pair( 2664 default_receive_ssrc_, 2665 new WebRtcVoiceChannelRenderer(voe_channel(), audio_transport))); 2666 if (!SetupSharedBweOnChannel(voe_channel())) { 2667 return false; 2668 } 2669 return SetPlayout(voe_channel(), playout_); 2670 } 2671 2672 // Create a new channel for receiving audio data. 2673 int channel = engine()->CreateMediaVoiceChannel(); 2674 if (channel == -1) { 2675 LOG_RTCERR0(CreateChannel); 2676 return false; 2677 } 2678 2679 if (!ConfigureRecvChannel(channel)) { 2680 DeleteChannel(channel); 2681 return false; 2682 } 2683 2684 receive_channels_.insert( 2685 std::make_pair( 2686 ssrc, new WebRtcVoiceChannelRenderer(channel, audio_transport))); 2687 2688 LOG(LS_INFO) << "New audio stream " << ssrc 2689 << " registered to VoiceEngine channel #" 2690 << channel << "."; 2691 return true; 2692 } 2693 2694 bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) { 2695 // Configure to use external transport, like our default channel. 2696 if (engine()->voe()->network()->RegisterExternalTransport( 2697 channel, *this) == -1) { 2698 LOG_RTCERR2(SetExternalTransport, channel, this); 2699 return false; 2700 } 2701 2702 // Use the same SSRC as our default channel (so the RTCP reports are correct). 2703 unsigned int send_ssrc = 0; 2704 webrtc::VoERTP_RTCP* rtp = engine()->voe()->rtp(); 2705 if (rtp->GetLocalSSRC(voe_channel(), send_ssrc) == -1) { 2706 LOG_RTCERR1(GetSendSSRC, channel); 2707 return false; 2708 } 2709 if (rtp->SetLocalSSRC(channel, send_ssrc) == -1) { 2710 LOG_RTCERR1(SetSendSSRC, channel); 2711 return false; 2712 } 2713 2714 // Use the same recv payload types as our default channel. 2715 ResetRecvCodecs(channel); 2716 if (!recv_codecs_.empty()) { 2717 for (std::vector<AudioCodec>::const_iterator it = recv_codecs_.begin(); 2718 it != recv_codecs_.end(); ++it) { 2719 webrtc::CodecInst voe_codec; 2720 if (engine()->FindWebRtcCodec(*it, &voe_codec)) { 2721 voe_codec.pltype = it->id; 2722 voe_codec.rate = 0; // Needed to make GetRecPayloadType work for ISAC 2723 if (engine()->voe()->codec()->GetRecPayloadType( 2724 voe_channel(), voe_codec) != -1) { 2725 if (engine()->voe()->codec()->SetRecPayloadType( 2726 channel, voe_codec) == -1) { 2727 LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); 2728 return false; 2729 } 2730 } 2731 } 2732 } 2733 } 2734 2735 if (InConferenceMode()) { 2736 // To be in par with the video, voe_channel() is not used for receiving in 2737 // a conference call. 2738 if (receive_channels_.empty() && default_receive_ssrc_ == 0 && playout_) { 2739 // This is the first stream in a multi user meeting. We can now 2740 // disable playback of the default stream. This since the default 2741 // stream will probably have received some initial packets before 2742 // the new stream was added. This will mean that the CN state from 2743 // the default channel will be mixed in with the other streams 2744 // throughout the whole meeting, which might be disturbing. 2745 LOG(LS_INFO) << "Disabling playback on the default voice channel"; 2746 SetPlayout(voe_channel(), false); 2747 } 2748 } 2749 SetNack(channel, nack_enabled_); 2750 2751 // Set RTP header extension for the new channel. 2752 if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) { 2753 return false; 2754 } 2755 2756 // Set up channel to be able to forward incoming packets to video engine BWE. 2757 if (!SetupSharedBweOnChannel(channel)) { 2758 return false; 2759 } 2760 2761 return SetPlayout(channel, playout_); 2762 } 2763 2764 bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) { 2765 rtc::CritScope lock(&receive_channels_cs_); 2766 ChannelMap::iterator it = receive_channels_.find(ssrc); 2767 if (it == receive_channels_.end()) { 2768 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc 2769 << " which doesn't exist."; 2770 return false; 2771 } 2772 2773 // Delete the WebRtcVoiceChannelRenderer object connected to the channel, this 2774 // will disconnect the audio renderer with the receive channel. 2775 // Cache the channel before the deletion. 2776 const int channel = it->second->channel(); 2777 delete it->second; 2778 receive_channels_.erase(it); 2779 2780 if (ssrc == default_receive_ssrc_) { 2781 ASSERT(IsDefaultChannel(channel)); 2782 // Recycle the default channel is for recv stream. 2783 if (playout_) 2784 SetPlayout(voe_channel(), false); 2785 2786 default_receive_ssrc_ = 0; 2787 return true; 2788 } 2789 2790 LOG(LS_INFO) << "Removing audio stream " << ssrc 2791 << " with VoiceEngine channel #" << channel << "."; 2792 if (!DeleteChannel(channel)) 2793 return false; 2794 2795 bool enable_default_channel_playout = false; 2796 if (receive_channels_.empty()) { 2797 // The last stream was removed. We can now enable the default 2798 // channel for new channels to be played out immediately without 2799 // waiting for AddStream messages. 2800 // We do this for both conference mode and non-conference mode. 2801 // TODO(oja): Does the default channel still have it's CN state? 2802 enable_default_channel_playout = true; 2803 } 2804 if (!InConferenceMode() && receive_channels_.size() == 1 && 2805 default_receive_ssrc_ != 0) { 2806 // Only the default channel is active, enable the playout on default 2807 // channel. 2808 enable_default_channel_playout = true; 2809 } 2810 if (enable_default_channel_playout && playout_) { 2811 LOG(LS_INFO) << "Enabling playback on the default voice channel"; 2812 SetPlayout(voe_channel(), true); 2813 } 2814 2815 return true; 2816 } 2817 2818 bool WebRtcVoiceMediaChannel::SetRemoteRenderer(uint32 ssrc, 2819 AudioRenderer* renderer) { 2820 ChannelMap::iterator it = receive_channels_.find(ssrc); 2821 if (it == receive_channels_.end()) { 2822 if (renderer) { 2823 // Return an error if trying to set a valid renderer with an invalid ssrc. 2824 LOG(LS_ERROR) << "SetRemoteRenderer failed with ssrc "<< ssrc; 2825 return false; 2826 } 2827 2828 // The channel likely has gone away, do nothing. 2829 return true; 2830 } 2831 2832 if (renderer) 2833 it->second->Start(renderer); 2834 else 2835 it->second->Stop(); 2836 2837 return true; 2838 } 2839 2840 bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32 ssrc, 2841 AudioRenderer* renderer) { 2842 ChannelMap::iterator it = send_channels_.find(ssrc); 2843 if (it == send_channels_.end()) { 2844 if (renderer) { 2845 // Return an error if trying to set a valid renderer with an invalid ssrc. 2846 LOG(LS_ERROR) << "SetLocalRenderer failed with ssrc "<< ssrc; 2847 return false; 2848 } 2849 2850 // The channel likely has gone away, do nothing. 2851 return true; 2852 } 2853 2854 if (renderer) 2855 it->second->Start(renderer); 2856 else 2857 it->second->Stop(); 2858 2859 return true; 2860 } 2861 2862 bool WebRtcVoiceMediaChannel::GetActiveStreams( 2863 AudioInfo::StreamList* actives) { 2864 // In conference mode, the default channel should not be in 2865 // |receive_channels_|. 2866 actives->clear(); 2867 for (ChannelMap::iterator it = receive_channels_.begin(); 2868 it != receive_channels_.end(); ++it) { 2869 int level = GetOutputLevel(it->second->channel()); 2870 if (level > 0) { 2871 actives->push_back(std::make_pair(it->first, level)); 2872 } 2873 } 2874 return true; 2875 } 2876 2877 int WebRtcVoiceMediaChannel::GetOutputLevel() { 2878 // return the highest output level of all streams 2879 int highest = GetOutputLevel(voe_channel()); 2880 for (ChannelMap::iterator it = receive_channels_.begin(); 2881 it != receive_channels_.end(); ++it) { 2882 int level = GetOutputLevel(it->second->channel()); 2883 highest = rtc::_max(level, highest); 2884 } 2885 return highest; 2886 } 2887 2888 int WebRtcVoiceMediaChannel::GetTimeSinceLastTyping() { 2889 int ret; 2890 if (engine()->voe()->processing()->TimeSinceLastTyping(ret) == -1) { 2891 // In case of error, log the info and continue 2892 LOG_RTCERR0(TimeSinceLastTyping); 2893 ret = -1; 2894 } else { 2895 ret *= 1000; // We return ms, webrtc returns seconds. 2896 } 2897 return ret; 2898 } 2899 2900 void WebRtcVoiceMediaChannel::SetTypingDetectionParameters(int time_window, 2901 int cost_per_typing, int reporting_threshold, int penalty_decay, 2902 int type_event_delay) { 2903 if (engine()->voe()->processing()->SetTypingDetectionParameters( 2904 time_window, cost_per_typing, 2905 reporting_threshold, penalty_decay, type_event_delay) == -1) { 2906 // In case of error, log the info and continue 2907 LOG_RTCERR5(SetTypingDetectionParameters, time_window, 2908 cost_per_typing, reporting_threshold, penalty_decay, 2909 type_event_delay); 2910 } 2911 } 2912 2913 bool WebRtcVoiceMediaChannel::SetOutputScaling( 2914 uint32 ssrc, double left, double right) { 2915 rtc::CritScope lock(&receive_channels_cs_); 2916 // Collect the channels to scale the output volume. 2917 std::vector<int> channels; 2918 if (0 == ssrc) { // Collect all channels, including the default one. 2919 // Default channel is not in receive_channels_ if it is not being used for 2920 // playout. 2921 if (default_receive_ssrc_ == 0) 2922 channels.push_back(voe_channel()); 2923 for (ChannelMap::const_iterator it = receive_channels_.begin(); 2924 it != receive_channels_.end(); ++it) { 2925 channels.push_back(it->second->channel()); 2926 } 2927 } else { // Collect only the channel of the specified ssrc. 2928 int channel = GetReceiveChannelNum(ssrc); 2929 if (-1 == channel) { 2930 LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc; 2931 return false; 2932 } 2933 channels.push_back(channel); 2934 } 2935 2936 // Scale the output volume for the collected channels. We first normalize to 2937 // scale the volume and then set the left and right pan. 2938 float scale = static_cast<float>(rtc::_max(left, right)); 2939 if (scale > 0.0001f) { 2940 left /= scale; 2941 right /= scale; 2942 } 2943 for (std::vector<int>::const_iterator it = channels.begin(); 2944 it != channels.end(); ++it) { 2945 if (-1 == engine()->voe()->volume()->SetChannelOutputVolumeScaling( 2946 *it, scale)) { 2947 LOG_RTCERR2(SetChannelOutputVolumeScaling, *it, scale); 2948 return false; 2949 } 2950 if (-1 == engine()->voe()->volume()->SetOutputVolumePan( 2951 *it, static_cast<float>(left), static_cast<float>(right))) { 2952 LOG_RTCERR3(SetOutputVolumePan, *it, left, right); 2953 // Do not return if fails. SetOutputVolumePan is not available for all 2954 // pltforms. 2955 } 2956 LOG(LS_INFO) << "SetOutputScaling to left=" << left * scale 2957 << " right=" << right * scale 2958 << " for channel " << *it << " and ssrc " << ssrc; 2959 } 2960 return true; 2961 } 2962 2963 bool WebRtcVoiceMediaChannel::GetOutputScaling( 2964 uint32 ssrc, double* left, double* right) { 2965 if (!left || !right) return false; 2966 2967 rtc::CritScope lock(&receive_channels_cs_); 2968 // Determine which channel based on ssrc. 2969 int channel = (0 == ssrc) ? voe_channel() : GetReceiveChannelNum(ssrc); 2970 if (channel == -1) { 2971 LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc; 2972 return false; 2973 } 2974 2975 float scaling; 2976 if (-1 == engine()->voe()->volume()->GetChannelOutputVolumeScaling( 2977 channel, scaling)) { 2978 LOG_RTCERR2(GetChannelOutputVolumeScaling, channel, scaling); 2979 return false; 2980 } 2981 2982 float left_pan; 2983 float right_pan; 2984 if (-1 == engine()->voe()->volume()->GetOutputVolumePan( 2985 channel, left_pan, right_pan)) { 2986 LOG_RTCERR3(GetOutputVolumePan, channel, left_pan, right_pan); 2987 // If GetOutputVolumePan fails, we use the default left and right pan. 2988 left_pan = 1.0f; 2989 right_pan = 1.0f; 2990 } 2991 2992 *left = scaling * left_pan; 2993 *right = scaling * right_pan; 2994 return true; 2995 } 2996 2997 bool WebRtcVoiceMediaChannel::SetRingbackTone(const char *buf, int len) { 2998 ringback_tone_.reset(new WebRtcSoundclipStream(buf, len)); 2999 return true; 3000 } 3001 3002 bool WebRtcVoiceMediaChannel::PlayRingbackTone(uint32 ssrc, 3003 bool play, bool loop) { 3004 if (!ringback_tone_) { 3005 return false; 3006 } 3007 3008 // The voe file api is not available in chrome. 3009 if (!engine()->voe()->file()) { 3010 return false; 3011 } 3012 3013 // Determine which VoiceEngine channel to play on. 3014 int channel = (ssrc == 0) ? voe_channel() : GetReceiveChannelNum(ssrc); 3015 if (channel == -1) { 3016 return false; 3017 } 3018 3019 // Make sure the ringtone is cued properly, and play it out. 3020 if (play) { 3021 ringback_tone_->set_loop(loop); 3022 ringback_tone_->Rewind(); 3023 if (engine()->voe()->file()->StartPlayingFileLocally(channel, 3024 ringback_tone_.get()) == -1) { 3025 LOG_RTCERR2(StartPlayingFileLocally, channel, ringback_tone_.get()); 3026 LOG(LS_ERROR) << "Unable to start ringback tone"; 3027 return false; 3028 } 3029 ringback_channels_.insert(channel); 3030 LOG(LS_INFO) << "Started ringback on channel " << channel; 3031 } else { 3032 if (engine()->voe()->file()->IsPlayingFileLocally(channel) == 1 && 3033 engine()->voe()->file()->StopPlayingFileLocally(channel) == -1) { 3034 LOG_RTCERR1(StopPlayingFileLocally, channel); 3035 return false; 3036 } 3037 LOG(LS_INFO) << "Stopped ringback on channel " << channel; 3038 ringback_channels_.erase(channel); 3039 } 3040 3041 return true; 3042 } 3043 3044 bool WebRtcVoiceMediaChannel::CanInsertDtmf() { 3045 return dtmf_allowed_; 3046 } 3047 3048 bool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event, 3049 int duration, int flags) { 3050 if (!dtmf_allowed_) { 3051 return false; 3052 } 3053 3054 // Send the event. 3055 if (flags & cricket::DF_SEND) { 3056 int channel = -1; 3057 if (ssrc == 0) { 3058 bool default_channel_is_inuse = false; 3059 for (ChannelMap::const_iterator iter = send_channels_.begin(); 3060 iter != send_channels_.end(); ++iter) { 3061 if (IsDefaultChannel(iter->second->channel())) { 3062 default_channel_is_inuse = true; 3063 break; 3064 } 3065 } 3066 if (default_channel_is_inuse) { 3067 channel = voe_channel(); 3068 } else if (!send_channels_.empty()) { 3069 channel = send_channels_.begin()->second->channel(); 3070 } 3071 } else { 3072 channel = GetSendChannelNum(ssrc); 3073 } 3074 if (channel == -1) { 3075 LOG(LS_WARNING) << "InsertDtmf - The specified ssrc " 3076 << ssrc << " is not in use."; 3077 return false; 3078 } 3079 // Send DTMF using out-of-band DTMF. ("true", as 3rd arg) 3080 if (engine()->voe()->dtmf()->SendTelephoneEvent( 3081 channel, event, true, duration) == -1) { 3082 LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration); 3083 return false; 3084 } 3085 } 3086 3087 // Play the event. 3088 if (flags & cricket::DF_PLAY) { 3089 // Play DTMF tone locally. 3090 if (engine()->voe()->dtmf()->PlayDtmfTone(event, duration) == -1) { 3091 LOG_RTCERR2(PlayDtmfTone, event, duration); 3092 return false; 3093 } 3094 } 3095 3096 return true; 3097 } 3098 3099 void WebRtcVoiceMediaChannel::OnPacketReceived( 3100 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { 3101 // Pick which channel to send this packet to. If this packet doesn't match 3102 // any multiplexed streams, just send it to the default channel. Otherwise, 3103 // send it to the specific decoder instance for that stream. 3104 int which_channel = GetReceiveChannelNum( 3105 ParseSsrc(packet->data(), packet->length(), false)); 3106 if (which_channel == -1) { 3107 which_channel = voe_channel(); 3108 } 3109 3110 // Stop any ringback that might be playing on the channel. 3111 // It's possible the ringback has already stopped, ih which case we'll just 3112 // use the opportunity to remove the channel from ringback_channels_. 3113 if (engine()->voe()->file()) { 3114 const std::set<int>::iterator it = ringback_channels_.find(which_channel); 3115 if (it != ringback_channels_.end()) { 3116 if (engine()->voe()->file()->IsPlayingFileLocally( 3117 which_channel) == 1) { 3118 engine()->voe()->file()->StopPlayingFileLocally(which_channel); 3119 LOG(LS_INFO) << "Stopped ringback on channel " << which_channel 3120 << " due to incoming media"; 3121 } 3122 ringback_channels_.erase(which_channel); 3123 } 3124 } 3125 3126 // Pass it off to the decoder. 3127 engine()->voe()->network()->ReceivedRTPPacket( 3128 which_channel, 3129 packet->data(), 3130 static_cast<unsigned int>(packet->length()), 3131 webrtc::PacketTime(packet_time.timestamp, packet_time.not_before)); 3132 } 3133 3134 void WebRtcVoiceMediaChannel::OnRtcpReceived( 3135 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { 3136 // Sending channels need all RTCP packets with feedback information. 3137 // Even sender reports can contain attached report blocks. 3138 // Receiving channels need sender reports in order to create 3139 // correct receiver reports. 3140 int type = 0; 3141 if (!GetRtcpType(packet->data(), packet->length(), &type)) { 3142 LOG(LS_WARNING) << "Failed to parse type from received RTCP packet"; 3143 return; 3144 } 3145 3146 // If it is a sender report, find the channel that is listening. 3147 bool has_sent_to_default_channel = false; 3148 if (type == kRtcpTypeSR) { 3149 int which_channel = GetReceiveChannelNum( 3150 ParseSsrc(packet->data(), packet->length(), true)); 3151 if (which_channel != -1) { 3152 engine()->voe()->network()->ReceivedRTCPPacket( 3153 which_channel, 3154 packet->data(), 3155 static_cast<unsigned int>(packet->length())); 3156 3157 if (IsDefaultChannel(which_channel)) 3158 has_sent_to_default_channel = true; 3159 } 3160 } 3161 3162 // SR may continue RR and any RR entry may correspond to any one of the send 3163 // channels. So all RTCP packets must be forwarded all send channels. VoE 3164 // will filter out RR internally. 3165 for (ChannelMap::iterator iter = send_channels_.begin(); 3166 iter != send_channels_.end(); ++iter) { 3167 // Make sure not sending the same packet to default channel more than once. 3168 if (IsDefaultChannel(iter->second->channel()) && 3169 has_sent_to_default_channel) 3170 continue; 3171 3172 engine()->voe()->network()->ReceivedRTCPPacket( 3173 iter->second->channel(), 3174 packet->data(), 3175 static_cast<unsigned int>(packet->length())); 3176 } 3177 } 3178 3179 bool WebRtcVoiceMediaChannel::MuteStream(uint32 ssrc, bool muted) { 3180 int channel = (ssrc == 0) ? voe_channel() : GetSendChannelNum(ssrc); 3181 if (channel == -1) { 3182 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use."; 3183 return false; 3184 } 3185 if (engine()->voe()->volume()->SetInputMute(channel, muted) == -1) { 3186 LOG_RTCERR2(SetInputMute, channel, muted); 3187 return false; 3188 } 3189 // We set the AGC to mute state only when all the channels are muted. 3190 // This implementation is not ideal, instead we should signal the AGC when 3191 // the mic channel is muted/unmuted. We can't do it today because there 3192 // is no good way to know which stream is mapping to the mic channel. 3193 bool all_muted = muted; 3194 for (ChannelMap::const_iterator iter = send_channels_.begin(); 3195 iter != send_channels_.end() && all_muted; ++iter) { 3196 if (engine()->voe()->volume()->GetInputMute(iter->second->channel(), 3197 all_muted)) { 3198 LOG_RTCERR1(GetInputMute, iter->second->channel()); 3199 return false; 3200 } 3201 } 3202 3203 webrtc::AudioProcessing* ap = engine()->voe()->base()->audio_processing(); 3204 if (ap) 3205 ap->set_output_will_be_muted(all_muted); 3206 return true; 3207 } 3208 3209 bool WebRtcVoiceMediaChannel::SetStartSendBandwidth(int bps) { 3210 // TODO(andresp): Add support for setting an independent start bandwidth when 3211 // bandwidth estimation is enabled for voice engine. 3212 return false; 3213 } 3214 3215 bool WebRtcVoiceMediaChannel::SetMaxSendBandwidth(int bps) { 3216 LOG(LS_INFO) << "WebRtcVoiceMediaChanne::SetSendBandwidth."; 3217 3218 return SetSendBandwidthInternal(bps); 3219 } 3220 3221 bool WebRtcVoiceMediaChannel::SetSendBandwidthInternal(int bps) { 3222 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendBandwidthInternal."; 3223 3224 send_bw_setting_ = true; 3225 send_bw_bps_ = bps; 3226 3227 if (!send_codec_) { 3228 LOG(LS_INFO) << "The send codec has not been set up yet. " 3229 << "The send bandwidth setting will be applied later."; 3230 return true; 3231 } 3232 3233 // Bandwidth is auto by default. 3234 // TODO(bemasc): Fix this so that if SetMaxSendBandwidth(50) is followed by 3235 // SetMaxSendBandwith(0), the second call removes the previous limit. 3236 if (bps <= 0) 3237 return true; 3238 3239 webrtc::CodecInst codec = *send_codec_; 3240 bool is_multi_rate = IsCodecMultiRate(codec); 3241 3242 if (is_multi_rate) { 3243 // If codec is multi-rate then just set the bitrate. 3244 codec.rate = bps; 3245 if (!SetSendCodec(codec)) { 3246 LOG(LS_INFO) << "Failed to set codec " << codec.plname 3247 << " to bitrate " << bps << " bps."; 3248 return false; 3249 } 3250 return true; 3251 } else { 3252 // If codec is not multi-rate and |bps| is less than the fixed bitrate 3253 // then fail. If codec is not multi-rate and |bps| exceeds or equal the 3254 // fixed bitrate then ignore. 3255 if (bps < codec.rate) { 3256 LOG(LS_INFO) << "Failed to set codec " << codec.plname 3257 << " to bitrate " << bps << " bps" 3258 << ", requires at least " << codec.rate << " bps."; 3259 return false; 3260 } 3261 return true; 3262 } 3263 } 3264 3265 bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { 3266 bool echo_metrics_on = false; 3267 // These can take on valid negative values, so use the lowest possible level 3268 // as default rather than -1. 3269 int echo_return_loss = -100; 3270 int echo_return_loss_enhancement = -100; 3271 // These can also be negative, but in practice -1 is only used to signal 3272 // insufficient data, since the resolution is limited to multiples of 4 ms. 3273 int echo_delay_median_ms = -1; 3274 int echo_delay_std_ms = -1; 3275 if (engine()->voe()->processing()->GetEcMetricsStatus( 3276 echo_metrics_on) != -1 && echo_metrics_on) { 3277 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary 3278 // here, but it appears to be unsuitable currently. Revisit after this is 3279 // investigated: http://b/issue?id=5666755 3280 int erl, erle, rerl, anlp; 3281 if (engine()->voe()->processing()->GetEchoMetrics( 3282 erl, erle, rerl, anlp) != -1) { 3283 echo_return_loss = erl; 3284 echo_return_loss_enhancement = erle; 3285 } 3286 3287 int median, std; 3288 if (engine()->voe()->processing()->GetEcDelayMetrics(median, std) != -1) { 3289 echo_delay_median_ms = median; 3290 echo_delay_std_ms = std; 3291 } 3292 } 3293 3294 webrtc::CallStatistics cs; 3295 unsigned int ssrc; 3296 webrtc::CodecInst codec; 3297 unsigned int level; 3298 3299 for (ChannelMap::const_iterator channel_iter = send_channels_.begin(); 3300 channel_iter != send_channels_.end(); ++channel_iter) { 3301 const int channel = channel_iter->second->channel(); 3302 3303 // Fill in the sender info, based on what we know, and what the 3304 // remote side told us it got from its RTCP report. 3305 VoiceSenderInfo sinfo; 3306 3307 if (engine()->voe()->rtp()->GetRTCPStatistics(channel, cs) == -1 || 3308 engine()->voe()->rtp()->GetLocalSSRC(channel, ssrc) == -1) { 3309 continue; 3310 } 3311 3312 sinfo.add_ssrc(ssrc); 3313 sinfo.codec_name = send_codec_.get() ? send_codec_->plname : ""; 3314 sinfo.bytes_sent = cs.bytesSent; 3315 sinfo.packets_sent = cs.packetsSent; 3316 // RTT isn't known until a RTCP report is received. Until then, VoiceEngine 3317 // returns 0 to indicate an error value. 3318 sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1; 3319 3320 // Get data from the last remote RTCP report. Use default values if no data 3321 // available. 3322 sinfo.fraction_lost = -1.0; 3323 sinfo.jitter_ms = -1; 3324 sinfo.packets_lost = -1; 3325 sinfo.ext_seqnum = -1; 3326 std::vector<webrtc::ReportBlock> receive_blocks; 3327 if (engine()->voe()->rtp()->GetRemoteRTCPReportBlocks( 3328 channel, &receive_blocks) != -1 && 3329 engine()->voe()->codec()->GetSendCodec(channel, codec) != -1) { 3330 std::vector<webrtc::ReportBlock>::iterator iter; 3331 for (iter = receive_blocks.begin(); iter != receive_blocks.end(); 3332 ++iter) { 3333 // Lookup report for send ssrc only. 3334 if (iter->source_SSRC == sinfo.ssrc()) { 3335 // Convert Q8 to floating point. 3336 sinfo.fraction_lost = static_cast<float>(iter->fraction_lost) / 256; 3337 // Convert samples to milliseconds. 3338 if (codec.plfreq / 1000 > 0) { 3339 sinfo.jitter_ms = iter->interarrival_jitter / (codec.plfreq / 1000); 3340 } 3341 sinfo.packets_lost = iter->cumulative_num_packets_lost; 3342 sinfo.ext_seqnum = iter->extended_highest_sequence_number; 3343 break; 3344 } 3345 } 3346 } 3347 3348 // Local speech level. 3349 sinfo.audio_level = (engine()->voe()->volume()-> 3350 GetSpeechInputLevelFullRange(level) != -1) ? level : -1; 3351 3352 // TODO(xians): We are injecting the same APM logging to all the send 3353 // channels here because there is no good way to know which send channel 3354 // is using the APM. The correct fix is to allow the send channels to have 3355 // their own APM so that we can feed the correct APM logging to different 3356 // send channels. See issue crbug/264611 . 3357 sinfo.echo_return_loss = echo_return_loss; 3358 sinfo.echo_return_loss_enhancement = echo_return_loss_enhancement; 3359 sinfo.echo_delay_median_ms = echo_delay_median_ms; 3360 sinfo.echo_delay_std_ms = echo_delay_std_ms; 3361 // TODO(ajm): Re-enable this metric once we have a reliable implementation. 3362 sinfo.aec_quality_min = -1; 3363 sinfo.typing_noise_detected = typing_noise_detected_; 3364 3365 info->senders.push_back(sinfo); 3366 } 3367 3368 // Build the list of receivers, one for each receiving channel, or 1 in 3369 // a 1:1 call. 3370 std::vector<int> channels; 3371 for (ChannelMap::const_iterator it = receive_channels_.begin(); 3372 it != receive_channels_.end(); ++it) { 3373 channels.push_back(it->second->channel()); 3374 } 3375 if (channels.empty()) { 3376 channels.push_back(voe_channel()); 3377 } 3378 3379 // Get the SSRC and stats for each receiver, based on our own calculations. 3380 for (std::vector<int>::const_iterator it = channels.begin(); 3381 it != channels.end(); ++it) { 3382 memset(&cs, 0, sizeof(cs)); 3383 if (engine()->voe()->rtp()->GetRemoteSSRC(*it, ssrc) != -1 && 3384 engine()->voe()->rtp()->GetRTCPStatistics(*it, cs) != -1 && 3385 engine()->voe()->codec()->GetRecCodec(*it, codec) != -1) { 3386 VoiceReceiverInfo rinfo; 3387 rinfo.add_ssrc(ssrc); 3388 rinfo.bytes_rcvd = cs.bytesReceived; 3389 rinfo.packets_rcvd = cs.packetsReceived; 3390 // The next four fields are from the most recently sent RTCP report. 3391 // Convert Q8 to floating point. 3392 rinfo.fraction_lost = static_cast<float>(cs.fractionLost) / (1 << 8); 3393 rinfo.packets_lost = cs.cumulativeLost; 3394 rinfo.ext_seqnum = cs.extendedMax; 3395 #ifdef USE_WEBRTC_DEV_BRANCH 3396 rinfo.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_; 3397 #endif 3398 if (codec.pltype != -1) { 3399 rinfo.codec_name = codec.plname; 3400 } 3401 // Convert samples to milliseconds. 3402 if (codec.plfreq / 1000 > 0) { 3403 rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000); 3404 } 3405 3406 // Get jitter buffer and total delay (alg + jitter + playout) stats. 3407 webrtc::NetworkStatistics ns; 3408 if (engine()->voe()->neteq() && 3409 engine()->voe()->neteq()->GetNetworkStatistics( 3410 *it, ns) != -1) { 3411 rinfo.jitter_buffer_ms = ns.currentBufferSize; 3412 rinfo.jitter_buffer_preferred_ms = ns.preferredBufferSize; 3413 rinfo.expand_rate = 3414 static_cast<float>(ns.currentExpandRate) / (1 << 14); 3415 } 3416 3417 webrtc::AudioDecodingCallStats ds; 3418 if (engine()->voe()->neteq() && 3419 engine()->voe()->neteq()->GetDecodingCallStatistics( 3420 *it, &ds) != -1) { 3421 rinfo.decoding_calls_to_silence_generator = 3422 ds.calls_to_silence_generator; 3423 rinfo.decoding_calls_to_neteq = ds.calls_to_neteq; 3424 rinfo.decoding_normal = ds.decoded_normal; 3425 rinfo.decoding_plc = ds.decoded_plc; 3426 rinfo.decoding_cng = ds.decoded_cng; 3427 rinfo.decoding_plc_cng = ds.decoded_plc_cng; 3428 } 3429 3430 if (engine()->voe()->sync()) { 3431 int jitter_buffer_delay_ms = 0; 3432 int playout_buffer_delay_ms = 0; 3433 engine()->voe()->sync()->GetDelayEstimate( 3434 *it, &jitter_buffer_delay_ms, &playout_buffer_delay_ms); 3435 rinfo.delay_estimate_ms = jitter_buffer_delay_ms + 3436 playout_buffer_delay_ms; 3437 } 3438 3439 // Get speech level. 3440 rinfo.audio_level = (engine()->voe()->volume()-> 3441 GetSpeechOutputLevelFullRange(*it, level) != -1) ? level : -1; 3442 info->receivers.push_back(rinfo); 3443 } 3444 } 3445 3446 return true; 3447 } 3448 3449 void WebRtcVoiceMediaChannel::GetLastMediaError( 3450 uint32* ssrc, VoiceMediaChannel::Error* error) { 3451 ASSERT(ssrc != NULL); 3452 ASSERT(error != NULL); 3453 FindSsrc(voe_channel(), ssrc); 3454 *error = WebRtcErrorToChannelError(GetLastEngineError()); 3455 } 3456 3457 bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) { 3458 rtc::CritScope lock(&receive_channels_cs_); 3459 ASSERT(ssrc != NULL); 3460 if (channel_num == -1 && send_ != SEND_NOTHING) { 3461 // Sometimes the VoiceEngine core will throw error with channel_num = -1. 3462 // This means the error is not limited to a specific channel. Signal the 3463 // message using ssrc=0. If the current channel is sending, use this 3464 // channel for sending the message. 3465 *ssrc = 0; 3466 return true; 3467 } else { 3468 // Check whether this is a sending channel. 3469 for (ChannelMap::const_iterator it = send_channels_.begin(); 3470 it != send_channels_.end(); ++it) { 3471 if (it->second->channel() == channel_num) { 3472 // This is a sending channel. 3473 uint32 local_ssrc = 0; 3474 if (engine()->voe()->rtp()->GetLocalSSRC( 3475 channel_num, local_ssrc) != -1) { 3476 *ssrc = local_ssrc; 3477 } 3478 return true; 3479 } 3480 } 3481 3482 // Check whether this is a receiving channel. 3483 for (ChannelMap::const_iterator it = receive_channels_.begin(); 3484 it != receive_channels_.end(); ++it) { 3485 if (it->second->channel() == channel_num) { 3486 *ssrc = it->first; 3487 return true; 3488 } 3489 } 3490 } 3491 return false; 3492 } 3493 3494 void WebRtcVoiceMediaChannel::OnError(uint32 ssrc, int error) { 3495 if (error == VE_TYPING_NOISE_WARNING) { 3496 typing_noise_detected_ = true; 3497 } else if (error == VE_TYPING_NOISE_OFF_WARNING) { 3498 typing_noise_detected_ = false; 3499 } 3500 SignalMediaError(ssrc, WebRtcErrorToChannelError(error)); 3501 } 3502 3503 int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) { 3504 unsigned int ulevel; 3505 int ret = 3506 engine()->voe()->volume()->GetSpeechOutputLevel(channel, ulevel); 3507 return (ret == 0) ? static_cast<int>(ulevel) : -1; 3508 } 3509 3510 int WebRtcVoiceMediaChannel::GetReceiveChannelNum(uint32 ssrc) { 3511 ChannelMap::iterator it = receive_channels_.find(ssrc); 3512 if (it != receive_channels_.end()) 3513 return it->second->channel(); 3514 return (ssrc == default_receive_ssrc_) ? voe_channel() : -1; 3515 } 3516 3517 int WebRtcVoiceMediaChannel::GetSendChannelNum(uint32 ssrc) { 3518 ChannelMap::iterator it = send_channels_.find(ssrc); 3519 if (it != send_channels_.end()) 3520 return it->second->channel(); 3521 3522 return -1; 3523 } 3524 3525 bool WebRtcVoiceMediaChannel::SetupSharedBandwidthEstimation( 3526 webrtc::VideoEngine* vie, int vie_channel) { 3527 shared_bwe_vie_ = vie; 3528 shared_bwe_vie_channel_ = vie_channel; 3529 3530 if (!SetupSharedBweOnChannel(voe_channel())) { 3531 return false; 3532 } 3533 for (ChannelMap::iterator it = receive_channels_.begin(); 3534 it != receive_channels_.end(); ++it) { 3535 if (!SetupSharedBweOnChannel(it->second->channel())) { 3536 return false; 3537 } 3538 } 3539 return true; 3540 } 3541 3542 bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec, 3543 const std::vector<AudioCodec>& all_codecs, webrtc::CodecInst* send_codec) { 3544 // Get the RED encodings from the parameter with no name. This may 3545 // change based on what is discussed on the Jingle list. 3546 // The encoding parameter is of the form "a/b"; we only support where 3547 // a == b. Verify this and parse out the value into red_pt. 3548 // If the parameter value is absent (as it will be until we wire up the 3549 // signaling of this message), use the second codec specified (i.e. the 3550 // one after "red") as the encoding parameter. 3551 int red_pt = -1; 3552 std::string red_params; 3553 CodecParameterMap::const_iterator it = red_codec.params.find(""); 3554 if (it != red_codec.params.end()) { 3555 red_params = it->second; 3556 std::vector<std::string> red_pts; 3557 if (rtc::split(red_params, '/', &red_pts) != 2 || 3558 red_pts[0] != red_pts[1] || 3559 !rtc::FromString(red_pts[0], &red_pt)) { 3560 LOG(LS_WARNING) << "RED params " << red_params << " not supported."; 3561 return false; 3562 } 3563 } else if (red_codec.params.empty()) { 3564 LOG(LS_WARNING) << "RED params not present, using defaults"; 3565 if (all_codecs.size() > 1) { 3566 red_pt = all_codecs[1].id; 3567 } 3568 } 3569 3570 // Try to find red_pt in |codecs|. 3571 std::vector<AudioCodec>::const_iterator codec; 3572 for (codec = all_codecs.begin(); codec != all_codecs.end(); ++codec) { 3573 if (codec->id == red_pt) 3574 break; 3575 } 3576 3577 // If we find the right codec, that will be the codec we pass to 3578 // SetSendCodec, with the desired payload type. 3579 if (codec != all_codecs.end() && 3580 engine()->FindWebRtcCodec(*codec, send_codec)) { 3581 } else { 3582 LOG(LS_WARNING) << "RED params " << red_params << " are invalid."; 3583 return false; 3584 } 3585 3586 return true; 3587 } 3588 3589 bool WebRtcVoiceMediaChannel::EnableRtcp(int channel) { 3590 if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) { 3591 LOG_RTCERR2(SetRTCPStatus, channel, 1); 3592 return false; 3593 } 3594 // TODO(juberti): Enable VQMon and RTCP XR reports, once we know what 3595 // what we want to do with them. 3596 // engine()->voe().EnableVQMon(voe_channel(), true); 3597 // engine()->voe().EnableRTCP_XR(voe_channel(), true); 3598 return true; 3599 } 3600 3601 bool WebRtcVoiceMediaChannel::ResetRecvCodecs(int channel) { 3602 int ncodecs = engine()->voe()->codec()->NumOfCodecs(); 3603 for (int i = 0; i < ncodecs; ++i) { 3604 webrtc::CodecInst voe_codec; 3605 if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) { 3606 voe_codec.pltype = -1; 3607 if (engine()->voe()->codec()->SetRecPayloadType( 3608 channel, voe_codec) == -1) { 3609 LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); 3610 return false; 3611 } 3612 } 3613 } 3614 return true; 3615 } 3616 3617 bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) { 3618 if (playout) { 3619 LOG(LS_INFO) << "Starting playout for channel #" << channel; 3620 if (engine()->voe()->base()->StartPlayout(channel) == -1) { 3621 LOG_RTCERR1(StartPlayout, channel); 3622 return false; 3623 } 3624 } else { 3625 LOG(LS_INFO) << "Stopping playout for channel #" << channel; 3626 engine()->voe()->base()->StopPlayout(channel); 3627 } 3628 return true; 3629 } 3630 3631 uint32 WebRtcVoiceMediaChannel::ParseSsrc(const void* data, size_t len, 3632 bool rtcp) { 3633 size_t ssrc_pos = (!rtcp) ? 8 : 4; 3634 uint32 ssrc = 0; 3635 if (len >= (ssrc_pos + sizeof(ssrc))) { 3636 ssrc = rtc::GetBE32(static_cast<const char*>(data) + ssrc_pos); 3637 } 3638 return ssrc; 3639 } 3640 3641 // Convert VoiceEngine error code into VoiceMediaChannel::Error enum. 3642 VoiceMediaChannel::Error 3643 WebRtcVoiceMediaChannel::WebRtcErrorToChannelError(int err_code) { 3644 switch (err_code) { 3645 case 0: 3646 return ERROR_NONE; 3647 case VE_CANNOT_START_RECORDING: 3648 case VE_MIC_VOL_ERROR: 3649 case VE_GET_MIC_VOL_ERROR: 3650 case VE_CANNOT_ACCESS_MIC_VOL: 3651 return ERROR_REC_DEVICE_OPEN_FAILED; 3652 case VE_SATURATION_WARNING: 3653 return ERROR_REC_DEVICE_SATURATION; 3654 case VE_REC_DEVICE_REMOVED: 3655 return ERROR_REC_DEVICE_REMOVED; 3656 case VE_RUNTIME_REC_WARNING: 3657 case VE_RUNTIME_REC_ERROR: 3658 return ERROR_REC_RUNTIME_ERROR; 3659 case VE_CANNOT_START_PLAYOUT: 3660 case VE_SPEAKER_VOL_ERROR: 3661 case VE_GET_SPEAKER_VOL_ERROR: 3662 case VE_CANNOT_ACCESS_SPEAKER_VOL: 3663 return ERROR_PLAY_DEVICE_OPEN_FAILED; 3664 case VE_RUNTIME_PLAY_WARNING: 3665 case VE_RUNTIME_PLAY_ERROR: 3666 return ERROR_PLAY_RUNTIME_ERROR; 3667 case VE_TYPING_NOISE_WARNING: 3668 return ERROR_REC_TYPING_NOISE_DETECTED; 3669 default: 3670 return VoiceMediaChannel::ERROR_OTHER; 3671 } 3672 } 3673 3674 bool WebRtcVoiceMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter, 3675 int channel_id, const RtpHeaderExtension* extension) { 3676 bool enable = false; 3677 int id = 0; 3678 std::string uri; 3679 if (extension) { 3680 enable = true; 3681 id = extension->id; 3682 uri = extension->uri; 3683 } 3684 if ((engine()->voe()->rtp()->*setter)(channel_id, enable, id) != 0) { 3685 LOG_RTCERR4(*setter, uri, channel_id, enable, id); 3686 return false; 3687 } 3688 return true; 3689 } 3690 3691 bool WebRtcVoiceMediaChannel::SetupSharedBweOnChannel(int voe_channel) { 3692 webrtc::ViENetwork* vie_network = NULL; 3693 int vie_channel = -1; 3694 if (options_.combined_audio_video_bwe.GetWithDefaultIfUnset(false) && 3695 shared_bwe_vie_ != NULL && shared_bwe_vie_channel_ != -1) { 3696 vie_network = webrtc::ViENetwork::GetInterface(shared_bwe_vie_); 3697 vie_channel = shared_bwe_vie_channel_; 3698 } 3699 if (engine()->voe()->rtp()->SetVideoEngineBWETarget(voe_channel, vie_network, 3700 vie_channel) == -1) { 3701 LOG_RTCERR3(SetVideoEngineBWETarget, voe_channel, vie_network, vie_channel); 3702 if (vie_network != NULL) { 3703 // Don't fail if we're tearing down. 3704 return false; 3705 } 3706 } 3707 return true; 3708 } 3709 3710 int WebRtcSoundclipStream::Read(void *buf, int len) { 3711 size_t res = 0; 3712 mem_.Read(buf, len, &res, NULL); 3713 return static_cast<int>(res); 3714 } 3715 3716 int WebRtcSoundclipStream::Rewind() { 3717 mem_.Rewind(); 3718 // Return -1 to keep VoiceEngine from looping. 3719 return (loop_) ? 0 : -1; 3720 } 3721 3722 } // namespace cricket 3723 3724 #endif // HAVE_WEBRTC_VOICE 3725