| /* | 
 |  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "modules/audio_device/audio_device_impl.h" | 
 |  | 
 | #include <cstdint> | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | #include "absl/base/nullability.h" | 
 | #include "api/audio/audio_device.h" | 
 | #include "api/audio/audio_device_defines.h" | 
 | #include "api/environment/environment.h" | 
 | #include "api/make_ref_counted.h" | 
 | #include "api/scoped_refptr.h" | 
 | #include "modules/audio_device/audio_device_generic.h" | 
 | #include "rtc_base/checks.h" | 
 | #include "rtc_base/logging.h" | 
 | #include "system_wrappers/include/metrics.h" | 
 |  | 
 | #if defined(WEBRTC_WIN) | 
 | #include "modules/audio_device/win/audio_device_core_win.h" | 
 | #elif defined(WEBRTC_LINUX) | 
 | #if defined(WEBRTC_ENABLE_LINUX_ALSA) | 
 | #include "modules/audio_device/linux/audio_device_alsa_linux.h" | 
 | #endif | 
 | #if defined(WEBRTC_ENABLE_LINUX_PULSE) | 
 | #include "modules/audio_device/linux/audio_device_pulse_linux.h" | 
 | #endif | 
 | #elif defined(WEBRTC_IOS) | 
 | #include "sdk/objc/native/src/audio/audio_device_ios.h" | 
 | #elif defined(WEBRTC_MAC) | 
 | #include "modules/audio_device/mac/audio_device_mac.h" | 
 | #endif | 
 | #if defined(WEBRTC_DUMMY_FILE_DEVICES) | 
 | #include "modules/audio_device/dummy/file_audio_device.h" | 
 | #include "modules/audio_device/dummy/file_audio_device_factory.h" | 
 | #endif | 
 | #include "modules/audio_device/dummy/audio_device_dummy.h" | 
 |  | 
 | #define CHECKinitialized_() \ | 
 |   {                         \ | 
 |     if (!initialized_) {    \ | 
 |       return -1;            \ | 
 |     }                       \ | 
 |   } | 
 |  | 
 | #define CHECKinitialized__BOOL() \ | 
 |   {                              \ | 
 |     if (!initialized_) {         \ | 
 |       return false;              \ | 
 |     }                            \ | 
 |   } | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | absl_nullable scoped_refptr<AudioDeviceModuleImpl> | 
 | AudioDeviceModuleImpl::Create(const Environment& env, AudioLayer audio_layer) { | 
 |   RTC_DLOG(LS_INFO) << __FUNCTION__; | 
 |  | 
 |   // The "AudioDeviceModule::kWindowsCoreAudio2" audio layer has its own | 
 |   // dedicated factory method which should be used instead. | 
 |   if (audio_layer == AudioDeviceModule::kWindowsCoreAudio2) { | 
 |     RTC_LOG(LS_ERROR) << "Use the CreateWindowsCoreAudioAudioDeviceModule() " | 
 |                          "factory method instead for this option."; | 
 |     return nullptr; | 
 |   } else if (audio_layer == AudioDeviceModule::kAndroidJavaAudio || | 
 |              audio_layer == AudioDeviceModule::kAndroidOpenSLESAudio || | 
 |              audio_layer == | 
 |                  AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio || | 
 |              audio_layer == kAndroidAAudioAudio || | 
 |              audio_layer == kAndroidJavaInputAndAAudioOutputAudio) { | 
 |     RTC_LOG(LS_ERROR) << "Use the CreateAndroidAudioDeviceModule() " | 
 |                          "factory method instead for this option."; | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Create the generic reference counted (platform independent) implementation. | 
 |   auto audio_device = make_ref_counted<AudioDeviceModuleImpl>(env, audio_layer); | 
 |  | 
 |   // Ensure that the current platform is supported. | 
 |   if (audio_device->CheckPlatform() == -1) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Create the platform-dependent implementation. | 
 |   if (audio_device->CreatePlatformSpecificObjects(env) == -1) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Ensure that the generic audio buffer can communicate with the platform | 
 |   // specific parts. | 
 |   if (audio_device->AttachAudioBuffer() == -1) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   return audio_device; | 
 | } | 
 |  | 
 | AudioDeviceModuleImpl::AudioDeviceModuleImpl(const Environment& env, | 
 |                                              AudioLayer audio_layer) | 
 |     : audio_layer_(audio_layer), audio_device_buffer_(env) { | 
 |   RTC_DLOG(LS_INFO) << __FUNCTION__; | 
 | } | 
 |  | 
 | AudioDeviceModuleImpl::AudioDeviceModuleImpl( | 
 |     const Environment& env, | 
 |     AudioLayer audio_layer, | 
 |     std::unique_ptr<AudioDeviceGeneric> audio_device, | 
 |     bool create_detached) | 
 |     : audio_layer_(audio_layer), | 
 |       audio_device_buffer_(env, create_detached), | 
 |       audio_device_(std::move(audio_device)) { | 
 |   RTC_DLOG(LS_INFO) << __FUNCTION__; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::CheckPlatform() { | 
 |   RTC_DLOG(LS_INFO) << __FUNCTION__; | 
 |   // Ensure that the current platform is supported | 
 |   PlatformType platform(kPlatformNotSupported); | 
 | #if defined(_WIN32) | 
 |   platform = kPlatformWin32; | 
 |   RTC_LOG(LS_INFO) << "current platform is Win32"; | 
 | #elif defined(WEBRTC_ANDROID) | 
 |   platform = kPlatformAndroid; | 
 |   RTC_LOG(LS_INFO) << "current platform is Android"; | 
 | #elif defined(WEBRTC_LINUX) | 
 |   platform = kPlatformLinux; | 
 |   RTC_LOG(LS_INFO) << "current platform is Linux"; | 
 | #elif defined(WEBRTC_IOS) | 
 |   platform = kPlatformIOS; | 
 |   RTC_LOG(LS_INFO) << "current platform is IOS"; | 
 | #elif defined(WEBRTC_MAC) | 
 |   platform = kPlatformMac; | 
 |   RTC_LOG(LS_INFO) << "current platform is Mac"; | 
 | #elif defined(WEBRTC_FUCHSIA) | 
 |   platform = kPlatformFuchsia; | 
 |   RTC_LOG(LS_INFO) << "current platform is Fuchsia"; | 
 | #endif | 
 |   if (platform == kPlatformNotSupported) { | 
 |     RTC_LOG(LS_ERROR) | 
 |         << "current platform is not supported => this module will self " | 
 |            "destruct!"; | 
 |     return -1; | 
 |   } | 
 |   platform_type_ = platform; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::CreatePlatformSpecificObjects( | 
 |     [[maybe_unused]] const Environment& env) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   if (audio_device_ != nullptr) { | 
 |     RTC_LOG(LS_INFO) << "Reusing provided audio device"; | 
 |     return 0; | 
 |   } | 
 | // Dummy ADM implementations if build flags are set. | 
 | #if defined(WEBRTC_DUMMY_AUDIO_BUILD) | 
 |   audio_device_.reset(new AudioDeviceDummy()); | 
 |   RTC_LOG(LS_INFO) << "Dummy Audio APIs will be utilized"; | 
 | #elif defined(WEBRTC_DUMMY_FILE_DEVICES) | 
 |   audio_device_.reset(FileAudioDeviceFactory::CreateFileAudioDevice()); | 
 |   if (audio_device_) { | 
 |     RTC_LOG(LS_INFO) << "Will use file-playing dummy device."; | 
 |   } else { | 
 |     // Create a dummy device instead. | 
 |     audio_device_.reset(new AudioDeviceDummy()); | 
 |     RTC_LOG(LS_INFO) << "Dummy Audio APIs will be utilized"; | 
 |   } | 
 |  | 
 | // Real (non-dummy) ADM implementations. | 
 | #else | 
 |   AudioLayer audio_layer(PlatformAudioLayer()); | 
 | #if defined(WEBRTC_WIN) | 
 |   // Windows ADM implementation. | 
 |   if ((audio_layer == kWindowsCoreAudio) || | 
 |       (audio_layer == kPlatformDefaultAudio)) { | 
 |     RTC_LOG(LS_INFO) << "Attempting to use the Windows Core Audio APIs..."; | 
 |     if (AudioDeviceWindowsCore::CoreAudioIsSupported()) { | 
 |       audio_device_.reset(new AudioDeviceWindowsCore()); | 
 |       RTC_LOG(LS_INFO) << "Windows Core Audio APIs will be utilized"; | 
 |     } | 
 |   } | 
 | #endif | 
 |  | 
 | // Linux ADM implementation. | 
 | // Note that, WEBRTC_ENABLE_LINUX_ALSA is always defined by default when | 
 | // WEBRTC_LINUX is defined. WEBRTC_ENABLE_LINUX_PULSE depends on the | 
 | // 'rtc_include_pulse_audio' build flag. | 
 | // TODO(bugs.webrtc.org/9127): improve support and make it more clear that | 
 | // PulseAudio is the default selection. | 
 | #if !defined(WEBRTC_ANDROID) && defined(WEBRTC_LINUX) | 
 | #if !defined(WEBRTC_ENABLE_LINUX_PULSE) | 
 |   // Build flag 'rtc_include_pulse_audio' is set to false. In this mode: | 
 |   // - kPlatformDefaultAudio => ALSA, and | 
 |   // - kLinuxAlsaAudio => ALSA, and | 
 |   // - kLinuxPulseAudio => Invalid selection. | 
 |   RTC_LOG(LS_WARNING) << "PulseAudio is disabled using build flag."; | 
 |   if ((audio_layer == kLinuxAlsaAudio) || | 
 |       (audio_layer == kPlatformDefaultAudio)) { | 
 |     audio_device_.reset(new AudioDeviceLinuxALSA()); | 
 |     RTC_LOG(LS_INFO) << "Linux ALSA APIs will be utilized."; | 
 |   } | 
 | #else | 
 |   // Build flag 'rtc_include_pulse_audio' is set to true (default). In this | 
 |   // mode: | 
 |   // - kPlatformDefaultAudio => PulseAudio, and | 
 |   // - kLinuxPulseAudio => PulseAudio, and | 
 |   // - kLinuxAlsaAudio => ALSA (supported but not default). | 
 |   RTC_LOG(LS_INFO) << "PulseAudio support is enabled."; | 
 |   if ((audio_layer == kLinuxPulseAudio) || | 
 |       (audio_layer == kPlatformDefaultAudio)) { | 
 |     // Linux PulseAudio implementation is default. | 
 |     audio_device_.reset(new AudioDeviceLinuxPulse()); | 
 |     RTC_LOG(LS_INFO) << "Linux PulseAudio APIs will be utilized"; | 
 |   } else if (audio_layer == kLinuxAlsaAudio) { | 
 |     audio_device_.reset(new AudioDeviceLinuxALSA()); | 
 |     RTC_LOG(LS_WARNING) << "Linux ALSA APIs will be utilized."; | 
 |   } | 
 | #endif  // #if !defined(WEBRTC_ENABLE_LINUX_PULSE) | 
 | #endif  // #if defined(WEBRTC_LINUX) | 
 |  | 
 | // iOS ADM implementation. | 
 | #if defined(WEBRTC_IOS) | 
 |   if (audio_layer == kPlatformDefaultAudio) { | 
 |     audio_device_ = std::make_unique<ios_adm::AudioDeviceIOS>( | 
 |         env, | 
 |         /*bypass_voice_processing=*/false, | 
 |         /*muted_speech_event_handler=*/nullptr, | 
 |         /*render_error_handler=*/nullptr); | 
 |     RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized."; | 
 |   } | 
 | // END #if defined(WEBRTC_IOS) | 
 |  | 
 | // Mac OS X ADM implementation. | 
 | #elif defined(WEBRTC_MAC) | 
 |   if (audio_layer == kPlatformDefaultAudio) { | 
 |     audio_device_.reset(new AudioDeviceMac()); | 
 |     RTC_LOG(LS_INFO) << "Mac OS X Audio APIs will be utilized."; | 
 |   } | 
 | #endif  // WEBRTC_MAC | 
 |  | 
 |   // Dummy ADM implementation. | 
 |   if (audio_layer == kDummyAudio) { | 
 |     audio_device_.reset(new AudioDeviceDummy()); | 
 |     RTC_LOG(LS_INFO) << "Dummy Audio APIs will be utilized."; | 
 |   } | 
 | #endif  // if defined(WEBRTC_DUMMY_AUDIO_BUILD) | 
 |  | 
 |   if (!audio_device_) { | 
 |     RTC_LOG(LS_ERROR) | 
 |         << "Failed to create the platform specific ADM implementation."; | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::AttachAudioBuffer() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   audio_device_->AttachAudioBuffer(&audio_device_buffer_); | 
 |   return 0; | 
 | } | 
 |  | 
 | AudioDeviceModuleImpl::~AudioDeviceModuleImpl() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::ActiveAudioLayer(AudioLayer* audioLayer) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   AudioLayer activeAudio; | 
 |   if (audio_device_->ActiveAudioLayer(activeAudio) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *audioLayer = activeAudio; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::Init() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   if (initialized_) | 
 |     return 0; | 
 |   RTC_CHECK(audio_device_); | 
 |   AudioDeviceGeneric::InitStatus status = audio_device_->Init(); | 
 |   RTC_HISTOGRAM_ENUMERATION( | 
 |       "WebRTC.Audio.InitializationResult", static_cast<int>(status), | 
 |       static_cast<int>(AudioDeviceGeneric::InitStatus::NUM_STATUSES)); | 
 |   if (status != AudioDeviceGeneric::InitStatus::OK) { | 
 |     RTC_LOG(LS_ERROR) << "Audio device initialization failed."; | 
 |     return -1; | 
 |   } | 
 |   initialized_ = true; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::Terminate() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   if (!initialized_) | 
 |     return 0; | 
 |   if (audio_device_->Terminate() == -1) { | 
 |     return -1; | 
 |   } | 
 |   initialized_ = false; | 
 |   return 0; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::Initialized() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << ": " << initialized_; | 
 |   return initialized_; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::InitSpeaker() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->InitSpeaker(); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::InitMicrophone() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->InitMicrophone(); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SpeakerVolumeIsAvailable(bool* available) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->SpeakerVolumeIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetSpeakerVolume(uint32_t volume) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << volume << ")"; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->SetSpeakerVolume(volume); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SpeakerVolume(uint32_t* volume) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   uint32_t level = 0; | 
 |   if (audio_device_->SpeakerVolume(level) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *volume = level; | 
 |   RTC_LOG(LS_INFO) << "output: " << *volume; | 
 |   return 0; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::SpeakerIsInitialized() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   bool isInitialized = audio_device_->SpeakerIsInitialized(); | 
 |   RTC_LOG(LS_INFO) << "output: " << isInitialized; | 
 |   return isInitialized; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::MicrophoneIsInitialized() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   bool isInitialized = audio_device_->MicrophoneIsInitialized(); | 
 |   RTC_LOG(LS_INFO) << "output: " << isInitialized; | 
 |   return isInitialized; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MaxSpeakerVolume(uint32_t* maxVolume) const { | 
 |   CHECKinitialized_(); | 
 |   uint32_t maxVol = 0; | 
 |   if (audio_device_->MaxSpeakerVolume(maxVol) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *maxVolume = maxVol; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MinSpeakerVolume(uint32_t* minVolume) const { | 
 |   CHECKinitialized_(); | 
 |   uint32_t minVol = 0; | 
 |   if (audio_device_->MinSpeakerVolume(minVol) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *minVolume = minVol; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SpeakerMuteIsAvailable(bool* available) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->SpeakerMuteIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetSpeakerMute(bool enable) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << enable << ")"; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->SetSpeakerMute(enable); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SpeakerMute(bool* enabled) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool muted = false; | 
 |   if (audio_device_->SpeakerMute(muted) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *enabled = muted; | 
 |   RTC_LOG(LS_INFO) << "output: " << muted; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MicrophoneMuteIsAvailable(bool* available) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->MicrophoneMuteIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetMicrophoneMute(bool enable) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << enable << ")"; | 
 |   CHECKinitialized_(); | 
 |   return (audio_device_->SetMicrophoneMute(enable)); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MicrophoneMute(bool* enabled) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool muted = false; | 
 |   if (audio_device_->MicrophoneMute(muted) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *enabled = muted; | 
 |   RTC_LOG(LS_INFO) << "output: " << muted; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MicrophoneVolumeIsAvailable(bool* available) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->MicrophoneVolumeIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetMicrophoneVolume(uint32_t volume) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << volume << ")"; | 
 |   CHECKinitialized_(); | 
 |   return (audio_device_->SetMicrophoneVolume(volume)); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MicrophoneVolume(uint32_t* volume) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   uint32_t level = 0; | 
 |   if (audio_device_->MicrophoneVolume(level) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *volume = level; | 
 |   RTC_LOG(LS_INFO) << "output: " << *volume; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StereoRecordingIsAvailable( | 
 |     bool* available) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->StereoRecordingIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetStereoRecording(bool enable) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << enable << ")"; | 
 |   CHECKinitialized_(); | 
 |   if (audio_device_->RecordingIsInitialized()) { | 
 |     RTC_LOG(LS_ERROR) | 
 |         << "unable to set stereo mode after recording is initialized"; | 
 |     return -1; | 
 |   } | 
 |   if (audio_device_->SetStereoRecording(enable) == -1) { | 
 |     if (enable) { | 
 |       RTC_LOG(LS_WARNING) << "failed to enable stereo recording"; | 
 |     } | 
 |     return -1; | 
 |   } | 
 |   int8_t nChannels(1); | 
 |   if (enable) { | 
 |     nChannels = 2; | 
 |   } | 
 |   audio_device_buffer_.SetRecordingChannels(nChannels); | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StereoRecording(bool* enabled) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool stereo = false; | 
 |   if (audio_device_->StereoRecording(stereo) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *enabled = stereo; | 
 |   RTC_LOG(LS_INFO) << "output: " << stereo; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StereoPlayoutIsAvailable(bool* available) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->StereoPlayoutIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetStereoPlayout(bool enable) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << enable << ")"; | 
 |   CHECKinitialized_(); | 
 |   if (audio_device_->PlayoutIsInitialized()) { | 
 |     RTC_LOG(LS_ERROR) | 
 |         << "unable to set stereo mode while playing side is initialized"; | 
 |     return -1; | 
 |   } | 
 |   if (audio_device_->SetStereoPlayout(enable)) { | 
 |     RTC_LOG(LS_WARNING) << "stereo playout is not supported"; | 
 |     return -1; | 
 |   } | 
 |   int8_t nChannels(1); | 
 |   if (enable) { | 
 |     nChannels = 2; | 
 |   } | 
 |   audio_device_buffer_.SetPlayoutChannels(nChannels); | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StereoPlayout(bool* enabled) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool stereo = false; | 
 |   if (audio_device_->StereoPlayout(stereo) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *enabled = stereo; | 
 |   RTC_LOG(LS_INFO) << "output: " << stereo; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::PlayoutIsAvailable(bool* available) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->PlayoutIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::RecordingIsAvailable(bool* available) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   bool isAvailable = false; | 
 |   if (audio_device_->RecordingIsAvailable(isAvailable) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *available = isAvailable; | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MaxMicrophoneVolume(uint32_t* maxVolume) const { | 
 |   CHECKinitialized_(); | 
 |   uint32_t maxVol(0); | 
 |   if (audio_device_->MaxMicrophoneVolume(maxVol) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *maxVolume = maxVol; | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::MinMicrophoneVolume(uint32_t* minVolume) const { | 
 |   CHECKinitialized_(); | 
 |   uint32_t minVol(0); | 
 |   if (audio_device_->MinMicrophoneVolume(minVol) == -1) { | 
 |     return -1; | 
 |   } | 
 |   *minVolume = minVol; | 
 |   return 0; | 
 | } | 
 |  | 
 | int16_t AudioDeviceModuleImpl::PlayoutDevices() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   uint16_t nPlayoutDevices = audio_device_->PlayoutDevices(); | 
 |   RTC_LOG(LS_INFO) << "output: " << nPlayoutDevices; | 
 |   return (int16_t)(nPlayoutDevices); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetPlayoutDevice(uint16_t index) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << index << ")"; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->SetPlayoutDevice(index); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetPlayoutDevice(WindowsDeviceType device) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->SetPlayoutDevice(device); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::PlayoutDeviceName( | 
 |     uint16_t index, | 
 |     char name[kAdmMaxDeviceNameSize], | 
 |     char guid[kAdmMaxGuidSize]) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << index << ", ...)"; | 
 |   CHECKinitialized_(); | 
 |   if (name == nullptr) { | 
 |     return -1; | 
 |   } | 
 |   if (audio_device_->PlayoutDeviceName(index, name, guid) == -1) { | 
 |     return -1; | 
 |   } | 
 |   if (name != nullptr) { | 
 |     RTC_LOG(LS_INFO) << "output: name = " << name; | 
 |   } | 
 |   if (guid != nullptr) { | 
 |     RTC_LOG(LS_INFO) << "output: guid = " << guid; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::RecordingDeviceName( | 
 |     uint16_t index, | 
 |     char name[kAdmMaxDeviceNameSize], | 
 |     char guid[kAdmMaxGuidSize]) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << index << ", ...)"; | 
 |   CHECKinitialized_(); | 
 |   if (name == nullptr) { | 
 |     return -1; | 
 |   } | 
 |   if (audio_device_->RecordingDeviceName(index, name, guid) == -1) { | 
 |     return -1; | 
 |   } | 
 |   if (name != nullptr) { | 
 |     RTC_LOG(LS_INFO) << "output: name = " << name; | 
 |   } | 
 |   if (guid != nullptr) { | 
 |     RTC_LOG(LS_INFO) << "output: guid = " << guid; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int16_t AudioDeviceModuleImpl::RecordingDevices() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   uint16_t nRecordingDevices = audio_device_->RecordingDevices(); | 
 |   RTC_LOG(LS_INFO) << "output: " << nRecordingDevices; | 
 |   return (int16_t)nRecordingDevices; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetRecordingDevice(uint16_t index) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << index << ")"; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->SetRecordingDevice(index); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::SetRecordingDevice(WindowsDeviceType device) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   return audio_device_->SetRecordingDevice(device); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::InitPlayout() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   if (PlayoutIsInitialized()) { | 
 |     return 0; | 
 |   } | 
 |   int32_t result = audio_device_->InitPlayout(); | 
 |   RTC_LOG(LS_INFO) << "output: " << result; | 
 |   RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.InitPlayoutSuccess", | 
 |                         static_cast<int>(result == 0)); | 
 |   return result; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::InitRecording() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   if (RecordingIsInitialized()) { | 
 |     return 0; | 
 |   } | 
 |   int32_t result = audio_device_->InitRecording(); | 
 |   RTC_LOG(LS_INFO) << "output: " << result; | 
 |   RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.InitRecordingSuccess", | 
 |                         static_cast<int>(result == 0)); | 
 |   return result; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::PlayoutIsInitialized() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   return audio_device_->PlayoutIsInitialized(); | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::RecordingIsInitialized() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   return audio_device_->RecordingIsInitialized(); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StartPlayout() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   if (Playing()) { | 
 |     return 0; | 
 |   } | 
 |   audio_device_buffer_.StartPlayout(); | 
 |   int32_t result = audio_device_->StartPlayout(); | 
 |   RTC_LOG(LS_INFO) << "output: " << result; | 
 |   RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.StartPlayoutSuccess", | 
 |                         static_cast<int>(result == 0)); | 
 |   return result; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StopPlayout() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   int32_t result = audio_device_->StopPlayout(); | 
 |   audio_device_buffer_.StopPlayout(); | 
 |   RTC_LOG(LS_INFO) << "output: " << result; | 
 |   RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.StopPlayoutSuccess", | 
 |                         static_cast<int>(result == 0)); | 
 |   return result; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::Playing() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   return audio_device_->Playing(); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StartRecording() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   if (Recording()) { | 
 |     return 0; | 
 |   } | 
 |   audio_device_buffer_.StartRecording(); | 
 |   int32_t result = audio_device_->StartRecording(); | 
 |   RTC_LOG(LS_INFO) << "output: " << result; | 
 |   RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.StartRecordingSuccess", | 
 |                         static_cast<int>(result == 0)); | 
 |   return result; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::StopRecording() { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized_(); | 
 |   int32_t result = audio_device_->StopRecording(); | 
 |   audio_device_buffer_.StopRecording(); | 
 |   RTC_LOG(LS_INFO) << "output: " << result; | 
 |   RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.StopRecordingSuccess", | 
 |                         static_cast<int>(result == 0)); | 
 |   return result; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::Recording() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   return audio_device_->Recording(); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::RegisterAudioCallback( | 
 |     AudioTransport* audioCallback) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   return audio_device_buffer_.RegisterAudioCallback(audioCallback); | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::PlayoutDelay(uint16_t* delayMS) const { | 
 |   CHECKinitialized_(); | 
 |   uint16_t delay = 0; | 
 |   if (audio_device_->PlayoutDelay(delay) == -1) { | 
 |     RTC_LOG(LS_ERROR) << "failed to retrieve the playout delay"; | 
 |     return -1; | 
 |   } | 
 |   *delayMS = delay; | 
 |   return 0; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::BuiltInAECIsAvailable() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   bool isAvailable = audio_device_->BuiltInAECIsAvailable(); | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return isAvailable; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::EnableBuiltInAEC(bool enable) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << enable << ")"; | 
 |   CHECKinitialized_(); | 
 |   int32_t ok = audio_device_->EnableBuiltInAEC(enable); | 
 |   RTC_LOG(LS_INFO) << "output: " << ok; | 
 |   return ok; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::BuiltInAGCIsAvailable() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   bool isAvailable = audio_device_->BuiltInAGCIsAvailable(); | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return isAvailable; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::EnableBuiltInAGC(bool enable) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << enable << ")"; | 
 |   CHECKinitialized_(); | 
 |   int32_t ok = audio_device_->EnableBuiltInAGC(enable); | 
 |   RTC_LOG(LS_INFO) << "output: " << ok; | 
 |   return ok; | 
 | } | 
 |  | 
 | bool AudioDeviceModuleImpl::BuiltInNSIsAvailable() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   CHECKinitialized__BOOL(); | 
 |   bool isAvailable = audio_device_->BuiltInNSIsAvailable(); | 
 |   RTC_LOG(LS_INFO) << "output: " << isAvailable; | 
 |   return isAvailable; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::EnableBuiltInNS(bool enable) { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << enable << ")"; | 
 |   CHECKinitialized_(); | 
 |   int32_t ok = audio_device_->EnableBuiltInNS(enable); | 
 |   RTC_LOG(LS_INFO) << "output: " << ok; | 
 |   return ok; | 
 | } | 
 |  | 
 | int32_t AudioDeviceModuleImpl::GetPlayoutUnderrunCount() const { | 
 |   CHECKinitialized_(); | 
 |   int32_t underrunCount = audio_device_->GetPlayoutUnderrunCount(); | 
 |   return underrunCount; | 
 | } | 
 |  | 
 | #if defined(WEBRTC_IOS) | 
 | int AudioDeviceModuleImpl::GetPlayoutAudioParameters( | 
 |     AudioParameters* params) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   int r = audio_device_->GetPlayoutAudioParameters(params); | 
 |   RTC_LOG(LS_INFO) << "output: " << r; | 
 |   return r; | 
 | } | 
 |  | 
 | int AudioDeviceModuleImpl::GetRecordAudioParameters( | 
 |     AudioParameters* params) const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   int r = audio_device_->GetRecordAudioParameters(params); | 
 |   RTC_LOG(LS_INFO) << "output: " << r; | 
 |   return r; | 
 | } | 
 | #endif  // WEBRTC_IOS | 
 |  | 
 | AudioDeviceModuleImpl::PlatformType AudioDeviceModuleImpl::Platform() const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   return platform_type_; | 
 | } | 
 |  | 
 | AudioDeviceModule::AudioLayer AudioDeviceModuleImpl::PlatformAudioLayer() | 
 |     const { | 
 |   RTC_LOG(LS_INFO) << __FUNCTION__; | 
 |   return audio_layer_; | 
 | } | 
 |  | 
 | }  // namespace webrtc |