/* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include #include namespace android::bluetooth::audio::aidl { enum class BluetoothStreamState : uint8_t { DISABLED = 0, // This stream is closing or Bluetooth profiles (A2DP/LE) is disabled STANDBY, STARTING, STARTED, SUSPENDING, UNKNOWN, }; std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state); /** * Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio * Session Control. All methods are not thread safe, so users must acquire a * lock. Note: currently, getState() of DevicePortProxy is only used for * verbose logging, it is not locked, so the state may not be synchronized. */ class BluetoothAudioPort { public: BluetoothAudioPort() = default; virtual ~BluetoothAudioPort() = default; /** * Fetch output control / data path of BluetoothAudioPort and setup * callbacks into BluetoothAudioProvider. If registerPort() returns false, the audio * HAL must delete this BluetoothAudioPort and return EINVAL to caller */ virtual bool registerPort( const ::aidl::android::media::audio::common::AudioDeviceDescription&) = 0; /** * Unregister this BluetoothAudioPort from BluetoothAudioSessionControl. * Audio HAL must delete this BluetoothAudioPort after calling this. */ virtual void unregisterPort() = 0; /** * When the Audio framework / HAL tries to query audio config about format, * channel mask and sample rate, it uses this function to fetch from the * Bluetooth stack */ virtual bool loadAudioConfig( ::aidl::android::hardware::bluetooth::audio::PcmConfiguration&) = 0; /** * When the Audio framework / HAL wants to change the stream state, it invokes * these 4 functions to control the Bluetooth stack (Audio Control Path). * Note: standby(), start() and suspend() will return true when there are no errors. * Called by Audio framework / HAL to change the state to stand by. When A2DP/LE profile is * disabled, the port is first set to STANDBY by calling suspend and then mState is set to * DISABLED. To reset the state back to STANDBY this method is called. */ virtual bool standby() = 0; /** * Called by Audio framework / HAL to start the stream */ virtual bool start() = 0; /** * Called by Audio framework / HAL to suspend the stream */ virtual bool suspend() = 0; /** * Called by Audio framework / HAL to stop the stream */ virtual void stop() = 0; /** * Called by the Audio framework / HAL to fetch information about audio frames * presented to an external sink, or frames presented fror an internal sink */ virtual bool getPresentationPosition( ::aidl::android::hardware::bluetooth::audio::PresentationPosition&) const = 0; /** * Called by the Audio framework / HAL when the metadata of the stream's * source has been changed. */ virtual bool updateSourceMetadata( const ::aidl::android::hardware::audio::common::SourceMetadata&) const { return false; } /** * Called by the Audio framework / HAL when the metadata of the stream's * sink has been changed. */ virtual bool updateSinkMetadata( const ::aidl::android::hardware::audio::common::SinkMetadata&) const { return false; } /** * Return the current BluetoothStreamState */ virtual BluetoothStreamState getState() const = 0; /** * Set the current BluetoothStreamState */ virtual bool setState(BluetoothStreamState) = 0; virtual bool isA2dp() const = 0; virtual bool isLeAudio() const = 0; virtual bool getPreferredDataIntervalUs(size_t&) const = 0; virtual size_t writeData(const void*, size_t) const { return 0; } virtual size_t readData(void*, size_t) const { return 0; } }; class BluetoothAudioPortAidl : public BluetoothAudioPort { public: BluetoothAudioPortAidl(); virtual ~BluetoothAudioPortAidl(); bool registerPort(const ::aidl::android::media::audio::common::AudioDeviceDescription& description) override; void unregisterPort() override; bool loadAudioConfig( ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override; bool standby() override; bool start() override; bool suspend() override; void stop() override; bool getPresentationPosition(::aidl::android::hardware::bluetooth::audio::PresentationPosition& presentation_position) const override; bool updateSourceMetadata(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata) const override; bool updateSinkMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata) const override; /** * Return the current BluetoothStreamState * Note: This method is used for logging, does not lock, so value returned may not be latest */ BluetoothStreamState getState() const override NO_THREAD_SAFETY_ANALYSIS; bool setState(BluetoothStreamState state) override; bool isA2dp() const override; bool isLeAudio() const override; bool getPreferredDataIntervalUs(size_t& interval_us) const override; protected: uint16_t mCookie; BluetoothStreamState mState GUARDED_BY(mCvMutex); ::aidl::android::hardware::bluetooth::audio::SessionType mSessionType; // WR to support Mono: True if fetching Stereo and mixing into Mono bool mIsStereoToMono = false; bool inUse() const; std::string debugMessage() const; private: // start()/suspend() report state change status via callback. Wait until kMaxWaitingTimeMs or a // state change after a call to start()/suspend() and analyse the returned status. Below mutex, // conditional variable serves this purpose. mutable std::mutex mCvMutex; std::condition_variable mInternalCv GUARDED_BY(mCvMutex); // Check and initialize session type for |devices| If failed, this // BluetoothAudioPortAidl is not initialized and must be deleted. bool initSessionType( const ::aidl::android::media::audio::common::AudioDeviceDescription& description); bool condWaitState(BluetoothStreamState state); void controlResultHandler( uint16_t cookie, const ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus& status); void sessionChangedHandler(uint16_t cookie); }; class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl { public: bool loadAudioConfig( ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override; // The audio data path to the Bluetooth stack (Software encoding) size_t writeData(const void* buffer, size_t bytes) const override; }; class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl { public: // The audio data path from the Bluetooth stack (Software decoded) size_t readData(void* buffer, size_t bytes) const override; }; } // namespace android::bluetooth::audio::aidl