| /* |
| * 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_ |