/* * 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 AUDIO_DEVICE_AUDIO_DEVICE_MAC_H_ #define AUDIO_DEVICE_AUDIO_DEVICE_MAC_H_ #include #include #include #include #include #include "absl/strings/string_view.h" #include "modules/audio_device/audio_device_generic.h" #include "modules/audio_device/mac/audio_mixer_manager_mac.h" #include "rtc_base/event.h" #include "rtc_base/logging.h" #include "rtc_base/platform_thread.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" struct PaUtilRingBuffer; namespace webrtc { const uint32_t N_REC_SAMPLES_PER_SEC = 48000; const uint32_t N_PLAY_SAMPLES_PER_SEC = 48000; const uint32_t N_REC_CHANNELS = 1; // default is mono recording const uint32_t N_PLAY_CHANNELS = 2; // default is stereo playout const uint32_t N_DEVICE_CHANNELS = 64; const int kBufferSizeMs = 10; const uint32_t ENGINE_REC_BUF_SIZE_IN_SAMPLES = N_REC_SAMPLES_PER_SEC * kBufferSizeMs / 1000; const uint32_t ENGINE_PLAY_BUF_SIZE_IN_SAMPLES = N_PLAY_SAMPLES_PER_SEC * kBufferSizeMs / 1000; const int N_BLOCKS_IO = 2; const int N_BUFFERS_IN = 2; // Must be at least N_BLOCKS_IO. const int N_BUFFERS_OUT = 3; // Must be at least N_BLOCKS_IO. const uint32_t TIMER_PERIOD_MS = 2 * 10 * N_BLOCKS_IO * 1000000; const uint32_t REC_BUF_SIZE_IN_SAMPLES = ENGINE_REC_BUF_SIZE_IN_SAMPLES * N_DEVICE_CHANNELS * N_BUFFERS_IN; const uint32_t PLAY_BUF_SIZE_IN_SAMPLES = ENGINE_PLAY_BUF_SIZE_IN_SAMPLES * N_PLAY_CHANNELS * N_BUFFERS_OUT; const int kGetMicVolumeIntervalMs = 1000; class AudioDeviceMac : public AudioDeviceGeneric { public: AudioDeviceMac(); ~AudioDeviceMac(); // Retrieve the currently utilized audio layer virtual int32_t ActiveAudioLayer( AudioDeviceModule::AudioLayer& audioLayer) const; // Main initializaton and termination virtual InitStatus Init() RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t Terminate() RTC_LOCKS_EXCLUDED(mutex_); virtual bool Initialized() const; // Device enumeration virtual int16_t PlayoutDevices(); virtual int16_t RecordingDevices(); virtual int32_t PlayoutDeviceName(uint16_t index, char name[kAdmMaxDeviceNameSize], char guid[kAdmMaxGuidSize]); virtual int32_t RecordingDeviceName(uint16_t index, char name[kAdmMaxDeviceNameSize], char guid[kAdmMaxGuidSize]); // Device selection virtual int32_t SetPlayoutDevice(uint16_t index) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device); virtual int32_t SetRecordingDevice(uint16_t index); virtual int32_t SetRecordingDevice( AudioDeviceModule::WindowsDeviceType device); // Audio transport initialization virtual int32_t PlayoutIsAvailable(bool& available); virtual int32_t InitPlayout() RTC_LOCKS_EXCLUDED(mutex_); virtual bool PlayoutIsInitialized() const; virtual int32_t RecordingIsAvailable(bool& available); virtual int32_t InitRecording() RTC_LOCKS_EXCLUDED(mutex_); virtual bool RecordingIsInitialized() const; // Audio transport control virtual int32_t StartPlayout() RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t StopPlayout() RTC_LOCKS_EXCLUDED(mutex_); virtual bool Playing() const; virtual int32_t StartRecording() RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t StopRecording() RTC_LOCKS_EXCLUDED(mutex_); virtual bool Recording() const; // Audio mixer initialization virtual int32_t InitSpeaker() RTC_LOCKS_EXCLUDED(mutex_); virtual bool SpeakerIsInitialized() const; virtual int32_t InitMicrophone() RTC_LOCKS_EXCLUDED(mutex_); virtual bool MicrophoneIsInitialized() const; // Speaker volume controls virtual int32_t SpeakerVolumeIsAvailable(bool& available) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t SetSpeakerVolume(uint32_t volume); virtual int32_t SpeakerVolume(uint32_t& volume) const; virtual int32_t MaxSpeakerVolume(uint32_t& maxVolume) const; virtual int32_t MinSpeakerVolume(uint32_t& minVolume) const; // Microphone volume controls virtual int32_t MicrophoneVolumeIsAvailable(bool& available) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t SetMicrophoneVolume(uint32_t volume); virtual int32_t MicrophoneVolume(uint32_t& volume) const; virtual int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const; virtual int32_t MinMicrophoneVolume(uint32_t& minVolume) const; // Microphone mute control virtual int32_t MicrophoneMuteIsAvailable(bool& available) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t SetMicrophoneMute(bool enable); virtual int32_t MicrophoneMute(bool& enabled) const; // Speaker mute control virtual int32_t SpeakerMuteIsAvailable(bool& available) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t SetSpeakerMute(bool enable); virtual int32_t SpeakerMute(bool& enabled) const; // Stereo support virtual int32_t StereoPlayoutIsAvailable(bool& available) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t SetStereoPlayout(bool enable); virtual int32_t StereoPlayout(bool& enabled) const; virtual int32_t StereoRecordingIsAvailable(bool& available); virtual int32_t SetStereoRecording(bool enable); virtual int32_t StereoRecording(bool& enabled) const; // Delay information and control virtual int32_t PlayoutDelay(uint16_t& delayMS) const; virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) RTC_LOCKS_EXCLUDED(mutex_); private: int32_t InitSpeakerLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); int32_t InitMicrophoneLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); virtual int32_t MicrophoneIsAvailable(bool& available) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t MicrophoneIsAvailableLocked(bool& available) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); virtual int32_t SpeakerIsAvailable(bool& available) RTC_LOCKS_EXCLUDED(mutex_); virtual int32_t SpeakerIsAvailableLocked(bool& available) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); static void AtomicSet32(int32_t* theValue, int32_t newValue); static int32_t AtomicGet32(int32_t* theValue); static void logCAMsg(rtc::LoggingSeverity sev, const char* msg, const char* err); int32_t GetNumberDevices(AudioObjectPropertyScope scope, AudioDeviceID scopedDeviceIds[], uint32_t deviceListLength); int32_t GetDeviceName(AudioObjectPropertyScope scope, uint16_t index, rtc::ArrayView name); int32_t InitDevice(uint16_t userDeviceIndex, AudioDeviceID& deviceId, bool isInput); // Always work with our preferred playout format inside VoE. // Then convert the output to the OS setting using an AudioConverter. OSStatus SetDesiredPlayoutFormat(); static OSStatus objectListenerProc( AudioObjectID objectId, UInt32 numberAddresses, const AudioObjectPropertyAddress addresses[], void* clientData); OSStatus implObjectListenerProc(AudioObjectID objectId, UInt32 numberAddresses, const AudioObjectPropertyAddress addresses[]); int32_t HandleDeviceChange(); int32_t HandleStreamFormatChange(AudioObjectID objectId, AudioObjectPropertyAddress propertyAddress); int32_t HandleDataSourceChange(AudioObjectID objectId, AudioObjectPropertyAddress propertyAddress); int32_t HandleProcessorOverload(AudioObjectPropertyAddress propertyAddress); static OSStatus deviceIOProc(AudioDeviceID device, const AudioTimeStamp* now, const AudioBufferList* inputData, const AudioTimeStamp* inputTime, AudioBufferList* outputData, const AudioTimeStamp* outputTime, void* clientData); static OSStatus outConverterProc( AudioConverterRef audioConverter, UInt32* numberDataPackets, AudioBufferList* data, AudioStreamPacketDescription** dataPacketDescription, void* userData); static OSStatus inDeviceIOProc(AudioDeviceID device, const AudioTimeStamp* now, const AudioBufferList* inputData, const AudioTimeStamp* inputTime, AudioBufferList* outputData, const AudioTimeStamp* outputTime, void* clientData); static OSStatus inConverterProc( AudioConverterRef audioConverter, UInt32* numberDataPackets, AudioBufferList* data, AudioStreamPacketDescription** dataPacketDescription, void* inUserData); OSStatus implDeviceIOProc(const AudioBufferList* inputData, const AudioTimeStamp* inputTime, AudioBufferList* outputData, const AudioTimeStamp* outputTime) RTC_LOCKS_EXCLUDED(mutex_); OSStatus implOutConverterProc(UInt32* numberDataPackets, AudioBufferList* data); OSStatus implInDeviceIOProc(const AudioBufferList* inputData, const AudioTimeStamp* inputTime) RTC_LOCKS_EXCLUDED(mutex_); OSStatus implInConverterProc(UInt32* numberDataPackets, AudioBufferList* data); static void RunCapture(void*); static void RunRender(void*); bool CaptureWorkerThread(); bool RenderWorkerThread(); bool KeyPressed(); AudioDeviceBuffer* _ptrAudioBuffer; Mutex mutex_; rtc::Event _stopEventRec; rtc::Event _stopEvent; // Only valid/running between calls to StartRecording and StopRecording. rtc::PlatformThread capture_worker_thread_; // Only valid/running between calls to StartPlayout and StopPlayout. rtc::PlatformThread render_worker_thread_; AudioMixerManagerMac _mixerManager; uint16_t _inputDeviceIndex; uint16_t _outputDeviceIndex; AudioDeviceID _inputDeviceID; AudioDeviceID _outputDeviceID; #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 AudioDeviceIOProcID _inDeviceIOProcID; AudioDeviceIOProcID _deviceIOProcID; #endif bool _inputDeviceIsSpecified; bool _outputDeviceIsSpecified; uint8_t _recChannels; uint8_t _playChannels; Float32* _captureBufData; SInt16* _renderBufData; SInt16 _renderConvertData[PLAY_BUF_SIZE_IN_SAMPLES]; bool _initialized; bool _isShutDown; bool _recording; bool _playing; bool _recIsInitialized; bool _playIsInitialized; // Atomically set varaibles std::atomic _renderDeviceIsAlive; std::atomic _captureDeviceIsAlive; bool _twoDevices; bool _doStop; // For play if not shared device or play+rec if shared device bool _doStopRec; // For rec if not shared device bool _macBookPro; bool _macBookProPanRight; AudioConverterRef _captureConverter; AudioConverterRef _renderConverter; AudioStreamBasicDescription _outStreamFormat; AudioStreamBasicDescription _outDesiredFormat; AudioStreamBasicDescription _inStreamFormat; AudioStreamBasicDescription _inDesiredFormat; uint32_t _captureLatencyUs; uint32_t _renderLatencyUs; // Atomically set variables mutable std::atomic _captureDelayUs; mutable std::atomic _renderDelayUs; int32_t _renderDelayOffsetSamples; PaUtilRingBuffer* _paCaptureBuffer; PaUtilRingBuffer* _paRenderBuffer; semaphore_t _renderSemaphore; semaphore_t _captureSemaphore; int _captureBufSizeSamples; int _renderBufSizeSamples; // Typing detection // 0x5c is key "9", after that comes function keys. bool prev_key_state_[0x5d]; }; } // namespace webrtc #endif // MODULES_AUDIO_DEVICE_MAIN_SOURCE_MAC_AUDIO_DEVICE_MAC_H_