blob: e9e42ea1cc515c22cf50629b9b3f2a65cfded42e [file] [log] [blame]
Peter Hanspers8d95e3b2018-05-15 08:22:361/*
2 * Copyright (c) 2012 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
Anders Carlsson7bca8ca2018-08-30 07:30:2911#ifndef SDK_OBJC_NATIVE_SRC_AUDIO_AUDIO_DEVICE_IOS_H_
12#define SDK_OBJC_NATIVE_SRC_AUDIO_AUDIO_DEVICE_IOS_H_
Peter Hanspers8d95e3b2018-05-15 08:22:3613
14#include <memory>
15
Artem Titovd15a5752021-02-10 13:31:2416#include "api/sequence_checker.h"
Peter Hanspers8d95e3b2018-05-15 08:22:3617#include "audio_session_observer.h"
Yves Gerey665174f2018-06-19 13:03:0518#include "modules/audio_device/audio_device_generic.h"
Peter Hanspers8d95e3b2018-05-15 08:22:3619#include "rtc_base/buffer.h"
20#include "rtc_base/thread.h"
21#include "rtc_base/thread_annotations.h"
Anders Carlsson7bca8ca2018-08-30 07:30:2922#include "sdk/objc/base/RTCMacros.h"
Yves Gerey665174f2018-06-19 13:03:0523#include "voice_processing_audio_unit.h"
Peter Hanspers8d95e3b2018-05-15 08:22:3624
25RTC_FWD_DECL_OBJC_CLASS(RTCNativeAudioSessionDelegateAdapter);
26
27namespace webrtc {
28
29class FineAudioBuffer;
30
31namespace ios_adm {
32
33// Implements full duplex 16-bit mono PCM audio support for iOS using a
34// Voice-Processing (VP) I/O audio unit in Core Audio. The VP I/O audio unit
35// supports audio echo cancellation. It also adds automatic gain control,
36// adjustment of voice-processing quality and muting.
37//
38// An instance must be created and destroyed on one and the same thread.
39// All supported public methods must also be called on the same thread.
40// A thread checker will RTC_DCHECK if any supported method is called on an
41// invalid thread.
42//
43// Recorded audio will be delivered on a real-time internal I/O thread in the
44// audio unit. The audio unit will also ask for audio data to play out on this
45// same thread.
46class AudioDeviceIOS : public AudioDeviceGeneric,
47 public AudioSessionObserver,
48 public VoiceProcessingAudioUnitObserver,
49 public rtc::MessageHandler {
50 public:
Sam Zackrisson76443ea2020-11-26 11:18:1151 explicit AudioDeviceIOS(bool bypass_voice_processing);
Mirko Bonadei17aff352018-07-26 10:20:4052 ~AudioDeviceIOS() override;
Peter Hanspers8d95e3b2018-05-15 08:22:3653
54 void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
55
56 InitStatus Init() override;
57 int32_t Terminate() override;
58 bool Initialized() const override;
59
60 int32_t InitPlayout() override;
61 bool PlayoutIsInitialized() const override;
62
63 int32_t InitRecording() override;
64 bool RecordingIsInitialized() const override;
65
66 int32_t StartPlayout() override;
67 int32_t StopPlayout() override;
Mirko Bonadei17aff352018-07-26 10:20:4068 bool Playing() const override;
Peter Hanspers8d95e3b2018-05-15 08:22:3669
70 int32_t StartRecording() override;
71 int32_t StopRecording() override;
Mirko Bonadei17aff352018-07-26 10:20:4072 bool Recording() const override;
Peter Hanspers8d95e3b2018-05-15 08:22:3673
74 // These methods returns hard-coded delay values and not dynamic delay
75 // estimates. The reason is that iOS supports a built-in AEC and the WebRTC
76 // AEC will always be disabled in the Libjingle layer to avoid running two
77 // AEC implementations at the same time. And, it saves resources to avoid
78 // updating these delay values continuously.
79 // TODO(henrika): it would be possible to mark these two methods as not
80 // implemented since they are only called for A/V-sync purposes today and
81 // A/V-sync is not supported on iOS. However, we avoid adding error messages
82 // the log by using these dummy implementations instead.
83 int32_t PlayoutDelay(uint16_t& delayMS) const override;
84
Noah Richardsbb0aac22019-11-13 20:31:4285 // No implementation for playout underrun on iOS. We override it to avoid a
86 // periodic log that it isn't available from the base class.
87 int32_t GetPlayoutUnderrunCount() const override { return -1; }
88
Peter Hanspers8d95e3b2018-05-15 08:22:3689 // Native audio parameters stored during construction.
90 // These methods are unique for the iOS implementation.
91 int GetPlayoutAudioParameters(AudioParameters* params) const override;
92 int GetRecordAudioParameters(AudioParameters* params) const override;
93
94 // These methods are currently not fully implemented on iOS:
95
96 // See audio_device_not_implemented.cc for trivial implementations.
97 int32_t ActiveAudioLayer(
98 AudioDeviceModule::AudioLayer& audioLayer) const override;
99 int32_t PlayoutIsAvailable(bool& available) override;
100 int32_t RecordingIsAvailable(bool& available) override;
101 int16_t PlayoutDevices() override;
102 int16_t RecordingDevices() override;
103 int32_t PlayoutDeviceName(uint16_t index,
104 char name[kAdmMaxDeviceNameSize],
105 char guid[kAdmMaxGuidSize]) override;
106 int32_t RecordingDeviceName(uint16_t index,
107 char name[kAdmMaxDeviceNameSize],
108 char guid[kAdmMaxGuidSize]) override;
109 int32_t SetPlayoutDevice(uint16_t index) override;
110 int32_t SetPlayoutDevice(
111 AudioDeviceModule::WindowsDeviceType device) override;
112 int32_t SetRecordingDevice(uint16_t index) override;
113 int32_t SetRecordingDevice(
114 AudioDeviceModule::WindowsDeviceType device) override;
115 int32_t InitSpeaker() override;
116 bool SpeakerIsInitialized() const override;
117 int32_t InitMicrophone() override;
118 bool MicrophoneIsInitialized() const override;
119 int32_t SpeakerVolumeIsAvailable(bool& available) override;
120 int32_t SetSpeakerVolume(uint32_t volume) override;
121 int32_t SpeakerVolume(uint32_t& volume) const override;
122 int32_t MaxSpeakerVolume(uint32_t& maxVolume) const override;
123 int32_t MinSpeakerVolume(uint32_t& minVolume) const override;
124 int32_t MicrophoneVolumeIsAvailable(bool& available) override;
125 int32_t SetMicrophoneVolume(uint32_t volume) override;
126 int32_t MicrophoneVolume(uint32_t& volume) const override;
127 int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const override;
128 int32_t MinMicrophoneVolume(uint32_t& minVolume) const override;
129 int32_t MicrophoneMuteIsAvailable(bool& available) override;
130 int32_t SetMicrophoneMute(bool enable) override;
131 int32_t MicrophoneMute(bool& enabled) const override;
132 int32_t SpeakerMuteIsAvailable(bool& available) override;
133 int32_t SetSpeakerMute(bool enable) override;
134 int32_t SpeakerMute(bool& enabled) const override;
135 int32_t StereoPlayoutIsAvailable(bool& available) override;
136 int32_t SetStereoPlayout(bool enable) override;
137 int32_t StereoPlayout(bool& enabled) const override;
138 int32_t StereoRecordingIsAvailable(bool& available) override;
139 int32_t SetStereoRecording(bool enable) override;
140 int32_t StereoRecording(bool& enabled) const override;
141
142 // AudioSessionObserver methods. May be called from any thread.
143 void OnInterruptionBegin() override;
144 void OnInterruptionEnd() override;
145 void OnValidRouteChange() override;
146 void OnCanPlayOrRecordChange(bool can_play_or_record) override;
147 void OnChangedOutputVolume() override;
148
149 // VoiceProcessingAudioUnitObserver methods.
150 OSStatus OnDeliverRecordedData(AudioUnitRenderActionFlags* flags,
151 const AudioTimeStamp* time_stamp,
152 UInt32 bus_number,
153 UInt32 num_frames,
154 AudioBufferList* io_data) override;
155 OSStatus OnGetPlayoutData(AudioUnitRenderActionFlags* flags,
156 const AudioTimeStamp* time_stamp,
157 UInt32 bus_number,
158 UInt32 num_frames,
159 AudioBufferList* io_data) override;
160
161 // Handles messages from posts.
Yves Gerey665174f2018-06-19 13:03:05162 void OnMessage(rtc::Message* msg) override;
Peter Hanspers8d95e3b2018-05-15 08:22:36163
164 bool IsInterrupted();
165
166 private:
167 // Called by the relevant AudioSessionObserver methods on |thread_|.
168 void HandleInterruptionBegin();
169 void HandleInterruptionEnd();
170 void HandleValidRouteChange();
171 void HandleCanPlayOrRecordChange(bool can_play_or_record);
172 void HandleSampleRateChange(float sample_rate);
173 void HandlePlayoutGlitchDetected();
174 void HandleOutputVolumeChange();
175
176 // Uses current |playout_parameters_| and |record_parameters_| to inform the
177 // audio device buffer (ADB) about our internal audio parameters.
178 void UpdateAudioDeviceBuffer();
179
180 // Since the preferred audio parameters are only hints to the OS, the actual
181 // values may be different once the AVAudioSession has been activated.
182 // This method asks for the current hardware parameters and takes actions
183 // if they should differ from what we have asked for initially. It also
184 // defines |playout_parameters_| and |record_parameters_|.
185 void SetupAudioBuffersForActiveAudioSession();
186
187 // Creates the audio unit.
188 bool CreateAudioUnit();
189
190 // Updates the audio unit state based on current state.
191 void UpdateAudioUnit(bool can_play_or_record);
192
193 // Configures the audio session for WebRTC.
194 bool ConfigureAudioSession();
195 // Unconfigures the audio session.
196 void UnconfigureAudioSession();
197
198 // Activates our audio session, creates and initializes the voice-processing
199 // audio unit and verifies that we got the preferred native audio parameters.
200 bool InitPlayOrRecord();
201
202 // Closes and deletes the voice-processing I/O unit.
203 void ShutdownPlayOrRecord();
204
henrika79445ea2018-05-29 14:04:16205 // Resets thread-checkers before a call is restarted.
206 void PrepareForNewStart();
207
Sam Zackrisson76443ea2020-11-26 11:18:11208 // Determines whether voice processing should be enabled or disabled.
209 const bool bypass_voice_processing_;
210
Peter Hanspers8d95e3b2018-05-15 08:22:36211 // Ensures that methods are called from the same thread as this object is
212 // created on.
Artem Titovc8421c42021-02-02 09:57:19213 SequenceChecker thread_checker_;
Peter Hanspers8d95e3b2018-05-15 08:22:36214
215 // Native I/O audio thread checker.
Artem Titovc8421c42021-02-02 09:57:19216 SequenceChecker io_thread_checker_;
Peter Hanspers8d95e3b2018-05-15 08:22:36217
218 // Thread that this object is created on.
219 rtc::Thread* thread_;
220
221 // Raw pointer handle provided to us in AttachAudioBuffer(). Owned by the
222 // AudioDeviceModuleImpl class and called by AudioDeviceModule::Create().
223 // The AudioDeviceBuffer is a member of the AudioDeviceModuleImpl instance
224 // and therefore outlives this object.
225 AudioDeviceBuffer* audio_device_buffer_;
226
227 // Contains audio parameters (sample rate, #channels, buffer size etc.) for
228 // the playout and recording sides. These structure is set in two steps:
229 // first, native sample rate and #channels are defined in Init(). Next, the
230 // audio session is activated and we verify that the preferred parameters
231 // were granted by the OS. At this stage it is also possible to add a third
232 // component to the parameters; the native I/O buffer duration.
233 // A RTC_CHECK will be hit if we for some reason fail to open an audio session
234 // using the specified parameters.
235 AudioParameters playout_parameters_;
236 AudioParameters record_parameters_;
237
238 // The AudioUnit used to play and record audio.
239 std::unique_ptr<VoiceProcessingAudioUnit> audio_unit_;
240
241 // FineAudioBuffer takes an AudioDeviceBuffer which delivers audio data
242 // in chunks of 10ms. It then allows for this data to be pulled in
243 // a finer or coarser granularity. I.e. interacting with this class instead
244 // of directly with the AudioDeviceBuffer one can ask for any number of
245 // audio data samples. Is also supports a similar scheme for the recording
246 // side.
247 // Example: native buffer size can be 128 audio frames at 16kHz sample rate.
248 // WebRTC will provide 480 audio frames per 10ms but iOS asks for 128
249 // in each callback (one every 8ms). This class can then ask for 128 and the
250 // FineAudioBuffer will ask WebRTC for new data only when needed and also
251 // cache non-utilized audio between callbacks. On the recording side, iOS
252 // can provide audio data frames of size 128 and these are accumulated until
253 // enough data to supply one 10ms call exists. This 10ms chunk is then sent
254 // to WebRTC and the remaining part is stored.
255 std::unique_ptr<FineAudioBuffer> fine_audio_buffer_;
256
257 // Temporary storage for recorded data. AudioUnitRender() renders into this
258 // array as soon as a frame of the desired buffer size has been recorded.
259 // On real iOS devices, the size will be fixed and set once. For iOS
260 // simulators, the size can vary from callback to callback and the size
261 // will be changed dynamically to account for this behavior.
262 rtc::BufferT<int16_t> record_audio_buffer_;
263
264 // Set to 1 when recording is active and 0 otherwise.
265 volatile int recording_;
266
267 // Set to 1 when playout is active and 0 otherwise.
268 volatile int playing_;
269
270 // Set to true after successful call to Init(), false otherwise.
271 bool initialized_ RTC_GUARDED_BY(thread_checker_);
272
273 // Set to true after successful call to InitRecording() or InitPlayout(),
274 // false otherwise.
275 bool audio_is_initialized_;
276
277 // Set to true if audio session is interrupted, false otherwise.
278 bool is_interrupted_;
279
280 // Audio interruption observer instance.
281 RTCNativeAudioSessionDelegateAdapter* audio_session_observer_
282 RTC_GUARDED_BY(thread_checker_);
283
284 // Set to true if we've activated the audio session.
285 bool has_configured_session_ RTC_GUARDED_BY(thread_checker_);
286
287 // Counts number of detected audio glitches on the playout side.
288 int64_t num_detected_playout_glitches_ RTC_GUARDED_BY(thread_checker_);
289 int64_t last_playout_time_ RTC_GUARDED_BY(io_thread_checker_);
290
291 // Counts number of playout callbacks per call.
292 // The value isupdated on the native I/O thread and later read on the
293 // creating thread (see thread_checker_) but at this stage no audio is
294 // active. Hence, it is a "thread safe" design and no lock is needed.
295 int64_t num_playout_callbacks_;
296
297 // Contains the time for when the last output volume change was detected.
298 int64_t last_output_volume_change_time_ RTC_GUARDED_BY(thread_checker_);
299};
300} // namespace ios_adm
301} // namespace webrtc
302
Anders Carlsson7bca8ca2018-08-30 07:30:29303#endif // SDK_OBJC_NATIVE_SRC_AUDIO_AUDIO_DEVICE_IOS_H_