1 /*
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 
11 #ifndef AUDIO_DEVICE_AUDIO_DEVICE_MAC_H_
12 #define AUDIO_DEVICE_AUDIO_DEVICE_MAC_H_
13 
14 #include <AudioToolbox/AudioConverter.h>
15 #include <CoreAudio/CoreAudio.h>
16 #include <mach/semaphore.h>
17 
18 #include <memory>
19 
20 #include "modules/audio_device/audio_device_generic.h"
21 #include "modules/audio_device/mac/audio_mixer_manager_mac.h"
22 #include "rtc_base/event.h"
23 #include "rtc_base/logging.h"
24 #include "rtc_base/synchronization/mutex.h"
25 #include "rtc_base/thread_annotations.h"
26 
27 struct PaUtilRingBuffer;
28 
29 namespace rtc {
30 class PlatformThread;
31 }  // namespace rtc
32 
33 namespace webrtc {
34 
35 const uint32_t N_REC_SAMPLES_PER_SEC = 48000;
36 const uint32_t N_PLAY_SAMPLES_PER_SEC = 48000;
37 
38 const uint32_t N_REC_CHANNELS = 1;   // default is mono recording
39 const uint32_t N_PLAY_CHANNELS = 2;  // default is stereo playout
40 const uint32_t N_DEVICE_CHANNELS = 64;
41 
42 const int kBufferSizeMs = 10;
43 
44 const uint32_t ENGINE_REC_BUF_SIZE_IN_SAMPLES =
45     N_REC_SAMPLES_PER_SEC * kBufferSizeMs / 1000;
46 const uint32_t ENGINE_PLAY_BUF_SIZE_IN_SAMPLES =
47     N_PLAY_SAMPLES_PER_SEC * kBufferSizeMs / 1000;
48 
49 const int N_BLOCKS_IO = 2;
50 const int N_BUFFERS_IN = 2;   // Must be at least N_BLOCKS_IO.
51 const int N_BUFFERS_OUT = 3;  // Must be at least N_BLOCKS_IO.
52 
53 const uint32_t TIMER_PERIOD_MS = 2 * 10 * N_BLOCKS_IO * 1000000;
54 
55 const uint32_t REC_BUF_SIZE_IN_SAMPLES =
56     ENGINE_REC_BUF_SIZE_IN_SAMPLES * N_DEVICE_CHANNELS * N_BUFFERS_IN;
57 const uint32_t PLAY_BUF_SIZE_IN_SAMPLES =
58     ENGINE_PLAY_BUF_SIZE_IN_SAMPLES * N_PLAY_CHANNELS * N_BUFFERS_OUT;
59 
60 const int kGetMicVolumeIntervalMs = 1000;
61 
62 class AudioDeviceMac : public AudioDeviceGeneric {
63  public:
64   AudioDeviceMac();
65   ~AudioDeviceMac();
66 
67   // Retrieve the currently utilized audio layer
68   virtual int32_t ActiveAudioLayer(
69       AudioDeviceModule::AudioLayer& audioLayer) const;
70 
71   // Main initializaton and termination
72   virtual InitStatus Init() RTC_LOCKS_EXCLUDED(mutex_);
73   virtual int32_t Terminate() RTC_LOCKS_EXCLUDED(mutex_);
74   virtual bool Initialized() const;
75 
76   // Device enumeration
77   virtual int16_t PlayoutDevices();
78   virtual int16_t RecordingDevices();
79   virtual int32_t PlayoutDeviceName(uint16_t index,
80                                     char name[kAdmMaxDeviceNameSize],
81                                     char guid[kAdmMaxGuidSize]);
82   virtual int32_t RecordingDeviceName(uint16_t index,
83                                       char name[kAdmMaxDeviceNameSize],
84                                       char guid[kAdmMaxGuidSize]);
85 
86   // Device selection
87   virtual int32_t SetPlayoutDevice(uint16_t index) RTC_LOCKS_EXCLUDED(mutex_);
88   virtual int32_t SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device);
89   virtual int32_t SetRecordingDevice(uint16_t index);
90   virtual int32_t SetRecordingDevice(
91       AudioDeviceModule::WindowsDeviceType device);
92 
93   // Audio transport initialization
94   virtual int32_t PlayoutIsAvailable(bool& available);
95   virtual int32_t InitPlayout() RTC_LOCKS_EXCLUDED(mutex_);
96   virtual bool PlayoutIsInitialized() const;
97   virtual int32_t RecordingIsAvailable(bool& available);
98   virtual int32_t InitRecording() RTC_LOCKS_EXCLUDED(mutex_);
99   virtual bool RecordingIsInitialized() const;
100 
101   // Audio transport control
102   virtual int32_t StartPlayout() RTC_LOCKS_EXCLUDED(mutex_);
103   virtual int32_t StopPlayout() RTC_LOCKS_EXCLUDED(mutex_);
104   virtual bool Playing() const;
105   virtual int32_t StartRecording() RTC_LOCKS_EXCLUDED(mutex_);
106   virtual int32_t StopRecording() RTC_LOCKS_EXCLUDED(mutex_);
107   virtual bool Recording() const;
108 
109   // Audio mixer initialization
110   virtual int32_t InitSpeaker() RTC_LOCKS_EXCLUDED(mutex_);
111   virtual bool SpeakerIsInitialized() const;
112   virtual int32_t InitMicrophone() RTC_LOCKS_EXCLUDED(mutex_);
113   virtual bool MicrophoneIsInitialized() const;
114 
115   // Speaker volume controls
116   virtual int32_t SpeakerVolumeIsAvailable(bool& available);
117   virtual int32_t SetSpeakerVolume(uint32_t volume);
118   virtual int32_t SpeakerVolume(uint32_t& volume) const;
119   virtual int32_t MaxSpeakerVolume(uint32_t& maxVolume) const;
120   virtual int32_t MinSpeakerVolume(uint32_t& minVolume) const;
121 
122   // Microphone volume controls
123   virtual int32_t MicrophoneVolumeIsAvailable(bool& available);
124   virtual int32_t SetMicrophoneVolume(uint32_t volume);
125   virtual int32_t MicrophoneVolume(uint32_t& volume) const;
126   virtual int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const;
127   virtual int32_t MinMicrophoneVolume(uint32_t& minVolume) const;
128 
129   // Microphone mute control
130   virtual int32_t MicrophoneMuteIsAvailable(bool& available);
131   virtual int32_t SetMicrophoneMute(bool enable);
132   virtual int32_t MicrophoneMute(bool& enabled) const;
133 
134   // Speaker mute control
135   virtual int32_t SpeakerMuteIsAvailable(bool& available);
136   virtual int32_t SetSpeakerMute(bool enable);
137   virtual int32_t SpeakerMute(bool& enabled) const;
138 
139   // Stereo support
140   virtual int32_t StereoPlayoutIsAvailable(bool& available);
141   virtual int32_t SetStereoPlayout(bool enable);
142   virtual int32_t StereoPlayout(bool& enabled) const;
143   virtual int32_t StereoRecordingIsAvailable(bool& available);
144   virtual int32_t SetStereoRecording(bool enable);
145   virtual int32_t StereoRecording(bool& enabled) const;
146 
147   // Delay information and control
148   virtual int32_t PlayoutDelay(uint16_t& delayMS) const;
149 
150   virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer)
151       RTC_LOCKS_EXCLUDED(mutex_);
152 
153  private:
154   int32_t InitSpeakerLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
155   int32_t InitMicrophoneLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
156 
157   virtual int32_t MicrophoneIsAvailable(bool& available);
158   virtual int32_t SpeakerIsAvailable(bool& available);
159 
160   static void AtomicSet32(int32_t* theValue, int32_t newValue);
161   static int32_t AtomicGet32(int32_t* theValue);
162 
163   static void logCAMsg(const rtc::LoggingSeverity sev,
164                        const char* msg,
165                        const char* err);
166 
167   int32_t GetNumberDevices(const AudioObjectPropertyScope scope,
168                            AudioDeviceID scopedDeviceIds[],
169                            const uint32_t deviceListLength);
170 
171   int32_t GetDeviceName(const AudioObjectPropertyScope scope,
172                         const uint16_t index,
173                         char* name);
174 
175   int32_t InitDevice(uint16_t userDeviceIndex,
176                      AudioDeviceID& deviceId,
177                      bool isInput);
178 
179   // Always work with our preferred playout format inside VoE.
180   // Then convert the output to the OS setting using an AudioConverter.
181   OSStatus SetDesiredPlayoutFormat();
182 
183   static OSStatus objectListenerProc(
184       AudioObjectID objectId,
185       UInt32 numberAddresses,
186       const AudioObjectPropertyAddress addresses[],
187       void* clientData);
188 
189   OSStatus implObjectListenerProc(AudioObjectID objectId,
190                                   UInt32 numberAddresses,
191                                   const AudioObjectPropertyAddress addresses[]);
192 
193   int32_t HandleDeviceChange();
194 
195   int32_t HandleStreamFormatChange(AudioObjectID objectId,
196                                    AudioObjectPropertyAddress propertyAddress);
197 
198   int32_t HandleDataSourceChange(AudioObjectID objectId,
199                                  AudioObjectPropertyAddress propertyAddress);
200 
201   int32_t HandleProcessorOverload(AudioObjectPropertyAddress propertyAddress);
202 
203   static OSStatus deviceIOProc(AudioDeviceID device,
204                                const AudioTimeStamp* now,
205                                const AudioBufferList* inputData,
206                                const AudioTimeStamp* inputTime,
207                                AudioBufferList* outputData,
208                                const AudioTimeStamp* outputTime,
209                                void* clientData);
210 
211   static OSStatus outConverterProc(
212       AudioConverterRef audioConverter,
213       UInt32* numberDataPackets,
214       AudioBufferList* data,
215       AudioStreamPacketDescription** dataPacketDescription,
216       void* userData);
217 
218   static OSStatus inDeviceIOProc(AudioDeviceID device,
219                                  const AudioTimeStamp* now,
220                                  const AudioBufferList* inputData,
221                                  const AudioTimeStamp* inputTime,
222                                  AudioBufferList* outputData,
223                                  const AudioTimeStamp* outputTime,
224                                  void* clientData);
225 
226   static OSStatus inConverterProc(
227       AudioConverterRef audioConverter,
228       UInt32* numberDataPackets,
229       AudioBufferList* data,
230       AudioStreamPacketDescription** dataPacketDescription,
231       void* inUserData);
232 
233   OSStatus implDeviceIOProc(const AudioBufferList* inputData,
234                             const AudioTimeStamp* inputTime,
235                             AudioBufferList* outputData,
236                             const AudioTimeStamp* outputTime)
237       RTC_LOCKS_EXCLUDED(mutex_);
238 
239   OSStatus implOutConverterProc(UInt32* numberDataPackets,
240                                 AudioBufferList* data);
241 
242   OSStatus implInDeviceIOProc(const AudioBufferList* inputData,
243                               const AudioTimeStamp* inputTime)
244       RTC_LOCKS_EXCLUDED(mutex_);
245 
246   OSStatus implInConverterProc(UInt32* numberDataPackets,
247                                AudioBufferList* data);
248 
249   static void RunCapture(void*);
250   static void RunRender(void*);
251   bool CaptureWorkerThread();
252   bool RenderWorkerThread();
253 
254   bool KeyPressed();
255 
256   AudioDeviceBuffer* _ptrAudioBuffer;
257 
258   Mutex mutex_;
259 
260   rtc::Event _stopEventRec;
261   rtc::Event _stopEvent;
262 
263   // TODO(pbos): Replace with direct members, just start/stop, no need to
264   // recreate the thread.
265   // Only valid/running between calls to StartRecording and StopRecording.
266   std::unique_ptr<rtc::PlatformThread> capture_worker_thread_;
267 
268   // Only valid/running between calls to StartPlayout and StopPlayout.
269   std::unique_ptr<rtc::PlatformThread> render_worker_thread_;
270 
271   AudioMixerManagerMac _mixerManager;
272 
273   uint16_t _inputDeviceIndex;
274   uint16_t _outputDeviceIndex;
275   AudioDeviceID _inputDeviceID;
276   AudioDeviceID _outputDeviceID;
277 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
278   AudioDeviceIOProcID _inDeviceIOProcID;
279   AudioDeviceIOProcID _deviceIOProcID;
280 #endif
281   bool _inputDeviceIsSpecified;
282   bool _outputDeviceIsSpecified;
283 
284   uint8_t _recChannels;
285   uint8_t _playChannels;
286 
287   Float32* _captureBufData;
288   SInt16* _renderBufData;
289 
290   SInt16 _renderConvertData[PLAY_BUF_SIZE_IN_SAMPLES];
291 
292   bool _initialized;
293   bool _isShutDown;
294   bool _recording;
295   bool _playing;
296   bool _recIsInitialized;
297   bool _playIsInitialized;
298 
299   // Atomically set varaibles
300   int32_t _renderDeviceIsAlive;
301   int32_t _captureDeviceIsAlive;
302 
303   bool _twoDevices;
304   bool _doStop;  // For play if not shared device or play+rec if shared device
305   bool _doStopRec;  // For rec if not shared device
306   bool _macBookPro;
307   bool _macBookProPanRight;
308 
309   AudioConverterRef _captureConverter;
310   AudioConverterRef _renderConverter;
311 
312   AudioStreamBasicDescription _outStreamFormat;
313   AudioStreamBasicDescription _outDesiredFormat;
314   AudioStreamBasicDescription _inStreamFormat;
315   AudioStreamBasicDescription _inDesiredFormat;
316 
317   uint32_t _captureLatencyUs;
318   uint32_t _renderLatencyUs;
319 
320   // Atomically set variables
321   mutable int32_t _captureDelayUs;
322   mutable int32_t _renderDelayUs;
323 
324   int32_t _renderDelayOffsetSamples;
325 
326   PaUtilRingBuffer* _paCaptureBuffer;
327   PaUtilRingBuffer* _paRenderBuffer;
328 
329   semaphore_t _renderSemaphore;
330   semaphore_t _captureSemaphore;
331 
332   int _captureBufSizeSamples;
333   int _renderBufSizeSamples;
334 
335   // Typing detection
336   // 0x5c is key "9", after that comes function keys.
337   bool prev_key_state_[0x5d];
338 };
339 
340 }  // namespace webrtc
341 
342 #endif  // MODULES_AUDIO_DEVICE_MAIN_SOURCE_MAC_AUDIO_DEVICE_MAC_H_
343