blob: 2067d88740c9f08f9a47eaf1ece4892f64fa0ab1 [file] [log] [blame]
sjlee@webrtc.org4b425082012-09-10 17:58:21 +00001/*
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
henrika86d907c2015-09-07 16:09:50 +020011#ifndef WEBRTC_MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_
12#define WEBRTC_MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000013
kwibergf01633e2016-02-24 05:00:36 -080014#include <memory>
15
mbonadeibcc21762017-09-12 04:45:24 -070016#include "webrtc/sdk/objc/Framework/Headers/WebRTC/RTCMacros.h"
pbos@webrtc.org811269d2013-07-11 13:24:38 +000017#include "webrtc/modules/audio_device/audio_device_generic.h"
tkchine54467f2016-03-15 16:54:03 -070018#include "webrtc/modules/audio_device/ios/audio_session_observer.h"
Zeke Chin1300caa2016-03-18 14:39:11 -070019#include "webrtc/modules/audio_device/ios/voice_processing_audio_unit.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020020#include "webrtc/rtc_base/buffer.h"
21#include "webrtc/rtc_base/gtest_prod_util.h"
22#include "webrtc/rtc_base/thread.h"
23#include "webrtc/rtc_base/thread_annotations.h"
24#include "webrtc/rtc_base/thread_checker.h"
tkchine54467f2016-03-15 16:54:03 -070025
26RTC_FWD_DECL_OBJC_CLASS(RTCAudioSessionDelegateAdapter);
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000027
28namespace webrtc {
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000029
henrika86d907c2015-09-07 16:09:50 +020030class FineAudioBuffer;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000031
henrika86d907c2015-09-07 16:09:50 +020032// Implements full duplex 16-bit mono PCM audio support for iOS using a
33// Voice-Processing (VP) I/O audio unit in Core Audio. The VP I/O audio unit
34// supports audio echo cancellation. It also adds automatic gain control,
35// adjustment of voice-processing quality and muting.
36//
37// An instance must be created and destroyed on one and the same thread.
38// All supported public methods must also be called on the same thread.
henrikg91d6ede2015-09-17 00:24:34 -070039// A thread checker will RTC_DCHECK if any supported method is called on an
40// invalid thread.
henrika86d907c2015-09-07 16:09:50 +020041//
42// Recorded audio will be delivered on a real-time internal I/O thread in the
43// audio unit. The audio unit will also ask for audio data to play out on this
44// same thread.
tkchine54467f2016-03-15 16:54:03 -070045class AudioDeviceIOS : public AudioDeviceGeneric,
Zeke Chin1300caa2016-03-18 14:39:11 -070046 public AudioSessionObserver,
tkchind2511962016-05-06 18:54:15 -070047 public VoiceProcessingAudioUnitObserver,
48 public rtc::MessageHandler {
tkchin@webrtc.org122caa52014-07-15 20:20:47 +000049 public:
henrikaba35d052015-07-14 17:04:08 +020050 AudioDeviceIOS();
tkchin@webrtc.org122caa52014-07-15 20:20:47 +000051 ~AudioDeviceIOS();
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000052
henrikaba35d052015-07-14 17:04:08 +020053 void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000054
Max Morin84cab202016-07-01 13:35:19 +020055 InitStatus Init() override;
henrikaba35d052015-07-14 17:04:08 +020056 int32_t Terminate() override;
henrikaaf35f832017-06-16 13:22:13 +020057 bool Initialized() const override;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000058
henrikaba35d052015-07-14 17:04:08 +020059 int32_t InitPlayout() override;
henrikaaf35f832017-06-16 13:22:13 +020060 bool PlayoutIsInitialized() const override;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000061
henrikaba35d052015-07-14 17:04:08 +020062 int32_t InitRecording() override;
henrikaaf35f832017-06-16 13:22:13 +020063 bool RecordingIsInitialized() const override;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000064
henrikaba35d052015-07-14 17:04:08 +020065 int32_t StartPlayout() override;
66 int32_t StopPlayout() override;
pbos46ad5422015-12-07 14:29:14 -080067 bool Playing() const override { return playing_; }
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000068
henrikaba35d052015-07-14 17:04:08 +020069 int32_t StartRecording() override;
70 int32_t StopRecording() override;
pbos46ad5422015-12-07 14:29:14 -080071 bool Recording() const override { return recording_; }
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000072
henrikaba35d052015-07-14 17:04:08 +020073 int32_t SetLoudspeakerStatus(bool enable) override;
74 int32_t GetLoudspeakerStatus(bool& enabled) const override;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000075
henrika86d907c2015-09-07 16:09:50 +020076 // These methods returns hard-coded delay values and not dynamic delay
77 // estimates. The reason is that iOS supports a built-in AEC and the WebRTC
78 // AEC will always be disabled in the Libjingle layer to avoid running two
79 // AEC implementations at the same time. And, it saves resources to avoid
80 // updating these delay values continuously.
81 // TODO(henrika): it would be possible to mark these two methods as not
82 // implemented since they are only called for A/V-sync purposes today and
83 // A/V-sync is not supported on iOS. However, we avoid adding error messages
84 // the log by using these dummy implementations instead.
henrikaba35d052015-07-14 17:04:08 +020085 int32_t PlayoutDelay(uint16_t& delayMS) const override;
86 int32_t RecordingDelay(uint16_t& delayMS) const override;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000087
henrikaba35d052015-07-14 17:04:08 +020088 // Native audio parameters stored during construction.
henrika86d907c2015-09-07 16:09:50 +020089 // These methods are unique for the iOS implementation.
henrikaba35d052015-07-14 17:04:08 +020090 int GetPlayoutAudioParameters(AudioParameters* params) const override;
91 int GetRecordAudioParameters(AudioParameters* params) const override;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000092
henrika86d907c2015-09-07 16:09:50 +020093 // These methods are currently not fully implemented on iOS:
sjlee@webrtc.org4b425082012-09-10 17:58:21 +000094
henrika86d907c2015-09-07 16:09:50 +020095 // See audio_device_not_implemented.cc for trivial implementations.
kjellander080a1e32016-05-25 11:37:11 -070096 int32_t ActiveAudioLayer(
97 AudioDeviceModule::AudioLayer& audioLayer) const override;
henrikaba35d052015-07-14 17:04:08 +020098 int32_t PlayoutIsAvailable(bool& available) override;
99 int32_t RecordingIsAvailable(bool& available) override;
100 int32_t SetAGC(bool enable) override;
101 bool AGC() const override;
102 int16_t PlayoutDevices() override;
103 int16_t RecordingDevices() override;
104 int32_t PlayoutDeviceName(uint16_t index,
105 char name[kAdmMaxDeviceNameSize],
106 char guid[kAdmMaxGuidSize]) override;
107 int32_t RecordingDeviceName(uint16_t index,
108 char name[kAdmMaxDeviceNameSize],
109 char guid[kAdmMaxGuidSize]) override;
110 int32_t SetPlayoutDevice(uint16_t index) override;
111 int32_t SetPlayoutDevice(
112 AudioDeviceModule::WindowsDeviceType device) override;
113 int32_t SetRecordingDevice(uint16_t index) override;
114 int32_t SetRecordingDevice(
115 AudioDeviceModule::WindowsDeviceType device) override;
henrikaba35d052015-07-14 17:04:08 +0200116 int32_t InitSpeaker() override;
117 bool SpeakerIsInitialized() const override;
118 int32_t InitMicrophone() override;
119 bool MicrophoneIsInitialized() const override;
120 int32_t SpeakerVolumeIsAvailable(bool& available) override;
121 int32_t SetSpeakerVolume(uint32_t volume) override;
122 int32_t SpeakerVolume(uint32_t& volume) const override;
123 int32_t MaxSpeakerVolume(uint32_t& maxVolume) const override;
124 int32_t MinSpeakerVolume(uint32_t& minVolume) const override;
henrikaba35d052015-07-14 17:04:08 +0200125 int32_t MicrophoneVolumeIsAvailable(bool& available) override;
126 int32_t SetMicrophoneVolume(uint32_t volume) override;
127 int32_t MicrophoneVolume(uint32_t& volume) const override;
128 int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const override;
129 int32_t MinMicrophoneVolume(uint32_t& minVolume) const override;
henrikaba35d052015-07-14 17:04:08 +0200130 int32_t MicrophoneMuteIsAvailable(bool& available) override;
131 int32_t SetMicrophoneMute(bool enable) override;
132 int32_t MicrophoneMute(bool& enabled) const override;
133 int32_t SpeakerMuteIsAvailable(bool& available) override;
134 int32_t SetSpeakerMute(bool enable) override;
135 int32_t SpeakerMute(bool& enabled) const override;
henrikaba35d052015-07-14 17:04:08 +0200136 int32_t StereoPlayoutIsAvailable(bool& available) override;
137 int32_t SetStereoPlayout(bool enable) override;
138 int32_t StereoPlayout(bool& enabled) const override;
139 int32_t StereoRecordingIsAvailable(bool& available) override;
140 int32_t SetStereoRecording(bool enable) override;
141 int32_t StereoRecording(bool& enabled) const override;
henrikaba35d052015-07-14 17:04:08 +0200142 bool PlayoutWarning() const override;
143 bool PlayoutError() const override;
144 bool RecordingWarning() const override;
145 bool RecordingError() const override;
henrika8c471e72015-10-01 07:36:45 -0700146 void ClearPlayoutWarning() override {}
147 void ClearPlayoutError() override {}
148 void ClearRecordingWarning() override {}
149 void ClearRecordingError() override {}
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000150
tkchine54467f2016-03-15 16:54:03 -0700151 // AudioSessionObserver methods. May be called from any thread.
152 void OnInterruptionBegin() override;
153 void OnInterruptionEnd() override;
154 void OnValidRouteChange() override;
tkchind2511962016-05-06 18:54:15 -0700155 void OnCanPlayOrRecordChange(bool can_play_or_record) override;
henrikaaf35f832017-06-16 13:22:13 +0200156 void OnChangedOutputVolume() override;
tkchine54467f2016-03-15 16:54:03 -0700157
Zeke Chin1300caa2016-03-18 14:39:11 -0700158 // VoiceProcessingAudioUnitObserver methods.
159 OSStatus OnDeliverRecordedData(AudioUnitRenderActionFlags* flags,
160 const AudioTimeStamp* time_stamp,
161 UInt32 bus_number,
162 UInt32 num_frames,
163 AudioBufferList* io_data) override;
164 OSStatus OnGetPlayoutData(AudioUnitRenderActionFlags* flags,
165 const AudioTimeStamp* time_stamp,
166 UInt32 bus_number,
167 UInt32 num_frames,
168 AudioBufferList* io_data) override;
169
tkchind2511962016-05-06 18:54:15 -0700170 // Handles messages from posts.
171 void OnMessage(rtc::Message *msg) override;
172
tkchin@webrtc.org122caa52014-07-15 20:20:47 +0000173 private:
tkchine54467f2016-03-15 16:54:03 -0700174 // Called by the relevant AudioSessionObserver methods on |thread_|.
175 void HandleInterruptionBegin();
176 void HandleInterruptionEnd();
177 void HandleValidRouteChange();
tkchind2511962016-05-06 18:54:15 -0700178 void HandleCanPlayOrRecordChange(bool can_play_or_record);
179 void HandleSampleRateChange(float sample_rate);
henrika7be78832017-06-13 17:34:16 +0200180 void HandlePlayoutGlitchDetected();
henrikaaf35f832017-06-16 13:22:13 +0200181 void HandleOutputVolumeChange();
tkchine54467f2016-03-15 16:54:03 -0700182
henrika8c471e72015-10-01 07:36:45 -0700183 // Uses current |playout_parameters_| and |record_parameters_| to inform the
henrika86d907c2015-09-07 16:09:50 +0200184 // audio device buffer (ADB) about our internal audio parameters.
185 void UpdateAudioDeviceBuffer();
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000186
henrika86d907c2015-09-07 16:09:50 +0200187 // Since the preferred audio parameters are only hints to the OS, the actual
188 // values may be different once the AVAudioSession has been activated.
189 // This method asks for the current hardware parameters and takes actions
190 // if they should differ from what we have asked for initially. It also
henrika8c471e72015-10-01 07:36:45 -0700191 // defines |playout_parameters_| and |record_parameters_|.
henrika86d907c2015-09-07 16:09:50 +0200192 void SetupAudioBuffersForActiveAudioSession();
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000193
Zeke Chin1300caa2016-03-18 14:39:11 -0700194 // Creates the audio unit.
195 bool CreateAudioUnit();
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000196
tkchind2511962016-05-06 18:54:15 -0700197 // Updates the audio unit state based on current state.
198 void UpdateAudioUnit(bool can_play_or_record);
199
200 // Configures the audio session for WebRTC.
jttehf84c1d62017-04-21 13:56:39 -0700201 bool ConfigureAudioSession();
tkchind2511962016-05-06 18:54:15 -0700202 // Unconfigures the audio session.
203 void UnconfigureAudioSession();
henrika45c136b2015-10-21 04:11:53 -0700204
henrika8c471e72015-10-01 07:36:45 -0700205 // Activates our audio session, creates and initializes the voice-processing
henrika86d907c2015-09-07 16:09:50 +0200206 // audio unit and verifies that we got the preferred native audio parameters.
207 bool InitPlayOrRecord();
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000208
henrika86d907c2015-09-07 16:09:50 +0200209 // Closes and deletes the voice-processing I/O unit.
henrika34911ad2015-11-20 15:47:09 +0100210 void ShutdownPlayOrRecord();
211
henrika86d907c2015-09-07 16:09:50 +0200212 // Ensures that methods are called from the same thread as this object is
213 // created on.
henrika8c471e72015-10-01 07:36:45 -0700214 rtc::ThreadChecker thread_checker_;
henrikaaf35f832017-06-16 13:22:13 +0200215
216 // Native I/O audio thread checker.
217 rtc::ThreadChecker io_thread_checker_;
218
tkchine54467f2016-03-15 16:54:03 -0700219 // Thread that this object is created on.
220 rtc::Thread* thread_;
henrikaba35d052015-07-14 17:04:08 +0200221
222 // Raw pointer handle provided to us in AttachAudioBuffer(). Owned by the
Peter Boström4adbbcf2016-05-03 15:51:26 -0400223 // AudioDeviceModuleImpl class and called by AudioDeviceModule::Create().
henrikaba35d052015-07-14 17:04:08 +0200224 // The AudioDeviceBuffer is a member of the AudioDeviceModuleImpl instance
225 // and therefore outlives this object.
henrika8c471e72015-10-01 07:36:45 -0700226 AudioDeviceBuffer* audio_device_buffer_;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000227
henrika86d907c2015-09-07 16:09:50 +0200228 // Contains audio parameters (sample rate, #channels, buffer size etc.) for
229 // the playout and recording sides. These structure is set in two steps:
230 // first, native sample rate and #channels are defined in Init(). Next, the
231 // audio session is activated and we verify that the preferred parameters
232 // were granted by the OS. At this stage it is also possible to add a third
233 // component to the parameters; the native I/O buffer duration.
henrikg91d6ede2015-09-17 00:24:34 -0700234 // A RTC_CHECK will be hit if we for some reason fail to open an audio session
henrika86d907c2015-09-07 16:09:50 +0200235 // using the specified parameters.
henrika8c471e72015-10-01 07:36:45 -0700236 AudioParameters playout_parameters_;
237 AudioParameters record_parameters_;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000238
Zeke Chin1300caa2016-03-18 14:39:11 -0700239 // The AudioUnit used to play and record audio.
240 std::unique_ptr<VoiceProcessingAudioUnit> audio_unit_;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000241
henrika86d907c2015-09-07 16:09:50 +0200242 // FineAudioBuffer takes an AudioDeviceBuffer which delivers audio data
243 // in chunks of 10ms. It then allows for this data to be pulled in
244 // a finer or coarser granularity. I.e. interacting with this class instead
245 // of directly with the AudioDeviceBuffer one can ask for any number of
246 // audio data samples. Is also supports a similar scheme for the recording
247 // side.
248 // Example: native buffer size can be 128 audio frames at 16kHz sample rate.
249 // WebRTC will provide 480 audio frames per 10ms but iOS asks for 128
250 // in each callback (one every 8ms). This class can then ask for 128 and the
251 // FineAudioBuffer will ask WebRTC for new data only when needed and also
252 // cache non-utilized audio between callbacks. On the recording side, iOS
253 // can provide audio data frames of size 128 and these are accumulated until
254 // enough data to supply one 10ms call exists. This 10ms chunk is then sent
255 // to WebRTC and the remaining part is stored.
kwibergf01633e2016-02-24 05:00:36 -0800256 std::unique_ptr<FineAudioBuffer> fine_audio_buffer_;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000257
henrika86d907c2015-09-07 16:09:50 +0200258 // Temporary storage for recorded data. AudioUnitRender() renders into this
259 // array as soon as a frame of the desired buffer size has been recorded.
henrikabc9ffad2017-06-01 14:25:45 +0200260 // On real iOS devices, the size will be fixed and set once. For iOS
261 // simulators, the size can vary from callback to callback and the size
262 // will be changed dynamically to account for this behavior.
263 rtc::BufferT<int8_t> record_audio_buffer_;
henrika86d907c2015-09-07 16:09:50 +0200264
265 // Set to 1 when recording is active and 0 otherwise.
pbos46ad5422015-12-07 14:29:14 -0800266 volatile int recording_;
henrika86d907c2015-09-07 16:09:50 +0200267
268 // Set to 1 when playout is active and 0 otherwise.
pbos46ad5422015-12-07 14:29:14 -0800269 volatile int playing_;
henrika86d907c2015-09-07 16:09:50 +0200270
271 // Set to true after successful call to Init(), false otherwise.
danilchap56359be2017-09-07 07:53:45 -0700272 bool initialized_ RTC_ACCESS_ON(thread_checker_);
henrika86d907c2015-09-07 16:09:50 +0200273
henrika17802ae2016-09-21 04:55:04 -0700274 // Set to true after successful call to InitRecording() or InitPlayout(),
275 // false otherwise.
276 bool audio_is_initialized_;
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000277
tkchine54467f2016-03-15 16:54:03 -0700278 // Set to true if audio session is interrupted, false otherwise.
279 bool is_interrupted_;
280
henrika86d907c2015-09-07 16:09:50 +0200281 // Audio interruption observer instance.
henrikaaf35f832017-06-16 13:22:13 +0200282 RTCAudioSessionDelegateAdapter* audio_session_observer_
danilchap56359be2017-09-07 07:53:45 -0700283 RTC_ACCESS_ON(thread_checker_);
tkchind2511962016-05-06 18:54:15 -0700284
285 // Set to true if we've activated the audio session.
danilchap56359be2017-09-07 07:53:45 -0700286 bool has_configured_session_ RTC_ACCESS_ON(thread_checker_);
jtteh5171a7f2017-05-09 15:09:37 -0700287
henrika7be78832017-06-13 17:34:16 +0200288 // Counts number of detected audio glitches on the playout side.
danilchap56359be2017-09-07 07:53:45 -0700289 int64_t num_detected_playout_glitches_ RTC_ACCESS_ON(thread_checker_);
290 int64_t last_playout_time_ RTC_ACCESS_ON(io_thread_checker_);
henrika7be78832017-06-13 17:34:16 +0200291
292 // Counts number of playout callbacks per call.
henrikaaf35f832017-06-16 13:22:13 +0200293 // The value isupdated on the native I/O thread and later read on the
294 // creating thread (see thread_checker_) but at this stage no audio is
295 // active. Hence, it is a "thread safe" design and no lock is needed.
henrika7be78832017-06-13 17:34:16 +0200296 int64_t num_playout_callbacks_;
297
henrikaaf35f832017-06-16 13:22:13 +0200298 // Contains the time for when the last output volume change was detected.
danilchap56359be2017-09-07 07:53:45 -0700299 int64_t last_output_volume_change_time_ RTC_ACCESS_ON(thread_checker_);
henrikaaf35f832017-06-16 13:22:13 +0200300
jtteh5171a7f2017-05-09 15:09:37 -0700301 // Exposes private members for testing purposes only.
302 FRIEND_TEST_ALL_PREFIXES(AudioDeviceTest, testInterruptedAudioSession);
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000303};
304
305} // namespace webrtc
306
henrika86d907c2015-09-07 16:09:50 +0200307#endif // WEBRTC_MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_