/* * 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 #import "components/audio/RTCAudioDevice.h" #include "api/audio/audio_device.h" #include "api/environment/environment.h" #include "modules/audio_device/audio_device_buffer.h" #include "rtc_base/thread.h" @class ObjCAudioDeviceDelegate; namespace webrtc { class FineAudioBuffer; namespace objc_adm { class ObjCAudioDeviceModule : public AudioDeviceModule { public: explicit ObjCAudioDeviceModule( const Environment& env, id 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& 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 audio_device_; const Environment env_; // 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 audio_device_buffer_; // Set to 1 when recording is active and 0 otherwise. std::atomic recording_ = false; // Set to 1 when playout is active and 0 otherwise. std::atomic 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 cached_playout_delay_ms_ = 0; // Same as `cached_playout_delay_ms_` but for audio input std::atomic cached_recording_delay_ms_ = 0; // Thread that is initialized audio device module. 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 record_fine_audio_buffer_; // Same as `record_fine_audio_buffer_` but for audio output. std::unique_ptr playout_fine_audio_buffer_; // Temporary storage for recorded data. webrtc::BufferT 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_