OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 webrtc::AudioState::Config config; | 242 webrtc::AudioState::Config config; |
243 config.voice_engine = voe_wrapper->engine(); | 243 config.voice_engine = voe_wrapper->engine(); |
244 return config; | 244 return config; |
245 } | 245 } |
246 | 246 |
247 class WebRtcVoiceCodecs final { | 247 class WebRtcVoiceCodecs final { |
248 public: | 248 public: |
249 // TODO(solenberg): Do this filtering once off-line, add a simple AudioCodec | 249 // TODO(solenberg): Do this filtering once off-line, add a simple AudioCodec |
250 // list and add a test which verifies VoE supports the listed codecs. | 250 // list and add a test which verifies VoE supports the listed codecs. |
251 static std::vector<AudioCodec> SupportedCodecs() { | 251 static std::vector<AudioCodec> SupportedCodecs() { |
252 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; | |
253 std::vector<AudioCodec> result; | 252 std::vector<AudioCodec> result; |
254 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { | 253 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { |
255 // Change the sample rate of G722 to 8000 to match SDP. | 254 // Change the sample rate of G722 to 8000 to match SDP. |
256 MaybeFixupG722(&voe_codec, 8000); | 255 MaybeFixupG722(&voe_codec, 8000); |
257 // Skip uncompressed formats. | 256 // Skip uncompressed formats. |
258 if (IsCodec(voe_codec, kL16CodecName)) { | 257 if (IsCodec(voe_codec, kL16CodecName)) { |
259 continue; | 258 continue; |
260 } | 259 } |
261 | 260 |
262 const CodecPref* pref = NULL; | 261 const CodecPref* pref = NULL; |
263 for (size_t j = 0; j < arraysize(kCodecPrefs); ++j) { | 262 for (size_t j = 0; j < arraysize(kCodecPrefs); ++j) { |
264 if (IsCodec(voe_codec, kCodecPrefs[j].name) && | 263 if (IsCodec(voe_codec, kCodecPrefs[j].name) && |
265 kCodecPrefs[j].clockrate == voe_codec.plfreq && | 264 kCodecPrefs[j].clockrate == voe_codec.plfreq && |
266 kCodecPrefs[j].channels == voe_codec.channels) { | 265 kCodecPrefs[j].channels == voe_codec.channels) { |
267 pref = &kCodecPrefs[j]; | 266 pref = &kCodecPrefs[j]; |
268 break; | 267 break; |
269 } | 268 } |
270 } | 269 } |
271 | 270 |
272 if (pref) { | 271 if (pref) { |
273 // Use the payload type that we've configured in our pref table; | 272 // Use the payload type that we've configured in our pref table; |
274 // use the offset in our pref table to determine the sort order. | 273 // use the offset in our pref table to determine the sort order. |
275 AudioCodec codec( | 274 AudioCodec codec( |
276 pref->payload_type, voe_codec.plname, voe_codec.plfreq, | 275 pref->payload_type, voe_codec.plname, voe_codec.plfreq, |
277 voe_codec.rate, voe_codec.channels, | 276 voe_codec.rate, voe_codec.channels, |
278 static_cast<int>(arraysize(kCodecPrefs)) - (pref - kCodecPrefs)); | 277 static_cast<int>(arraysize(kCodecPrefs)) - (pref - kCodecPrefs)); |
279 LOG(LS_INFO) << ToString(codec); | |
280 if (IsCodec(codec, kIsacCodecName)) { | 278 if (IsCodec(codec, kIsacCodecName)) { |
281 // Indicate auto-bitrate in signaling. | 279 // Indicate auto-bitrate in signaling. |
282 codec.bitrate = 0; | 280 codec.bitrate = 0; |
283 } | 281 } |
284 if (IsCodec(codec, kOpusCodecName)) { | 282 if (IsCodec(codec, kOpusCodecName)) { |
285 // Only add fmtp parameters that differ from the spec. | 283 // Only add fmtp parameters that differ from the spec. |
286 if (kPreferredMinPTime != kOpusDefaultMinPTime) { | 284 if (kPreferredMinPTime != kOpusDefaultMinPTime) { |
287 codec.params[kCodecParamMinPTime] = | 285 codec.params[kCodecParamMinPTime] = |
288 rtc::ToString(kPreferredMinPTime); | 286 rtc::ToString(kPreferredMinPTime); |
289 } | 287 } |
290 if (kPreferredMaxPTime != kOpusDefaultMaxPTime) { | 288 if (kPreferredMaxPTime != kOpusDefaultMaxPTime) { |
291 codec.params[kCodecParamMaxPTime] = | 289 codec.params[kCodecParamMaxPTime] = |
292 rtc::ToString(kPreferredMaxPTime); | 290 rtc::ToString(kPreferredMaxPTime); |
293 } | 291 } |
294 codec.SetParam(kCodecParamUseInbandFec, 1); | 292 codec.SetParam(kCodecParamUseInbandFec, 1); |
295 codec.AddFeedbackParam( | 293 codec.AddFeedbackParam( |
296 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); | 294 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); |
297 | 295 |
298 // TODO(hellner): Add ptime, sprop-stereo, and stereo | 296 // TODO(hellner): Add ptime, sprop-stereo, and stereo |
299 // when they can be set to values other than the default. | 297 // when they can be set to values other than the default. |
300 } | 298 } |
301 result.push_back(codec); | 299 result.push_back(codec); |
302 } else { | 300 } else { |
303 LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec); | 301 LOG(LS_INFO) << "[Unused] " << ToString(voe_codec); |
304 } | 302 } |
305 } | 303 } |
306 // Make sure they are in local preference order. | 304 // Make sure they are in local preference order. |
307 std::sort(result.begin(), result.end(), &AudioCodec::Preferable); | 305 std::sort(result.begin(), result.end(), &AudioCodec::Preferable); |
308 return result; | 306 return result; |
309 } | 307 } |
310 | 308 |
311 static bool ToCodecInst(const AudioCodec& in, | 309 static bool ToCodecInst(const AudioCodec& in, |
312 webrtc::CodecInst* out) { | 310 webrtc::CodecInst* out) { |
313 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { | 311 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 { kRedCodecName, 8000, 1, 127, false, { } }, | 506 { kRedCodecName, 8000, 1, 127, false, { } }, |
509 { kDtmfCodecName, 8000, 1, 126, false, { } }, | 507 { kDtmfCodecName, 8000, 1, 126, false, { } }, |
510 }; | 508 }; |
511 } // namespace { | 509 } // namespace { |
512 | 510 |
513 bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in, | 511 bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in, |
514 webrtc::CodecInst* out) { | 512 webrtc::CodecInst* out) { |
515 return WebRtcVoiceCodecs::ToCodecInst(in, out); | 513 return WebRtcVoiceCodecs::ToCodecInst(in, out); |
516 } | 514 } |
517 | 515 |
518 WebRtcVoiceEngine::WebRtcVoiceEngine() | 516 WebRtcVoiceEngine::WebRtcVoiceEngine(webrtc::AudioDeviceModule* adm) |
519 : voe_wrapper_(new VoEWrapper()), | 517 : WebRtcVoiceEngine(adm, new VoEWrapper()) { |
520 audio_state_(webrtc::AudioState::Create(MakeAudioStateConfig(voe()))) { | 518 audio_state_ = webrtc::AudioState::Create(MakeAudioStateConfig(voe())); |
521 Construct(); | |
522 } | 519 } |
523 | 520 |
524 WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper) | 521 WebRtcVoiceEngine::WebRtcVoiceEngine(webrtc::AudioDeviceModule* adm, |
525 : voe_wrapper_(voe_wrapper) { | 522 VoEWrapper* voe_wrapper) |
526 Construct(); | 523 : adm_(adm), voe_wrapper_(voe_wrapper) { |
527 } | |
528 | |
529 void WebRtcVoiceEngine::Construct() { | |
530 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 524 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
531 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; | 525 LOG(LS_INFO) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; |
| 526 RTC_DCHECK(voe_wrapper); |
532 | 527 |
533 signal_thread_checker_.DetachFromThread(); | 528 signal_thread_checker_.DetachFromThread(); |
534 std::memset(&default_agc_config_, 0, sizeof(default_agc_config_)); | 529 |
| 530 // Load our audio codec list. |
| 531 LOG(LS_INFO) << "Supported codecs in order of preference:"; |
| 532 codecs_ = WebRtcVoiceCodecs::SupportedCodecs(); |
| 533 for (const AudioCodec& codec : codecs_) { |
| 534 LOG(LS_INFO) << ToString(codec); |
| 535 } |
| 536 |
535 voe_config_.Set<webrtc::VoicePacing>(new webrtc::VoicePacing(true)); | 537 voe_config_.Set<webrtc::VoicePacing>(new webrtc::VoicePacing(true)); |
536 | 538 |
537 webrtc::Trace::set_level_filter(kDefaultTraceFilter); | 539 // Temporarily turn logging level up for the Init() call. |
538 webrtc::Trace::SetTraceCallback(this); | 540 webrtc::Trace::SetTraceCallback(this); |
539 | |
540 // Load our audio codec list. | |
541 codecs_ = WebRtcVoiceCodecs::SupportedCodecs(); | |
542 } | |
543 | |
544 WebRtcVoiceEngine::~WebRtcVoiceEngine() { | |
545 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | |
546 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; | |
547 if (adm_) { | |
548 voe_wrapper_.reset(); | |
549 adm_->Release(); | |
550 adm_ = NULL; | |
551 } | |
552 webrtc::Trace::SetTraceCallback(nullptr); | |
553 } | |
554 | |
555 bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) { | |
556 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | |
557 RTC_DCHECK(worker_thread == rtc::Thread::Current()); | |
558 LOG(LS_INFO) << "WebRtcVoiceEngine::Init"; | |
559 bool res = InitInternal(); | |
560 if (res) { | |
561 LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!"; | |
562 } else { | |
563 LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed"; | |
564 Terminate(); | |
565 } | |
566 return res; | |
567 } | |
568 | |
569 bool WebRtcVoiceEngine::InitInternal() { | |
570 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | |
571 // Temporarily turn logging level up for the Init call. | |
572 webrtc::Trace::set_level_filter(kElevatedTraceFilter); | 541 webrtc::Trace::set_level_filter(kElevatedTraceFilter); |
573 LOG(LS_INFO) << webrtc::VoiceEngine::GetVersionString(); | 542 LOG(LS_INFO) << webrtc::VoiceEngine::GetVersionString(); |
574 if (voe_wrapper_->base()->Init(adm_) == -1) { | 543 RTC_CHECK_EQ(0, voe_wrapper_->base()->Init(adm_.get())); |
575 LOG_RTCERR0_EX(Init, voe_wrapper_->error()); | 544 webrtc::Trace::set_level_filter(kDefaultTraceFilter); |
576 return false; | 545 |
| 546 // No ADM supplied? Get the default one from VoE. |
| 547 if (!adm_) { |
| 548 adm_ = voe_wrapper_->base()->audio_device_module(); |
577 } | 549 } |
578 webrtc::Trace::set_level_filter(kDefaultTraceFilter); | 550 RTC_DCHECK(adm_); |
579 | 551 |
580 // Save the default AGC configuration settings. This must happen before | 552 // Save the default AGC configuration settings. This must happen before |
581 // calling ApplyOptions or the default will be overwritten. | 553 // calling ApplyOptions or the default will be overwritten. |
582 if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) { | 554 int error = voe_wrapper_->processing()->GetAgcConfig(default_agc_config_); |
583 LOG_RTCERR0(GetAgcConfig); | 555 RTC_DCHECK_EQ(0, error); |
584 return false; | |
585 } | |
586 | 556 |
587 // Set default engine options. | 557 // Set default engine options. |
588 { | 558 { |
589 AudioOptions options; | 559 AudioOptions options; |
590 options.echo_cancellation = rtc::Optional<bool>(true); | 560 options.echo_cancellation = rtc::Optional<bool>(true); |
591 options.auto_gain_control = rtc::Optional<bool>(true); | 561 options.auto_gain_control = rtc::Optional<bool>(true); |
592 options.noise_suppression = rtc::Optional<bool>(true); | 562 options.noise_suppression = rtc::Optional<bool>(true); |
593 options.highpass_filter = rtc::Optional<bool>(true); | 563 options.highpass_filter = rtc::Optional<bool>(true); |
594 options.stereo_swapping = rtc::Optional<bool>(false); | 564 options.stereo_swapping = rtc::Optional<bool>(false); |
595 options.audio_jitter_buffer_max_packets = rtc::Optional<int>(50); | 565 options.audio_jitter_buffer_max_packets = rtc::Optional<int>(50); |
596 options.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(false); | 566 options.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(false); |
597 options.typing_detection = rtc::Optional<bool>(true); | 567 options.typing_detection = rtc::Optional<bool>(true); |
598 options.adjust_agc_delta = rtc::Optional<int>(0); | 568 options.adjust_agc_delta = rtc::Optional<int>(0); |
599 options.experimental_agc = rtc::Optional<bool>(false); | 569 options.experimental_agc = rtc::Optional<bool>(false); |
600 options.extended_filter_aec = rtc::Optional<bool>(false); | 570 options.extended_filter_aec = rtc::Optional<bool>(false); |
601 options.delay_agnostic_aec = rtc::Optional<bool>(false); | 571 options.delay_agnostic_aec = rtc::Optional<bool>(false); |
602 options.experimental_ns = rtc::Optional<bool>(false); | 572 options.experimental_ns = rtc::Optional<bool>(false); |
603 if (!ApplyOptions(options)) { | 573 bool error = ApplyOptions(options); |
604 return false; | 574 RTC_DCHECK(error); |
605 } | |
606 } | |
607 | |
608 // Print our codec list again for the call diagnostic log. | |
609 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; | |
610 for (const AudioCodec& codec : codecs_) { | |
611 LOG(LS_INFO) << ToString(codec); | |
612 } | 575 } |
613 | 576 |
614 SetDefaultDevices(); | 577 SetDefaultDevices(); |
615 | |
616 initialized_ = true; | |
617 return true; | |
618 } | 578 } |
619 | 579 |
620 void WebRtcVoiceEngine::Terminate() { | 580 WebRtcVoiceEngine::~WebRtcVoiceEngine() { |
621 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 581 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
622 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; | 582 LOG(LS_INFO) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; |
623 initialized_ = false; | |
624 | |
625 StopAecDump(); | 583 StopAecDump(); |
626 | |
627 voe_wrapper_->base()->Terminate(); | 584 voe_wrapper_->base()->Terminate(); |
| 585 webrtc::Trace::SetTraceCallback(nullptr); |
628 } | 586 } |
629 | 587 |
630 rtc::scoped_refptr<webrtc::AudioState> | 588 rtc::scoped_refptr<webrtc::AudioState> |
631 WebRtcVoiceEngine::GetAudioState() const { | 589 WebRtcVoiceEngine::GetAudioState() const { |
632 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 590 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
633 return audio_state_; | 591 return audio_state_; |
634 } | 592 } |
635 | 593 |
636 VoiceMediaChannel* WebRtcVoiceEngine::CreateChannel( | 594 VoiceMediaChannel* WebRtcVoiceEngine::CreateChannel( |
637 webrtc::Call* call, | 595 webrtc::Call* call, |
638 const MediaConfig& config, | 596 const MediaConfig& config, |
639 const AudioOptions& options) { | 597 const AudioOptions& options) { |
640 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 598 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
641 return new WebRtcVoiceMediaChannel(this, config, options, call); | 599 return new WebRtcVoiceMediaChannel(this, config, options, call); |
642 } | 600 } |
643 | 601 |
644 bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { | 602 bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { |
645 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 603 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
646 LOG(LS_INFO) << "ApplyOptions: " << options_in.ToString(); | 604 LOG(LS_INFO) << "WebRtcVoiceEngine::ApplyOptions: " << options_in.ToString(); |
647 AudioOptions options = options_in; // The options are modified below. | 605 AudioOptions options = options_in; // The options are modified below. |
648 | 606 |
649 // kEcConference is AEC with high suppression. | 607 // kEcConference is AEC with high suppression. |
650 webrtc::EcModes ec_mode = webrtc::kEcConference; | 608 webrtc::EcModes ec_mode = webrtc::kEcConference; |
651 webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone; | 609 webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone; |
652 webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog; | 610 webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog; |
653 webrtc::NsModes ns_mode = webrtc::kNsHighSuppression; | 611 webrtc::NsModes ns_mode = webrtc::kNsHighSuppression; |
654 if (options.aecm_generate_comfort_noise) { | 612 if (options.aecm_generate_comfort_noise) { |
655 LOG(LS_VERBOSE) << "Comfort noise explicitly set to " | 613 LOG(LS_VERBOSE) << "Comfort noise explicitly set to " |
656 << *options.aecm_generate_comfort_noise | 614 << *options.aecm_generate_comfort_noise |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1041 << default_agc_config_.targetLeveldBOv << "dB to -" | 999 << default_agc_config_.targetLeveldBOv << "dB to -" |
1042 << config.targetLeveldBOv << "dB"; | 1000 << config.targetLeveldBOv << "dB"; |
1043 | 1001 |
1044 if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) { | 1002 if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) { |
1045 LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv); | 1003 LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv); |
1046 return false; | 1004 return false; |
1047 } | 1005 } |
1048 return true; | 1006 return true; |
1049 } | 1007 } |
1050 | 1008 |
1051 bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm) { | |
1052 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | |
1053 if (initialized_) { | |
1054 LOG(LS_WARNING) << "SetAudioDeviceModule can not be called after Init."; | |
1055 return false; | |
1056 } | |
1057 if (adm_) { | |
1058 adm_->Release(); | |
1059 adm_ = NULL; | |
1060 } | |
1061 if (adm) { | |
1062 adm_ = adm; | |
1063 adm_->AddRef(); | |
1064 } | |
1065 return true; | |
1066 } | |
1067 | |
1068 bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file, | 1009 bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file, |
1069 int64_t max_size_bytes) { | 1010 int64_t max_size_bytes) { |
1070 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1011 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1071 FILE* aec_dump_file_stream = rtc::FdopenPlatformFileForWriting(file); | 1012 FILE* aec_dump_file_stream = rtc::FdopenPlatformFileForWriting(file); |
1072 if (!aec_dump_file_stream) { | 1013 if (!aec_dump_file_stream) { |
1073 LOG(LS_ERROR) << "Could not open AEC dump file stream."; | 1014 LOG(LS_ERROR) << "Could not open AEC dump file stream."; |
1074 if (!rtc::ClosePlatformFile(file)) | 1015 if (!rtc::ClosePlatformFile(file)) |
1075 LOG(LS_WARNING) << "Could not close file."; | 1016 LOG(LS_WARNING) << "Could not close file."; |
1076 return false; | 1017 return false; |
1077 } | 1018 } |
(...skipping 1473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2551 } | 2492 } |
2552 } else { | 2493 } else { |
2553 LOG(LS_INFO) << "Stopping playout for channel #" << channel; | 2494 LOG(LS_INFO) << "Stopping playout for channel #" << channel; |
2554 engine()->voe()->base()->StopPlayout(channel); | 2495 engine()->voe()->base()->StopPlayout(channel); |
2555 } | 2496 } |
2556 return true; | 2497 return true; |
2557 } | 2498 } |
2558 } // namespace cricket | 2499 } // namespace cricket |
2559 | 2500 |
2560 #endif // HAVE_WEBRTC_VOICE | 2501 #endif // HAVE_WEBRTC_VOICE |
OLD | NEW |