unplugged-vendor/system/bt/audio_hal_interface/le_audio_software.cc

759 lines
27 KiB
C++
Raw Permalink Normal View History

/*
* Copyright 2019 HIMSA II K/S - www.himsa.dk. Represented by EHIMA -
* www.ehima.com
*
* 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.
*/
#define LOG_TAG "BTAudioClientLeAudio"
#include "le_audio_software.h"
#include <hardware/bluetooth.h>
#include "client_interface.h"
#include "osi/include/log.h"
#include "osi/include/properties.h"
#include "btif/include/btif_hf.h"
bool gLeSinkState;
bool gLeSourceState;
namespace {
/** M: Fix for build pass @{ */
using ::vendor::mediatek::hardware::bluetooth::audio::V2_1::LhdcLowLatencyEn;
/** @} */
using ::vendor::mediatek::hardware::bluetooth::audio::V2_2::CodecType;
using ::vendor::mediatek::hardware::bluetooth::audio::V2_2::LeAudioCodecConfiguration;
using ::vendor::mediatek::hardware::bluetooth::audio::V2_2::PlcMethod;
using ::vendor::mediatek::hardware::bluetooth::audio::V2_2::Lc3Parameters;
using ::vendor::mediatek::hardware::bluetooth::audio::V2_2::Lc3FrameDuration;
using ::vendor::mediatek::hardware::bluetooth::audio::V2_2::ConnParam;
using ::bluetooth::audio::AudioConfiguration;
using ::bluetooth::audio::AudioConfiguration_2_1;
using ::bluetooth::audio::BitsPerSample;
using ::bluetooth::audio::ChannelMode;
using ::bluetooth::audio::PcmParameters;
using ::bluetooth::audio::PcmParameters_2_1;
using ::bluetooth::audio::SampleRate;
using ::bluetooth::audio::SampleRate_2_1;
using ::bluetooth::audio::SessionType;
using ::bluetooth::audio::SessionType_2_1;
using ::bluetooth::audio::BluetoothAudioCtrlAck;
using ::bluetooth::audio::le_audio::StreamCallbacks;
using ::bluetooth::audio::BluetoothAudioSinkClientInterface;
using ::bluetooth::audio::BluetoothAudioSourceClientInterface;
#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28 * 512)
#define LE_AUDIO_OFFLOAD_PROP "persist.vendor.bluetooth.leaudio_mode"
#define LE_AUDIO_OFFLOAD_UMS 0x01
#define LE_AUDIO_OFFLOAD_CG 0x02
#define LE_AUDIO_OFFLOAD_MODE_UNINIT 0xF0
unsigned int g_leaudio_offload_mode = LE_AUDIO_OFFLOAD_MODE_UNINIT;
// Sink transport implementation for Le Audio
class LeAudioSinkTransport
: public bluetooth::audio::IBluetoothSinkTransportInstance {
public:
LeAudioSinkTransport(SessionType_2_1 sessionType, StreamCallbacks stream_cb)
: IBluetoothSinkTransportInstance(
sessionType, {}),
stream_cb_(std::move(stream_cb)),
remote_delay_report_ms_(0),
total_bytes_read_(0),
data_position_({}),
/*pcm_config_({SampleRate::RATE_16000, ChannelMode::STEREO,
BitsPerSample::BITS_16}){};*/
/** M: Fix for build pass @{ */
pcm_config_({SampleRate_2_1::RATE_16000, ChannelMode::STEREO,
BitsPerSample::BITS_16, LhdcLowLatencyEn::Disabled,0}){};
/** @} */
BluetoothAudioCtrlAck StartRequest() override {
LOG(INFO) << __func__;
// Don't send START request to stack while we are in a call
if (!bluetooth::headset::IsCallIdleForCG()) {
LOG(ERROR) << __func__ << ": call state is busy";
return BluetoothAudioCtrlAck::FAILURE;
}
if (stream_cb_.on_resume_(true)) {
return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
}
return BluetoothAudioCtrlAck::FAILURE;
}
BluetoothAudioCtrlAck SuspendRequest() override {
LOG(INFO) << __func__;
if (stream_cb_.on_suspend_()) {
if (!::bluetooth::audio::le_audio::is_leaudio_offload_enabled()) {
uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
::bluetooth::audio::le_audio::read(p_buf, sizeof(p_buf));
}
return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
} else {
return BluetoothAudioCtrlAck::FAILURE;
}
}
void StopRequest() override {
LOG(INFO) << __func__;
if (stream_cb_.on_suspend_()) {
// flush
uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
::bluetooth::audio::le_audio::read(p_buf, sizeof(p_buf));
}
}
bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
uint64_t* total_bytes_read,
timespec* data_position) override {
/*VLOG(2) << __func__ << ": data=" << total_bytes_read_
<< " byte(s), timestamp=" << data_position_.tv_sec << "."
<< data_position_.tv_nsec
<< "s, delay report=" << remote_delay_report_ms_ << " msec.";*/
if (remote_delay_report_ns != nullptr) {
*remote_delay_report_ns = remote_delay_report_ms_ * 1000000u;
}
if (total_bytes_read != nullptr) *total_bytes_read = total_bytes_read_;
if (data_position != nullptr) *data_position = data_position_;
return true;
}
void MetadataChanged(const source_metadata_t& source_metadata) override {
auto track_count = source_metadata.track_count;
auto tracks = source_metadata.tracks;
LOG(INFO) << __func__ << ": " << track_count << " track(s) received";
while (track_count) {
VLOG(1) << __func__ << ": usage=" << tracks->usage
<< ", content_type=" << tracks->content_type
<< ", gain=" << tracks->gain;
--track_count;
++tracks;
}
}
void EnterGameMode(int enter) override {
VLOG(1) << __func__ << ": ble audio Sink enter = " << enter;
stream_cb_.on_gamemode_(enter);
}
void ResetPresentationPosition() override {
VLOG(2) << __func__ << ": called.";
remote_delay_report_ms_ = 0;
total_bytes_read_ = 0;
data_position_ = {};
}
void LogBytesRead(size_t bytes_read) override {
if (bytes_read) {
total_bytes_read_ += bytes_read;
clock_gettime(CLOCK_MONOTONIC, &data_position_);
}
}
bool* GetBluetoothStateAddress() {
return &gLeSinkState;
}
void SetRemoteDelay(uint16_t delay_report_ms) {
LOG(INFO) << __func__ << ": delay_report=" << delay_report_ms << " msec";
remote_delay_report_ms_ = delay_report_ms;
}
const PcmParameters_2_1& LeAudioGetSelectedHalPcmConfig() { return pcm_config_; }
void LeAudioSetSelectedHalPcmConfig(SampleRate_2_1 sample_rate,
BitsPerSample bit_rate,
ChannelMode channel_mode,
int gamemode,
int data_interval_ms) {
pcm_config_.sampleRate = sample_rate;
pcm_config_.bitsPerSample = bit_rate;
pcm_config_.channelMode = channel_mode;
pcm_config_.isLowLatencyEnabled = (gamemode == 1) ?
LhdcLowLatencyEn::Enabled : LhdcLowLatencyEn::Disabled;
pcm_config_.dataIntervalUs = data_interval_ms*1000;
}
const LeAudioCodecConfiguration& LeAudioGetSelectedHalCodecConfig() {
return leAudioCodecConfig_;
}
void LeAudioSetSelectedHalCodecConfig(CodecType codec_type, uint32_t audio_channel_allocation,
uint32_t encoded_audio_bitrate, uint8_t le_audio_type,
Lc3Parameters lc3_config) {
leAudioCodecConfig_.codecType = codec_type;
leAudioCodecConfig_.audioChannelAllocation = audio_channel_allocation;
leAudioCodecConfig_.encodedAudioBitrate = encoded_audio_bitrate;
leAudioCodecConfig_.le_audio_type = le_audio_type;
leAudioCodecConfig_.bfi_ext = false;
leAudioCodecConfig_.plc_method = PlcMethod::STANDARD_PLC;
leAudioCodecConfig_.lc3Config = lc3_config;
LOG(INFO) << __func__ << ": LeAudioCodecConfiguration=" << toString(leAudioCodecConfig_);
return;
}
const ConnParam& LeAudioSetConnParameter(uint16_t l_cis_conn_hdl, uint16_t r_cis_conn_hdl, uint8_t bn) {
connParam_.conn_handle_R = l_cis_conn_hdl;
connParam_.conn_handle_L = r_cis_conn_hdl;
connParam_.bn = bn;
LOG(INFO) << __func__ << ": Connection Parameter=" << toString(connParam_);
return connParam_;
}
private:
StreamCallbacks stream_cb_;
uint16_t remote_delay_report_ms_;
uint64_t total_bytes_read_;
timespec data_position_;
PcmParameters_2_1 pcm_config_;
LeAudioCodecConfiguration leAudioCodecConfig_;
ConnParam connParam_;
};
class LeAudioSourceTransport
: public bluetooth::audio::IBluetoothSourceTransportInstance {
public:
LeAudioSourceTransport(SessionType_2_1 sessionType, StreamCallbacks stream_cb)
: IBluetoothSourceTransportInstance(
sessionType, {}),
stream_cb_(std::move(stream_cb)),
remote_delay_report_ms_(0),
total_bytes_written_(0),
data_position_({}),
/*pcm_config_({SampleRate::RATE_16000, ChannelMode::MONO,
BitsPerSample::BITS_16}){};*/
/** M: Fix for build pass @{ */
pcm_config_({SampleRate_2_1::RATE_16000, ChannelMode::MONO,
BitsPerSample::BITS_16, LhdcLowLatencyEn::Disabled, 0}){};
/** @} */
BluetoothAudioCtrlAck StartRequest() override {
LOG(INFO) << __func__;
if (stream_cb_.on_resume_(true)) {
return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
}
return BluetoothAudioCtrlAck::FAILURE;
}
BluetoothAudioCtrlAck SuspendRequest() override {
LOG(INFO) << __func__;
if (stream_cb_.on_suspend_()) {
if (!::bluetooth::audio::le_audio::is_leaudio_offload_enabled()) {
/* TODO (gkolodziejczyk): Clean exact value of buffer */
uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
::bluetooth::audio::le_audio::read(p_buf, sizeof(p_buf));
}
return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
} else {
return BluetoothAudioCtrlAck::FAILURE;
}
}
void StopRequest() override {
LOG(INFO) << __func__;
if (stream_cb_.on_suspend_()) {
if (!::bluetooth::audio::le_audio::is_leaudio_offload_enabled()) {
// flush
/* TODO (gkolodziejczyk): Clean exact value of buffer */
uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
::bluetooth::audio::le_audio::read(p_buf, sizeof(p_buf));
}
}
}
/* TODO (gkolodziejczyk): Shouldn't this be in oposite ? Set for AF */
bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
uint64_t* total_bytes_written,
timespec* data_position) override {
VLOG(2) << __func__ << ": data=" << total_bytes_written_
<< " byte(s), timestamp=" << data_position_.tv_sec << "."
<< data_position_.tv_nsec
<< "s, delay report=" << remote_delay_report_ms_ << " msec.";
if (remote_delay_report_ns != nullptr) {
*remote_delay_report_ns = remote_delay_report_ms_ * 1000000u;
}
if (total_bytes_written != nullptr)
*total_bytes_written = total_bytes_written_;
if (data_position != nullptr) *data_position = data_position_;
return true;
}
void MetadataChanged(const source_metadata_t& source_metadata) override {
auto track_count = source_metadata.track_count;
auto tracks = source_metadata.tracks;
LOG(INFO) << __func__ << ": " << track_count << " track(s) received";
while (track_count) {
VLOG(1) << __func__ << ": usage=" << tracks->usage
<< ", content_type=" << tracks->content_type
<< ", gain=" << tracks->gain;
--track_count;
++tracks;
}
}
void EnterGameMode(int enter) override {
VLOG(1) << __func__ << ": ble audio Source enter = " << enter;
stream_cb_.on_gamemode_(enter);
}
void ResetPresentationPosition() override {
VLOG(2) << __func__ << ": called.";
remote_delay_report_ms_ = 0;
total_bytes_written_ = 0;
data_position_ = {};
}
void LogBytesWritten(size_t bytes_written) override {
if (bytes_written) {
total_bytes_written_ += bytes_written;
clock_gettime(CLOCK_MONOTONIC, &data_position_);
}
}
void LogBytesRead(size_t bytes_read) override {
}
bool* GetBluetoothStateAddress() {
return &gLeSourceState;
}
void SetRemoteDelay(uint16_t delay_report_ms) {
LOG(INFO) << __func__ << ": delay_report=" << delay_report_ms << " msec";
remote_delay_report_ms_ = delay_report_ms;
}
const PcmParameters_2_1& LeAudioGetSelectedHalPcmConfig() { return pcm_config_; }
void LeAudioSetSelectedHalPcmConfig(SampleRate_2_1 sample_rate,
BitsPerSample bit_rate,
ChannelMode channel_mode,
int data_interval_ms) {
pcm_config_.sampleRate = sample_rate;
pcm_config_.bitsPerSample = bit_rate;
pcm_config_.channelMode = channel_mode;
pcm_config_.dataIntervalUs = data_interval_ms*1000;
}
const LeAudioCodecConfiguration& LeAudioGetSelectedHalCodecConfig() {
return leAudioCodecConfig_;
}
void LeAudioSetSelectedHalCodecConfig(CodecType codec_type, uint32_t audio_channel_allocation,
uint32_t encoded_audio_bitrate, uint8_t le_audio_type,
Lc3Parameters lc3_config) {
leAudioCodecConfig_.codecType = codec_type;
leAudioCodecConfig_.audioChannelAllocation = audio_channel_allocation;
leAudioCodecConfig_.encodedAudioBitrate = encoded_audio_bitrate;
leAudioCodecConfig_.le_audio_type = le_audio_type;
leAudioCodecConfig_.bfi_ext = false;
leAudioCodecConfig_.plc_method = PlcMethod::STANDARD_PLC;
leAudioCodecConfig_.lc3Config = lc3_config;
LOG(INFO) << __func__ << ": LeAudioCodecConfiguration=" << toString(leAudioCodecConfig_);
return;
}
const ConnParam& LeAudioSetConnParameter(uint16_t l_cis_conn_hdl, uint16_t r_cis_conn_hdl, uint8_t bn) {
connParam_.conn_handle_R = l_cis_conn_hdl;
connParam_.conn_handle_L = r_cis_conn_hdl;
connParam_.bn = bn;
LOG(INFO) << __func__ << ": Connection Parameter=" << toString(connParam_);
return connParam_;
}
private:
StreamCallbacks stream_cb_;
uint16_t remote_delay_report_ms_;
uint64_t total_bytes_written_;
timespec data_position_;
PcmParameters_2_1 pcm_config_;
LeAudioCodecConfiguration leAudioCodecConfig_;
ConnParam connParam_;
};
// Instance of Le Audio to provide call-in APIs for Bluetooth Audio Hal
LeAudioSinkTransport* le_audio_sink = nullptr;
LeAudioSourceTransport* le_audio_source = nullptr;
// Common interfaces to call-out into Bluetooth Audio Hal
bluetooth::audio::BluetoothAudioSinkClientInterface*
le_audio_sink_hal_clientinterface = nullptr;
bluetooth::audio::BluetoothAudioSourceClientInterface*
le_audio_source_hal_clientinterface = nullptr;
bool btaudio_le_audio_disabled = false;
bool is_configured = false;
// Save the value if the remote reports its delay before le_audio_sink is
// initialized
uint16_t remote_delay_ms = 0;
bool is_hal_2_0_force_disabled() {
if (!is_configured) {
btaudio_le_audio_disabled =
osi_property_get_bool(BLUETOOTH_AUDIO_HAL_PROP_DISABLED, false);
is_configured = true;
}
return btaudio_le_audio_disabled;
}
} // namespace
namespace bluetooth {
namespace audio {
namespace le_audio {
/* TODO (gkolodziejczyk): Do it smarter. btw. do this really check if hal 2.0 is
* enabled ?
*/
bool is_sink_hal_enabled() {
return le_audio_sink_hal_clientinterface != nullptr;
}
bool is_source_hal_enabled() {
return le_audio_source_hal_clientinterface != nullptr;
}
//TODO
bool is_leaudio_offload_enabled() {
if (g_leaudio_offload_mode == LE_AUDIO_OFFLOAD_MODE_UNINIT) {
char value[PROPERTY_VALUE_MAX];
value[0] = '\0';
osi_property_get(LE_AUDIO_OFFLOAD_PROP, value, "off");
g_leaudio_offload_mode = 0;
if (strcmp(value,"ums-cg") == 0) {
g_leaudio_offload_mode |= LE_AUDIO_OFFLOAD_UMS;
g_leaudio_offload_mode |= LE_AUDIO_OFFLOAD_CG;
}
LOG(INFO) << __func__ << ", le offload prop value: " << value <<" mode: " << g_leaudio_offload_mode;
}
return (g_leaudio_offload_mode & (LE_AUDIO_OFFLOAD_UMS | LE_AUDIO_OFFLOAD_CG)) ? true:false;
}
/* TODO (gkolodziejczyk): Think about optimization sink and source methods */
bool init_sink(StreamCallbacks stream_cb,
bluetooth::common::MessageLoopThread* message_loop) {
LOG(INFO) << __func__;
if (is_hal_2_0_force_disabled()) {
LOG(ERROR) << __func__ << ": BluetoothAudio HAL is disabled";
return false;
}
if (is_leaudio_offload_enabled()) {
le_audio_sink =
new LeAudioSinkTransport(
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,std::move(stream_cb));
} else {
le_audio_sink =
new LeAudioSinkTransport(
SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH, std::move(stream_cb));
}
le_audio_sink_hal_clientinterface =
new BluetoothAudioSinkClientInterface(le_audio_sink,message_loop);
if (!le_audio_sink_hal_clientinterface->IsValid()) {
LOG(WARNING) << __func__
<< ": BluetoothAudio HAL for Le Audio is invalid?!";
delete le_audio_sink_hal_clientinterface;
le_audio_sink_hal_clientinterface = nullptr;
delete le_audio_sink;
le_audio_sink = nullptr;
return false;
}
if (remote_delay_ms != 0) {
LOG(INFO) << __func__ << ": restore DELAY " << remote_delay_ms << " ms";
le_audio_sink->SetRemoteDelay(remote_delay_ms);
remote_delay_ms = 0;
}
gLeSinkState = true;
LOG(INFO) << __func__ << ": gLeSinkState = " << (bool*)&gLeSinkState;
return true;
}
bool init_source(StreamCallbacks stream_cb,
bluetooth::common::MessageLoopThread* message_loop) {
LOG(INFO) << __func__;
if (is_hal_2_0_force_disabled()) {
LOG(ERROR) << __func__ << ": BluetoothAudio HAL is disabled";
return false;
}
if (is_leaudio_offload_enabled()) {
le_audio_source =
new LeAudioSourceTransport(
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,std::move(stream_cb));
} else {
le_audio_source =
new LeAudioSourceTransport(
SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH, std::move(stream_cb));
}
le_audio_source_hal_clientinterface =
new bluetooth::audio::BluetoothAudioSourceClientInterface(le_audio_source,
message_loop);
if (!le_audio_sink_hal_clientinterface->IsValid()) {
LOG(WARNING) << __func__
<< ": BluetoothAudio HAL for Le Audio is invalid?!";
delete le_audio_source_hal_clientinterface;
le_audio_source_hal_clientinterface = nullptr;
delete le_audio_source;
le_audio_source = nullptr;
return false;
}
if (remote_delay_ms != 0) {
LOG(INFO) << __func__ << ": restore DELAY " << remote_delay_ms << " ms";
le_audio_source->SetRemoteDelay(remote_delay_ms);
remote_delay_ms = 0;
}
gLeSourceState = true;
LOG(INFO) << __func__ << ": gLeSourceState = " << (bool*)&gLeSourceState;
return true;
}
void cleanup_sink() {
LOG(INFO) << __func__;
gLeSinkState = false;
if (!is_sink_hal_enabled()) return;
end_sink_session();
delete le_audio_sink_hal_clientinterface;
le_audio_sink_hal_clientinterface = nullptr;
delete le_audio_sink;
le_audio_sink = nullptr;
remote_delay_ms = 0;
}
void cleanup_source() {
LOG(INFO) << __func__;
gLeSourceState = false;
if (!is_source_hal_enabled()) return;
end_source_session();
delete le_audio_source_hal_clientinterface;
le_audio_source_hal_clientinterface = nullptr;
delete le_audio_source;
le_audio_source = nullptr;
remote_delay_ms = 0;
}
void start_sink_session() {
LOG(INFO) << __func__;
if (!is_sink_hal_enabled()) return;
AudioConfiguration_2_1 audio_config;
if (is_leaudio_offload_enabled()) {
audio_config.leAudioCodecConfig(le_audio_sink->LeAudioGetSelectedHalCodecConfig());
} else {
audio_config.pcmConfig(le_audio_sink->LeAudioGetSelectedHalPcmConfig());
}
if (!le_audio_sink_hal_clientinterface->UpdateAudioConfig_2_1(audio_config)) {
LOG(ERROR) << __func__ << ": cannot update audio config to HAL";
return;
}
le_audio_sink_hal_clientinterface->StartSession_2_1();
}
void start_source_session() {
LOG(INFO) << __func__;
if (!is_source_hal_enabled()) return;
AudioConfiguration_2_1 audio_config;
if (is_leaudio_offload_enabled()) {
audio_config.leAudioCodecConfig(le_audio_source->LeAudioGetSelectedHalCodecConfig());
} else {
audio_config.pcmConfig(le_audio_source->LeAudioGetSelectedHalPcmConfig());
}
if (!le_audio_source_hal_clientinterface->UpdateAudioConfig_2_1(audio_config)) {
LOG(ERROR) << __func__ << ": cannot update audio config to HAL";
return;
}
le_audio_source_hal_clientinterface->StartSession_2_1();
}
void update_source_conn_param(uint16_t l_cis_conn_hdl, uint16_t r_cis_conn_hdl, uint8_t bn) {
LOG(INFO) << __func__;
if (!is_source_hal_enabled()) return;
AudioConfiguration_2_1 audio_config;
if (is_leaudio_offload_enabled()) {
if (!le_audio_source_hal_clientinterface->UpdateConnParam(
le_audio_source->LeAudioSetConnParameter(l_cis_conn_hdl, r_cis_conn_hdl, bn))) {
LOG(ERROR) << __func__ << ": cannot update connection parameter to HAL";
return;
}
}
}
void update_sink_conn_param(uint16_t l_cis_conn_hdl, uint16_t r_cis_conn_hdl, uint8_t bn) {
LOG(INFO) << __func__;
if (!is_source_hal_enabled()) return;
if (is_leaudio_offload_enabled()) {
if (!le_audio_sink_hal_clientinterface->UpdateConnParam(
le_audio_sink->LeAudioSetConnParameter(l_cis_conn_hdl, r_cis_conn_hdl, bn))) {
LOG(ERROR) << __func__ << ": cannot update connection parameter to HAL";
return;
}
}
}
void end_sink_session() {
LOG(INFO) << __func__;
if (!is_sink_hal_enabled()) return;
le_audio_sink_hal_clientinterface->EndSession();
}
void end_source_session() {
LOG(INFO) << __func__;
if (!is_source_hal_enabled()) return;
le_audio_source_hal_clientinterface->EndSession();
}
size_t read(uint8_t* p_buf, uint32_t len) {
if (!is_sink_hal_enabled()) return 0;
return le_audio_sink_hal_clientinterface->ReadAudioData(p_buf, len);
}
size_t write(const uint8_t* p_buf, uint32_t len) {
if (!is_source_hal_enabled()) return 0;
return le_audio_source_hal_clientinterface->WriteAudioData(p_buf, len);
}
// Update Le Audio delay report to BluetoothAudio HAL
void set_sink_remote_delay(uint16_t delay_report_ms) {
if (!is_sink_hal_enabled()) {
LOG(INFO) << __func__ << ": not ready for DelayReport " << delay_report_ms
<< " ms";
remote_delay_ms = delay_report_ms;
return;
}
LOG(INFO) << __func__ << ": delay_report_ms=" << delay_report_ms << " ms";
le_audio_sink->SetRemoteDelay(delay_report_ms);
}
void set_source_remote_delay(uint16_t delay_report_ms) {
if (!is_source_hal_enabled()) {
LOG(INFO) << __func__ << ": not ready for DelayReport " << delay_report_ms
<< " ms";
remote_delay_ms = delay_report_ms;
return;
}
LOG(INFO) << __func__ << ": delay_report_ms=" << delay_report_ms << " ms";
le_audio_source->SetRemoteDelay(delay_report_ms);
}
static SampleRate_2_1 le_audio_sample_rate2audio_hal(uint32_t sample_rate) {
switch (sample_rate) {
case 44100:
return SampleRate_2_1::RATE_44100;
case 48000:
return SampleRate_2_1::RATE_48000;
case 88200:
return SampleRate_2_1::RATE_88200;
case 96000:
return SampleRate_2_1::RATE_96000;
case 176400:
return SampleRate_2_1::RATE_176400;
case 192000:
return SampleRate_2_1::RATE_192000;
case 24000:
return SampleRate_2_1::RATE_24000;
case 16000:
return SampleRate_2_1::RATE_16000;
case 32000:
return SampleRate_2_1::RATE_32000;
case 8000:
return SampleRate_2_1::RATE_8000;
};
return SampleRate_2_1::RATE_UNKNOWN;
}
static BitsPerSample le_audio_bit_rate2audio_hal(uint8_t bitrate) {
switch (bitrate) {
case 16:
return BitsPerSample::BITS_16;
case 24:
return BitsPerSample::BITS_24;
case 32:
return BitsPerSample::BITS_32;
};
return BitsPerSample::BITS_UNKNOWN;
}
static ChannelMode le_audio_channel_mode2audio_hal(uint8_t channel_mode) {
switch (channel_mode) {
case 1:
return ChannelMode::MONO;
case 2:
return ChannelMode::STEREO;
}
return ChannelMode::UNKNOWN;
}
static Lc3FrameDuration le_audio_duration_mode2audio_hal(uint16_t frame_duration) {
switch (frame_duration) {
case 10:
return Lc3FrameDuration::DURATION_10000US;
}
return Lc3FrameDuration::DURATION_7500US;
}
static CodecType le_audio_duration_codec_hal(uint8_t codec_type) {
return CodecType::LC3;
}
void set_sink_pcm_parameters(uint32_t sample_rate, uint8_t bit_rate,
uint8_t channel_mode, int gamemode, int data_interval_ms) {
le_audio_sink->LeAudioSetSelectedHalPcmConfig(
le_audio_sample_rate2audio_hal(sample_rate),
le_audio_bit_rate2audio_hal(bit_rate),
le_audio_channel_mode2audio_hal(channel_mode),
gamemode,data_interval_ms);
}
void set_sink_offload_parameters(uint8_t codec_type, uint8_t audio_channel_allocation,
uint32_t encoded_audio_bitrate, uint8_t le_audio_type, uint32_t bits_per_sample,
uint32_t sample_rate, uint16_t data_interval_ms, uint32_t sdu_size) {
Lc3Parameters lc3_config;
lc3_config.pcmBitDepth = le_audio_bit_rate2audio_hal(bits_per_sample);
lc3_config.samplingFrequency = le_audio_sample_rate2audio_hal(sample_rate);
lc3_config.frameDuration = le_audio_duration_mode2audio_hal(data_interval_ms);
lc3_config.octetsPerFrame = sdu_size;
lc3_config.blocksPerSdu = 0;
le_audio_sink->LeAudioSetSelectedHalCodecConfig(le_audio_duration_codec_hal(codec_type),
(uint32_t)audio_channel_allocation, encoded_audio_bitrate, le_audio_type, lc3_config);
}
void set_source_pcm_parameters(uint32_t sample_rate, uint8_t bit_rate,
uint8_t channel_mode, int data_interval_ms) {
le_audio_source->LeAudioSetSelectedHalPcmConfig(
le_audio_sample_rate2audio_hal(sample_rate),
le_audio_bit_rate2audio_hal(bit_rate),
le_audio_channel_mode2audio_hal(channel_mode),
data_interval_ms);
}
void set_source_offload_parameters(uint8_t codec_type, uint8_t audio_channel_allocation,
uint32_t encoded_audio_bitrate, uint8_t le_audio_type, uint32_t bits_per_sample,
uint32_t sample_rate, uint16_t data_interval_ms, uint32_t sdu_size) {
Lc3Parameters lc3_config;
lc3_config.pcmBitDepth = le_audio_bit_rate2audio_hal(bits_per_sample);
lc3_config.samplingFrequency = le_audio_sample_rate2audio_hal(sample_rate);
lc3_config.frameDuration = le_audio_duration_mode2audio_hal(data_interval_ms);
lc3_config.octetsPerFrame = sdu_size;
lc3_config.blocksPerSdu = 0;
le_audio_source->LeAudioSetSelectedHalCodecConfig(le_audio_duration_codec_hal(codec_type),
(uint32_t)audio_channel_allocation, encoded_audio_bitrate, le_audio_type, lc3_config);
}
} // namespace le_audio
} // namespace audio
} // namespace bluetooth