Add bluetooth.audio@2.2 implementation
Bug: 201292721
Bug: 150670922
Bug: 197297498
Test: m android.hardware.bluetooth.audio@2.2-impl
Change-Id: I224b1e001337165e5191060f0ae532933a419b68
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 551bc50..19d2d92 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -14,14 +14,17 @@
srcs: [
"session/BluetoothAudioSession.cpp",
"session/BluetoothAudioSession_2_1.cpp",
+ "session/BluetoothAudioSession_2_2.cpp",
"session/BluetoothAudioSupportedCodecsDB.cpp",
"session/BluetoothAudioSupportedCodecsDB_2_1.cpp",
+ "session/BluetoothAudioSupportedCodecsDB_2_2.cpp",
],
export_include_dirs: ["session/"],
header_libs: ["libhardware_headers"],
shared_libs: [
"android.hardware.bluetooth.audio@2.0",
"android.hardware.bluetooth.audio@2.1",
+ "android.hardware.bluetooth.audio@2.2",
"libbase",
"libcutils",
"libfmq",
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession.h b/bluetooth/audio/utils/session/BluetoothAudioSession.h
index 83e20ad..3469cc0 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession.h
@@ -80,6 +80,7 @@
class BluetoothAudioSession {
friend class BluetoothAudioSession_2_1;
+ friend class BluetoothAudioSession_2_2;
private:
// using recursive_mutex to allow hwbinder to re-enter agian.
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h
new file mode 100644
index 0000000..194259a
--- /dev/null
+++ b/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 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 "BluetoothAudioSession_2_2.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionReport_2_2 {
+ public:
+ // The API reports the Bluetooth stack has started the session, and will
+ // inform registered bluetooth_audio outputs
+ static void OnSessionStarted(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type,
+ const sp<IBluetoothAudioPort> host_iface,
+ const DataMQ::Descriptor* dataMQ,
+ const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
+ audio_config) {
+ std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
+ BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->OnSessionStarted(host_iface, dataMQ, audio_config);
+ }
+ }
+
+ // The API reports the Bluetooth stack has ended the session, and will
+ // inform registered bluetooth_audio outputs
+ static void OnSessionEnded(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type) {
+ std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
+ BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->GetAudioSession()->OnSessionEnded();
+ }
+ }
+ // The API reports the Bluetooth stack has replied the result of startStream
+ // or suspendStream, and will inform registered bluetooth_audio outputs
+ static void ReportControlStatus(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type,
+ const bool& start_resp, const BluetoothAudioStatus& status) {
+ std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
+ BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->GetAudioSession()->ReportControlStatus(start_resp, status);
+ }
+ }
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
new file mode 100644
index 0000000..9d9ea41
--- /dev/null
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
@@ -0,0 +1,227 @@
+/*
+ * 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>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+using SessionType_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::SessionType;
+using SessionType_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SessionType;
+
+::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+ BluetoothAudioSession_2_2::invalidSoftwareAudioConfiguration = {};
+::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+ BluetoothAudioSession_2_2::invalidOffloadAudioConfiguration = {};
+
+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))) {
+ 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;
+}
+
+// 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) return audio_config_2_2_;
+
+ ::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
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
new file mode 100644
index 0000000..d3d0bd3
--- /dev/null
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.2/types.h>
+
+#include <mutex>
+#include <unordered_map>
+
+#include "BluetoothAudioSession.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSession_2_2 {
+ private:
+ std::shared_ptr<BluetoothAudioSession> audio_session;
+
+ ::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
+
+ // audio data configuration for both software and offloading
+ ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+ audio_config_2_2_;
+
+ bool UpdateAudioConfig(
+ const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
+ audio_config);
+
+ static ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+ invalidSoftwareAudioConfiguration;
+ static ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+ invalidOffloadAudioConfiguration;
+
+ public:
+ BluetoothAudioSession_2_2(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type);
+
+ // The function helps to check if this session is ready or not
+ // @return: true if the Bluetooth stack has started the specified session
+ bool IsSessionReady();
+
+ std::shared_ptr<BluetoothAudioSession> GetAudioSession();
+
+ // 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 OnSessionStarted(
+ const sp<IBluetoothAudioPort> stack_iface,
+ const DataMQ::Descriptor* dataMQ,
+ const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
+ audio_config);
+
+ // The control function is for the bluetooth_audio module to get the current
+ // AudioConfiguration
+ const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+ GetAudioConfig();
+
+ static constexpr ::android::hardware::bluetooth::audio::V2_2::
+ AudioConfiguration& kInvalidSoftwareAudioConfiguration =
+ invalidSoftwareAudioConfiguration;
+ static constexpr ::android::hardware::bluetooth::audio::V2_2::
+ AudioConfiguration& kInvalidOffloadAudioConfiguration =
+ invalidOffloadAudioConfiguration;
+};
+
+class BluetoothAudioSessionInstance_2_2 {
+ public:
+ // The API is to fetch the specified session of A2DP / Hearing Aid
+ static std::shared_ptr<BluetoothAudioSession_2_2> GetSessionInstance(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type);
+
+ private:
+ static std::unique_ptr<BluetoothAudioSessionInstance_2_2> instance_ptr;
+ std::mutex mutex_;
+ std::unordered_map<::android::hardware::bluetooth::audio::V2_1::SessionType,
+ std::shared_ptr<BluetoothAudioSession_2_2>>
+ sessions_map_;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp
new file mode 100644
index 0000000..5becdaa
--- /dev/null
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 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 "BTAudioProviderSessionCodecsDB_2_2"
+
+#include "BluetoothAudioSupportedCodecsDB_2_2.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::SessionType;
+
+bool IsOffloadLeAudioConfigurationValid(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type,
+ const ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration&) {
+ if (session_type !=
+ SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type !=
+ SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return false;
+ }
+
+ // TODO: perform checks on le_audio_codec_config once we know supported
+ // parameters
+
+ return true;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h
new file mode 100644
index 0000000..59d22b7
--- /dev/null
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 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 <android/hardware/bluetooth/audio/2.2/types.h>
+
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+bool IsOffloadLeAudioConfigurationValid(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type,
+ const ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration&
+ le_audio_codec_config);
+} // namespace audio
+} // namespace bluetooth
+} // namespace android