Merge "health impl: compare interfaces with their binders"
diff --git a/bluetooth/audio/2.2/Android.bp b/bluetooth/audio/2.2/Android.bp
new file mode 100644
index 0000000..6449c08
--- /dev/null
+++ b/bluetooth/audio/2.2/Android.bp
@@ -0,0 +1,32 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+hidl_interface {
+ name: "android.hardware.bluetooth.audio@2.2",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ "IBluetoothAudioProvider.hal",
+ "IBluetoothAudioProvidersFactory.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@5.0",
+ "android.hardware.bluetooth.audio@2.0",
+ "android.hardware.bluetooth.audio@2.1",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.bluetooth.updatable",
+ ],
+ gen_java: false,
+}
diff --git a/bluetooth/audio/2.2/IBluetoothAudioProvider.hal b/bluetooth/audio/2.2/IBluetoothAudioProvider.hal
new file mode 100644
index 0000000..ad8c839
--- /dev/null
+++ b/bluetooth/audio/2.2/IBluetoothAudioProvider.hal
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package android.hardware.bluetooth.audio@2.2;
+
+import @2.1::IBluetoothAudioProvider;
+import @2.0::IBluetoothAudioPort;
+import @2.0::Status;
+
+/**
+ * HAL interface from the Bluetooth stack to the Audio HAL
+ *
+ * The Bluetooth stack calls methods in this interface to start and end audio
+ * sessions and sends callback events to the Audio HAL.
+ *
+ * Note: For HIDL APIs with a "generates" statement, the callback parameter used
+ * for return value must be invoked synchronously before the API call returns.
+ */
+interface IBluetoothAudioProvider extends @2.1::IBluetoothAudioProvider {
+
+ /**
+ * This method indicates that the Bluetooth stack is ready to stream audio.
+ * It registers an instance of IBluetoothAudioPort with and provides the
+ * current negotiated codec to the Audio HAL. After this method is called,
+ * the Audio HAL can invoke IBluetoothAudioPort.startStream().
+ *
+ * Note: endSession() must be called to unregister this IBluetoothAudioPort
+ *
+ * @param hostIf An instance of IBluetoothAudioPort for stream control
+ * @param audioConfig The audio configuration negotiated with the remote
+ * device. The PCM parameters are set if software based encoding,
+ * otherwise the correct codec configuration is used for hardware
+ * encoding.
+ *
+ * @return status One of the following
+ * SUCCESS if this IBluetoothAudioPort was successfully registered with
+ * the Audio HAL
+ * UNSUPPORTED_CODEC_CONFIGURATION if the Audio HAL cannot register this
+ * IBluetoothAudioPort with the given codec configuration
+ * FAILURE if the Audio HAL cannot register this IBluetoothAudioPort for
+ * any other reason
+ * @return dataMQ The fast message queue for audio data from/to this
+ * provider. Audio data will be in PCM format as specified by the
+ * audioConfig.pcmConfig parameter. Invalid if streaming is offloaded
+ * from/to hardware or on failure.
+ */
+ startSession_2_2(IBluetoothAudioPort hostIf, AudioConfiguration audioConfig)
+ generates (Status status, fmq_sync<uint8_t> dataMQ);
+};
diff --git a/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal b/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal
new file mode 100644
index 0000000..eeff4de
--- /dev/null
+++ b/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.hardware.bluetooth.audio@2.2;
+
+import @2.1::IBluetoothAudioProvidersFactory;
+
+/**
+ * This factory allows a HAL implementation to be split into multiple
+ * independent providers.
+ *
+ * When the Bluetooth stack is ready to create an audio session, it must first
+ * obtain the IBluetoothAudioProvider for that session type by calling
+ * openProvider().
+ *
+ * Note: For HIDL APIs with a "generates" statement, the callback parameter used
+ * for return value must be invoked synchronously before the API call returns.
+ */
+interface IBluetoothAudioProvidersFactory extends @2.1::IBluetoothAudioProvidersFactory {
+};
diff --git a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..126bc9e
--- /dev/null
+++ b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "BTAudioProviderA2dpOffload"
+
+#include "A2dpOffloadAudioProvider.h"
+
+#include <android-base/logging.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioSessionReport_2_2.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+A2dpOffloadAudioProvider::A2dpOffloadAudioProvider()
+ : BluetoothAudioProvider() {
+ session_type_ = V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH;
+}
+
+bool A2dpOffloadAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+ return isValid(static_cast<V2_1::SessionType>(sessionType));
+}
+
+bool A2dpOffloadAudioProvider::isValid(const V2_1::SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+Return<void> A2dpOffloadAudioProvider::startSession(
+ const sp<IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ /**
+ * Initialize the audio platform if audioConfiguration is supported.
+ * Save the IBluetoothAudioPort interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ if (audioConfig.getDiscriminator() !=
+ AudioConfiguration::hidl_discriminator::codecConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ } else if (!android::bluetooth::audio::IsOffloadCodecConfigurationValid(
+ session_type_, audioConfig.codecConfig())) {
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> A2dpOffloadAudioProvider::onSessionReady(
+ startSession_cb _hidl_cb) {
+ BluetoothAudioSessionReport_2_2::OnSessionStarted(session_type_, stack_iface_,
+ nullptr, audio_config_);
+ _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.h
new file mode 100644
index 0000000..7ccdedc
--- /dev/null
+++ b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.h
@@ -0,0 +1,48 @@
+/*
+ * 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 "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+ A2dpOffloadAudioProvider();
+
+ bool isValid(const V2_1::SessionType& sessionType) override;
+ bool isValid(const V2_0::SessionType& sessionType) override;
+
+ Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const V2_0::AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ private:
+ Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..0d918e1
--- /dev/null
+++ b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 "BTAudioProviderA2dpSoftware"
+
+#include "A2dpSoftwareAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport_2_2.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+// Here the buffer size is based on SBC
+static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
+// SBC is 128, and here we choose the LCM of 16, 24, and 32
+static constexpr uint32_t kPcmFrameCount = 96;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+// The max counts by 1 tick (20ms) for SBC is about 7. Since using 96 for the
+// PCM counts, here we just choose a greater number
+static constexpr uint32_t kRtpFrameCount = 10;
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 2; // double buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
+ : BluetoothAudioProvider(), mDataMQ(nullptr) {
+ LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+ << " byte(s)";
+ std::unique_ptr<DataMQ> tempDataMQ(
+ new DataMQ(kDataMqSize, /* EventFlag */ true));
+ if (tempDataMQ && tempDataMQ->isValid()) {
+ mDataMQ = std::move(tempDataMQ);
+ session_type_ = V2_1::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+ } else {
+ ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+ ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+ }
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+ return isValid(static_cast<V2_1::SessionType>(sessionType));
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const V2_1::SessionType& sessionType) {
+ return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
+}
+
+Return<void> A2dpSoftwareAudioProvider::startSession(
+ const sp<IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ /**
+ * Initialize the audio platform if audioConfiguration is supported.
+ * Save the IBluetoothAudioPort interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ if (audioConfig.getDiscriminator() !=
+ AudioConfiguration::hidl_discriminator::pcmConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
+ audioConfig.pcmConfig())) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << toString(audioConfig.pcmConfig());
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> A2dpSoftwareAudioProvider::onSessionReady(
+ startSession_cb _hidl_cb) {
+ if (mDataMQ && mDataMQ->isValid()) {
+ BluetoothAudioSessionReport_2_2::OnSessionStarted(
+ session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+ _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+ } else {
+ _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h
new file mode 100644
index 0000000..3d4f0cc
--- /dev/null
+++ b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+ A2dpSoftwareAudioProvider();
+
+ bool isValid(const V2_1::SessionType& sessionType) override;
+ bool isValid(const V2_0::SessionType& sessionType) override;
+
+ Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+ const V2_0::AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ private:
+ // audio data queue for software encoding
+ std::unique_ptr<DataMQ> mDataMQ;
+
+ Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/Android.bp b/bluetooth/audio/2.2/default/Android.bp
new file mode 100644
index 0000000..7a5ae75
--- /dev/null
+++ b/bluetooth/audio/2.2/default/Android.bp
@@ -0,0 +1,37 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "android.hardware.bluetooth.audio@2.2-impl",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "BluetoothAudioProvidersFactory.cpp",
+ "BluetoothAudioProvider.cpp",
+ "A2dpOffloadAudioProvider.cpp",
+ "A2dpSoftwareAudioProvider.cpp",
+ "HearingAidAudioProvider.cpp",
+ "LeAudioAudioProvider.cpp",
+ "LeAudioOffloadAudioProvider.cpp",
+ ],
+ 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",
+ "libbluetooth_audio_session",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp
new file mode 100644
index 0000000..3655bc0
--- /dev/null
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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 "BTAudioProviderStub"
+
+#include "BluetoothAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport_2_2.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Void;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+void BluetoothAudioDeathRecipient::serviceDied(
+ uint64_t cookie __unused,
+ const wp<::android::hidl::base::V1_0::IBase>& who __unused) {
+ LOG(ERROR) << "BluetoothAudioDeathRecipient::" << __func__
+ << " - BluetoothAudio Service died";
+ provider_->endSession();
+}
+
+BluetoothAudioProvider::BluetoothAudioProvider()
+ : death_recipient_(new BluetoothAudioDeathRecipient(this)),
+ session_type_(V2_1::SessionType::UNKNOWN),
+ audio_config_({}) {}
+
+Return<void> BluetoothAudioProvider::startSession(
+ const sp<IBluetoothAudioPort>& hostIf,
+ const V2_0::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ AudioConfiguration audioConfig_2_2;
+
+ if (audioConfig.getDiscriminator() ==
+ V2_0::AudioConfiguration::hidl_discriminator::pcmConfig) {
+ audioConfig_2_2.pcmConfig(
+ {.sampleRate =
+ static_cast<V2_1::SampleRate>(audioConfig.pcmConfig().sampleRate),
+ .channelMode = audioConfig.pcmConfig().channelMode,
+ .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
+ .dataIntervalUs = 0});
+ } else {
+ audioConfig_2_2.codecConfig(audioConfig.codecConfig());
+ }
+
+ return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+}
+
+Return<void> BluetoothAudioProvider::startSession_2_1(
+ const sp<IBluetoothAudioPort>& hostIf,
+ const V2_1::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ AudioConfiguration audioConfig_2_2;
+ if (audioConfig.getDiscriminator() ==
+ V2_1::AudioConfiguration::hidl_discriminator::leAudioCodecConfig) {
+ audioConfig_2_2.leAudioConfig().mode = LeAudioMode::UNKNOWN;
+ audioConfig_2_2.leAudioConfig().config.unicastConfig() = {
+ .streamMap = {{
+ .streamHandle = 0xFFFF,
+ .audioChannelAllocation =
+ audioConfig.leAudioCodecConfig().audioChannelAllocation,
+ }},
+ .peerDelay = 0,
+ .lc3Config = audioConfig.leAudioCodecConfig().lc3Config};
+ } else if (audioConfig.getDiscriminator() ==
+ V2_1::AudioConfiguration::hidl_discriminator::pcmConfig) {
+ audioConfig_2_2.pcmConfig(audioConfig.pcmConfig());
+ } else {
+ audioConfig_2_2.codecConfig(audioConfig.codecConfig());
+ }
+
+ return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+}
+
+Return<void> BluetoothAudioProvider::startSession_2_2(
+ const sp<IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ if (hostIf == nullptr) {
+ _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+ return Void();
+ }
+
+ /**
+ * Initialize the audio platform if audioConfiguration is supported.
+ * Save the IBluetoothAudioPort interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ audio_config_ = audioConfig;
+ stack_iface_ = hostIf;
+ stack_iface_->linkToDeath(death_recipient_, 0);
+
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", AudioConfiguration=[" << toString(audio_config_) << "]";
+
+ onSessionReady(_hidl_cb);
+ return Void();
+}
+
+Return<void> BluetoothAudioProvider::streamStarted(
+ BluetoothAudioStatus status) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status);
+
+ /**
+ * Streaming on control path has started,
+ * HAL server should start the streaming on data path.
+ */
+ if (stack_iface_) {
+ BluetoothAudioSessionReport_2_2::ReportControlStatus(session_type_, true,
+ status);
+ } else {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status) << " has NO session";
+ }
+
+ return Void();
+}
+
+Return<void> BluetoothAudioProvider::streamSuspended(
+ BluetoothAudioStatus status) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status);
+
+ /**
+ * Streaming on control path has suspend,
+ * HAL server should suspend the streaming on data path.
+ */
+ if (stack_iface_) {
+ BluetoothAudioSessionReport_2_2::ReportControlStatus(session_type_, false,
+ status);
+ } else {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status) << " has NO session";
+ }
+
+ return Void();
+}
+
+Return<void> BluetoothAudioProvider::endSession() {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+ if (stack_iface_) {
+ BluetoothAudioSessionReport_2_2::OnSessionEnded(session_type_);
+ stack_iface_->unlinkToDeath(death_recipient_);
+ } else {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ }
+
+ /**
+ * Clean up the audio platform as remote audio device is no
+ * longer active
+ */
+ stack_iface_ = nullptr;
+ audio_config_ = {};
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvider.h b/bluetooth/audio/2.2/default/BluetoothAudioProvider.h
new file mode 100644
index 0000000..b7581ba
--- /dev/null
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvider.h
@@ -0,0 +1,85 @@
+/*
+ * 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/IBluetoothAudioProvider.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+
+using BluetoothAudioStatus =
+ ::android::hardware::bluetooth::audio::V2_0::Status;
+
+class BluetoothAudioDeathRecipient;
+
+class BluetoothAudioProvider : public IBluetoothAudioProvider {
+ public:
+ BluetoothAudioProvider();
+ ~BluetoothAudioProvider() = default;
+
+ virtual bool isValid(const V2_1::SessionType& sessionType) = 0;
+ virtual bool isValid(const V2_0::SessionType& sessionType) = 0;
+
+ Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+ const V2_0::AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+ Return<void> startSession_2_1(const sp<IBluetoothAudioPort>& hostIf,
+ const V2_1::AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+ Return<void> startSession_2_2(const sp<IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+ Return<void> streamStarted(BluetoothAudioStatus status) override;
+ Return<void> streamSuspended(BluetoothAudioStatus status) override;
+ Return<void> endSession() override;
+
+ protected:
+ sp<BluetoothAudioDeathRecipient> death_recipient_;
+
+ V2_1::SessionType session_type_;
+ AudioConfiguration audio_config_;
+ sp<V2_0::IBluetoothAudioPort> stack_iface_;
+
+ virtual Return<void> onSessionReady(startSession_cb _hidl_cb) = 0;
+};
+
+class BluetoothAudioDeathRecipient : public hidl_death_recipient {
+ public:
+ BluetoothAudioDeathRecipient(const sp<BluetoothAudioProvider> provider)
+ : provider_(provider) {}
+
+ virtual void serviceDied(
+ uint64_t cookie,
+ const wp<::android::hidl::base::V1_0::IBase>& who) override;
+
+ private:
+ sp<BluetoothAudioProvider> provider_;
+};
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
new file mode 100644
index 0000000..7438c80
--- /dev/null
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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 "BTAudioProvidersFactory"
+
+#include "BluetoothAudioProvidersFactory.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
+
+A2dpSoftwareAudioProvider
+ BluetoothAudioProvidersFactory::a2dp_software_provider_instance_;
+A2dpOffloadAudioProvider
+ BluetoothAudioProvidersFactory::a2dp_offload_provider_instance_;
+HearingAidAudioProvider
+ BluetoothAudioProvidersFactory::hearing_aid_provider_instance_;
+LeAudioOutputAudioProvider
+ BluetoothAudioProvidersFactory::leaudio_output_provider_instance_;
+LeAudioOffloadOutputAudioProvider
+ BluetoothAudioProvidersFactory::leaudio_offload_output_provider_instance_;
+LeAudioInputAudioProvider
+ BluetoothAudioProvidersFactory::leaudio_input_provider_instance_;
+LeAudioOffloadInputAudioProvider
+ BluetoothAudioProvidersFactory::leaudio_offload_input_provider_instance_;
+
+Return<void> BluetoothAudioProvidersFactory::openProvider(
+ const V2_0::SessionType sessionType, openProvider_cb _hidl_cb) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
+ BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
+ BluetoothAudioProvider* provider = nullptr;
+
+ switch (sessionType) {
+ case V2_0::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+ provider = &a2dp_software_provider_instance_;
+ break;
+ case V2_0::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
+ provider = &a2dp_offload_provider_instance_;
+ break;
+ case V2_0::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+ provider = &hearing_aid_provider_instance_;
+ break;
+ default:
+ status = BluetoothAudioStatus::FAILURE;
+ }
+
+ if (provider == nullptr || !provider->isValid(sessionType)) {
+ provider = nullptr;
+ status = BluetoothAudioStatus::FAILURE;
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
+ << ", status=" << toString(status);
+ }
+
+ _hidl_cb(status, provider);
+ return Void();
+}
+
+Return<void> BluetoothAudioProvidersFactory::openProvider_2_1(
+ const V2_1::SessionType sessionType, openProvider_2_1_cb _hidl_cb) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
+ BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
+ BluetoothAudioProvider* provider = nullptr;
+
+ switch (sessionType) {
+ case V2_1::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+ provider = &a2dp_software_provider_instance_;
+ break;
+ case V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
+ provider = &a2dp_offload_provider_instance_;
+ break;
+ case V2_1::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+ provider = &hearing_aid_provider_instance_;
+ break;
+ case V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
+ provider = &leaudio_output_provider_instance_;
+ break;
+ case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ provider = &leaudio_offload_output_provider_instance_;
+ break;
+ case V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
+ provider = &leaudio_input_provider_instance_;
+ break;
+ case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ provider = &leaudio_offload_input_provider_instance_;
+ break;
+ default:
+ status = BluetoothAudioStatus::FAILURE;
+ }
+
+ if (provider == nullptr || !provider->isValid(sessionType)) {
+ provider = nullptr;
+ status = BluetoothAudioStatus::FAILURE;
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
+ << ", status=" << toString(status);
+ }
+
+ _hidl_cb(status, provider);
+ return Void();
+}
+
+Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities(
+ const V2_0::SessionType sessionType, getProviderCapabilities_cb _hidl_cb) {
+ hidl_vec<V2_0::AudioCapabilities> audio_capabilities =
+ hidl_vec<V2_0::AudioCapabilities>(0);
+ if (sessionType == V2_0::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+ std::vector<CodecCapabilities> db_codec_capabilities =
+ android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
+ if (db_codec_capabilities.size()) {
+ audio_capabilities.resize(db_codec_capabilities.size());
+ for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+ audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
+ }
+ }
+ } else if (sessionType != V2_0::SessionType::UNKNOWN) {
+ std::vector<::android::hardware::bluetooth::audio::V2_0::PcmParameters>
+ db_pcm_capabilities =
+ android::bluetooth::audio::GetSoftwarePcmCapabilities();
+ if (db_pcm_capabilities.size() == 1) {
+ audio_capabilities.resize(1);
+ audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
+ }
+ }
+ LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
+ << " supports " << audio_capabilities.size() << " codecs";
+ _hidl_cb(audio_capabilities);
+ return Void();
+}
+
+Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities_2_1(
+ const V2_1::SessionType sessionType,
+ getProviderCapabilities_2_1_cb _hidl_cb) {
+ hidl_vec<V2_1::AudioCapabilities> audio_capabilities =
+ hidl_vec<V2_1::AudioCapabilities>(0);
+ if (sessionType == V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+ std::vector<CodecCapabilities> db_codec_capabilities =
+ android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
+ if (db_codec_capabilities.size()) {
+ audio_capabilities.resize(db_codec_capabilities.size());
+ for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+ audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
+ }
+ }
+ } else if (sessionType != V2_1::SessionType::UNKNOWN) {
+ std::vector<V2_1::PcmParameters> db_pcm_capabilities =
+ android::bluetooth::audio::GetSoftwarePcmCapabilities_2_1();
+ if (db_pcm_capabilities.size() == 1) {
+ audio_capabilities.resize(1);
+ audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
+ }
+ }
+ LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
+ << " supports " << audio_capabilities.size() << " codecs";
+ _hidl_cb(audio_capabilities);
+ return Void();
+}
+
+IBluetoothAudioProvidersFactory* HIDL_FETCH_IBluetoothAudioProvidersFactory(
+ const char* /* name */) {
+ return new BluetoothAudioProvidersFactory();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h
new file mode 100644
index 0000000..8db330b
--- /dev/null
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h
@@ -0,0 +1,73 @@
+/*
+ * 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/IBluetoothAudioProvidersFactory.h>
+
+#include "A2dpOffloadAudioProvider.h"
+#include "A2dpSoftwareAudioProvider.h"
+#include "BluetoothAudioProvider.h"
+#include "HearingAidAudioProvider.h"
+#include "LeAudioAudioProvider.h"
+#include "LeAudioOffloadAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+class BluetoothAudioProvidersFactory : public IBluetoothAudioProvidersFactory {
+ public:
+ BluetoothAudioProvidersFactory() {}
+
+ Return<void> openProvider(const V2_0::SessionType sessionType,
+ openProvider_cb _hidl_cb) override;
+
+ Return<void> getProviderCapabilities(
+ const V2_0::SessionType sessionType,
+ getProviderCapabilities_cb _hidl_cb) override;
+
+ Return<void> openProvider_2_1(const V2_1::SessionType sessionType,
+ openProvider_2_1_cb _hidl_cb) override;
+
+ Return<void> getProviderCapabilities_2_1(
+ const V2_1::SessionType sessionType,
+ getProviderCapabilities_2_1_cb _hidl_cb) override;
+
+ private:
+ static A2dpSoftwareAudioProvider a2dp_software_provider_instance_;
+ static A2dpOffloadAudioProvider a2dp_offload_provider_instance_;
+ static HearingAidAudioProvider hearing_aid_provider_instance_;
+ static LeAudioOutputAudioProvider leaudio_output_provider_instance_;
+ static LeAudioInputAudioProvider leaudio_input_provider_instance_;
+ static LeAudioOffloadOutputAudioProvider
+ leaudio_offload_output_provider_instance_;
+ static LeAudioOffloadInputAudioProvider
+ leaudio_offload_input_provider_instance_;
+};
+
+extern "C" IBluetoothAudioProvidersFactory*
+HIDL_FETCH_IBluetoothAudioProvidersFactory(const char* name);
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp b/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp
new file mode 100644
index 0000000..c79b910
--- /dev/null
+++ b/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "BTAudioProviderHearingAid"
+
+#include "HearingAidAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport_2_2.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
+static constexpr uint32_t kPcmFrameCount = 128;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+static constexpr uint32_t kRtpFrameCount = 7; // max counts by 1 tick (20ms)
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 1; // single buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+HearingAidAudioProvider::HearingAidAudioProvider()
+ : BluetoothAudioProvider(), mDataMQ(nullptr) {
+ LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+ << " byte(s)";
+ std::unique_ptr<DataMQ> tempDataMQ(
+ new DataMQ(kDataMqSize, /* EventFlag */ true));
+ if (tempDataMQ && tempDataMQ->isValid()) {
+ mDataMQ = std::move(tempDataMQ);
+ session_type_ = V2_1::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+ } else {
+ ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+ ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+ }
+}
+
+bool HearingAidAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+ return isValid(static_cast<V2_1::SessionType>(sessionType));
+}
+
+bool HearingAidAudioProvider::isValid(const V2_1::SessionType& sessionType) {
+ return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
+}
+
+Return<void> HearingAidAudioProvider::startSession(
+ const sp<IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ /**
+ * Initialize the audio platform if audioConfiguration is supported.
+ * Save the IBluetoothAudioPort interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ if (audioConfig.getDiscriminator() !=
+ AudioConfiguration::hidl_discriminator::pcmConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
+ audioConfig.pcmConfig())) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << toString(audioConfig.pcmConfig());
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> HearingAidAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
+ if (mDataMQ && mDataMQ->isValid()) {
+ BluetoothAudioSessionReport_2_2::OnSessionStarted(
+ session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+ _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+ } else {
+ _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/HearingAidAudioProvider.h b/bluetooth/audio/2.2/default/HearingAidAudioProvider.h
new file mode 100644
index 0000000..426c443
--- /dev/null
+++ b/bluetooth/audio/2.2/default/HearingAidAudioProvider.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class HearingAidAudioProvider : public BluetoothAudioProvider {
+ public:
+ HearingAidAudioProvider();
+
+ bool isValid(const V2_1::SessionType& sessionType) override;
+ bool isValid(const V2_0::SessionType& sessionType) override;
+
+ Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+ const V2_0::AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ private:
+ // audio data queue for software encoding
+ std::unique_ptr<DataMQ> mDataMQ;
+
+ Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp b/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp
new file mode 100644
index 0000000..af6ec99
--- /dev/null
+++ b/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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 "BTAudioProviderLeAudio"
+
+#include "LeAudioAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport_2_2.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
+static constexpr uint32_t kBufferOutCount = 2; // two frame buffer
+static constexpr uint32_t kBufferInCount = 2; // two frame buffer
+
+LeAudioOutputAudioProvider::LeAudioOutputAudioProvider()
+ : LeAudioAudioProvider() {
+ session_type_ = V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+}
+
+LeAudioInputAudioProvider::LeAudioInputAudioProvider()
+ : LeAudioAudioProvider() {
+ session_type_ = V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH;
+}
+
+LeAudioAudioProvider::LeAudioAudioProvider()
+ : BluetoothAudioProvider(), mDataMQ(nullptr) {}
+
+bool LeAudioAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+ LOG(ERROR) << __func__ << ", invalid session type for Le Audio provider: "
+ << toString(sessionType);
+
+ return false;
+}
+
+bool LeAudioAudioProvider::isValid(const V2_1::SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+Return<void> LeAudioAudioProvider::startSession_2_1(
+ const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const V2_1::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ if (audioConfig.getDiscriminator() !=
+ V2_1::AudioConfiguration::hidl_discriminator::pcmConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ AudioConfiguration audioConfig_2_2;
+ audioConfig_2_2.pcmConfig(
+ {.sampleRate =
+ static_cast<V2_1::SampleRate>(audioConfig.pcmConfig().sampleRate),
+ .channelMode = audioConfig.pcmConfig().channelMode,
+ .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
+ .dataIntervalUs = 0});
+
+ return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+}
+
+Return<void> LeAudioAudioProvider::startSession_2_2(
+ const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ /**
+ * Initialize the audio platform if audioConfiguration is supported.
+ * Save the IBluetoothAudioPort interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ if (audioConfig.getDiscriminator() !=
+ AudioConfiguration::hidl_discriminator::pcmConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid_2_1(
+ audioConfig.pcmConfig())) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << toString(audioConfig.pcmConfig());
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ uint32_t kDataMqSize = 0;
+ switch (audioConfig.pcmConfig().sampleRate) {
+ case SampleRate::RATE_8000:
+ kDataMqSize = 8000;
+ break;
+ case SampleRate::RATE_16000:
+ kDataMqSize = 16000;
+ break;
+ case SampleRate::RATE_24000:
+ kDataMqSize = 24000;
+ break;
+ case SampleRate::RATE_32000:
+ kDataMqSize = 32000;
+ break;
+ case SampleRate::RATE_44100:
+ kDataMqSize = 44100;
+ break;
+ case SampleRate::RATE_48000:
+ kDataMqSize = 48000;
+ break;
+ default:
+ LOG(WARNING) << __func__ << " - Unsupported sampling frequency="
+ << toString(audioConfig.pcmConfig());
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ /* Number of samples per millisecond */
+ kDataMqSize = ceil(kDataMqSize / 1000);
+
+ switch (audioConfig.pcmConfig().channelMode) {
+ case ChannelMode::MONO:
+ break;
+ case ChannelMode::STEREO:
+ kDataMqSize *= 2;
+ break;
+ default:
+ /* This should never happen it would be caught while validating
+ * parameters.
+ */
+ break;
+ }
+
+ switch (audioConfig.pcmConfig().bitsPerSample) {
+ case BitsPerSample::BITS_16:
+ kDataMqSize *= 2;
+ break;
+ case BitsPerSample::BITS_24:
+ kDataMqSize *= 3;
+ break;
+ case BitsPerSample::BITS_32:
+ kDataMqSize *= 4;
+ break;
+ default:
+ /* This should never happen it would be caught while validating
+ * parameters.
+ */
+ break;
+ }
+
+ if (session_type_ == V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH)
+ kDataMqSize *= kBufferOutCount;
+ else if (session_type_ ==
+ V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH)
+ kDataMqSize *= kBufferInCount;
+ else
+ LOG(WARNING) << __func__ << ", default single buffer used";
+
+ kDataMqSize *= audioConfig.pcmConfig().dataIntervalUs / 1000;
+
+ LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+ << " byte(s)";
+
+ std::unique_ptr<DataMQ> tempDataMQ(
+ new DataMQ(kDataMqSize, /* EventFlag */ true));
+ if (tempDataMQ && tempDataMQ->isValid()) {
+ mDataMQ = std::move(tempDataMQ);
+ } else {
+ ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+ ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+ _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+ return Void();
+ }
+
+ return BluetoothAudioProvider::startSession_2_2(hostIf, audioConfig,
+ _hidl_cb);
+}
+
+Return<void> LeAudioAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
+ if (mDataMQ && mDataMQ->isValid()) {
+ BluetoothAudioSessionReport_2_2::OnSessionStarted(
+ session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+ _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+ } else {
+ _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioAudioProvider.h b/bluetooth/audio/2.2/default/LeAudioAudioProvider.h
new file mode 100644
index 0000000..40c26e0
--- /dev/null
+++ b/bluetooth/audio/2.2/default/LeAudioAudioProvider.h
@@ -0,0 +1,74 @@
+/*
+ * 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 <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class LeAudioAudioProvider : public BluetoothAudioProvider {
+ public:
+ LeAudioAudioProvider();
+
+ bool isValid(const V2_1::SessionType& sessionType) override;
+ bool isValid(const V2_0::SessionType& sessionType) override;
+
+ Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const V2_1::AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ Return<void> startSession_2_2(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ private:
+ /** queue for software encodec/decoded audio data */
+ std::unique_ptr<DataMQ> mDataMQ;
+
+ Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+class LeAudioOutputAudioProvider : public LeAudioAudioProvider {
+ public:
+ LeAudioOutputAudioProvider();
+};
+
+class LeAudioInputAudioProvider : public LeAudioAudioProvider {
+ public:
+ LeAudioInputAudioProvider();
+};
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp
new file mode 100644
index 0000000..7b70654
--- /dev/null
+++ b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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 "BTAudioProviderLeAudioOffload"
+
+#include "LeAudioOffloadAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport_2_2.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_2.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ =
+ V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ =
+ V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+}
+
+LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
+ : BluetoothAudioProvider() {}
+
+bool LeAudioOffloadAudioProvider::isValid(
+ const V2_0::SessionType& sessionType) {
+ LOG(ERROR) << __func__
+ << ", invalid session type for Offloaded Le Audio provider: "
+ << toString(sessionType);
+
+ return false;
+}
+
+bool LeAudioOffloadAudioProvider::isValid(
+ const V2_1::SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+Return<void> LeAudioOffloadAudioProvider::startSession_2_1(
+ const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const V2_1::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ if (audioConfig.getDiscriminator() !=
+ V2_1::AudioConfiguration::hidl_discriminator::leAudioCodecConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ AudioConfiguration audioConfig_2_2;
+ audioConfig_2_2.leAudioConfig().mode = LeAudioMode::UNKNOWN;
+ audioConfig_2_2.leAudioConfig().config.unicastConfig() = {
+ .streamMap = {{
+ .streamHandle = 0xFFFF,
+ .audioChannelAllocation =
+ audioConfig.leAudioCodecConfig().audioChannelAllocation,
+ }},
+ .peerDelay = 0,
+ .lc3Config = audioConfig.leAudioCodecConfig().lc3Config};
+
+ return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+}
+
+Return<void> LeAudioOffloadAudioProvider::startSession_2_2(
+ const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ /**
+ * Initialize the audio platform if audioConfiguration is supported.
+ * Save the IBluetoothAudioPort interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ if (audioConfig.getDiscriminator() !=
+ AudioConfiguration::hidl_discriminator::leAudioConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ if (!android::bluetooth::audio::IsOffloadLeAudioConfigurationValid(
+ session_type_, audioConfig.leAudioConfig())) {
+ LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
+ << toString(audioConfig.leAudioConfig());
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ return BluetoothAudioProvider::startSession_2_2(hostIf, audioConfig,
+ _hidl_cb);
+}
+
+Return<void> LeAudioOffloadAudioProvider::onSessionReady(
+ startSession_cb _hidl_cb) {
+ BluetoothAudioSessionReport_2_2::OnSessionStarted(session_type_, stack_iface_,
+ nullptr, audio_config_);
+ _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h
new file mode 100644
index 0000000..5620295
--- /dev/null
+++ b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h
@@ -0,0 +1,64 @@
+/*
+ * 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 "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+ LeAudioOffloadAudioProvider();
+
+ bool isValid(const V2_1::SessionType& sessionType) override;
+ bool isValid(const V2_0::SessionType& sessionType) override;
+
+ Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const V2_1::AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ Return<void> startSession_2_2(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ private:
+ Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadOutputAudioProvider();
+};
+
+class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadInputAudioProvider();
+};
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.2/types.hal b/bluetooth/audio/2.2/types.hal
new file mode 100644
index 0000000..d5f8a3f
--- /dev/null
+++ b/bluetooth/audio/2.2/types.hal
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package android.hardware.bluetooth.audio@2.2;
+
+import @2.1::Lc3Parameters;
+import @2.1::PcmParameters;
+import @2.0::CodecConfiguration;
+
+enum LeAudioMode : uint8_t {
+ UNKNOWN = 0x00,
+ UNICAST = 0x01,
+ BROADCAST = 0x02,
+};
+
+struct UnicastStreamMap {
+ /* The connection handle used for a unicast or a broadcast group. */
+ uint16_t streamHandle;
+ /* Audio channel allocation is a bit field, each enabled bit means that given audio direction,
+ * i.e. "left", or "right" is used. Ordering of audio channels comes from the least significant
+ * bit to the most significant bit. */
+ uint32_t audioChannelAllocation;
+};
+
+struct BroadcastStreamMap {
+ /* The connection handle used for a unicast or a broadcast group. */
+ uint16_t streamHandle;
+ /* Audio channel allocation is a bit field, each enabled bit means that given audio direction,
+ * i.e. "left", or "right" is used. Ordering of audio channels comes from the least significant
+ * bit to the most significant bit. */
+ uint32_t audioChannelAllocation;
+ Lc3Parameters lc3Config;
+};
+
+struct UnicastConfig {
+ vec<UnicastStreamMap> streamMap;
+ uint32_t peerDelay;
+ Lc3Parameters lc3Config;
+};
+
+struct BroadcastConfig {
+ vec<BroadcastStreamMap> streamMap;
+};
+
+struct LeAudioConfiguration {
+ /* The mode of the LE audio */
+ LeAudioMode mode;
+ safe_union CodecConfig {
+ UnicastConfig unicastConfig;
+ BroadcastConfig broadcastConfig;
+ } config;
+};
+
+/** Used to configure either a Hardware or Software Encoding session based on session type */
+safe_union AudioConfiguration {
+ PcmParameters pcmConfig;
+ CodecConfiguration codecConfig;
+ LeAudioConfiguration leAudioConfig;
+};
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
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 49e00f4..5c886ee 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -6197,14 +6197,13 @@
return;
}
- // Test that if more than one color cameras facing the same direction are
- // supported, there must be at least one logical camera facing that
- // direction.
+ // Test that if more than one rear-facing color camera is
+ // supported, there must be at least one rear-facing logical camera.
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
- // Front and back facing non-logical color cameras
- std::set<std::string> frontColorCameras, rearColorCameras;
- // Front and back facing logical cameras' physical camera Id sets
- std::set<std::set<std::string>> frontPhysicalIds, rearPhysicalIds;
+ // Back facing non-logical color cameras
+ std::set<std::string> rearColorCameras;
+ // Back facing logical cameras' physical camera Id sets
+ std::set<std::set<std::string>> rearPhysicalIds;
for (const auto& name : cameraDeviceNames) {
std::string cameraId;
int deviceVersion = getCameraDeviceVersionAndId(name, mProviderType, &cameraId);
@@ -6236,8 +6235,8 @@
return;
}
- // Check camera facing. Skip if facing is neither FRONT
- // nor BACK. If this is not a logical camera, only note down
+ // Check camera facing. Skip if facing is not BACK.
+ // If this is not a logical camera, only note down
// the camera ID, and skip.
camera_metadata_ro_entry entry;
int retcode = find_camera_metadata_ro_entry(
@@ -6246,18 +6245,12 @@
ASSERT_GT(entry.count, 0);
uint8_t facing = entry.data.u8[0];
bool isLogicalCamera = (isLogicalMultiCamera(metadata) == Status::OK);
- if (facing == ANDROID_LENS_FACING_FRONT) {
- if (!isLogicalCamera) {
- frontColorCameras.insert(cameraId);
- return;
- }
- } else if (facing == ANDROID_LENS_FACING_BACK) {
- if (!isLogicalCamera) {
- rearColorCameras.insert(cameraId);
- return;
- }
- } else {
- // Not FRONT or BACK facing. Skip.
+ if (facing != ANDROID_LENS_FACING_BACK) {
+ // Not BACK facing. Skip.
+ return;
+ }
+ if (!isLogicalCamera) {
+ rearColorCameras.insert(cameraId);
return;
}
@@ -6266,11 +6259,7 @@
std::unordered_set<std::string> physicalCameraIds;
Status s = getPhysicalCameraIds(metadata, &physicalCameraIds);
ASSERT_EQ(Status::OK, s);
- if (facing == ANDROID_LENS_FACING_FRONT) {
- frontPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
- } else {
- rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
- }
+ rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
for (const auto& physicalId : physicalCameraIds) {
// Skip if the physicalId is publicly available
for (auto& deviceName : cameraDeviceNames) {
@@ -6297,11 +6286,7 @@
(camera_metadata_t*)chars.data();
if (CameraHidlTest::isColorCamera(physicalMetadata)) {
- if (facing == ANDROID_LENS_FACING_FRONT) {
- frontColorCameras.insert(physicalId);
- } else if (facing == ANDROID_LENS_FACING_BACK) {
- rearColorCameras.insert(physicalId);
- }
+ rearColorCameras.insert(physicalId);
}
});
ASSERT_TRUE(ret.isOk());
@@ -6319,20 +6304,9 @@
}
}
- // If there are more than one color cameras facing one direction, a logical
- // multi-camera must be defined consisting of all color cameras facing that
- // direction.
- if (frontColorCameras.size() > 1) {
- bool hasFrontLogical = false;
- for (const auto& physicalIds : frontPhysicalIds) {
- if (std::includes(physicalIds.begin(), physicalIds.end(),
- frontColorCameras.begin(), frontColorCameras.end())) {
- hasFrontLogical = true;
- break;
- }
- }
- ASSERT_TRUE(hasFrontLogical);
- }
+ // If there are more than one rear-facing color camera, a logical
+ // multi-camera must be defined consisting of all rear-facing color
+ // cameras.
if (rearColorCameras.size() > 1) {
bool hasRearLogical = false;
for (const auto& physicalIds : rearPhysicalIds) {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index b2c0ccd..ece4de7 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -133,7 +133,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.bluetooth.audio</name>
- <version>2.0-1</version>
+ <version>2.0-2</version>
<interface>
<name>IBluetoothAudioProvidersFactory</name>
<instance>default</instance>
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index 3a11e64..65bdbbc 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
aidl_interface {
name: "android.hardware.health",
vendor_available: true,
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index cb78e77..9fc8b7d 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
cc_defaults {
name: "libhealth_aidl_common_defaults",
vendor: true,
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 37acfa9..12ce859 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1307,7 +1307,8 @@
AuthorizationSet expected_sw_enforced, //
AuthorizationSet expected_hw_enforced, //
SecurityLevel security_level,
- const vector<uint8_t>& attestation_cert) {
+ const vector<uint8_t>& attestation_cert,
+ vector<uint8_t>* unique_id) {
X509_Ptr cert(parse_cert_blob(attestation_cert));
EXPECT_TRUE(!!cert.get());
if (!cert.get()) return false;
@@ -1472,6 +1473,10 @@
expected_hw_enforced.Sort();
EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
+ if (unique_id != nullptr) {
+ *unique_id = att_unique_id;
+ }
+
return true;
}
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index ec3fcf6..7b3b9d4 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -338,7 +338,8 @@
AuthorizationSet expected_sw_enforced, //
AuthorizationSet expected_hw_enforced, //
SecurityLevel security_level,
- const vector<uint8_t>& attestation_cert);
+ const vector<uint8_t>& attestation_cert,
+ vector<uint8_t>* unique_id = nullptr);
string bin2hex(const vector<uint8_t>& data);
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index e41a851..670043d 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1621,6 +1621,94 @@
}
/*
+ * NewKeyGenerationTest.EcdsaAttestationUniqueId
+ *
+ * Verifies that creation of an attested ECDSA key with a UNIQUE_ID included.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationUniqueId) {
+ auto get_unique_id = [this](const std::string& app_id, uint64_t datetime,
+ vector<uint8_t>* unique_id) {
+ auto challenge = "hello";
+ auto subject = "cert subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+ uint64_t serial_int = 0x1010;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+ const AuthorizationSetBuilder builder =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CREATION_DATETIME, datetime)
+ .SetDefaultValidity();
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(builder));
+ ASSERT_GT(key_blob_.size(), 0U);
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics_);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics_);
+
+ // Check that the unique ID field in the extension is non-empty.
+ EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced,
+ SecLevel(), cert_chain_[0].encodedCertificate,
+ unique_id));
+ EXPECT_GT(unique_id->size(), 0);
+ CheckedDeleteKey();
+ };
+
+ // Generate unique ID
+ auto app_id = "foo";
+ uint64_t cert_date = 1619621648000; // Wed Apr 28 14:54:08 2021 in ms since epoch
+ vector<uint8_t> unique_id;
+ get_unique_id(app_id, cert_date, &unique_id);
+
+ // Generating a new key with the same parameters should give the same unique ID.
+ vector<uint8_t> unique_id2;
+ get_unique_id(app_id, cert_date, &unique_id2);
+ EXPECT_EQ(unique_id, unique_id2);
+
+ // Generating a new key with a slightly different date should give the same unique ID.
+ uint64_t rounded_date = cert_date / 2592000000LLU;
+ uint64_t min_date = rounded_date * 2592000000LLU;
+ uint64_t max_date = ((rounded_date + 1) * 2592000000LLU) - 1;
+
+ vector<uint8_t> unique_id3;
+ get_unique_id(app_id, min_date, &unique_id3);
+ EXPECT_EQ(unique_id, unique_id3);
+
+ vector<uint8_t> unique_id4;
+ get_unique_id(app_id, max_date, &unique_id4);
+ EXPECT_EQ(unique_id, unique_id4);
+
+ // A different attestation application ID should yield a different unique ID.
+ auto app_id2 = "different_foo";
+ vector<uint8_t> unique_id5;
+ get_unique_id(app_id2, cert_date, &unique_id5);
+ EXPECT_NE(unique_id, unique_id5);
+
+ // A radically different date should yield a different unique ID.
+ vector<uint8_t> unique_id6;
+ get_unique_id(app_id, 1611621648000, &unique_id6);
+ EXPECT_NE(unique_id, unique_id6);
+
+ vector<uint8_t> unique_id7;
+ get_unique_id(app_id, max_date + 1, &unique_id7);
+ EXPECT_NE(unique_id, unique_id7);
+
+ vector<uint8_t> unique_id8;
+ get_unique_id(app_id, min_date - 1, &unique_id8);
+ EXPECT_NE(unique_id, unique_id8);
+}
+
+/*
* NewKeyGenerationTest.EcdsaAttestationTagNoApplicationId
*
* Verifies that creation of an attested ECDSA key does not include APPLICATION_ID.
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 38f3586..76fb79b 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -222,7 +222,7 @@
// Generate an ECDSA key that is attested by the generated P256 keypair.
AuthorizationSet keyDesc = AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.AttestationChallenge("foo")
.AttestationApplicationId("bar")
.Digest(Digest::NONE)
diff --git a/security/keymint/support/authorization_set.cpp b/security/keymint/support/authorization_set.cpp
index 25eace3..c1b5d48 100644
--- a/security/keymint/support/authorization_set.cpp
+++ b/security/keymint/support/authorization_set.cpp
@@ -161,11 +161,6 @@
return EncryptionKey();
}
-AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
- EcdsaKey(key_size);
- return SigningKey();
-}
-
AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) {
EcdsaKey(curve);
return SigningKey();
diff --git a/security/keymint/support/include/keymint_support/authorization_set.h b/security/keymint/support/include/keymint_support/authorization_set.h
index ca51b08..e41a329 100644
--- a/security/keymint/support/include/keymint_support/authorization_set.h
+++ b/security/keymint/support/include/keymint_support/authorization_set.h
@@ -281,7 +281,6 @@
AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
- AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size);