blob: ee8969b00572863b8186589fa2a6b0f5630c752f [file] [log] [blame]
/*
* Copyright 2021 HIMSA II K/S - www.himsa.com. 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 "BTAudioClientLeAudioAIDL"
#include "le_audio_software_aidl.h"
#include <unordered_map>
#include <vector>
#include "codec_status_aidl.h"
#include "hal_version_manager.h"
namespace bluetooth {
namespace audio {
namespace aidl {
namespace le_audio {
using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration;
using ::aidl::android::hardware::bluetooth::audio::AudioLocation;
using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
using ::aidl::android::hardware::bluetooth::audio::CodecType;
using ::aidl::android::hardware::bluetooth::audio::Lc3Configuration;
using ::aidl::android::hardware::bluetooth::audio::LeAudioCodecConfiguration;
using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
using ::bluetooth::audio::aidl::AudioConfiguration;
using ::bluetooth::audio::aidl::BluetoothAudioCtrlAck;
using ::bluetooth::audio::le_audio::LeAudioClientInterface;
using ::bluetooth::audio::le_audio::StreamCallbacks;
using ::le_audio::set_configurations::SetConfiguration;
using ::le_audio::types::LeAudioLc3Config;
static ChannelMode le_audio_channel_mode2audio_hal(uint8_t channels_count) {
switch (channels_count) {
case 1:
return ChannelMode::MONO;
case 2:
return ChannelMode::STEREO;
}
return ChannelMode::UNKNOWN;
}
LeAudioTransport::LeAudioTransport(void (*flush)(void),
StreamCallbacks stream_cb,
PcmConfiguration pcm_config)
: flush_(std::move(flush)),
stream_cb_(std::move(stream_cb)),
remote_delay_report_ms_(0),
total_bytes_processed_(0),
data_position_({}),
pcm_config_(std::move(pcm_config)),
is_pending_start_request_(false){};
BluetoothAudioCtrlAck LeAudioTransport::StartRequest(bool is_low_latency) {
LOG(INFO) << __func__;
if (stream_cb_.on_resume_(true)) {
is_pending_start_request_ = true;
return BluetoothAudioCtrlAck::PENDING;
}
return BluetoothAudioCtrlAck::FAILURE;
}
BluetoothAudioCtrlAck LeAudioTransport::SuspendRequest() {
LOG(INFO) << __func__;
if (stream_cb_.on_suspend_()) {
flush_();
return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
} else {
return BluetoothAudioCtrlAck::FAILURE;
}
}
void LeAudioTransport::StopRequest() {
LOG(INFO) << __func__;
if (stream_cb_.on_suspend_()) {
flush_();
}
}
bool LeAudioTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns,
uint64_t* total_bytes_processed,
timespec* data_position) {
VLOG(2) << __func__ << ": data=" << total_bytes_processed_
<< " 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_processed != nullptr)
*total_bytes_processed = total_bytes_processed_;
if (data_position != nullptr) *data_position = data_position_;
return true;
}
void LeAudioTransport::SourceMetadataChanged(
const source_metadata_t& source_metadata) {
auto track_count = source_metadata.track_count;
if (track_count == 0) {
LOG(WARNING) << ", invalid number of metadata changed tracks";
return;
}
stream_cb_.on_metadata_update_(source_metadata);
}
void LeAudioTransport::SinkMetadataChanged(
const sink_metadata_t& sink_metadata) {
auto track_count = sink_metadata.track_count;
if (track_count == 0) {
LOG(WARNING) << ", invalid number of metadata changed tracks";
return;
}
if (stream_cb_.on_sink_metadata_update_)
stream_cb_.on_sink_metadata_update_(sink_metadata);
}
void LeAudioTransport::ResetPresentationPosition() {
VLOG(2) << __func__ << ": called.";
remote_delay_report_ms_ = 0;
total_bytes_processed_ = 0;
data_position_ = {};
}
void LeAudioTransport::LogBytesProcessed(size_t bytes_processed) {
if (bytes_processed) {
total_bytes_processed_ += bytes_processed;
clock_gettime(CLOCK_MONOTONIC, &data_position_);
}
}
void LeAudioTransport::SetRemoteDelay(uint16_t delay_report_ms) {
LOG(INFO) << __func__ << ": delay_report=" << delay_report_ms << " msec";
remote_delay_report_ms_ = delay_report_ms;
}
const PcmConfiguration& LeAudioTransport::LeAudioGetSelectedHalPcmConfig() {
return pcm_config_;
}
void LeAudioTransport::LeAudioSetSelectedHalPcmConfig(uint32_t sample_rate_hz,
uint8_t bit_rate,
uint8_t channels_count,
uint32_t data_interval) {
pcm_config_.sampleRateHz = (sample_rate_hz);
pcm_config_.bitsPerSample = (bit_rate);
pcm_config_.channelMode = le_audio_channel_mode2audio_hal(channels_count);
pcm_config_.dataIntervalUs = data_interval;
}
bool LeAudioTransport::IsPendingStartStream(void) {
return is_pending_start_request_;
}
void LeAudioTransport::ClearPendingStartStream(void) {
is_pending_start_request_ = false;
}
inline void flush_unicast_sink() {
if (LeAudioSinkTransport::interface_unicast_ == nullptr) return;
LeAudioSinkTransport::interface_unicast_->FlushAudioData();
}
inline void flush_broadcast_sink() {
if (LeAudioSinkTransport::interface_broadcast_ == nullptr) return;
LeAudioSinkTransport::interface_broadcast_->FlushAudioData();
}
inline bool is_broadcaster_session(SessionType session_type) {
if (session_type ==
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
session_type ==
SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH) {
return true;
}
return false;
}
LeAudioSinkTransport::LeAudioSinkTransport(SessionType session_type,
StreamCallbacks stream_cb)
: IBluetoothSinkTransportInstance(session_type, (AudioConfiguration){}) {
transport_ = new LeAudioTransport(
is_broadcaster_session(session_type) ? flush_broadcast_sink
: flush_unicast_sink,
std::move(stream_cb), {16000, ChannelMode::STEREO, 16, 0});
};
LeAudioSinkTransport::~LeAudioSinkTransport() { delete transport_; }
BluetoothAudioCtrlAck LeAudioSinkTransport::StartRequest(bool is_low_latency) {
return transport_->StartRequest(is_low_latency);
}
BluetoothAudioCtrlAck LeAudioSinkTransport::SuspendRequest() {
return transport_->SuspendRequest();
}
void LeAudioSinkTransport::StopRequest() { transport_->StopRequest(); }
bool LeAudioSinkTransport::GetPresentationPosition(
uint64_t* remote_delay_report_ns, uint64_t* total_bytes_read,
timespec* data_position) {
return transport_->GetPresentationPosition(remote_delay_report_ns,
total_bytes_read, data_position);
}
void LeAudioSinkTransport::SourceMetadataChanged(
const source_metadata_t& source_metadata) {
transport_->SourceMetadataChanged(source_metadata);
}
void LeAudioSinkTransport::SinkMetadataChanged(
const sink_metadata_t& sink_metadata) {
transport_->SinkMetadataChanged(sink_metadata);
}
void LeAudioSinkTransport::ResetPresentationPosition() {
transport_->ResetPresentationPosition();
}
void LeAudioSinkTransport::LogBytesRead(size_t bytes_read) {
transport_->LogBytesProcessed(bytes_read);
}
void LeAudioSinkTransport::SetRemoteDelay(uint16_t delay_report_ms) {
transport_->SetRemoteDelay(delay_report_ms);
}
const PcmConfiguration& LeAudioSinkTransport::LeAudioGetSelectedHalPcmConfig() {
return transport_->LeAudioGetSelectedHalPcmConfig();
}
void LeAudioSinkTransport::LeAudioSetSelectedHalPcmConfig(
uint32_t sample_rate_hz, uint8_t bit_rate, uint8_t channels_count,
uint32_t data_interval) {
transport_->LeAudioSetSelectedHalPcmConfig(sample_rate_hz, bit_rate,
channels_count, data_interval);
}
bool LeAudioSinkTransport::IsPendingStartStream(void) {
return transport_->IsPendingStartStream();
}
void LeAudioSinkTransport::ClearPendingStartStream(void) {
transport_->ClearPendingStartStream();
}
void flush_source() {
if (LeAudioSourceTransport::interface == nullptr) return;
LeAudioSourceTransport::interface->FlushAudioData();
}
LeAudioSourceTransport::LeAudioSourceTransport(SessionType session_type,
StreamCallbacks stream_cb)
: IBluetoothSourceTransportInstance(session_type, (AudioConfiguration){}) {
transport_ = new LeAudioTransport(flush_source, std::move(stream_cb),
{16000, ChannelMode::STEREO, 16, 0});
};
LeAudioSourceTransport::~LeAudioSourceTransport() { delete transport_; }
BluetoothAudioCtrlAck LeAudioSourceTransport::StartRequest(
bool is_low_latency) {
return transport_->StartRequest(is_low_latency);
}
BluetoothAudioCtrlAck LeAudioSourceTransport::SuspendRequest() {
return transport_->SuspendRequest();
}
void LeAudioSourceTransport::StopRequest() { transport_->StopRequest(); }
bool LeAudioSourceTransport::GetPresentationPosition(
uint64_t* remote_delay_report_ns, uint64_t* total_bytes_written,
timespec* data_position) {
return transport_->GetPresentationPosition(
remote_delay_report_ns, total_bytes_written, data_position);
}
void LeAudioSourceTransport::SourceMetadataChanged(
const source_metadata_t& source_metadata) {
transport_->SourceMetadataChanged(source_metadata);
}
void LeAudioSourceTransport::SinkMetadataChanged(
const sink_metadata_t& sink_metadata) {
transport_->SinkMetadataChanged(sink_metadata);
}
void LeAudioSourceTransport::ResetPresentationPosition() {
transport_->ResetPresentationPosition();
}
void LeAudioSourceTransport::LogBytesWritten(size_t bytes_written) {
transport_->LogBytesProcessed(bytes_written);
}
void LeAudioSourceTransport::SetRemoteDelay(uint16_t delay_report_ms) {
transport_->SetRemoteDelay(delay_report_ms);
}
const PcmConfiguration&
LeAudioSourceTransport::LeAudioGetSelectedHalPcmConfig() {
return transport_->LeAudioGetSelectedHalPcmConfig();
}
void LeAudioSourceTransport::LeAudioSetSelectedHalPcmConfig(
uint32_t sample_rate_hz, uint8_t bit_rate, uint8_t channels_count,
uint32_t data_interval) {
transport_->LeAudioSetSelectedHalPcmConfig(sample_rate_hz, bit_rate,
channels_count, data_interval);
}
bool LeAudioSourceTransport::IsPendingStartStream(void) {
return transport_->IsPendingStartStream();
}
void LeAudioSourceTransport::ClearPendingStartStream(void) {
transport_->ClearPendingStartStream();
}
std::unordered_map<int32_t, uint8_t> sampling_freq_map{
{8000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq8000Hz},
{16000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq16000Hz},
{24000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq24000Hz},
{32000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq32000Hz},
{44100, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq44100Hz},
{48000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq48000Hz},
{88200, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq88200Hz},
{96000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq96000Hz},
{176400, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq176400Hz},
{192000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq192000Hz}};
std::unordered_map<int32_t, uint8_t> frame_duration_map{
{7500, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameDur7500us},
{10000, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameDur10000us}};
std::unordered_map<int32_t, uint16_t> octets_per_frame_map{
{30, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen30},
{40, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen40},
{60, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen60},
{120, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen120}};
std::unordered_map<AudioLocation, uint32_t> audio_location_map{
{AudioLocation::UNKNOWN,
::le_audio::codec_spec_conf::kLeAudioLocationFrontCenter},
{AudioLocation::FRONT_LEFT,
::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft},
{AudioLocation::FRONT_RIGHT,
::le_audio::codec_spec_conf::kLeAudioLocationFrontRight},
{static_cast<AudioLocation>(
static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
static_cast<uint8_t>(AudioLocation::FRONT_RIGHT)),
::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft |
::le_audio::codec_spec_conf::kLeAudioLocationFrontRight}};
bool hal_ucast_capability_to_stack_format(
const UnicastCapability& hal_capability,
CodecCapabilitySetting& stack_capability) {
if (hal_capability.codecType != CodecType::LC3) {
LOG(WARNING) << "Unsupported codecType: "
<< toString(hal_capability.codecType);
return false;
}
if (hal_capability.leAudioCodecCapabilities.getTag() !=
UnicastCapability::LeAudioCodecCapabilities::lc3Capabilities) {
LOG(WARNING) << "Unknown LE Audio capabilities(vendor proprietary?)";
return false;
}
auto& hal_lc3_capability =
hal_capability.leAudioCodecCapabilities
.get<UnicastCapability::LeAudioCodecCapabilities::lc3Capabilities>();
auto supportedChannel = hal_capability.supportedChannel;
auto sample_rate_hz = hal_lc3_capability.samplingFrequencyHz[0];
auto frame_duration_us = hal_lc3_capability.frameDurationUs[0];
auto octets_per_frame = hal_lc3_capability.octetsPerFrame[0];
auto channel_count = hal_capability.channelCountPerDevice;
if (sampling_freq_map.find(sample_rate_hz) == sampling_freq_map.end() ||
frame_duration_map.find(frame_duration_us) == frame_duration_map.end() ||
octets_per_frame_map.find(octets_per_frame) ==
octets_per_frame_map.end() ||
audio_location_map.find(supportedChannel) == audio_location_map.end()) {
LOG(ERROR) << __func__ << ": Failed to convert HAL format to stack format"
<< "\nsample rate = " << sample_rate_hz
<< "\nframe duration = " << frame_duration_us
<< "\noctets per frame= " << octets_per_frame
<< "\naudio location = " << toString(supportedChannel);
return false;
}
stack_capability = {
.id = ::le_audio::set_configurations::LeAudioCodecIdLc3,
.config = LeAudioLc3Config(
{.sampling_frequency = sampling_freq_map[sample_rate_hz],
.frame_duration = frame_duration_map[frame_duration_us],
.octets_per_codec_frame = octets_per_frame_map[octets_per_frame],
.audio_channel_allocation = audio_location_map[supportedChannel],
.channel_count = static_cast<uint8_t>(channel_count)})};
return true;
}
std::vector<AudioSetConfiguration> get_offload_capabilities() {
LOG(INFO) << __func__;
std::vector<AudioSetConfiguration> offload_capabilities;
std::vector<AudioCapabilities> le_audio_hal_capabilities =
BluetoothAudioSinkClientInterface::GetAudioCapabilities(
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
std::string str_capability_log;
for (auto hal_cap : le_audio_hal_capabilities) {
CodecCapabilitySetting encode_cap;
CodecCapabilitySetting decode_cap;
UnicastCapability hal_encode_cap =
hal_cap.get<AudioCapabilities::leAudioCapabilities>()
.unicastEncodeCapability;
UnicastCapability hal_decode_cap =
hal_cap.get<AudioCapabilities::leAudioCapabilities>()
.unicastDecodeCapability;
AudioSetConfiguration audio_set_config = {.name = "offload capability"};
str_capability_log.clear();
if (hal_ucast_capability_to_stack_format(hal_encode_cap, encode_cap)) {
audio_set_config.confs.push_back(SetConfiguration(
::le_audio::types::kLeAudioDirectionSink, hal_encode_cap.deviceCount,
hal_encode_cap.deviceCount * hal_encode_cap.channelCountPerDevice,
::le_audio::types::kTargetLatencyBalancedLatencyReliability,
encode_cap));
str_capability_log = " Encode Capability: " + hal_encode_cap.toString();
}
if (hal_ucast_capability_to_stack_format(hal_decode_cap, decode_cap)) {
audio_set_config.confs.push_back(SetConfiguration(
::le_audio::types::kLeAudioDirectionSource,
hal_decode_cap.deviceCount,
hal_decode_cap.deviceCount * hal_decode_cap.channelCountPerDevice,
::le_audio::types::kTargetLatencyBalancedLatencyReliability,
decode_cap));
str_capability_log += " Decode Capability: " + hal_decode_cap.toString();
}
if (!audio_set_config.confs.empty()) {
offload_capabilities.push_back(audio_set_config);
LOG(INFO) << __func__
<< ": Supported codec capability =" << str_capability_log;
} else {
LOG(INFO) << __func__
<< ": Unknown codec capability =" << hal_cap.toString();
}
}
return offload_capabilities;
}
AudioConfiguration offload_config_to_hal_audio_config(
const ::le_audio::offload_config& offload_config) {
Lc3Configuration lc3_config{
.pcmBitDepth = static_cast<int8_t>(offload_config.bits_per_sample),
.samplingFrequencyHz = static_cast<int32_t>(offload_config.sampling_rate),
.frameDurationUs = static_cast<int32_t>(offload_config.frame_duration),
.octetsPerFrame = static_cast<int32_t>(offload_config.octets_per_frame),
.blocksPerSdu = static_cast<int8_t>(offload_config.blocks_per_sdu),
};
LeAudioConfiguration ucast_config = {
.peerDelayUs = static_cast<int32_t>(offload_config.peer_delay_ms * 1000),
.leAudioCodecConfig = LeAudioCodecConfiguration(lc3_config)};
for (auto& [handle, location] : offload_config.stream_map) {
ucast_config.streamMap.push_back({
.streamHandle = handle,
.audioChannelAllocation = static_cast<int32_t>(location),
});
}
return AudioConfiguration(ucast_config);
}
} // namespace le_audio
} // namespace aidl
} // namespace audio
} // namespace bluetooth