diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/sdk/objc/native/src/objc_audio_device.h | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/third_party/libwebrtc/sdk/objc/native/src/objc_audio_device.h b/third_party/libwebrtc/sdk/objc/native/src/objc_audio_device.h new file mode 100644 index 0000000000..fcfe7a6e8b --- /dev/null +++ b/third_party/libwebrtc/sdk/objc/native/src/objc_audio_device.h @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2022 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 SDK_OBJC_NATIVE_SRC_OBJC_AUDIO_DEVICE_H_ +#define SDK_OBJC_NATIVE_SRC_OBJC_AUDIO_DEVICE_H_ + +#include <memory> + +#import "components/audio/RTCAudioDevice.h" + +#include "modules/audio_device/audio_device_buffer.h" +#include "modules/audio_device/include/audio_device.h" +#include "rtc_base/thread.h" + +@class ObjCAudioDeviceDelegate; + +namespace webrtc { + +class FineAudioBuffer; + +namespace objc_adm { + +class ObjCAudioDeviceModule : public AudioDeviceModule { + public: + explicit ObjCAudioDeviceModule(id<RTC_OBJC_TYPE(RTCAudioDevice)> audio_device); + ~ObjCAudioDeviceModule() override; + + // Retrieve the currently utilized audio layer + int32_t ActiveAudioLayer(AudioLayer* audioLayer) const override; + + // Full-duplex transportation of PCM audio + int32_t RegisterAudioCallback(AudioTransport* audioCallback) override; + + // Main initialization and termination + int32_t Init() override; + int32_t Terminate() override; + bool Initialized() const override; + + // Device enumeration + 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; + + // Device selection + int32_t SetPlayoutDevice(uint16_t index) override; + int32_t SetPlayoutDevice(WindowsDeviceType device) override; + int32_t SetRecordingDevice(uint16_t index) override; + int32_t SetRecordingDevice(WindowsDeviceType device) override; + + // Audio transport initialization + int32_t PlayoutIsAvailable(bool* available) override; + int32_t InitPlayout() override; + bool PlayoutIsInitialized() const override; + int32_t RecordingIsAvailable(bool* available) override; + int32_t InitRecording() override; + bool RecordingIsInitialized() const override; + + // Audio transport control + int32_t StartPlayout() override; + int32_t StopPlayout() override; + bool Playing() const override; + int32_t StartRecording() override; + int32_t StopRecording() override; + bool Recording() const override; + + // Audio mixer initialization + int32_t InitSpeaker() override; + bool SpeakerIsInitialized() const override; + int32_t InitMicrophone() override; + bool MicrophoneIsInitialized() const override; + + // Speaker volume controls + 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; + + // Microphone volume controls + 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; + + // Speaker mute control + int32_t SpeakerMuteIsAvailable(bool* available) override; + int32_t SetSpeakerMute(bool enable) override; + int32_t SpeakerMute(bool* enabled) const override; + + // Microphone mute control + int32_t MicrophoneMuteIsAvailable(bool* available) override; + int32_t SetMicrophoneMute(bool enable) override; + int32_t MicrophoneMute(bool* enabled) const override; + + // Stereo support + int32_t StereoPlayoutIsAvailable(bool* available) const override; + int32_t SetStereoPlayout(bool enable) override; + int32_t StereoPlayout(bool* enabled) const override; + int32_t StereoRecordingIsAvailable(bool* available) const override; + int32_t SetStereoRecording(bool enable) override; + int32_t StereoRecording(bool* enabled) const override; + + // Playout delay + int32_t PlayoutDelay(uint16_t* delayMS) const override; + + // Only supported on Android. + bool BuiltInAECIsAvailable() const override; + bool BuiltInAGCIsAvailable() const override; + bool BuiltInNSIsAvailable() const override; + + // Enables the built-in audio effects. Only supported on Android. + int32_t EnableBuiltInAEC(bool enable) override; + int32_t EnableBuiltInAGC(bool enable) override; + int32_t EnableBuiltInNS(bool enable) override; + + // Play underrun count. Only supported on Android. + int32_t GetPlayoutUnderrunCount() const override; + +#if defined(WEBRTC_IOS) + int GetPlayoutAudioParameters(AudioParameters* params) const override; + int GetRecordAudioParameters(AudioParameters* params) const override; +#endif // WEBRTC_IOS + + public: + OSStatus OnDeliverRecordedData(AudioUnitRenderActionFlags* flags, + const AudioTimeStamp* time_stamp, + NSInteger bus_number, + UInt32 num_frames, + const AudioBufferList* io_data, + void* render_context, + RTC_OBJC_TYPE(RTCAudioDeviceRenderRecordedDataBlock) render_block); + + OSStatus OnGetPlayoutData(AudioUnitRenderActionFlags* flags, + const AudioTimeStamp* time_stamp, + NSInteger bus_number, + UInt32 num_frames, + AudioBufferList* io_data); + + // Notifies `ObjCAudioDeviceModule` that at least one of the audio input + // parameters or audio input latency of `RTCAudioDevice` has changed. It necessary to + // update `record_parameters_` with current audio parameter of `RTCAudioDevice` + // via `UpdateAudioParameters` and if parameters are actually change then + // ADB parameters are updated with `UpdateInputAudioDeviceBuffer`. Audio input latency + // stored in `cached_recording_delay_ms_` is also updated with current latency + // of `RTCAudioDevice`. + void HandleAudioInputParametersChange(); + + // Same as `HandleAudioInputParametersChange` but should be called when audio output + // parameters of `RTCAudioDevice` has changed. + void HandleAudioOutputParametersChange(); + + // Notifies `ObjCAudioDeviceModule` about audio input interruption happen due to + // any reason so `ObjCAudioDeviceModule` is can prepare to restart of audio IO. + void HandleAudioInputInterrupted(); + + // Same as `ObjCAudioDeviceModule` but should be called when audio output + // is interrupted. + void HandleAudioOutputInterrupted(); + + private: + // Update our audio parameters if they are different from current device audio parameters + // Returns true when our parameters are update, false - otherwise. + // `ObjCAudioDeviceModule` has audio device buffer (ADB) which has audio parameters + // of playout & recording. The ADB is configured to work with specific sample rate & channel + // count. `ObjCAudioDeviceModule` stores audio parameters which were used to configure ADB in the + // fields `playout_parameters_` and `recording_parameters_`. + // `RTCAudioDevice` protocol has its own audio parameters exposed as individual properties. + // `RTCAudioDevice` audio parameters might change when playout/recording is already in progress, + // for example, when device is switched. `RTCAudioDevice` audio parameters must be kept in sync + // with ADB audio parameters. This method is invoked when `RTCAudioDevice` reports that it's audio + // parameters (`device_params`) are changed and it detects if there any difference with our + // current audio parameters (`params`). Our parameters are updated in case of actual change and + // method returns true. In case of actual change there is follow-up call to either + // `UpdateOutputAudioDeviceBuffer` or `UpdateInputAudioDeviceBuffer` to apply updated + // `playout_parameters_` or `recording_parameters_` to ADB. + + bool UpdateAudioParameters(AudioParameters& params, const AudioParameters& device_params); + + // Update our cached audio latency with device latency. Device latency is reported by + // `RTCAudioDevice` object. Whenever latency is changed, `RTCAudioDevice` is obliged to notify ADM + // about the change via `HandleAudioInputParametersChange` or `HandleAudioOutputParametersChange`. + // Current device IO latency is cached in the atomic field and used from audio IO thread + // to be reported to audio device buffer. It is highly recommended by Apple not to call any + // ObjC methods from audio IO thread, that is why implementation relies on caching latency + // into a field and being notified when latency is changed, which is the case when device + // is switched. + void UpdateAudioDelay(std::atomic<int>& delay_ms, const NSTimeInterval device_latency); + + // Uses current `playout_parameters_` to inform the audio device buffer (ADB) + // about our internal audio parameters. + void UpdateOutputAudioDeviceBuffer(); + + // Uses current `record_parameters_` to inform the audio device buffer (ADB) + // about our internal audio parameters. + void UpdateInputAudioDeviceBuffer(); + + private: + id<RTC_OBJC_TYPE(RTCAudioDevice)> audio_device_; + + const std::unique_ptr<TaskQueueFactory> task_queue_factory_; + + // AudioDeviceBuffer is a buffer to consume audio recorded by `RTCAudioDevice` + // and provide audio to be played via `RTCAudioDevice`. + // Audio PCMs could have different sample rate and channels count, but expected + // to be in 16-bit integer interleaved linear PCM format. + // The current parameters ADB configured to work with is stored in field + // `playout_parameters_` for playout and `record_parameters_` for recording. + // These parameters and ADB must kept in sync with `RTCAudioDevice` audio parameters. + std::unique_ptr<AudioDeviceBuffer> audio_device_buffer_; + + // Set to 1 when recording is active and 0 otherwise. + std::atomic<bool> recording_ = false; + + // Set to 1 when playout is active and 0 otherwise. + std::atomic<bool> playing_ = false; + + // Stores cached value of `RTCAudioDevice outputLatency` to be used from + // audio IO thread. Latency is updated on audio output parameters change. + std::atomic<int> cached_playout_delay_ms_ = 0; + + // Same as `cached_playout_delay_ms_` but for audio input + std::atomic<int> cached_recording_delay_ms_ = 0; + + // Thread that is initialized audio device module. + rtc::Thread* thread_; + + // Ensures that methods are called from the same thread as this object is + // initialized on. + SequenceChecker thread_checker_; + + // I/O audio thread checker. + SequenceChecker io_playout_thread_checker_; + SequenceChecker io_record_thread_checker_; + + bool is_initialized_ RTC_GUARDED_BY(thread_checker_) = false; + bool is_playout_initialized_ RTC_GUARDED_BY(thread_checker_) = false; + bool is_recording_initialized_ RTC_GUARDED_BY(thread_checker_) = false; + + // Contains audio parameters (sample rate, #channels, buffer size etc.) for + // the playout and recording sides. + AudioParameters playout_parameters_; + AudioParameters record_parameters_; + + // `FineAudioBuffer` takes an `AudioDeviceBuffer` which delivers audio data + // in chunks of 10ms. `RTCAudioDevice` might deliver recorded data in + // chunks which are not 10ms long. `FineAudioBuffer` implements adaptation + // from undetermined chunk size to 10ms chunks. + std::unique_ptr<FineAudioBuffer> record_fine_audio_buffer_; + + // Same as `record_fine_audio_buffer_` but for audio output. + std::unique_ptr<FineAudioBuffer> playout_fine_audio_buffer_; + + // Temporary storage for recorded data. + rtc::BufferT<int16_t> record_audio_buffer_; + + // Delegate object provided to RTCAudioDevice during initialization + ObjCAudioDeviceDelegate* audio_device_delegate_; +}; + +} // namespace objc_adm + +} // namespace webrtc + +#endif // SDK_OBJC_NATIVE_SRC_OBJC_AUDIO_DEVICE_H_ |