aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/audio_device/ios/audio_device_ios.h
blob: c4eb0d6f6451a5e8b8efa8da3924eb0236cc26bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef WEBRTC_MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_
#define WEBRTC_MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_

#include <AudioUnit/AudioUnit.h>

#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread_checker.h"
#include "webrtc/modules/audio_device/audio_device_generic.h"

namespace webrtc {

class FineAudioBuffer;

// Implements full duplex 16-bit mono PCM audio support for iOS using a
// Voice-Processing (VP) I/O audio unit in Core Audio. The VP I/O audio unit
// supports audio echo cancellation. It also adds automatic gain control,
// adjustment of voice-processing quality and muting.
//
// An instance must be created and destroyed on one and the same thread.
// All supported public methods must also be called on the same thread.
// A thread checker will RTC_DCHECK if any supported method is called on an
// invalid thread.
//
// Recorded audio will be delivered on a real-time internal I/O thread in the
// audio unit. The audio unit will also ask for audio data to play out on this
// same thread.
class AudioDeviceIOS : public AudioDeviceGeneric {
 public:
  AudioDeviceIOS();
  ~AudioDeviceIOS();

  void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;

  int32_t Init() override;
  int32_t Terminate() override;
  bool Initialized() const override { return initialized_; }

  int32_t InitPlayout() override;
  bool PlayoutIsInitialized() const override { return play_is_initialized_; }

  int32_t InitRecording() override;
  bool RecordingIsInitialized() const override { return rec_is_initialized_; }

  int32_t StartPlayout() override;
  int32_t StopPlayout() override;
  bool Playing() const override { return playing_; }

  int32_t StartRecording() override;
  int32_t StopRecording() override;
  bool Recording() const override { return recording_; }

  int32_t SetLoudspeakerStatus(bool enable) override;
  int32_t GetLoudspeakerStatus(bool& enabled) const override;

  // These methods returns hard-coded delay values and not dynamic delay
  // estimates. The reason is that iOS supports a built-in AEC and the WebRTC
  // AEC will always be disabled in the Libjingle layer to avoid running two
  // AEC implementations at the same time. And, it saves resources to avoid
  // updating these delay values continuously.
  // TODO(henrika): it would be possible to mark these two methods as not
  // implemented since they are only called for A/V-sync purposes today and
  // A/V-sync is not supported on iOS. However, we avoid adding error messages
  // the log by using these dummy implementations instead.
  int32_t PlayoutDelay(uint16_t& delayMS) const override;
  int32_t RecordingDelay(uint16_t& delayMS) const override;

  // Native audio parameters stored during construction.
  // These methods are unique for the iOS implementation.
  int GetPlayoutAudioParameters(AudioParameters* params) const override;
  int GetRecordAudioParameters(AudioParameters* params) const override;

  // These methods are currently not fully implemented on iOS:

  // See audio_device_not_implemented.cc for trivial implementations.
  int32_t PlayoutBuffer(AudioDeviceModule::BufferType& type,
                        uint16_t& sizeMS) const override;
  int32_t ActiveAudioLayer(AudioDeviceModule::AudioLayer& audioLayer) const;
  int32_t ResetAudioDevice() override;
  int32_t PlayoutIsAvailable(bool& available) override;
  int32_t RecordingIsAvailable(bool& available) override;
  int32_t SetAGC(bool enable) override;
  bool AGC() const override;
  int16_t PlayoutDevices() override;
  int16_t RecordingDevices() override;
  int32_t PlayoutDeviceName(uint16_t index,
                            char name[kAdmMaxDeviceNameSize],
                            char guid[kAdmMaxGuidSize]) override;
  int32_t RecordingDeviceName(uint16_t index,
                              char name[kAdmMaxDeviceNameSize],
                              char guid[kAdmMaxGuidSize]) override;
  int32_t SetPlayoutDevice(uint16_t index) override;
  int32_t SetPlayoutDevice(
      AudioDeviceModule::WindowsDeviceType device) override;
  int32_t SetRecordingDevice(uint16_t index) override;
  int32_t SetRecordingDevice(
      AudioDeviceModule::WindowsDeviceType device) override;
  int32_t SetWaveOutVolume(uint16_t volumeLeft, uint16_t volumeRight) override;
  int32_t WaveOutVolume(uint16_t& volumeLeft,
                        uint16_t& volumeRight) const override;
  int32_t InitSpeaker() override;
  bool SpeakerIsInitialized() const override;
  int32_t InitMicrophone() override;
  bool MicrophoneIsInitialized() const override;
  int32_t SpeakerVolumeIsAvailable(bool& available) override;
  int32_t SetSpeakerVolume(uint32_t volume) override;
  int32_t SpeakerVolume(uint32_t& volume) const override;
  int32_t MaxSpeakerVolume(uint32_t& maxVolume) const override;
  int32_t MinSpeakerVolume(uint32_t& minVolume) const override;
  int32_t SpeakerVolumeStepSize(uint16_t& stepSize) const override;
  int32_t MicrophoneVolumeIsAvailable(bool& available) override;
  int32_t SetMicrophoneVolume(uint32_t volume) override;
  int32_t MicrophoneVolume(uint32_t& volume) const override;
  int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const override;
  int32_t MinMicrophoneVolume(uint32_t& minVolume) const override;
  int32_t MicrophoneVolumeStepSize(uint16_t& stepSize) const override;
  int32_t MicrophoneMuteIsAvailable(bool& available) override;
  int32_t SetMicrophoneMute(bool enable) override;
  int32_t MicrophoneMute(bool& enabled) const override;
  int32_t SpeakerMuteIsAvailable(bool& available) override;
  int32_t SetSpeakerMute(bool enable) override;
  int32_t SpeakerMute(bool& enabled) const override;
  int32_t MicrophoneBoostIsAvailable(bool& available) override;
  int32_t SetMicrophoneBoost(bool enable) override;
  int32_t MicrophoneBoost(bool& enabled) const override;
  int32_t StereoPlayoutIsAvailable(bool& available) override;
  int32_t SetStereoPlayout(bool enable) override;
  int32_t StereoPlayout(bool& enabled) const override;
  int32_t StereoRecordingIsAvailable(bool& available) override;
  int32_t SetStereoRecording(bool enable) override;
  int32_t StereoRecording(bool& enabled) const override;
  int32_t SetPlayoutBuffer(const AudioDeviceModule::BufferType type,
                           uint16_t sizeMS) override;
  int32_t CPULoad(uint16_t& load) const override;
  bool PlayoutWarning() const override;
  bool PlayoutError() const override;
  bool RecordingWarning() const override;
  bool RecordingError() const override;
  void ClearPlayoutWarning() override {}
  void ClearPlayoutError() override {}
  void ClearRecordingWarning() override {}
  void ClearRecordingError() override {}

 private:
  // Uses current |playout_parameters_| and |record_parameters_| to inform the
  // audio device buffer (ADB) about our internal audio parameters.
  void UpdateAudioDeviceBuffer();

  // Registers observers for the AVAudioSessionRouteChangeNotification and
  // AVAudioSessionInterruptionNotification notifications.
  void RegisterNotificationObservers();
  void UnregisterNotificationObservers();

  // Since the preferred audio parameters are only hints to the OS, the actual
  // values may be different once the AVAudioSession has been activated.
  // This method asks for the current hardware parameters and takes actions
  // if they should differ from what we have asked for initially. It also
  // defines |playout_parameters_| and |record_parameters_|.
  void SetupAudioBuffersForActiveAudioSession();

  // Creates a Voice-Processing I/O unit and configures it for full-duplex
  // audio. The selected stream format is selected to avoid internal resampling
  // and to match the 10ms callback rate for WebRTC as well as possible.
  // This method also initializes the created audio unit.
  bool SetupAndInitializeVoiceProcessingAudioUnit();

  // Restarts active audio streams using a new sample rate. Required when e.g.
  // a BT headset is enabled or disabled.
  bool RestartAudioUnitWithNewFormat(float sample_rate);

  // Activates our audio session, creates and initializes the voice-processing
  // audio unit and verifies that we got the preferred native audio parameters.
  bool InitPlayOrRecord();

  // Closes and deletes the voice-processing I/O unit.
  void ShutdownPlayOrRecord();

  // Helper method for destroying the existing audio unit.
  void DisposeAudioUnit();

  // Callback function called on a real-time priority I/O thread from the audio
  // unit. This method is used to signal that recorded audio is available.
  static OSStatus RecordedDataIsAvailable(
      void* in_ref_con,
      AudioUnitRenderActionFlags* io_action_flags,
      const AudioTimeStamp* time_stamp,
      UInt32 in_bus_number,
      UInt32 in_number_frames,
      AudioBufferList* io_data);
  OSStatus OnRecordedDataIsAvailable(
      AudioUnitRenderActionFlags* io_action_flags,
      const AudioTimeStamp* time_stamp,
      UInt32 in_bus_number,
      UInt32 in_number_frames);

  // Callback function called on a real-time priority I/O thread from the audio
  // unit. This method is used to provide audio samples to the audio unit.
  static OSStatus GetPlayoutData(void* in_ref_con,
                                 AudioUnitRenderActionFlags* io_action_flags,
                                 const AudioTimeStamp* time_stamp,
                                 UInt32 in_bus_number,
                                 UInt32 in_number_frames,
                                 AudioBufferList* io_data);
  OSStatus OnGetPlayoutData(AudioUnitRenderActionFlags* io_action_flags,
                            UInt32 in_number_frames,
                            AudioBufferList* io_data);

  // Ensures that methods are called from the same thread as this object is
  // created on.
  rtc::ThreadChecker thread_checker_;

  // Raw pointer handle provided to us in AttachAudioBuffer(). Owned by the
  // AudioDeviceModuleImpl class and called by AudioDeviceModuleImpl::Create().
  // The AudioDeviceBuffer is a member of the AudioDeviceModuleImpl instance
  // and therefore outlives this object.
  AudioDeviceBuffer* audio_device_buffer_;

  // Contains audio parameters (sample rate, #channels, buffer size etc.) for
  // the playout and recording sides. These structure is set in two steps:
  // first, native sample rate and #channels are defined in Init(). Next, the
  // audio session is activated and we verify that the preferred parameters
  // were granted by the OS. At this stage it is also possible to add a third
  // component to the parameters; the native I/O buffer duration.
  // A RTC_CHECK will be hit if we for some reason fail to open an audio session
  // using the specified parameters.
  AudioParameters playout_parameters_;
  AudioParameters record_parameters_;

  // The Voice-Processing I/O unit has the same characteristics as the
  // Remote I/O unit (supports full duplex low-latency audio input and output)
  // and adds AEC for for two-way duplex communication. It also adds AGC,
  // adjustment of voice-processing quality, and muting. Hence, ideal for
  // VoIP applications.
  AudioUnit vpio_unit_;

  // FineAudioBuffer takes an AudioDeviceBuffer which delivers audio data
  // in chunks of 10ms. It then allows for this data to be pulled in
  // a finer or coarser granularity. I.e. interacting with this class instead
  // of directly with the AudioDeviceBuffer one can ask for any number of
  // audio data samples. Is also supports a similar scheme for the recording
  // side.
  // Example: native buffer size can be 128 audio frames at 16kHz sample rate.
  // WebRTC will provide 480 audio frames per 10ms but iOS asks for 128
  // in each callback (one every 8ms). This class can then ask for 128 and the
  // FineAudioBuffer will ask WebRTC for new data only when needed and also
  // cache non-utilized audio between callbacks. On the recording side, iOS
  // can provide audio data frames of size 128 and these are accumulated until
  // enough data to supply one 10ms call exists. This 10ms chunk is then sent
  // to WebRTC and the remaining part is stored.
  rtc::scoped_ptr<FineAudioBuffer> fine_audio_buffer_;

  // Extra audio buffer to be used by the playout side for rendering audio.
  // The buffer size is given by FineAudioBuffer::RequiredBufferSizeBytes().
  rtc::scoped_ptr<SInt8[]> playout_audio_buffer_;

  // Provides a mechanism for encapsulating one or more buffers of audio data.
  // Only used on the recording side.
  AudioBufferList audio_record_buffer_list_;

  // Temporary storage for recorded data. AudioUnitRender() renders into this
  // array as soon as a frame of the desired buffer size has been recorded.
  rtc::scoped_ptr<SInt8[]> record_audio_buffer_;

  // Set to 1 when recording is active and 0 otherwise.
  volatile int recording_;

  // Set to 1 when playout is active and 0 otherwise.
  volatile int playing_;

  // Set to true after successful call to Init(), false otherwise.
  bool initialized_;

  // Set to true after successful call to InitRecording(), false otherwise.
  bool rec_is_initialized_;

  // Set to true after successful call to InitPlayout(), false otherwise.
  bool play_is_initialized_;

  // Audio interruption observer instance.
  void* audio_interruption_observer_;
  void* route_change_observer_;

  // Contains the audio data format specification for a stream of audio.
  AudioStreamBasicDescription application_format_;
};

}  // namespace webrtc

#endif  // WEBRTC_MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_