Files
hardware_interfaces/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
Jakub Pawlowski 8d87eb7e53 Pass sink metadata to Bluetooth
When just microphone is enabled, i.e. for recording audio, we will
receive just sink metadata update.

Bug: 150670922
Change-Id: I795385d19e64ec5c6bc0a8549beda52da27d25a1
2021-12-06 22:07:06 +01:00

306 lines
12 KiB
C++

/*
* Copyright 2018 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.
*/
#define LOG_TAG "BTAudioProviderSession_2_2"
#include "BluetoothAudioSession_2_2.h"
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioPort.h>
namespace android {
namespace bluetooth {
namespace audio {
using ::android::hardware::audio::common::V5_0::AudioSource;
using ::android::hardware::audio::common::V5_0::RecordTrackMetadata;
using ::android::hardware::audio::common::V5_0::SinkMetadata;
using SessionType_2_1 =
::android::hardware::bluetooth::audio::V2_1::SessionType;
using SessionType_2_0 =
::android::hardware::bluetooth::audio::V2_0::SessionType;
using AudioConfiguration_2_1 =
::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
BluetoothAudioSession_2_2::invalidSoftwareAudioConfiguration = {};
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
BluetoothAudioSession_2_2::invalidOffloadAudioConfiguration = {};
using IBluetoothAudioPort_2_2 =
::android::hardware::bluetooth::audio::V2_2::IBluetoothAudioPort;
namespace {
bool is_2_0_session_type(
const ::android::hardware::bluetooth::audio::V2_1::SessionType&
session_type) {
if (session_type == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
session_type == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
session_type == SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH) {
return true;
} else {
return false;
}
}
} // namespace
BluetoothAudioSession_2_2::BluetoothAudioSession_2_2(
const ::android::hardware::bluetooth::audio::V2_1::SessionType&
session_type)
: audio_session(BluetoothAudioSessionInstance::GetSessionInstance(
static_cast<SessionType_2_0>(session_type))),
audio_session_2_1(
BluetoothAudioSessionInstance_2_1::GetSessionInstance(session_type)) {
if (is_2_0_session_type(session_type)) {
session_type_2_1_ = (SessionType_2_1::UNKNOWN);
} else {
session_type_2_1_ = (session_type);
}
}
bool BluetoothAudioSession_2_2::IsSessionReady() {
if (session_type_2_1_ !=
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
return audio_session->IsSessionReady();
}
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
return audio_session->stack_iface_ != nullptr;
}
std::shared_ptr<BluetoothAudioSession>
BluetoothAudioSession_2_2::GetAudioSession() {
return audio_session;
}
std::shared_ptr<BluetoothAudioSession_2_1>
BluetoothAudioSession_2_2::GetAudioSession_2_1() {
return audio_session_2_1;
}
void BluetoothAudioSession_2_2::UpdateSinkMetadata(
const struct sink_metadata* sink_metadata) {
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
<< " has NO session";
return;
}
ssize_t track_count = sink_metadata->track_count;
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
<< ", " << track_count << " track(s)";
if (session_type_2_1_ == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
return;
}
struct record_track_metadata* track = sink_metadata->tracks;
SinkMetadata sinkMetadata;
RecordTrackMetadata* halMetadata;
sinkMetadata.tracks.resize(track_count);
halMetadata = sinkMetadata.tracks.data();
while (track_count && track) {
halMetadata->source = static_cast<AudioSource>(track->source);
halMetadata->gain = track->gain;
// halMetadata->destination leave unspecified
LOG(INFO) << __func__
<< " - SessionType=" << toString(GetAudioSession()->session_type_)
<< ", source=" << track->source
<< ", dest_device=" << track->dest_device
<< ", gain=" << track->gain
<< ", dest_device_address=" << track->dest_device_address;
--track_count;
++track;
++halMetadata;
}
/* This is called just for 2.2 sessions, so it's safe to do this casting*/
IBluetoothAudioPort_2_2* stack_iface_2_2_ =
static_cast<IBluetoothAudioPort_2_2*>(audio_session->stack_iface_.get());
auto hal_retval = stack_iface_2_2_->updateSinkMetadata(sinkMetadata);
if (!hal_retval.isOk()) {
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
<< toString(session_type_2_1_) << " failed";
}
}
// The control function is for the bluetooth_audio module to get the current
// AudioConfiguration
const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
BluetoothAudioSession_2_2::GetAudioConfig() {
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (IsSessionReady()) {
// If session is unknown it means it should be 2.0 type
if (session_type_2_1_ != SessionType_2_1::UNKNOWN) {
if (audio_config_2_2_ != invalidSoftwareAudioConfiguration)
return audio_config_2_2_;
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration toConf;
const AudioConfiguration_2_1 fromConf =
GetAudioSession_2_1()->GetAudioConfig();
if (fromConf.getDiscriminator() ==
AudioConfiguration_2_1::hidl_discriminator::pcmConfig) {
toConf.pcmConfig() = fromConf.pcmConfig();
return toConf;
}
}
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration toConf;
const AudioConfiguration fromConf = GetAudioSession()->GetAudioConfig();
// pcmConfig only differs between 2.0 and 2.1 in AudioConfiguration
if (fromConf.getDiscriminator() ==
AudioConfiguration::hidl_discriminator::codecConfig) {
toConf.codecConfig() = fromConf.codecConfig();
} else {
toConf.pcmConfig() = {
.sampleRate = static_cast<
::android::hardware::bluetooth::audio::V2_1::SampleRate>(
fromConf.pcmConfig().sampleRate),
.channelMode = fromConf.pcmConfig().channelMode,
.bitsPerSample = fromConf.pcmConfig().bitsPerSample,
.dataIntervalUs = 0};
}
return toConf;
} else if (session_type_2_1_ ==
SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
return kInvalidOffloadAudioConfiguration;
} else {
return kInvalidSoftwareAudioConfiguration;
}
}
bool BluetoothAudioSession_2_2::UpdateAudioConfig(
const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
audio_config) {
bool is_software_session =
(session_type_2_1_ == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
session_type_2_1_ ==
SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
session_type_2_1_ ==
SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
session_type_2_1_ ==
SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
bool is_offload_a2dp_session =
(session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH);
bool is_offload_le_audio_session =
(session_type_2_1_ ==
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
session_type_2_1_ ==
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
auto audio_config_discriminator = audio_config.getDiscriminator();
bool is_software_audio_config =
(is_software_session &&
audio_config_discriminator ==
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
hidl_discriminator::pcmConfig);
bool is_a2dp_offload_audio_config =
(is_offload_a2dp_session &&
audio_config_discriminator ==
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
hidl_discriminator::codecConfig);
bool is_le_audio_offload_audio_config =
(is_offload_le_audio_session &&
audio_config_discriminator ==
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
hidl_discriminator::leAudioConfig);
if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
!is_le_audio_offload_audio_config) {
return false;
}
audio_config_2_2_ = audio_config;
return true;
}
// The report function is used to report that the Bluetooth stack has started
// this session without any failure, and will invoke session_changed_cb_ to
// notify those registered bluetooth_audio outputs
void BluetoothAudioSession_2_2::OnSessionStarted(
const sp<IBluetoothAudioPort> stack_iface, const DataMQ::Descriptor* dataMQ,
const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
audio_config) {
if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
::android::hardware::bluetooth::audio::V2_0::AudioConfiguration config;
if (audio_config.getDiscriminator() ==
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
hidl_discriminator::codecConfig) {
config.codecConfig(audio_config.codecConfig());
} else {
auto& tmpPcm = audio_config.pcmConfig();
config.pcmConfig(
::android::hardware::bluetooth::audio::V2_0::PcmParameters{
.sampleRate = static_cast<SampleRate>(tmpPcm.sampleRate),
.channelMode = tmpPcm.channelMode,
.bitsPerSample = tmpPcm.bitsPerSample
/*dataIntervalUs is not passed to 2.0 */
});
}
audio_session->OnSessionStarted(stack_iface, dataMQ, config);
} else {
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (stack_iface == nullptr) {
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
<< ", IBluetoothAudioPort Invalid";
} else if (!UpdateAudioConfig(audio_config)) {
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
<< ", AudioConfiguration=" << toString(audio_config)
<< " Invalid";
} else if (!audio_session->UpdateDataPath(dataMQ)) {
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
<< " DataMQ Invalid";
audio_config_2_2_ =
(session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH
? kInvalidOffloadAudioConfiguration
: kInvalidSoftwareAudioConfiguration);
} else {
audio_session->stack_iface_ = stack_iface;
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
<< ", AudioConfiguration=" << toString(audio_config);
audio_session->ReportSessionStatus();
};
}
}
std::unique_ptr<BluetoothAudioSessionInstance_2_2>
BluetoothAudioSessionInstance_2_2::instance_ptr =
std::unique_ptr<BluetoothAudioSessionInstance_2_2>(
new BluetoothAudioSessionInstance_2_2());
// API to fetch the session of A2DP / Hearing Aid
std::shared_ptr<BluetoothAudioSession_2_2>
BluetoothAudioSessionInstance_2_2::GetSessionInstance(
const SessionType_2_1& session_type) {
std::lock_guard<std::mutex> guard(instance_ptr->mutex_);
if (!instance_ptr->sessions_map_.empty()) {
auto entry = instance_ptr->sessions_map_.find(session_type);
if (entry != instance_ptr->sessions_map_.end()) {
return entry->second;
}
}
std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
std::make_shared<BluetoothAudioSession_2_2>(session_type);
instance_ptr->sessions_map_[session_type] = session_ptr;
return session_ptr;
}
} // namespace audio
} // namespace bluetooth
} // namespace android