xref: /aosp_15_r20/external/webrtc/sdk/objc/native/src/objc_audio_device_delegate.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#import <AudioUnit/AudioUnit.h>
12#import <Foundation/Foundation.h>
13
14#import "objc_audio_device.h"
15#import "objc_audio_device_delegate.h"
16
17#include "api/make_ref_counted.h"
18#include "api/ref_counted_base.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
21#include "rtc_base/thread.h"
22
23namespace {
24
25constexpr double kPreferredInputSampleRate = 48000.0;
26constexpr double kPreferredOutputSampleRate = 48000.0;
27
28// WebRTC processes audio in chunks of 10ms. Preferring 20ms audio chunks
29// is a compromize between performance and power consumption.
30constexpr NSTimeInterval kPeferredInputIOBufferDuration = 0.02;
31constexpr NSTimeInterval kPeferredOutputIOBufferDuration = 0.02;
32
33class AudioDeviceDelegateImpl final : public rtc::RefCountedNonVirtual<AudioDeviceDelegateImpl> {
34 public:
35  AudioDeviceDelegateImpl(
36      rtc::scoped_refptr<webrtc::objc_adm::ObjCAudioDeviceModule> audio_device_module,
37      rtc::Thread* thread)
38      : audio_device_module_(audio_device_module), thread_(thread) {
39    RTC_DCHECK(audio_device_module_);
40    RTC_DCHECK(thread_);
41  }
42
43  webrtc::objc_adm::ObjCAudioDeviceModule* audio_device_module() const {
44    return audio_device_module_.get();
45  }
46
47  rtc::Thread* thread() const { return thread_; }
48
49  void reset_audio_device_module() { audio_device_module_ = nullptr; }
50
51 private:
52  rtc::scoped_refptr<webrtc::objc_adm::ObjCAudioDeviceModule> audio_device_module_;
53  rtc::Thread* thread_;
54};
55
56}  // namespace
57
58@implementation ObjCAudioDeviceDelegate {
59  rtc::scoped_refptr<AudioDeviceDelegateImpl> impl_;
60}
61
62@synthesize getPlayoutData = getPlayoutData_;
63
64@synthesize deliverRecordedData = deliverRecordedData_;
65
66@synthesize preferredInputSampleRate = preferredInputSampleRate_;
67
68@synthesize preferredInputIOBufferDuration = preferredInputIOBufferDuration_;
69
70@synthesize preferredOutputSampleRate = preferredOutputSampleRate_;
71
72@synthesize preferredOutputIOBufferDuration = preferredOutputIOBufferDuration_;
73
74- (instancetype)initWithAudioDeviceModule:
75                    (rtc::scoped_refptr<webrtc::objc_adm::ObjCAudioDeviceModule>)audioDeviceModule
76                        audioDeviceThread:(rtc::Thread*)thread {
77  RTC_DCHECK_RUN_ON(thread);
78  if (self = [super init]) {
79    impl_ = rtc::make_ref_counted<AudioDeviceDelegateImpl>(audioDeviceModule, thread);
80    preferredInputSampleRate_ = kPreferredInputSampleRate;
81    preferredInputIOBufferDuration_ = kPeferredInputIOBufferDuration;
82    preferredOutputSampleRate_ = kPreferredOutputSampleRate;
83    preferredOutputIOBufferDuration_ = kPeferredOutputIOBufferDuration;
84
85    rtc::scoped_refptr<AudioDeviceDelegateImpl> playout_delegate = impl_;
86    getPlayoutData_ = ^OSStatus(AudioUnitRenderActionFlags* _Nonnull actionFlags,
87                                const AudioTimeStamp* _Nonnull timestamp,
88                                NSInteger inputBusNumber,
89                                UInt32 frameCount,
90                                AudioBufferList* _Nonnull outputData) {
91      webrtc::objc_adm::ObjCAudioDeviceModule* audio_device =
92          playout_delegate->audio_device_module();
93      if (audio_device) {
94        return audio_device->OnGetPlayoutData(
95            actionFlags, timestamp, inputBusNumber, frameCount, outputData);
96      } else {
97        *actionFlags |= kAudioUnitRenderAction_OutputIsSilence;
98        RTC_LOG(LS_VERBOSE) << "No alive audio device";
99        return noErr;
100      }
101    };
102
103    rtc::scoped_refptr<AudioDeviceDelegateImpl> record_delegate = impl_;
104    deliverRecordedData_ =
105        ^OSStatus(AudioUnitRenderActionFlags* _Nonnull actionFlags,
106                  const AudioTimeStamp* _Nonnull timestamp,
107                  NSInteger inputBusNumber,
108                  UInt32 frameCount,
109                  const AudioBufferList* _Nullable inputData,
110                  void* renderContext,
111                  RTC_OBJC_TYPE(RTCAudioDeviceRenderRecordedDataBlock) _Nullable renderBlock) {
112          webrtc::objc_adm::ObjCAudioDeviceModule* audio_device =
113              record_delegate->audio_device_module();
114          if (audio_device) {
115            return audio_device->OnDeliverRecordedData(actionFlags,
116                                                       timestamp,
117                                                       inputBusNumber,
118                                                       frameCount,
119                                                       inputData,
120                                                       renderContext,
121                                                       renderBlock);
122          } else {
123            RTC_LOG(LS_VERBOSE) << "No alive audio device";
124            return noErr;
125          }
126        };
127  }
128  return self;
129}
130
131- (void)notifyAudioInputParametersChange {
132  RTC_DCHECK_RUN_ON(impl_->thread());
133  webrtc::objc_adm::ObjCAudioDeviceModule* audio_device_module = impl_->audio_device_module();
134  if (audio_device_module) {
135    audio_device_module->HandleAudioInputParametersChange();
136  }
137}
138
139- (void)notifyAudioOutputParametersChange {
140  RTC_DCHECK_RUN_ON(impl_->thread());
141  webrtc::objc_adm::ObjCAudioDeviceModule* audio_device_module = impl_->audio_device_module();
142  if (audio_device_module) {
143    audio_device_module->HandleAudioOutputParametersChange();
144  }
145}
146
147- (void)notifyAudioInputInterrupted {
148  RTC_DCHECK_RUN_ON(impl_->thread());
149  webrtc::objc_adm::ObjCAudioDeviceModule* audio_device_module = impl_->audio_device_module();
150  if (audio_device_module) {
151    audio_device_module->HandleAudioInputInterrupted();
152  }
153}
154
155- (void)notifyAudioOutputInterrupted {
156  RTC_DCHECK_RUN_ON(impl_->thread());
157  webrtc::objc_adm::ObjCAudioDeviceModule* audio_device_module = impl_->audio_device_module();
158  if (audio_device_module) {
159    audio_device_module->HandleAudioOutputInterrupted();
160  }
161}
162
163- (void)dispatchAsync:(dispatch_block_t)block {
164  rtc::Thread* thread = impl_->thread();
165  RTC_DCHECK(thread);
166  thread->PostTask([block] {
167    @autoreleasepool {
168      block();
169    }
170  });
171}
172
173- (void)dispatchSync:(dispatch_block_t)block {
174  rtc::Thread* thread = impl_->thread();
175  RTC_DCHECK(thread);
176  if (thread->IsCurrent()) {
177    @autoreleasepool {
178      block();
179    }
180  } else {
181    thread->BlockingCall([block] {
182      @autoreleasepool {
183        block();
184      }
185    });
186  }
187}
188
189- (void)resetAudioDeviceModule {
190  RTC_DCHECK_RUN_ON(impl_->thread());
191  impl_->reset_audio_device_module();
192}
193
194@end
195