android_device_peter_gsi/bluetooth/audio/hw/device_port_proxy.h
Peter Cai c71693def3 gsi: Initial implementation of sysbta, a system-side bluetooth audio HAL
On platform release T, the legacy `audio.a2dp.default` HAL no longer
exists, and cannot be trivially restored for generic system-side A2DP
audio support. Rather than trying to cling on to its existence (which
does not even work anymore even if one did so), it is time to come up
with a new solution.

This commit introduces a system-side implementation of the generic
bluetooth audio HAL. The HAL itself is modelled after the default
bluetooth audio HAL, while substantial components of the default audio
HAL are also included as it has to also implement the audio HAL
interfaces.

The audio HAL implementation is delegated to `audio.sysbta.default`,
forked from `audio.bluetooth.default` from the Bluetooth apex package.
It then communicates with the bluetooth audio HAL interfaces, which need
to live in the same process (in this case, the process of the sysbta
HAL). This is why we cannot just load `audio.sysbta.default` into the
default audio HAL or the audioserver process directly, but rather have
to include our own simplistic audio HAL implementation.

For now, the audio HAL implementation only includes one for the 6.0
version, but technically, an interface for *every* audio HAL version
needs to exist. This, along with other messiness in the sysbta
implementation, will be addressed in a future commit.

Note that to actually make use of the sysbta audio hal, patches in
frameworks/av and packages/modules/Bluetooth are required to introduce
support for the property `persist.bluetooth.system_audio_hal.enabled`.
2022-08-24 15:47:06 -04:00

214 lines
6.5 KiB
C++

/*
* Copyright 2022 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 <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
#include <hardware/audio.h>
#include <condition_variable>
#include <mutex>
#include <unordered_map>
enum class BluetoothStreamState : uint8_t;
namespace android {
namespace bluetooth {
namespace audio {
/***
* 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, in stream_apis.cc, if GetState() is only used for
* verbose logging, it is not locked, so the state may not be synchronized.
***/
class BluetoothAudioPort {
public:
BluetoothAudioPort(){};
virtual ~BluetoothAudioPort() = default;
/***
* Fetch output control / data path of BluetoothAudioPort and setup
* callbacks into BluetoothAudioProvider. If SetUp() returns false, the audio
* HAL must delete this BluetoothAudioPort and return EINVAL to caller
***/
virtual bool SetUp(audio_devices_t) { return false; }
/***
* Unregister this BluetoothAudioPort from BluetoothAudioSessionControl.
* Audio HAL must delete this BluetoothAudioPort after calling this.
***/
virtual void TearDown() {}
/***
* 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(audio_config_t*) const { return false; };
/***
* WAR to support Mono mode / 16 bits per sample
***/
virtual void ForcePcmStereoToMono(bool) {}
/***
* When the Audio framework / HAL wants to change the stream state, it invokes
* these 3 functions to control the Bluetooth stack (Audio Control Path).
* Note: Both Start() and Suspend() will return true when there are no errors.
* Called by Audio framework / HAL to start the stream
***/
virtual bool Start() { return false; }
/***
* Called by Audio framework / HAL to suspend the stream
***/
virtual bool Suspend() { return false; };
/***
virtual bool Suspend() { return false; }
* Called by Audio framework / HAL to stop the stream
***/
virtual void Stop() {}
/***
* 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(uint64_t*, uint64_t*, timespec*) const {
return false;
}
/***
* Called by the Audio framework / HAL when the metadata of the stream's
* source has been changed.
***/
virtual void UpdateSourceMetadata(const source_metadata*) const {};
/***
* Return the current BluetoothStreamState
***/
virtual BluetoothStreamState GetState() const {
return static_cast<BluetoothStreamState>(0);
}
/***
* Set the current BluetoothStreamState
***/
virtual void SetState(BluetoothStreamState state) {}
virtual bool IsA2dp() const { return false; }
virtual bool GetPreferredDataIntervalUs(size_t* interval_us) const {
return false;
};
virtual size_t WriteData(const void* buffer, size_t bytes) const {
return 0;
};
virtual size_t ReadData(void* buffer, size_t bytes) const { return 0; };
};
namespace aidl {
using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
using ::aidl::android::hardware::bluetooth::audio::SessionType;
class BluetoothAudioPortAidl : public BluetoothAudioPort {
public:
BluetoothAudioPortAidl();
virtual ~BluetoothAudioPortAidl() = default;
bool SetUp(audio_devices_t devices) override;
void TearDown() override;
void ForcePcmStereoToMono(bool force) override { is_stereo_to_mono_ = force; }
bool Start() override;
bool Suspend() override;
void Stop() override;
bool GetPresentationPosition(uint64_t* delay_ns, uint64_t* byte,
timespec* timestamp) const override;
void UpdateSourceMetadata(
const source_metadata* source_metadata) const override;
/***
* Called by the Audio framework / HAL when the metadata of the stream's
* sink has been changed.
***/
virtual void UpdateSinkMetadata(const sink_metadata* sink_metadata) const;
BluetoothStreamState GetState() const override;
void SetState(BluetoothStreamState state) override;
bool IsA2dp() const override {
return session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
session_type_ ==
SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
}
bool GetPreferredDataIntervalUs(size_t* interval_us) const override;
protected:
uint16_t cookie_;
BluetoothStreamState state_;
SessionType session_type_;
// WR to support Mono: True if fetching Stereo and mixing into Mono
bool is_stereo_to_mono_ = false;
virtual bool in_use() const;
private:
mutable std::mutex cv_mutex_;
std::condition_variable internal_cv_;
// Check and initialize session type for |devices| If failed, this
// BluetoothAudioPortAidl is not initialized and must be deleted.
bool init_session_type(audio_devices_t device);
bool CondwaitState(BluetoothStreamState state);
void ControlResultHandler(const BluetoothAudioStatus& status);
void SessionChangedHandler();
};
class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
public:
~BluetoothAudioPortAidlOut();
// The audio data path to the Bluetooth stack (Software encoding)
size_t WriteData(const void* buffer, size_t bytes) const override;
bool LoadAudioConfig(audio_config_t* audio_cfg) const override;
};
class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl {
public:
~BluetoothAudioPortAidlIn();
// The audio data path from the Bluetooth stack (Software decoded)
size_t ReadData(void* buffer, size_t bytes) const override;
bool LoadAudioConfig(audio_config_t* audio_cfg) const override;
};
} // namespace aidl
} // namespace audio
} // namespace bluetooth
} // namespace android