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