1/* 2 * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 * 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 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "objc_audio_device.h" 12#include "objc_audio_device_delegate.h" 13 14#import "components/audio/RTCAudioDevice.h" 15#include "modules/audio_device/fine_audio_buffer.h" 16 17#include "api/task_queue/default_task_queue_factory.h" 18#include "rtc_base/logging.h" 19#include "rtc_base/numerics/safe_minmax.h" 20#include "rtc_base/time_utils.h" 21 22namespace { 23 24webrtc::AudioParameters RecordParameters(id<RTC_OBJC_TYPE(RTCAudioDevice)> audio_device) { 25 const double sample_rate = static_cast<int>([audio_device deviceInputSampleRate]); 26 const size_t channels = static_cast<size_t>([audio_device inputNumberOfChannels]); 27 const size_t frames_per_buffer = 28 static_cast<size_t>(sample_rate * [audio_device inputIOBufferDuration] + .5); 29 return webrtc::AudioParameters(sample_rate, channels, frames_per_buffer); 30} 31 32webrtc::AudioParameters PlayoutParameters(id<RTC_OBJC_TYPE(RTCAudioDevice)> audio_device) { 33 const double sample_rate = static_cast<int>([audio_device deviceOutputSampleRate]); 34 const size_t channels = static_cast<size_t>([audio_device outputNumberOfChannels]); 35 const size_t frames_per_buffer = 36 static_cast<size_t>(sample_rate * [audio_device outputIOBufferDuration] + .5); 37 return webrtc::AudioParameters(sample_rate, channels, frames_per_buffer); 38} 39 40} // namespace 41 42namespace webrtc { 43namespace objc_adm { 44 45ObjCAudioDeviceModule::ObjCAudioDeviceModule(id<RTC_OBJC_TYPE(RTCAudioDevice)> audio_device) 46 : audio_device_(audio_device), task_queue_factory_(CreateDefaultTaskQueueFactory()) { 47 RTC_DLOG_F(LS_VERBOSE) << ""; 48 RTC_DCHECK(audio_device_); 49 thread_checker_.Detach(); 50 io_playout_thread_checker_.Detach(); 51 io_record_thread_checker_.Detach(); 52} 53 54ObjCAudioDeviceModule::~ObjCAudioDeviceModule() { 55 RTC_DLOG_F(LS_VERBOSE) << ""; 56} 57 58int32_t ObjCAudioDeviceModule::RegisterAudioCallback(AudioTransport* audioCallback) { 59 RTC_DLOG_F(LS_VERBOSE) << ""; 60 RTC_DCHECK(audio_device_buffer_); 61 return audio_device_buffer_->RegisterAudioCallback(audioCallback); 62} 63 64int32_t ObjCAudioDeviceModule::Init() { 65 RTC_DLOG_F(LS_VERBOSE) << ""; 66 RTC_DCHECK_RUN_ON(&thread_checker_); 67 68 if (Initialized()) { 69 RTC_LOG_F(LS_INFO) << "Already initialized"; 70 return 0; 71 } 72 io_playout_thread_checker_.Detach(); 73 io_record_thread_checker_.Detach(); 74 75 thread_ = rtc::Thread::Current(); 76 audio_device_buffer_.reset(new webrtc::AudioDeviceBuffer(task_queue_factory_.get())); 77 78 if (![audio_device_ isInitialized]) { 79 if (audio_device_delegate_ == nil) { 80 audio_device_delegate_ = [[ObjCAudioDeviceDelegate alloc] 81 initWithAudioDeviceModule:rtc::scoped_refptr<ObjCAudioDeviceModule>(this) 82 audioDeviceThread:thread_]; 83 } 84 85 if (![audio_device_ initializeWithDelegate:audio_device_delegate_]) { 86 RTC_LOG_F(LS_WARNING) << "Failed to initialize audio device"; 87 [audio_device_delegate_ resetAudioDeviceModule]; 88 audio_device_delegate_ = nil; 89 return -1; 90 } 91 } 92 93 playout_parameters_.reset([audio_device_delegate_ preferredOutputSampleRate], 1); 94 UpdateOutputAudioDeviceBuffer(); 95 96 record_parameters_.reset([audio_device_delegate_ preferredInputSampleRate], 1); 97 UpdateInputAudioDeviceBuffer(); 98 99 is_initialized_ = true; 100 101 RTC_LOG_F(LS_INFO) << "Did initialize"; 102 return 0; 103} 104 105int32_t ObjCAudioDeviceModule::Terminate() { 106 RTC_DLOG_F(LS_VERBOSE) << ""; 107 RTC_DCHECK_RUN_ON(&thread_checker_); 108 109 if (!Initialized()) { 110 RTC_LOG_F(LS_INFO) << "Not initialized"; 111 return 0; 112 } 113 114 if ([audio_device_ isInitialized]) { 115 if (![audio_device_ terminateDevice]) { 116 RTC_LOG_F(LS_ERROR) << "Failed to terminate audio device"; 117 return -1; 118 } 119 } 120 121 if (audio_device_delegate_ != nil) { 122 [audio_device_delegate_ resetAudioDeviceModule]; 123 audio_device_delegate_ = nil; 124 } 125 126 is_initialized_ = false; 127 is_playout_initialized_ = false; 128 is_recording_initialized_ = false; 129 thread_ = nullptr; 130 131 RTC_LOG_F(LS_INFO) << "Did terminate"; 132 return 0; 133} 134 135bool ObjCAudioDeviceModule::Initialized() const { 136 RTC_DLOG_F(LS_VERBOSE) << ""; 137 RTC_DCHECK_RUN_ON(&thread_checker_); 138 return is_initialized_ && [audio_device_ isInitialized]; 139} 140 141int32_t ObjCAudioDeviceModule::PlayoutIsAvailable(bool* available) { 142 RTC_DLOG_F(LS_VERBOSE) << ""; 143 RTC_DCHECK_RUN_ON(&thread_checker_); 144 *available = Initialized(); 145 return 0; 146} 147 148bool ObjCAudioDeviceModule::PlayoutIsInitialized() const { 149 RTC_DLOG_F(LS_VERBOSE) << ""; 150 RTC_DCHECK_RUN_ON(&thread_checker_); 151 return Initialized() && is_playout_initialized_ && [audio_device_ isPlayoutInitialized]; 152} 153 154int32_t ObjCAudioDeviceModule::InitPlayout() { 155 RTC_DLOG_F(LS_VERBOSE) << ""; 156 RTC_DCHECK_RUN_ON(&thread_checker_); 157 if (!Initialized()) { 158 return -1; 159 } 160 if (PlayoutIsInitialized()) { 161 return 0; 162 } 163 RTC_DCHECK(!playing_.load()); 164 165 if (![audio_device_ isPlayoutInitialized]) { 166 if (![audio_device_ initializePlayout]) { 167 RTC_LOG_F(LS_ERROR) << "Failed to initialize audio device playout"; 168 return -1; 169 } 170 } 171 172 if (UpdateAudioParameters(playout_parameters_, PlayoutParameters(audio_device_))) { 173 UpdateOutputAudioDeviceBuffer(); 174 } 175 176 is_playout_initialized_ = true; 177 RTC_LOG_F(LS_INFO) << "Did initialize playout"; 178 return 0; 179} 180 181bool ObjCAudioDeviceModule::Playing() const { 182 RTC_DLOG_F(LS_VERBOSE) << ""; 183 RTC_DCHECK_RUN_ON(&thread_checker_); 184 return playing_.load() && [audio_device_ isPlaying]; 185} 186 187int32_t ObjCAudioDeviceModule::StartPlayout() { 188 RTC_DLOG_F(LS_VERBOSE) << ""; 189 RTC_DCHECK_RUN_ON(&thread_checker_); 190 if (!PlayoutIsInitialized()) { 191 return -1; 192 } 193 if (Playing()) { 194 return 0; 195 } 196 197 audio_device_buffer_->StartPlayout(); 198 if (playout_fine_audio_buffer_) { 199 playout_fine_audio_buffer_->ResetPlayout(); 200 } 201 if (![audio_device_ startPlayout]) { 202 RTC_LOG_F(LS_ERROR) << "Failed to start audio device playout"; 203 return -1; 204 } 205 playing_.store(true, std::memory_order_release); 206 RTC_LOG_F(LS_INFO) << "Did start playout"; 207 return 0; 208} 209 210int32_t ObjCAudioDeviceModule::StopPlayout() { 211 RTC_DLOG_F(LS_VERBOSE) << ""; 212 RTC_DCHECK_RUN_ON(&thread_checker_); 213 214 if (![audio_device_ stopPlayout]) { 215 RTC_LOG_F(LS_WARNING) << "Failed to stop playout"; 216 return -1; 217 } 218 219 audio_device_buffer_->StopPlayout(); 220 playing_.store(false, std::memory_order_release); 221 RTC_LOG_F(LS_INFO) << "Did stop playout"; 222 return 0; 223} 224 225int32_t ObjCAudioDeviceModule::PlayoutDelay(uint16_t* delayMS) const { 226 RTC_DCHECK_RUN_ON(&thread_checker_); 227 *delayMS = static_cast<uint16_t>(rtc::SafeClamp<int>( 228 cached_playout_delay_ms_.load(), 0, std::numeric_limits<uint16_t>::max())); 229 return 0; 230} 231 232int32_t ObjCAudioDeviceModule::RecordingIsAvailable(bool* available) { 233 RTC_DLOG_F(LS_VERBOSE) << ""; 234 RTC_DCHECK_RUN_ON(&thread_checker_); 235 *available = Initialized(); 236 return 0; 237} 238 239bool ObjCAudioDeviceModule::RecordingIsInitialized() const { 240 RTC_DLOG_F(LS_VERBOSE) << ""; 241 RTC_DCHECK_RUN_ON(&thread_checker_); 242 return Initialized() && is_recording_initialized_ && [audio_device_ isRecordingInitialized]; 243} 244 245int32_t ObjCAudioDeviceModule::InitRecording() { 246 RTC_DLOG_F(LS_VERBOSE) << ""; 247 RTC_DCHECK_RUN_ON(&thread_checker_); 248 if (!Initialized()) { 249 return -1; 250 } 251 if (RecordingIsInitialized()) { 252 return 0; 253 } 254 RTC_DCHECK(!recording_.load()); 255 256 if (![audio_device_ isRecordingInitialized]) { 257 if (![audio_device_ initializeRecording]) { 258 RTC_LOG_F(LS_ERROR) << "Failed to initialize audio device recording"; 259 return -1; 260 } 261 } 262 263 if (UpdateAudioParameters(record_parameters_, RecordParameters(audio_device_))) { 264 UpdateInputAudioDeviceBuffer(); 265 } 266 267 is_recording_initialized_ = true; 268 RTC_LOG_F(LS_INFO) << "Did initialize recording"; 269 return 0; 270} 271 272bool ObjCAudioDeviceModule::Recording() const { 273 RTC_DLOG_F(LS_VERBOSE) << ""; 274 RTC_DCHECK_RUN_ON(&thread_checker_); 275 return recording_.load() && [audio_device_ isRecording]; 276} 277 278int32_t ObjCAudioDeviceModule::StartRecording() { 279 RTC_DLOG_F(LS_VERBOSE) << ""; 280 RTC_DCHECK_RUN_ON(&thread_checker_); 281 if (!RecordingIsInitialized()) { 282 return -1; 283 } 284 if (Recording()) { 285 return 0; 286 } 287 288 audio_device_buffer_->StartRecording(); 289 if (record_fine_audio_buffer_) { 290 record_fine_audio_buffer_->ResetRecord(); 291 } 292 293 if (![audio_device_ startRecording]) { 294 RTC_LOG_F(LS_ERROR) << "Failed to start audio device recording"; 295 return -1; 296 } 297 recording_.store(true, std::memory_order_release); 298 RTC_LOG_F(LS_INFO) << "Did start recording"; 299 return 0; 300} 301 302int32_t ObjCAudioDeviceModule::StopRecording() { 303 RTC_DLOG_F(LS_VERBOSE) << ""; 304 RTC_DCHECK_RUN_ON(&thread_checker_); 305 306 if (![audio_device_ stopRecording]) { 307 RTC_LOG_F(LS_WARNING) << "Failed to stop recording"; 308 return -1; 309 } 310 audio_device_buffer_->StopRecording(); 311 recording_.store(false, std::memory_order_release); 312 RTC_LOG_F(LS_INFO) << "Did stop recording"; 313 return 0; 314} 315 316#if defined(WEBRTC_IOS) 317 318int ObjCAudioDeviceModule::GetPlayoutAudioParameters(AudioParameters* params) const { 319 RTC_DLOG_F(LS_VERBOSE) << ""; 320 RTC_DCHECK(playout_parameters_.is_valid()); 321 RTC_DCHECK_RUN_ON(&thread_checker_); 322 *params = playout_parameters_; 323 return 0; 324} 325 326int ObjCAudioDeviceModule::GetRecordAudioParameters(AudioParameters* params) const { 327 RTC_DLOG_F(LS_VERBOSE) << ""; 328 RTC_DCHECK(record_parameters_.is_valid()); 329 RTC_DCHECK_RUN_ON(&thread_checker_); 330 *params = record_parameters_; 331 return 0; 332} 333 334#endif // WEBRTC_IOS 335 336void ObjCAudioDeviceModule::UpdateOutputAudioDeviceBuffer() { 337 RTC_DLOG_F(LS_VERBOSE) << ""; 338 RTC_DCHECK_RUN_ON(&thread_checker_); 339 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first"; 340 341 RTC_DCHECK_GT(playout_parameters_.sample_rate(), 0); 342 RTC_DCHECK(playout_parameters_.channels() == 1 || playout_parameters_.channels() == 2); 343 344 audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate()); 345 audio_device_buffer_->SetPlayoutChannels(playout_parameters_.channels()); 346 playout_fine_audio_buffer_.reset(new FineAudioBuffer(audio_device_buffer_.get())); 347} 348 349void ObjCAudioDeviceModule::UpdateInputAudioDeviceBuffer() { 350 RTC_DLOG_F(LS_VERBOSE) << ""; 351 RTC_DCHECK_RUN_ON(&thread_checker_); 352 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first"; 353 354 RTC_DCHECK_GT(record_parameters_.sample_rate(), 0); 355 RTC_DCHECK(record_parameters_.channels() == 1 || record_parameters_.channels() == 2); 356 357 audio_device_buffer_->SetRecordingSampleRate(record_parameters_.sample_rate()); 358 audio_device_buffer_->SetRecordingChannels(record_parameters_.channels()); 359 record_fine_audio_buffer_.reset(new FineAudioBuffer(audio_device_buffer_.get())); 360} 361 362void ObjCAudioDeviceModule::UpdateAudioDelay(std::atomic<int>& delay_ms, 363 const NSTimeInterval device_latency) { 364 RTC_DLOG_F(LS_VERBOSE) << ""; 365 RTC_DCHECK_RUN_ON(&thread_checker_); 366 int latency_ms = static_cast<int>(rtc::kNumMillisecsPerSec * device_latency); 367 if (latency_ms <= 0) { 368 return; 369 } 370 const int old_latency_ms = delay_ms.exchange(latency_ms); 371 if (old_latency_ms != latency_ms) { 372 RTC_LOG_F(LS_INFO) << "Did change audio IO latency from: " << old_latency_ms 373 << " ms to: " << latency_ms << " ms"; 374 } 375} 376 377bool ObjCAudioDeviceModule::UpdateAudioParameters(AudioParameters& params, 378 const AudioParameters& device_params) { 379 RTC_DLOG_F(LS_VERBOSE) << ""; 380 RTC_DCHECK_RUN_ON(&thread_checker_); 381 if (!device_params.is_complete()) { 382 RTC_LOG_F(LS_INFO) << "Device params are incomplete: " << device_params.ToString(); 383 return false; 384 } 385 if (params.channels() == device_params.channels() && 386 params.frames_per_buffer() == device_params.frames_per_buffer() && 387 params.sample_rate() == device_params.sample_rate()) { 388 RTC_LOG_F(LS_INFO) << "Device params: " << device_params.ToString() 389 << " are not different from: " << params.ToString(); 390 return false; 391 } 392 393 RTC_LOG_F(LS_INFO) << "Audio params will be changed from: " << params.ToString() 394 << " to: " << device_params.ToString(); 395 params.reset( 396 device_params.sample_rate(), device_params.channels(), device_params.frames_per_buffer()); 397 return true; 398} 399 400OSStatus ObjCAudioDeviceModule::OnDeliverRecordedData( 401 AudioUnitRenderActionFlags* flags, 402 const AudioTimeStamp* time_stamp, 403 NSInteger bus_number, 404 UInt32 num_frames, 405 const AudioBufferList* io_data, 406 void* render_context, 407 RTC_OBJC_TYPE(RTCAudioDeviceRenderRecordedDataBlock) render_block) { 408 RTC_DCHECK_RUN_ON(&io_record_thread_checker_); 409 OSStatus result = noErr; 410 // Simply return if recording is not enabled. 411 if (!recording_.load()) return result; 412 413 if (io_data != nullptr) { 414 // AudioBuffer already fullfilled with audio data 415 RTC_DCHECK_EQ(1, io_data->mNumberBuffers); 416 const AudioBuffer* audio_buffer = &io_data->mBuffers[0]; 417 RTC_DCHECK(audio_buffer->mNumberChannels == 1 || audio_buffer->mNumberChannels == 2); 418 419 record_fine_audio_buffer_->DeliverRecordedData( 420 rtc::ArrayView<const int16_t>(static_cast<int16_t*>(audio_buffer->mData), num_frames), 421 cached_recording_delay_ms_.load()); 422 return noErr; 423 } 424 RTC_DCHECK(render_block != nullptr) << "Either io_data or render_block must be provided"; 425 426 // Set the size of our own audio buffer and clear it first to avoid copying 427 // in combination with potential reallocations. 428 // On real iOS devices, the size will only be set once (at first callback). 429 const int channels_count = record_parameters_.channels(); 430 record_audio_buffer_.Clear(); 431 record_audio_buffer_.SetSize(num_frames * channels_count); 432 433 // Allocate AudioBuffers to be used as storage for the received audio. 434 // The AudioBufferList structure works as a placeholder for the 435 // AudioBuffer structure, which holds a pointer to the actual data buffer 436 // in `record_audio_buffer_`. Recorded audio will be rendered into this memory 437 // at each input callback when calling `render_block`. 438 AudioBufferList audio_buffer_list; 439 audio_buffer_list.mNumberBuffers = 1; 440 AudioBuffer* audio_buffer = &audio_buffer_list.mBuffers[0]; 441 audio_buffer->mNumberChannels = channels_count; 442 audio_buffer->mDataByteSize = 443 record_audio_buffer_.size() * sizeof(decltype(record_audio_buffer_)::value_type); 444 audio_buffer->mData = reinterpret_cast<int8_t*>(record_audio_buffer_.data()); 445 446 // Obtain the recorded audio samples by initiating a rendering cycle into own buffer. 447 result = 448 render_block(flags, time_stamp, bus_number, num_frames, &audio_buffer_list, render_context); 449 if (result != noErr) { 450 RTC_LOG_F(LS_ERROR) << "Failed to render audio: " << result; 451 return result; 452 } 453 454 // Get a pointer to the recorded audio and send it to the WebRTC ADB. 455 // Use the FineAudioBuffer instance to convert between native buffer size 456 // and the 10ms buffer size used by WebRTC. 457 record_fine_audio_buffer_->DeliverRecordedData(record_audio_buffer_, 458 cached_recording_delay_ms_.load()); 459 return noErr; 460} 461 462OSStatus ObjCAudioDeviceModule::OnGetPlayoutData(AudioUnitRenderActionFlags* flags, 463 const AudioTimeStamp* time_stamp, 464 NSInteger bus_number, 465 UInt32 num_frames, 466 AudioBufferList* io_data) { 467 RTC_DCHECK_RUN_ON(&io_playout_thread_checker_); 468 // Verify 16-bit, noninterleaved mono or stereo PCM signal format. 469 RTC_DCHECK_EQ(1, io_data->mNumberBuffers); 470 AudioBuffer* audio_buffer = &io_data->mBuffers[0]; 471 RTC_DCHECK(audio_buffer->mNumberChannels == 1 || audio_buffer->mNumberChannels == 2); 472 RTC_DCHECK_EQ(audio_buffer->mDataByteSize, 473 sizeof(int16_t) * num_frames * audio_buffer->mNumberChannels); 474 475 // Produce silence and give player a hint about it if playout is not 476 // activated. 477 if (!playing_.load()) { 478 *flags |= kAudioUnitRenderAction_OutputIsSilence; 479 memset(static_cast<int8_t*>(audio_buffer->mData), 0, audio_buffer->mDataByteSize); 480 return noErr; 481 } 482 483 // Read decoded 16-bit PCM samples from WebRTC into the 484 // `io_data` destination buffer. 485 playout_fine_audio_buffer_->GetPlayoutData( 486 rtc::ArrayView<int16_t>(static_cast<int16_t*>(audio_buffer->mData), 487 num_frames * audio_buffer->mNumberChannels), 488 cached_playout_delay_ms_.load()); 489 490 return noErr; 491} 492 493void ObjCAudioDeviceModule::HandleAudioInputInterrupted() { 494 RTC_DLOG_F(LS_VERBOSE) << ""; 495 RTC_DCHECK_RUN_ON(&thread_checker_); 496 io_record_thread_checker_.Detach(); 497} 498 499void ObjCAudioDeviceModule::HandleAudioOutputInterrupted() { 500 RTC_DLOG_F(LS_VERBOSE) << ""; 501 RTC_DCHECK_RUN_ON(&thread_checker_); 502 io_playout_thread_checker_.Detach(); 503} 504 505void ObjCAudioDeviceModule::HandleAudioInputParametersChange() { 506 RTC_DLOG_F(LS_VERBOSE) << ""; 507 RTC_DCHECK_RUN_ON(&thread_checker_); 508 509 if (UpdateAudioParameters(record_parameters_, RecordParameters(audio_device_))) { 510 UpdateInputAudioDeviceBuffer(); 511 } 512 513 UpdateAudioDelay(cached_recording_delay_ms_, [audio_device_ inputLatency]); 514} 515 516void ObjCAudioDeviceModule::HandleAudioOutputParametersChange() { 517 RTC_DLOG_F(LS_VERBOSE) << ""; 518 RTC_DCHECK_RUN_ON(&thread_checker_); 519 520 if (UpdateAudioParameters(playout_parameters_, PlayoutParameters(audio_device_))) { 521 UpdateOutputAudioDeviceBuffer(); 522 } 523 524 UpdateAudioDelay(cached_playout_delay_ms_, [audio_device_ outputLatency]); 525} 526 527#pragma mark - Not implemented/Not relevant methods from AudioDeviceModule 528 529int32_t ObjCAudioDeviceModule::ActiveAudioLayer(AudioLayer* audioLayer) const { 530 return -1; 531} 532 533int16_t ObjCAudioDeviceModule::PlayoutDevices() { 534 return 0; 535} 536 537int16_t ObjCAudioDeviceModule::RecordingDevices() { 538 return 0; 539} 540 541int32_t ObjCAudioDeviceModule::PlayoutDeviceName(uint16_t index, 542 char name[kAdmMaxDeviceNameSize], 543 char guid[kAdmMaxGuidSize]) { 544 return -1; 545} 546 547int32_t ObjCAudioDeviceModule::RecordingDeviceName(uint16_t index, 548 char name[kAdmMaxDeviceNameSize], 549 char guid[kAdmMaxGuidSize]) { 550 return -1; 551} 552 553int32_t ObjCAudioDeviceModule::SetPlayoutDevice(uint16_t index) { 554 return 0; 555} 556 557int32_t ObjCAudioDeviceModule::SetPlayoutDevice(WindowsDeviceType device) { 558 return -1; 559} 560 561int32_t ObjCAudioDeviceModule::SetRecordingDevice(uint16_t index) { 562 return 0; 563} 564 565int32_t ObjCAudioDeviceModule::SetRecordingDevice(WindowsDeviceType device) { 566 return -1; 567} 568 569int32_t ObjCAudioDeviceModule::InitSpeaker() { 570 return 0; 571} 572 573bool ObjCAudioDeviceModule::SpeakerIsInitialized() const { 574 return true; 575} 576 577int32_t ObjCAudioDeviceModule::InitMicrophone() { 578 return 0; 579} 580 581bool ObjCAudioDeviceModule::MicrophoneIsInitialized() const { 582 return true; 583} 584 585int32_t ObjCAudioDeviceModule::SpeakerVolumeIsAvailable(bool* available) { 586 *available = false; 587 return 0; 588} 589 590int32_t ObjCAudioDeviceModule::SetSpeakerVolume(uint32_t volume) { 591 return -1; 592} 593 594int32_t ObjCAudioDeviceModule::SpeakerVolume(uint32_t* volume) const { 595 return -1; 596} 597 598int32_t ObjCAudioDeviceModule::MaxSpeakerVolume(uint32_t* maxVolume) const { 599 return -1; 600} 601 602int32_t ObjCAudioDeviceModule::MinSpeakerVolume(uint32_t* minVolume) const { 603 return -1; 604} 605 606int32_t ObjCAudioDeviceModule::SpeakerMuteIsAvailable(bool* available) { 607 *available = false; 608 return 0; 609} 610 611int32_t ObjCAudioDeviceModule::SetSpeakerMute(bool enable) { 612 return -1; 613} 614 615int32_t ObjCAudioDeviceModule::SpeakerMute(bool* enabled) const { 616 return -1; 617} 618 619int32_t ObjCAudioDeviceModule::MicrophoneMuteIsAvailable(bool* available) { 620 *available = false; 621 return 0; 622} 623 624int32_t ObjCAudioDeviceModule::SetMicrophoneMute(bool enable) { 625 return -1; 626} 627 628int32_t ObjCAudioDeviceModule::MicrophoneMute(bool* enabled) const { 629 return -1; 630} 631 632int32_t ObjCAudioDeviceModule::MicrophoneVolumeIsAvailable(bool* available) { 633 *available = false; 634 return 0; 635} 636 637int32_t ObjCAudioDeviceModule::SetMicrophoneVolume(uint32_t volume) { 638 return -1; 639} 640 641int32_t ObjCAudioDeviceModule::MicrophoneVolume(uint32_t* volume) const { 642 return -1; 643} 644 645int32_t ObjCAudioDeviceModule::MaxMicrophoneVolume(uint32_t* maxVolume) const { 646 return -1; 647} 648 649int32_t ObjCAudioDeviceModule::MinMicrophoneVolume(uint32_t* minVolume) const { 650 return -1; 651} 652 653int32_t ObjCAudioDeviceModule::StereoPlayoutIsAvailable(bool* available) const { 654 *available = false; 655 return 0; 656} 657 658int32_t ObjCAudioDeviceModule::SetStereoPlayout(bool enable) { 659 return -1; 660} 661 662int32_t ObjCAudioDeviceModule::StereoPlayout(bool* enabled) const { 663 *enabled = false; 664 return 0; 665} 666 667int32_t ObjCAudioDeviceModule::StereoRecordingIsAvailable(bool* available) const { 668 *available = false; 669 return 0; 670} 671 672int32_t ObjCAudioDeviceModule::SetStereoRecording(bool enable) { 673 return -1; 674} 675 676int32_t ObjCAudioDeviceModule::StereoRecording(bool* enabled) const { 677 *enabled = false; 678 return 0; 679} 680 681bool ObjCAudioDeviceModule::BuiltInAECIsAvailable() const { 682 return false; 683} 684 685int32_t ObjCAudioDeviceModule::EnableBuiltInAEC(bool enable) { 686 return 0; 687} 688 689bool ObjCAudioDeviceModule::BuiltInAGCIsAvailable() const { 690 return false; 691} 692 693int32_t ObjCAudioDeviceModule::EnableBuiltInAGC(bool enable) { 694 return 0; 695} 696 697bool ObjCAudioDeviceModule::BuiltInNSIsAvailable() const { 698 return false; 699} 700 701int32_t ObjCAudioDeviceModule::EnableBuiltInNS(bool enable) { 702 return 0; 703} 704 705int32_t ObjCAudioDeviceModule::GetPlayoutUnderrunCount() const { 706 return -1; 707} 708 709} // namespace objc_adm 710 711} // namespace webrtc 712