blob: ccb23bbe5bf9a4f58a676502a544e537e6cf47a7 [file] [log] [blame]
/*
* 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 <condition_variable>
#include <mutex>
#include <android-base/thread_annotations.h>
#include <aidl/android/hardware/audio/common/SinkMetadata.h>
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
#include <aidl/android/hardware/bluetooth/audio/PresentationPosition.h>
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
#include <aidl/android/media/audio/common/AudioDeviceDescription.h>
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