xref: /aosp_15_r20/external/webrtc/sdk/objc/native/src/objc_audio_device.mm (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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