text: /*
   *  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 MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_
  #define MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_
  
  #include <memory>
  
  #include "sdk/objc/Framework/Headers/WebRTC/RTCMacros.h"
  #include "modules/audio_device/audio_device_generic.h"
  #include "modules/audio_device/ios/audio_session_observer.h"
  #include "modules/audio_device/ios/voice_processing_audio_unit.h"
  #include "rtc_base/buffer.h"
  #include "rtc_base/gtest_prod_util.h"
  #include "rtc_base/thread.h"
  #include "rtc_base/thread_annotations.h"
  #include "rtc_base/thread_checker.h"
  
  RTC_FWD_DECL_OBJC_CLASS(RTCAudioSessionDelegateAdapter);
  
  namespace webrtc {
  
  class FineAudioBuffer;
  
  // Implements full duplex 16-bit mono PCM audio support for iOS using a
  // Voice-Processing (VP) I/O audio unit in Core Audio. The VP I/O audio unit
  // supports audio echo cancellation. It also adds automatic gain control,
  // adjustment of voice-processing quality and muting.
  //
  // An instance must be created and destroyed on one and the same thread.
  // All supported public methods must also be called on the same thread.
  // A thread checker will RTC_DCHECK if any supported method is called on an
  // invalid thread.
  //
  // Recorded audio will be delivered on a real-time internal I/O thread in the
  // audio unit. The audio unit will also ask for audio data to play out on this
  // same thread.
  class AudioDeviceIOS : public AudioDeviceGeneric,
                         public AudioSessionObserver,
                         public VoiceProcessingAudioUnitObserver,
                         public rtc::MessageHandler {
   public:
    AudioDeviceIOS();
    ~AudioDeviceIOS();
  
    void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
  
    InitStatus Init() override;
    int32_t Terminate() override;
    bool Initialized() const override;
  
    int32_t InitPlayout() override;
    bool PlayoutIsInitialized() const override;
  
    int32_t InitRecording() override;
    bool RecordingIsInitialized() const override;
  
    int32_t StartPlayout() override;
    int32_t StopPlayout() override;
    bool Playing() const override { return playing_; }
  
    int32_t StartRecording() override;
    int32_t StopRecording() override;
    bool Recording() const override { return recording_; }
  
    int32_t SetLoudspeakerStatus(bool enable) override;
    int32_t GetLoudspeakerStatus(bool& enabled) const override;
  
    // These methods returns hard-coded delay values and not dynamic delay
    // estimates. The reason is that iOS supports a built-in AEC and the WebRTC
    // AEC will always be disabled in the Libjingle layer to avoid running two
    // AEC implementations at the same time. And, it saves resources to avoid
    // updating these delay values continuously.
    // TODO(henrika): it would be possible to mark these two methods as not
    // implemented since they are only called for A/V-sync purposes today and
    // A/V-sync is not supported on iOS. However, we avoid adding error messages
    // the log by using these dummy implementations instead.
    int32_t PlayoutDelay(uint16_t& delayMS) const override;
  
    // Native audio parameters stored during construction.
    // These methods are unique for the iOS implementation.
    int GetPlayoutAudioParameters(AudioParameters* params) const override;
    int GetRecordAudioParameters(AudioParameters* params) const override;
  
    // These methods are currently not fully implemented on iOS:
  
    // See audio_device_not_implemented.cc for trivial implementations.
    int32_t ActiveAudioLayer(
        AudioDeviceModule::AudioLayer& audioLayer) const override;
    int32_t PlayoutIsAvailable(bool& available) override;
    int32_t RecordingIsAvailable(bool& available) override;
    int32_t SetAGC(bool enable) override;
    bool AGC() const override;
    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;
    int32_t SetPlayoutDevice(uint16_t index) override;
    int32_t SetPlayoutDevice(
        AudioDeviceModule::WindowsDeviceType device) override;
    int32_t SetRecordingDevice(uint16_t index) override;
    int32_t SetRecordingDevice(
        AudioDeviceModule::WindowsDeviceType device) override;
    int32_t InitSpeaker() override;
    bool SpeakerIsInitialized() const override;
    int32_t InitMicrophone() override;
    bool MicrophoneIsInitialized() const override;
    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;
    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;
    int32_t MicrophoneMuteIsAvailable(bool& available) override;
    int32_t SetMicrophoneMute(bool enable) override;
    int32_t MicrophoneMute(bool& enabled) const override;
    int32_t SpeakerMuteIsAvailable(bool& available) override;
    int32_t SetSpeakerMute(bool enable) override;
    int32_t SpeakerMute(bool& enabled) const override;
    int32_t StereoPlayoutIsAvailable(bool& available) override;
    int32_t SetStereoPlayout(bool enable) override;
    int32_t StereoPlayout(bool& enabled) const override;
    int32_t StereoRecordingIsAvailable(bool& available) override;
    int32_t SetStereoRecording(bool enable) override;
    int32_t StereoRecording(bool& enabled) const override;
  
    // AudioSessionObserver methods. May be called from any thread.
    void OnInterruptionBegin() override;
    void OnInterruptionEnd() override;
    void OnValidRouteChange() override;
    void OnCanPlayOrRecordChange(bool can_play_or_record) override;
    void OnChangedOutputVolume() override;
  
    // VoiceProcessingAudioUnitObserver methods.
    OSStatus OnDeliverRecordedData(AudioUnitRenderActionFlags* flags,
                                   const AudioTimeStamp* time_stamp,
                                   UInt32 bus_number,
                                   UInt32 num_frames,
                                   AudioBufferList* io_data) override;
    OSStatus OnGetPlayoutData(AudioUnitRenderActionFlags* flags,
                              const AudioTimeStamp* time_stamp,
                              UInt32 bus_number,
                              UInt32 num_frames,
                              AudioBufferList* io_data) override;
  
    // Handles messages from posts.
    void OnMessage(rtc::Message *msg) override;
  
   private:
    // Called by the relevant AudioSessionObserver methods on |thread_|.
    void HandleInterruptionBegin();
    void HandleInterruptionEnd();
    void HandleValidRouteChange();
    void HandleCanPlayOrRecordChange(bool can_play_or_record);
    void HandleSampleRateChange(float sample_rate);
    void HandlePlayoutGlitchDetected();
    void HandleOutputVolumeChange();
  
    // Uses current |playout_parameters_| and |record_parameters_| to inform the
    // audio device buffer (ADB) about our internal audio parameters.
    void UpdateAudioDeviceBuffer();
  
    // Since the preferred audio parameters are only hints to the OS, the actual
    // values may be different once the AVAudioSession has been activated.
    // This method asks for the current hardware parameters and takes actions
    // if they should differ from what we have asked for initially. It also
    // defines |playout_parameters_| and |record_parameters_|.
    void SetupAudioBuffersForActiveAudioSession();
  
    // Creates the audio unit.
    bool CreateAudioUnit();
  
    // Updates the audio unit state based on current state.
    void UpdateAudioUnit(bool can_play_or_record);
  
    // Configures the audio session for WebRTC.
    bool ConfigureAudioSession();
    // Unconfigures the audio session.
    void UnconfigureAudioSession();
  
    // Activates our audio session, creates and initializes the voice-processing
    // audio unit and verifies that we got the preferred native audio parameters.
    bool InitPlayOrRecord();
  
    // Closes and deletes the voice-processing I/O unit.
    void ShutdownPlayOrRecord();
  
    // Ensures that methods are called from the same thread as this object is
    // created on.
    rtc::ThreadChecker thread_checker_;
  
    // Native I/O audio thread checker.
    rtc::ThreadChecker io_thread_checker_;
  
    // Thread that this object is created on.
    rtc::Thread* thread_;
  
    // Raw pointer handle provided to us in AttachAudioBuffer(). Owned by the
    // AudioDeviceModuleImpl class and called by AudioDeviceModule::Create().
    // The AudioDeviceBuffer is a member of the AudioDeviceModuleImpl instance
    // and therefore outlives this object.
    AudioDeviceBuffer* audio_device_buffer_;
  
    // Contains audio parameters (sample rate, #channels, buffer size etc.) for
    // the playout and recording sides. These structure is set in two steps:
    // first, native sample rate and #channels are defined in Init(). Next, the
    // audio session is activated and we verify that the preferred parameters
    // were granted by the OS. At this stage it is also possible to add a third
    // component to the parameters; the native I/O buffer duration.
    // A RTC_CHECK will be hit if we for some reason fail to open an audio session
    // using the specified parameters.
    AudioParameters playout_parameters_;
    AudioParameters record_parameters_;
  
    // The AudioUnit used to play and record audio.
    std::unique_ptr<VoiceProcessingAudioUnit> audio_unit_;
  
    // FineAudioBuffer takes an AudioDeviceBuffer which delivers audio data
    // in chunks of 10ms. It then allows for this data to be pulled in
    // a finer or coarser granularity. I.e. interacting with this class instead
    // of directly with the AudioDeviceBuffer one can ask for any number of
    // audio data samples. Is also supports a similar scheme for the recording
    // side.
    // Example: native buffer size can be 128 audio frames at 16kHz sample rate.
    // WebRTC will provide 480 audio frames per 10ms but iOS asks for 128
    // in each callback (one every 8ms). This class can then ask for 128 and the
    // FineAudioBuffer will ask WebRTC for new data only when needed and also
    // cache non-utilized audio between callbacks. On the recording side, iOS
    // can provide audio data frames of size 128 and these are accumulated until
    // enough data to supply one 10ms call exists. This 10ms chunk is then sent
    // to WebRTC and the remaining part is stored.
    std::unique_ptr<FineAudioBuffer> fine_audio_buffer_;
  
    // Temporary storage for recorded data. AudioUnitRender() renders into this
    // array as soon as a frame of the desired buffer size has been recorded.
    // On real iOS devices, the size will be fixed and set once. For iOS
    // simulators, the size can vary from callback to callback and the size
    // will be changed dynamically to account for this behavior.
    rtc::BufferT<int8_t> record_audio_buffer_;
  
    // Set to 1 when recording is active and 0 otherwise.
    volatile int recording_;
  
    // Set to 1 when playout is active and 0 otherwise.
    volatile int playing_;
  
    // Set to true after successful call to Init(), false otherwise.
    bool initialized_ RTC_ACCESS_ON(thread_checker_);
  
    // Set to true after successful call to InitRecording() or InitPlayout(),
    // false otherwise.
    bool audio_is_initialized_;
  
    // Set to true if audio session is interrupted, false otherwise.
    bool is_interrupted_;
  
    // Audio interruption observer instance.
    RTCAudioSessionDelegateAdapter* audio_session_observer_
        RTC_ACCESS_ON(thread_checker_);
  
    // Set to true if we've activated the audio session.
    bool has_configured_session_ RTC_ACCESS_ON(thread_checker_);
  
    // Counts number of detected audio glitches on the playout side.
    int64_t num_detected_playout_glitches_ RTC_ACCESS_ON(thread_checker_);
    int64_t last_playout_time_ RTC_ACCESS_ON(io_thread_checker_);
  
    // Counts number of playout callbacks per call.
    // The value isupdated on the native I/O thread and later read on the
    // creating thread (see thread_checker_) but at this stage no audio is
    // active. Hence, it is a "thread safe" design and no lock is needed.
    int64_t num_playout_callbacks_;
  
    // Contains the time for when the last output volume change was detected.
    int64_t last_output_volume_change_time_ RTC_ACCESS_ON(thread_checker_);
  
    // Exposes private members for testing purposes only.
    FRIEND_TEST_ALL_PREFIXES(AudioDeviceTest, testInterruptedAudioSession);
  };
  
  }  // namespace webrtc
  
  #endif  // MODULES_AUDIO_DEVICE_IOS_AUDIO_DEVICE_IOS_H_
  