diff --git a/base.mk b/base.mk
index af27de5..2293510 100644
--- a/base.mk
+++ b/base.mk
@@ -8,6 +8,15 @@ PRODUCT_COPY_FILES := \
frameworks/native/data/etc/android.hardware.bluetooth_le.xml:system/etc/permissions/android.hardware.bluetooth_le.xml \
frameworks/native/data/etc/android.hardware.usb.host.xml:system/etc/permissions/android.hardware.usb.host.xml \
+# Bluetooth Audio (System-side HAL, sysbta)
+PRODUCT_PACKAGES += \
+ audio.sysbta.default \
+ android.hardware.bluetooth.audio-service-system
+
+PRODUCT_COPY_FILES += \
+ device/phh/treble/bluetooth/audio/config/sysbta_audio_policy_configuration.xml:$(TARGET_COPY_OUT_SYSTEM)/etc/sysbta_audio_policy_configuration.xml \
+ device/phh/treble/bluetooth/audio/config/sysbta_audio_policy_configuration_7_0.xml:$(TARGET_COPY_OUTY_SYSTEM)/etc/sysbta_audio_policy_configuration_7_0.xml
+
#Use a more decent APN config
PRODUCT_COPY_FILES += \
device/sample/etc/apns-full-conf.xml:system/etc/apns-conf.xml
diff --git a/bluetooth/audio/config/sysbta_audio_policy_configuration.xml b/bluetooth/audio/config/sysbta_audio_policy_configuration.xml
new file mode 100644
index 0000000..79d1643
--- /dev/null
+++ b/bluetooth/audio/config/sysbta_audio_policy_configuration.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bluetooth/audio/config/sysbta_audio_policy_configuration_7_0.xml b/bluetooth/audio/config/sysbta_audio_policy_configuration_7_0.xml
new file mode 100644
index 0000000..47228b2
--- /dev/null
+++ b/bluetooth/audio/config/sysbta_audio_policy_configuration_7_0.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bluetooth/audio/hal/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/hal/A2dpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..2d0d8c9
--- /dev/null
+++ b/bluetooth/audio/hal/A2dpOffloadAudioProvider.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 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 "BTAudioProviderA2dpHW"
+
+#include "A2dpOffloadAudioProvider.h"
+
+#include
+#include
+#include
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+A2dpOffloadEncodingAudioProvider::A2dpOffloadEncodingAudioProvider()
+ : A2dpOffloadAudioProvider() {
+ session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+A2dpOffloadDecodingAudioProvider::A2dpOffloadDecodingAudioProvider()
+ : A2dpOffloadAudioProvider() {
+ session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+}
+
+A2dpOffloadAudioProvider::A2dpOffloadAudioProvider() {}
+
+bool A2dpOffloadAudioProvider::isValid(const SessionType& session_type) {
+ return (session_type == session_type_);
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+ session_type_, audio_config.get())) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ return BluetoothAudioProvider::startSession(
+ host_if, audio_config, latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ *_aidl_return = DataMQDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/A2dpOffloadAudioProvider.h b/bluetooth/audio/hal/A2dpOffloadAudioProvider.h
new file mode 100644
index 0000000..e6f188b
--- /dev/null
+++ b/bluetooth/audio/hal/A2dpOffloadAudioProvider.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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 aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+ A2dpOffloadAudioProvider();
+
+ bool isValid(const SessionType& session_type) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes,
+ DataMQDesc* _aidl_return);
+
+ private:
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class A2dpOffloadEncodingAudioProvider : public A2dpOffloadAudioProvider {
+ public:
+ A2dpOffloadEncodingAudioProvider();
+};
+
+class A2dpOffloadDecodingAudioProvider : public A2dpOffloadAudioProvider {
+ public:
+ A2dpOffloadDecodingAudioProvider();
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/hal/A2dpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..bd2da95
--- /dev/null
+++ b/bluetooth/audio/hal/A2dpSoftwareAudioProvider.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 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 "BTAudioProviderA2dpSW"
+
+#include "A2dpSoftwareAudioProvider.h"
+
+#include
+#include
+#include
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+// 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;
+
+A2dpSoftwareEncodingAudioProvider::A2dpSoftwareEncodingAudioProvider()
+ : A2dpSoftwareAudioProvider() {
+ session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+}
+
+A2dpSoftwareDecodingAudioProvider::A2dpSoftwareDecodingAudioProvider()
+ : A2dpSoftwareAudioProvider() {
+ session_type_ = SessionType::A2DP_SOFTWARE_DECODING_DATAPATH;
+}
+
+A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
+ : BluetoothAudioProvider(), data_mq_(nullptr) {
+ LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+ << " byte(s)";
+ std::unique_ptr data_mq(
+ new DataMQ(kDataMqSize, /* EventFlag */ true));
+ if (data_mq && data_mq->isValid()) {
+ data_mq_ = std::move(data_mq);
+ } else {
+ ALOGE_IF(!data_mq, "failed to allocate data MQ");
+ ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
+ }
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
+}
+
+ndk::ScopedAStatus A2dpSoftwareAudioProvider::startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const PcmConfiguration& pcm_config =
+ audio_config.get();
+ if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << pcm_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return BluetoothAudioProvider::startSession(
+ host_if, audio_config, latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus A2dpSoftwareAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ if (data_mq_ == nullptr || !data_mq_->isValid()) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = data_mq_->dupeDesc();
+ auto desc = data_mq_->dupeDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/A2dpSoftwareAudioProvider.h b/bluetooth/audio/hal/A2dpSoftwareAudioProvider.h
new file mode 100644
index 0000000..3ebecf2
--- /dev/null
+++ b/bluetooth/audio/hal/A2dpSoftwareAudioProvider.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 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 aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+ A2dpSoftwareAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes,
+ DataMQDesc* _aidl_return);
+
+ private:
+ // audio data queue for software encoding
+ std::unique_ptr data_mq_;
+
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class A2dpSoftwareEncodingAudioProvider : public A2dpSoftwareAudioProvider {
+ public:
+ A2dpSoftwareEncodingAudioProvider();
+};
+
+class A2dpSoftwareDecodingAudioProvider : public A2dpSoftwareAudioProvider {
+ public:
+ A2dpSoftwareDecodingAudioProvider();
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/Android.bp b/bluetooth/audio/hal/Android.bp
new file mode 100644
index 0000000..e52a6b7
--- /dev/null
+++ b/bluetooth/audio/hal/Android.bp
@@ -0,0 +1,92 @@
+cc_library_shared {
+ name: "android.hardware.bluetooth.audio-system-impl",
+ vintf_fragments: ["bluetooth_audio.xml"],
+ srcs: [
+ "BluetoothAudioProvider.cpp",
+ "BluetoothAudioProviderFactory.cpp",
+ "A2dpOffloadAudioProvider.cpp",
+ "A2dpSoftwareAudioProvider.cpp",
+ "HearingAidAudioProvider.cpp",
+ "LeAudioOffloadAudioProvider.cpp",
+ "LeAudioSoftwareAudioProvider.cpp",
+ "service.cpp",
+ ],
+ export_include_dirs: ["."],
+ header_libs: ["libhardware_headers"],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "android.hardware.bluetooth.audio-V2-ndk",
+ "libbluetooth_audio_session_aidl_system",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.bluetooth.audio-service-system",
+ vintf_fragments: ["bluetooth_audio_system.xml"],
+ init_rc: ["android.hardware.bluetooth.audio-service-system.rc"],
+ relative_install_path: "hw",
+ srcs: [
+ "BluetoothAudioProvider.cpp",
+ "BluetoothAudioProviderFactory.cpp",
+ "A2dpOffloadAudioProvider.cpp",
+ "A2dpSoftwareAudioProvider.cpp",
+ "HearingAidAudioProvider.cpp",
+ "LeAudioOffloadAudioProvider.cpp",
+ "LeAudioSoftwareAudioProvider.cpp",
+ "Device.cpp",
+ "DevicesFactory.cpp",
+ "ParametersUtil.cpp",
+ "PrimaryDevice.cpp",
+ "Stream.cpp",
+ "StreamIn.cpp",
+ "StreamOut.cpp",
+ "service_system.cpp",
+ ],
+ header_libs: [
+ "libhardware_headers",
+ "android.hardware.audio.common.util@all-versions",
+ "libaudioutils_headers",
+ "libaudio_system_headers",
+ "libmedia_headers",
+ "libmediautils_headers",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "android.hardware.bluetooth.audio-V2-ndk",
+ "libbluetooth_audio_session_aidl_system",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libmedia_helper",
+ "libmediautils_vendor",
+ "libmemunreachable",
+ "libutils",
+ "android.hardware.audio.common-util",
+ "android.hardware.audio@6.0",
+// "android.hardware.audio@7.1",
+ "android.hardware.audio@6.0-util",
+ "android.hardware.audio.common@6.0",
+// "android.hardware.audio.common@6.0-enums",
+ "android.hardware.audio.common@6.0-util",
+ ],
+ static_libs: [
+ "libaudiofoundation",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-DCOMMON_TYPES_MINOR_VERSION=0",
+ "-DCORE_TYPES_MINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ],
+}
diff --git a/bluetooth/audio/hal/BluetoothAudioProvider.cpp b/bluetooth/audio/hal/BluetoothAudioProvider.cpp
new file mode 100644
index 0000000..2a88959
--- /dev/null
+++ b/bluetooth/audio/hal/BluetoothAudioProvider.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2022 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
+#include
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+BluetoothAudioProvider::BluetoothAudioProvider() {
+ death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(binderDiedCallbackAidl));
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latencyModes,
+ DataMQDesc* _aidl_return) {
+ if (host_if == nullptr) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ latency_modes_ = latencyModes;
+ audio_config_ = std::make_unique(audio_config);
+ stack_iface_ = host_if;
+ is_binder_died = false;
+
+ AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(),
+ this);
+
+ onSessionReady(_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::endSession() {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+ if (stack_iface_ != nullptr) {
+ BluetoothAudioSessionReport::OnSessionEnded(session_type_);
+
+ if (!is_binder_died) {
+ AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
+ death_recipient_.get(), this);
+ }
+ } else {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ }
+
+ stack_iface_ = nullptr;
+ audio_config_ = nullptr;
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::streamStarted(
+ BluetoothAudioStatus status) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status);
+
+ if (stack_iface_ != nullptr) {
+ BluetoothAudioSessionReport::ReportControlStatus(session_type_, true,
+ status);
+ } else {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status) << " has NO session";
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::streamSuspended(
+ BluetoothAudioStatus status) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status);
+
+ if (stack_iface_ != nullptr) {
+ BluetoothAudioSessionReport::ReportControlStatus(session_type_, false,
+ status);
+ } else {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status) << " has NO session";
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration(
+ const AudioConfiguration& audio_config) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+ if (stack_iface_ == nullptr || audio_config_ == nullptr) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (audio_config.getTag() != audio_config_->getTag()) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " audio config type is not match";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ audio_config_ = std::make_unique(audio_config);
+ BluetoothAudioSessionReport::ReportAudioConfigChanged(session_type_,
+ *audio_config_);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::setLowLatencyModeAllowed(
+ bool allowed) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+ if (stack_iface_ == nullptr) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ LOG(INFO) << __func__ << " - allowed " << allowed;
+ BluetoothAudioSessionReport::ReportLowLatencyModeAllowedChanged(
+ session_type_, allowed);
+ return ndk::ScopedAStatus::ok();
+}
+
+void BluetoothAudioProvider::binderDiedCallbackAidl(void* ptr) {
+ LOG(ERROR) << __func__ << " - BluetoothAudio Service died";
+ auto provider = static_cast(ptr);
+ if (provider == nullptr) {
+ LOG(ERROR) << __func__ << ": Null AudioProvider HAL died";
+ return;
+ }
+ provider->is_binder_died = true;
+ provider->endSession();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/hal/BluetoothAudioProvider.h b/bluetooth/audio/hal/BluetoothAudioProvider.h
new file mode 100644
index 0000000..dbfff7d
--- /dev/null
+++ b/bluetooth/audio/hal/BluetoothAudioProvider.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 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
+#include
+#include
+#include
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using MqDataType = int8_t;
+using MqDataMode = SynchronizedReadWrite;
+using DataMQ = AidlMessageQueue;
+using DataMQDesc = MQDescriptor;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioProvider : public BnBluetoothAudioProvider {
+ public:
+ BluetoothAudioProvider();
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes,
+ DataMQDesc* _aidl_return);
+ ndk::ScopedAStatus endSession();
+ ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status);
+ ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status);
+ ndk::ScopedAStatus updateAudioConfiguration(
+ const AudioConfiguration& audio_config);
+ ndk::ScopedAStatus setLowLatencyModeAllowed(bool allowed);
+
+ virtual bool isValid(const SessionType& sessionType) = 0;
+
+ protected:
+ virtual ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) = 0;
+ static void binderDiedCallbackAidl(void* cookie_ptr);
+
+ ::ndk::ScopedAIBinder_DeathRecipient death_recipient_;
+
+ std::shared_ptr stack_iface_;
+ std::unique_ptr audio_config_ = nullptr;
+ SessionType session_type_;
+ std::vector latency_modes_;
+ bool is_binder_died = false;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/hal/BluetoothAudioProviderFactory.cpp
new file mode 100644
index 0000000..91731d4
--- /dev/null
+++ b/bluetooth/audio/hal/BluetoothAudioProviderFactory.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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 "BTAudioProviderFactoryAIDL"
+
+#include "BluetoothAudioProviderFactory.h"
+
+#include
+#include
+
+#include "A2dpOffloadAudioProvider.h"
+#include "A2dpSoftwareAudioProvider.h"
+#include "BluetoothAudioProvider.h"
+#include "HearingAidAudioProvider.h"
+#include "LeAudioOffloadAudioProvider.h"
+#include "LeAudioSoftwareAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
+
+ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
+ const SessionType session_type,
+ std::shared_ptr* _aidl_return) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type);
+ std::shared_ptr provider = nullptr;
+
+ switch (session_type) {
+ case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH:
+ provider =
+ ndk::SharedRefBase::make();
+ break;
+ case SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ provider =
+ ndk::SharedRefBase::make();
+ break;
+ case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ provider = ndk::SharedRefBase::make();
+ break;
+ default:
+ provider = nullptr;
+ break;
+ }
+
+ if (provider == nullptr || !provider->isValid(session_type)) {
+ provider = nullptr;
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = provider;
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderCapabilities(
+ const SessionType session_type,
+ std::vector* _aidl_return) {
+ if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ auto codec_capabilities =
+ BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(session_type);
+ _aidl_return->resize(codec_capabilities.size());
+ for (int i = 0; i < codec_capabilities.size(); i++) {
+ _aidl_return->at(i).set(
+ codec_capabilities[i]);
+ }
+ } else if (session_type ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+ session_type ==
+ SessionType::
+ LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ std::vector db_codec_capabilities =
+ BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(session_type);
+ if (db_codec_capabilities.size()) {
+ _aidl_return->resize(db_codec_capabilities.size());
+ for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+ _aidl_return->at(i).set(
+ db_codec_capabilities[i]);
+ }
+ }
+ } else if (session_type != SessionType::UNKNOWN) {
+ auto pcm_capabilities = BluetoothAudioCodecs::GetSoftwarePcmCapabilities();
+ _aidl_return->resize(pcm_capabilities.size());
+ for (int i = 0; i < pcm_capabilities.size(); i++) {
+ _aidl_return->at(i).set(
+ pcm_capabilities[i]);
+ }
+ }
+
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type)
+ << " supports " << _aidl_return->size() << " codecs";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/hal/BluetoothAudioProviderFactory.h b/bluetooth/audio/hal/BluetoothAudioProviderFactory.h
new file mode 100644
index 0000000..b38cfd2
--- /dev/null
+++ b/bluetooth/audio/hal/BluetoothAudioProviderFactory.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 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
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioProviderFactory : public BnBluetoothAudioProviderFactory {
+ public:
+ BluetoothAudioProviderFactory();
+
+ ndk::ScopedAStatus openProvider(
+ const SessionType session_type,
+ std::shared_ptr* _aidl_return) override;
+
+ ndk::ScopedAStatus getProviderCapabilities(
+ const SessionType session_type,
+ std::vector* _aidl_return) override;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/Device.cpp b/bluetooth/audio/hal/Device.cpp
new file mode 100644
index 0000000..85b2768
--- /dev/null
+++ b/bluetooth/audio/hal/Device.cpp
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 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 "DeviceHAL"
+
+#include "Device.h"
+#include "common/all-versions/default/EffectMap.h"
+#include "StreamIn.h"
+#include "StreamOut.h"
+#include "Util.h"
+
+//#define LOG_NDEBUG 0
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace CPP_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
+namespace util {
+using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::util;
+}
+
+Device::Device(audio_hw_device_t* device) : mIsClosed(false), mDevice(device) {}
+
+Device::~Device() {
+ (void)doClose();
+ mDevice = nullptr;
+}
+
+Result Device::analyzeStatus(const char* funcName, int status,
+ const std::vector& ignoreErrors) {
+ return util::analyzeStatus("Device", funcName, status, ignoreErrors);
+}
+
+void Device::closeInputStream(audio_stream_in_t* stream) {
+ mDevice->close_input_stream(mDevice, stream);
+ LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
+ --mOpenedStreamsCount;
+}
+
+void Device::closeOutputStream(audio_stream_out_t* stream) {
+ mDevice->close_output_stream(mDevice, stream);
+ LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
+ --mOpenedStreamsCount;
+}
+
+char* Device::halGetParameters(const char* keys) {
+ return mDevice->get_parameters(mDevice, keys);
+}
+
+int Device::halSetParameters(const char* keysAndValues) {
+ return mDevice->set_parameters(mDevice, keysAndValues);
+}
+
+// Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow.
+Return Device::initCheck() {
+ return analyzeStatus("init_check", mDevice->init_check(mDevice));
+}
+
+Return Device::setMasterVolume(float volume) {
+ if (mDevice->set_master_volume == NULL) {
+ return Result::NOT_SUPPORTED;
+ }
+ if (!util::isGainNormalized(volume)) {
+ ALOGW("Can not set a master volume (%f) outside [0,1]", volume);
+ return Result::INVALID_ARGUMENTS;
+ }
+ return analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume),
+ {ENOSYS} /*ignore*/);
+}
+
+Return Device::getMasterVolume(getMasterVolume_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ float volume = 0;
+ if (mDevice->get_master_volume != NULL) {
+ retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume),
+ {ENOSYS} /*ignore*/);
+ }
+ _hidl_cb(retval, volume);
+ return Void();
+}
+
+Return Device::setMicMute(bool mute) {
+ return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute), {ENOSYS} /*ignore*/);
+}
+
+Return Device::getMicMute(getMicMute_cb _hidl_cb) {
+ bool mute = false;
+ Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute),
+ {ENOSYS} /*ignore*/);
+ _hidl_cb(retval, mute);
+ return Void();
+}
+
+Return Device::setMasterMute(bool mute) {
+ Result retval(Result::NOT_SUPPORTED);
+ if (mDevice->set_master_mute != NULL) {
+ retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute),
+ {ENOSYS} /*ignore*/);
+ }
+ return retval;
+}
+
+Return Device::getMasterMute(getMasterMute_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ bool mute = false;
+ if (mDevice->get_master_mute != NULL) {
+ retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute),
+ {ENOSYS} /*ignore*/);
+ }
+ _hidl_cb(retval, mute);
+ return Void();
+}
+
+Return Device::getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
+ audio_config_t halConfig;
+ Result retval(Result::INVALID_ARGUMENTS);
+ uint64_t bufferSize = 0;
+ if (HidlUtils::audioConfigToHal(config, &halConfig) == NO_ERROR) {
+ size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
+ if (halBufferSize != 0) {
+ retval = Result::OK;
+ bufferSize = halBufferSize;
+ }
+ }
+ _hidl_cb(retval, bufferSize);
+ return Void();
+}
+
+std::tuple> Device::openOutputStreamCore(int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ const AudioOutputFlags& flags,
+ AudioConfig* suggestedConfig) {
+ audio_config_t halConfig;
+ if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) {
+ return {Result::INVALID_ARGUMENTS, nullptr};
+ }
+ audio_stream_out_t* halStream;
+ audio_devices_t halDevice;
+ char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ if (CoreUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress) != NO_ERROR) {
+ return {Result::INVALID_ARGUMENTS, nullptr};
+ }
+ audio_output_flags_t halFlags;
+ if (CoreUtils::audioOutputFlagsToHal(flags, &halFlags) != NO_ERROR) {
+ return {Result::INVALID_ARGUMENTS, nullptr};
+ }
+ ALOGV("open_output_stream handle: %d devices: %x flags: %#x "
+ "srate: %d format %#x channels %x address %s",
+ ioHandle, halDevice, halFlags, halConfig.sample_rate, halConfig.format,
+ halConfig.channel_mask, halDeviceAddress);
+ int status = mDevice->open_output_stream(mDevice, ioHandle, halDevice, halFlags, &halConfig,
+ &halStream, halDeviceAddress);
+ ALOGV("open_output_stream status %d stream %p", status, halStream);
+ sp streamOut;
+ if (status == OK) {
+ streamOut = new StreamOut(this, halStream);
+ ++mOpenedStreamsCount;
+ }
+ status_t convertStatus =
+ HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, suggestedConfig);
+ ALOGW_IF(convertStatus != OK, "%s: suggested config with incompatible fields", __func__);
+ return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut};
+}
+
+std::tuple> Device::openInputStreamCore(
+ int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
+ const AudioInputFlags& flags, AudioSource source, AudioConfig* suggestedConfig) {
+ audio_config_t halConfig;
+ if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) {
+ return {Result::INVALID_ARGUMENTS, nullptr};
+ }
+ audio_stream_in_t* halStream;
+ audio_devices_t halDevice;
+ char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ if (CoreUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress) != NO_ERROR) {
+ return {Result::INVALID_ARGUMENTS, nullptr};
+ }
+ audio_input_flags_t halFlags;
+ audio_source_t halSource;
+ if (CoreUtils::audioInputFlagsToHal(flags, &halFlags) != NO_ERROR ||
+ HidlUtils::audioSourceToHal(source, &halSource) != NO_ERROR) {
+ return {Result::INVALID_ARGUMENTS, nullptr};
+ }
+ ALOGV("open_input_stream handle: %d devices: %x flags: %#x "
+ "srate: %d format %#x channels %x address %s source %d",
+ ioHandle, halDevice, halFlags, halConfig.sample_rate, halConfig.format,
+ halConfig.channel_mask, halDeviceAddress, halSource);
+ int status = mDevice->open_input_stream(mDevice, ioHandle, halDevice, &halConfig, &halStream,
+ halFlags, halDeviceAddress, halSource);
+ ALOGV("open_input_stream status %d stream %p", status, halStream);
+ sp streamIn;
+ if (status == OK) {
+ streamIn = new StreamIn(this, halStream);
+ ++mOpenedStreamsCount;
+ }
+ status_t convertStatus =
+ HidlUtils::audioConfigFromHal(halConfig, true /*isInput*/, suggestedConfig);
+ ALOGW_IF(convertStatus != OK, "%s: suggested config with incompatible fields", __func__);
+ return {analyzeStatus("open_input_stream", status, {EINVAL} /*ignore*/), streamIn};
+}
+
+#if MAJOR_VERSION == 2
+Return Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config, AudioOutputFlags flags,
+ openOutputStream_cb _hidl_cb) {
+ AudioConfig suggestedConfig;
+ auto [result, streamOut] =
+ openOutputStreamCore(ioHandle, device, config, flags, &suggestedConfig);
+ _hidl_cb(result, streamOut, suggestedConfig);
+ return Void();
+}
+
+Return Device::openInputStream(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config, AudioInputFlags flags,
+ AudioSource source, openInputStream_cb _hidl_cb) {
+ AudioConfig suggestedConfig;
+ auto [result, streamIn] =
+ openInputStreamCore(ioHandle, device, config, flags, source, &suggestedConfig);
+ _hidl_cb(result, streamIn, suggestedConfig);
+ return Void();
+}
+
+#elif MAJOR_VERSION >= 4
+std::tuple, AudioConfig> Device::openOutputStreamImpl(
+ int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
+ const SourceMetadata& sourceMetadata,
+#if MAJOR_VERSION <= 6
+ AudioOutputFlags flags) {
+ if (status_t status = CoreUtils::sourceMetadataToHal(sourceMetadata, nullptr);
+ status != NO_ERROR) {
+#else
+ const AudioOutputFlags& flags) {
+ if (status_t status = CoreUtils::sourceMetadataToHalV7(sourceMetadata,
+ false /*ignoreNonVendorTags*/, nullptr);
+ status != NO_ERROR) {
+#endif
+ return {analyzeStatus("sourceMetadataToHal", status), nullptr, {}};
+ }
+ AudioConfig suggestedConfig;
+ auto [result, streamOut] =
+ openOutputStreamCore(ioHandle, device, config, flags, &suggestedConfig);
+ if (streamOut) {
+ streamOut->updateSourceMetadata(sourceMetadata);
+ }
+ return {result, streamOut, suggestedConfig};
+}
+
+Return Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config,
+#if MAJOR_VERSION <= 6
+ AudioOutputFlags flags,
+#else
+ const AudioOutputFlags& flags,
+#endif
+ const SourceMetadata& sourceMetadata,
+ openOutputStream_cb _hidl_cb) {
+ auto [result, streamOut, suggestedConfig] =
+ openOutputStreamImpl(ioHandle, device, config, sourceMetadata, flags);
+ _hidl_cb(result, streamOut, suggestedConfig);
+ return Void();
+}
+
+std::tuple, AudioConfig> Device::openInputStreamImpl(
+ int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
+#if MAJOR_VERSION <= 6
+ AudioInputFlags flags,
+#else
+ const AudioInputFlags& flags,
+#endif
+ const SinkMetadata& sinkMetadata) {
+ if (sinkMetadata.tracks.size() == 0) {
+ // This should never happen, the framework must not create as stream
+ // if there is no client
+ ALOGE("openInputStream called without tracks connected");
+ return {Result::INVALID_ARGUMENTS, nullptr, AudioConfig{}};
+ }
+#if MAJOR_VERSION <= 6
+ if (status_t status = CoreUtils::sinkMetadataToHal(sinkMetadata, nullptr); status != NO_ERROR) {
+#else
+ if (status_t status = CoreUtils::sinkMetadataToHalV7(sinkMetadata,
+ false /*ignoreNonVendorTags*/, nullptr);
+ status != NO_ERROR) {
+#endif
+ return {analyzeStatus("sinkMetadataToHal", status), nullptr, AudioConfig{}};
+ }
+ // Pick the first one as the main.
+ AudioSource source = sinkMetadata.tracks[0].source;
+ AudioConfig suggestedConfig;
+ auto [result, streamIn] =
+ openInputStreamCore(ioHandle, device, config, flags, source, &suggestedConfig);
+ if (streamIn) {
+ streamIn->updateSinkMetadata(sinkMetadata);
+ }
+ return {result, streamIn, suggestedConfig};
+}
+
+Return Device::openInputStream(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config,
+#if MAJOR_VERSION <= 6
+ AudioInputFlags flags,
+#else
+ const AudioInputFlags& flags,
+#endif
+ const SinkMetadata& sinkMetadata,
+ openInputStream_cb _hidl_cb) {
+ auto [result, streamIn, suggestedConfig] =
+ openInputStreamImpl(ioHandle, device, config, flags, sinkMetadata);
+ _hidl_cb(result, streamIn, suggestedConfig);
+ return Void();
+}
+#endif /* MAJOR_VERSION */
+
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+Return Device::openOutputStream_7_1(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config, const AudioOutputFlags& flags,
+ const SourceMetadata& sourceMetadata,
+ openOutputStream_7_1_cb _hidl_cb) {
+ auto [result, streamOut, suggestedConfig] =
+ openOutputStreamImpl(ioHandle, device, config, sourceMetadata, flags);
+ _hidl_cb(result, streamOut, suggestedConfig);
+ return Void();
+}
+#endif // V7.1
+
+Return Device::supportsAudioPatches() {
+ return version() >= AUDIO_DEVICE_API_VERSION_3_0;
+}
+
+Return Device::createAudioPatch(const hidl_vec& sources,
+ const hidl_vec& sinks,
+ createAudioPatch_cb _hidl_cb) {
+ auto [retval, patch] = createOrUpdateAudioPatch(AudioPatchHandle{}, sources, sinks);
+ _hidl_cb(retval, patch);
+ return Void();
+}
+
+std::tuple Device::createOrUpdateAudioPatch(
+ AudioPatchHandle patch, const hidl_vec& sources,
+ const hidl_vec& sinks) {
+ Result retval(Result::NOT_SUPPORTED);
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ audio_patch_handle_t halPatch = static_cast(patch);
+ std::unique_ptr halSources;
+ if (status_t status = HidlUtils::audioPortConfigsToHal(sources, &halSources);
+ status != NO_ERROR) {
+ return {analyzeStatus("audioPortConfigsToHal;sources", status), patch};
+ }
+ std::unique_ptr halSinks;
+ if (status_t status = HidlUtils::audioPortConfigsToHal(sinks, &halSinks);
+ status != NO_ERROR) {
+ return {analyzeStatus("audioPortConfigsToHal;sinks", status), patch};
+ }
+ retval = analyzeStatus("create_audio_patch",
+ mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
+ sinks.size(), &halSinks[0], &halPatch));
+ if (retval == Result::OK) {
+ patch = static_cast(halPatch);
+ }
+ }
+ return {retval, patch};
+}
+
+Return Device::releaseAudioPatch(int32_t patch) {
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ return analyzeStatus(
+ "release_audio_patch",
+ mDevice->release_audio_patch(mDevice, static_cast(patch)));
+ }
+ return Result::NOT_SUPPORTED;
+}
+
+template
+Return Device::getAudioPortImpl(const AudioPort& port, getAudioPort_cb _hidl_cb,
+ int (*halGetter)(audio_hw_device_t*, HalPort*),
+ const char* halGetterName) {
+ HalPort halPort;
+ if (status_t status = HidlUtils::audioPortToHal(port, &halPort); status != NO_ERROR) {
+ _hidl_cb(analyzeStatus("audioPortToHal", status), port);
+ return Void();
+ }
+ Result retval = analyzeStatus(halGetterName, halGetter(mDevice, &halPort));
+ AudioPort resultPort = port;
+ if (retval == Result::OK) {
+ if (status_t status = HidlUtils::audioPortFromHal(halPort, &resultPort);
+ status != NO_ERROR) {
+ _hidl_cb(analyzeStatus("audioPortFromHal", status), port);
+ return Void();
+ }
+ }
+ _hidl_cb(retval, resultPort);
+ return Void();
+}
+
+#if MAJOR_VERSION <= 6
+Return Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+ return getAudioPortImpl(port, _hidl_cb, mDevice->get_audio_port, "get_audio_port");
+}
+#else
+Return Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_2) {
+ // get_audio_port_v7 is mandatory if legacy HAL support this API version.
+ return getAudioPortImpl(port, _hidl_cb, mDevice->get_audio_port_v7, "get_audio_port_v7");
+ } else {
+ return getAudioPortImpl(port, _hidl_cb, mDevice->get_audio_port, "get_audio_port");
+ }
+}
+#endif
+
+Return Device::setAudioPortConfig(const AudioPortConfig& config) {
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ struct audio_port_config halPortConfig;
+ if (status_t status = HidlUtils::audioPortConfigToHal(config, &halPortConfig);
+ status != NO_ERROR) {
+ return analyzeStatus("audioPortConfigToHal", status);
+ }
+ return analyzeStatus("set_audio_port_config",
+ mDevice->set_audio_port_config(mDevice, &halPortConfig));
+ }
+ return Result::NOT_SUPPORTED;
+}
+
+#if MAJOR_VERSION == 2
+Return Device::getHwAvSync() {
+ int halHwAvSync;
+ Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync);
+ return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID;
+}
+#elif MAJOR_VERSION >= 4
+Return Device::getHwAvSync(getHwAvSync_cb _hidl_cb) {
+ int halHwAvSync;
+ Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync);
+ _hidl_cb(retval, halHwAvSync);
+ return Void();
+}
+#endif
+
+Return Device::setScreenState(bool turnedOn) {
+ return setParam(AudioParameter::keyScreenState, turnedOn);
+}
+
+#if MAJOR_VERSION == 2
+Return Device::getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) {
+ getParametersImpl({}, keys, _hidl_cb);
+ return Void();
+}
+
+Return Device::setParameters(const hidl_vec& parameters) {
+ return setParametersImpl({} /* context */, parameters);
+}
+#elif MAJOR_VERSION >= 4
+Return Device::getParameters(const hidl_vec& context,
+ const hidl_vec& keys, getParameters_cb _hidl_cb) {
+ getParametersImpl(context, keys, _hidl_cb);
+ return Void();
+}
+Return Device::setParameters(const hidl_vec& context,
+ const hidl_vec& parameters) {
+ return setParametersImpl(context, parameters);
+}
+#endif
+
+#if MAJOR_VERSION == 2
+Return Device::debugDump(const hidl_handle& fd) {
+ return debug(fd, {});
+}
+#endif
+
+Return Device::debug(const hidl_handle& fd, const hidl_vec& options) {
+ if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
+ const int fd0 = fd->data[0];
+ bool dumpMem = false;
+ bool unreachableMemory = false;
+ for (const auto& option : options) {
+ if (option == "-m") {
+ dumpMem = true;
+ } else if (option == "--unreachable") {
+ unreachableMemory = true;
+ }
+ }
+
+ if (dumpMem) {
+ dprintf(fd0, "\nDumping memory:\n");
+ std::string s = dumpMemoryAddresses(100 /* limit */);
+ write(fd0, s.c_str(), s.size());
+ }
+ if (unreachableMemory) {
+ dprintf(fd0, "\nDumping unreachable memory:\n");
+ // TODO - should limit be an argument parameter?
+ std::string s = GetUnreachableMemoryString(true /* contents */, 100 /* limit */);
+ write(fd0, s.c_str(), s.size());
+ }
+
+ analyzeStatus("dump", mDevice->dump(mDevice, fd0));
+ }
+ return Void();
+}
+
+#if MAJOR_VERSION >= 4
+Return Device::getMicrophones(getMicrophones_cb _hidl_cb) {
+ Result retval = Result::NOT_SUPPORTED;
+ size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
+ audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT];
+
+ hidl_vec microphones;
+ if (mDevice->get_microphones != NULL &&
+ mDevice->get_microphones(mDevice, &mic_array[0], &actual_mics) == 0) {
+ microphones.resize(actual_mics);
+ for (size_t i = 0; i < actual_mics; ++i) {
+ (void)CoreUtils::microphoneInfoFromHal(mic_array[i], µphones[i]);
+ }
+ retval = Result::OK;
+ }
+ _hidl_cb(retval, microphones);
+ return Void();
+}
+
+Return Device::setConnectedState(const DeviceAddress& address, bool connected) {
+ auto key = connected ? AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect;
+ return setParam(key, address);
+}
+#endif
+
+Result Device::doClose() {
+ if (mIsClosed || mOpenedStreamsCount != 0) return Result::INVALID_STATE;
+ mIsClosed = true;
+ return analyzeStatus("close", audio_hw_device_close(mDevice));
+}
+
+#if MAJOR_VERSION >= 6
+Return Device::close() {
+ return doClose();
+}
+
+Return Device::addDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+ if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->add_device_effect == nullptr) {
+ return Result::NOT_SUPPORTED;
+ }
+
+ effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+ if (halEffect != NULL) {
+ return analyzeStatus("add_device_effect",
+ mDevice->add_device_effect(
+ mDevice, static_cast(device), halEffect));
+ } else {
+ ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId);
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return Device::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+ if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->remove_device_effect == nullptr) {
+ return Result::NOT_SUPPORTED;
+ }
+
+ effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+ if (halEffect != NULL) {
+ return analyzeStatus("remove_device_effect",
+ mDevice->remove_device_effect(
+ mDevice, static_cast(device), halEffect));
+ } else {
+ ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId);
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return Device::updateAudioPatch(int32_t previousPatch,
+ const hidl_vec& sources,
+ const hidl_vec& sinks,
+ createAudioPatch_cb _hidl_cb) {
+ if (previousPatch != static_cast(AudioPatchHandle{})) {
+ auto [retval, patch] = createOrUpdateAudioPatch(previousPatch, sources, sinks);
+ _hidl_cb(retval, patch);
+ } else {
+ _hidl_cb(Result::INVALID_ARGUMENTS, previousPatch);
+ }
+ return Void();
+}
+
+#endif
+
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+Return Device::setConnectedState_7_1(const AudioPort& devicePort, bool connected) {
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_2 &&
+ mDevice->set_device_connected_state_v7 != nullptr) {
+ audio_port_v7 halPort;
+ if (status_t status = HidlUtils::audioPortToHal(devicePort, &halPort); status != NO_ERROR) {
+ return analyzeStatus("audioPortToHal", status);
+ }
+ return analyzeStatus("set_device_connected_state_v7",
+ mDevice->set_device_connected_state_v7(mDevice, &halPort, connected));
+ }
+ return Result::NOT_SUPPORTED;
+}
+#endif
+
+} // namespace implementation
+} // namespace CPP_VERSION
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/hal/Device.h b/bluetooth/audio/hal/Device.h
new file mode 100644
index 0000000..0696f97
--- /dev/null
+++ b/bluetooth/audio/hal/Device.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_DEVICE_H
+#define ANDROID_HARDWARE_AUDIO_DEVICE_H
+
+#include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
+
+#include "ParametersUtil.h"
+
+#include
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace CPP_VERSION {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::ParametersUtil;
+using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
+using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
+using namespace ::android::hardware::audio::CPP_VERSION;
+using AudioInputFlags = CoreUtils::AudioInputFlags;
+using AudioOutputFlags = CoreUtils::AudioOutputFlags;
+
+struct Device : public IDevice, public ParametersUtil {
+ explicit Device(audio_hw_device_t* device);
+
+ // Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow.
+ Return initCheck() override;
+ Return setMasterVolume(float volume) override;
+ Return getMasterVolume(getMasterVolume_cb _hidl_cb) override;
+ Return setMicMute(bool mute) override;
+ Return getMicMute(getMicMute_cb _hidl_cb) override;
+ Return setMasterMute(bool mute) override;
+ Return getMasterMute(getMasterMute_cb _hidl_cb) override;
+ Return getInputBufferSize(const AudioConfig& config,
+ getInputBufferSize_cb _hidl_cb) override;
+
+ std::tuple> openOutputStreamCore(int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ const AudioOutputFlags& flags,
+ AudioConfig* suggestedConfig);
+ std::tuple> openInputStreamCore(
+ int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
+ const AudioInputFlags& flags, AudioSource source, AudioConfig* suggestedConfig);
+#if MAJOR_VERSION >= 4
+ std::tuple, AudioConfig> openOutputStreamImpl(
+ int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
+ const SourceMetadata& sourceMetadata,
+#if MAJOR_VERSION <= 6
+ AudioOutputFlags flags);
+#else
+ const AudioOutputFlags& flags);
+#endif
+ std::tuple, AudioConfig> openInputStreamImpl(
+ int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
+#if MAJOR_VERSION <= 6
+ AudioInputFlags flags,
+#else
+ const AudioInputFlags& flags,
+#endif
+ const SinkMetadata& sinkMetadata);
+#endif // MAJOR_VERSION >= 4
+
+ Return openOutputStream(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config,
+#if MAJOR_VERSION <= 6
+ AudioOutputFlags flags,
+#else
+ const AudioOutputFlags& flags,
+#endif
+#if MAJOR_VERSION >= 4
+ const SourceMetadata& sourceMetadata,
+#endif
+ openOutputStream_cb _hidl_cb) override;
+ Return openInputStream(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config,
+#if MAJOR_VERSION <= 6
+ AudioInputFlags flags,
+#else
+ const AudioInputFlags& flags,
+#endif
+#if MAJOR_VERSION == 2
+ AudioSource source,
+#elif MAJOR_VERSION >= 4
+ const SinkMetadata& sinkMetadata,
+#endif
+ openInputStream_cb _hidl_cb) override;
+
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ Return openOutputStream_7_1(int32_t ioHandle, const DeviceAddress& device,
+ const AudioConfig& config, const AudioOutputFlags& flags,
+ const SourceMetadata& sourceMetadata,
+ openOutputStream_7_1_cb _hidl_cb) override;
+#endif
+
+ Return supportsAudioPatches() override;
+ Return createAudioPatch(const hidl_vec& sources,
+ const hidl_vec& sinks,
+ createAudioPatch_cb _hidl_cb) override;
+ Return releaseAudioPatch(int32_t patch) override;
+ Return getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override;
+ Return setAudioPortConfig(const AudioPortConfig& config) override;
+
+ Return setScreenState(bool turnedOn) override;
+
+#if MAJOR_VERSION == 2
+ Return getHwAvSync() override;
+ Return getParameters(const hidl_vec& keys,
+ getParameters_cb _hidl_cb) override;
+ Return setParameters(const hidl_vec& parameters) override;
+ Return debugDump(const hidl_handle& fd) override;
+#elif MAJOR_VERSION >= 4
+ Return getHwAvSync(getHwAvSync_cb _hidl_cb) override;
+ Return getParameters(const hidl_vec& context,
+ const hidl_vec& keys,
+ getParameters_cb _hidl_cb) override;
+ Return setParameters(const hidl_vec& context,
+ const hidl_vec& parameters) override;
+ Return getMicrophones(getMicrophones_cb _hidl_cb) override;
+ Return setConnectedState(const DeviceAddress& address, bool connected) override;
+#endif
+#if MAJOR_VERSION >= 6
+ Return close() override;
+ Return addDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return updateAudioPatch(int32_t previousPatch, const hidl_vec& sources,
+ const hidl_vec& sinks,
+ createAudioPatch_cb _hidl_cb) override;
+#endif
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ Return setConnectedState_7_1(const AudioPort& devicePort, bool connected) override;
+#endif
+ Return debug(const hidl_handle& fd, const hidl_vec& options) override;
+
+ // Utility methods for extending interfaces.
+ Result analyzeStatus(const char* funcName, int status,
+ const std::vector& ignoreErrors = {});
+ void closeInputStream(audio_stream_in_t* stream);
+ void closeOutputStream(audio_stream_out_t* stream);
+ audio_hw_device_t* device() const { return mDevice; }
+
+ uint32_t version() const { return mDevice->common.version; }
+
+ private:
+ bool mIsClosed;
+ audio_hw_device_t* mDevice;
+ int mOpenedStreamsCount = 0;
+
+ virtual ~Device();
+
+ Result doClose();
+ std::tuple createOrUpdateAudioPatch(
+ AudioPatchHandle patch, const hidl_vec& sources,
+ const hidl_vec& sinks);
+ template
+ Return getAudioPortImpl(const AudioPort& port, getAudioPort_cb _hidl_cb,
+ int (*halGetter)(audio_hw_device_t*, HalPort*),
+ const char* halGetterName);
+
+ // Methods from ParametersUtil.
+ char* halGetParameters(const char* keys) override;
+ int halSetParameters(const char* keysAndValues) override;
+};
+
+} // namespace implementation
+} // namespace CPP_VERSION
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_DEVICE_H
diff --git a/bluetooth/audio/hal/DevicesFactory.cpp b/bluetooth/audio/hal/DevicesFactory.cpp
new file mode 100644
index 0000000..cc42293
--- /dev/null
+++ b/bluetooth/audio/hal/DevicesFactory.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 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 "DevicesFactoryHAL"
+
+#include "DevicesFactory.h"
+#include "Device.h"
+#include "PrimaryDevice.h"
+
+#include
+
+#include
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace CPP_VERSION {
+namespace implementation {
+
+#if MAJOR_VERSION == 2
+Return DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) {
+ switch (device) {
+ case IDevicesFactory::Device::PRIMARY:
+ return openDevice(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
+ case IDevicesFactory::Device::A2DP:
+ return openDevice(AUDIO_HARDWARE_MODULE_ID_A2DP, _hidl_cb);
+ case IDevicesFactory::Device::USB:
+ return openDevice(AUDIO_HARDWARE_MODULE_ID_USB, _hidl_cb);
+ case IDevicesFactory::Device::R_SUBMIX:
+ return openDevice(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, _hidl_cb);
+ case IDevicesFactory::Device::STUB:
+ return openDevice(AUDIO_HARDWARE_MODULE_ID_STUB, _hidl_cb);
+ }
+ _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+ return Void();
+}
+
+Return DevicesFactory::openDevice(const char* moduleName, openDevice_cb _hidl_cb) {
+ return openDevice(moduleName, _hidl_cb);
+}
+#elif MAJOR_VERSION >= 4
+Return DevicesFactory::openDevice(const hidl_string& moduleName, openDevice_cb _hidl_cb) {
+ if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) {
+ return openDevice(moduleName.c_str(), _hidl_cb);
+ }
+ return openDevice(moduleName.c_str(), _hidl_cb);
+}
+Return DevicesFactory::openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) {
+ return openDevice(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
+}
+#endif
+
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+Return DevicesFactory::openDevice_7_1(const hidl_string& moduleName,
+ openDevice_7_1_cb _hidl_cb) {
+ if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) {
+ Result result;
+ sp primary;
+ auto ret = openDevice(
+ AUDIO_HARDWARE_MODULE_ID_PRIMARY,
+ [&result, &primary](Result r, const sp& p) {
+ result = r;
+ primary = p;
+ });
+ if (ret.isOk() && result == Result::OK && primary != nullptr) {
+ auto getDeviceRet = primary->getDevice();
+ if (getDeviceRet.isOk()) {
+ _hidl_cb(result, getDeviceRet);
+ } else {
+ _hidl_cb(Result::NOT_INITIALIZED, nullptr);
+ }
+ } else {
+ _hidl_cb(result, nullptr);
+ }
+ return Void();
+ }
+ return openDevice(moduleName.c_str(), _hidl_cb);
+}
+
+Return DevicesFactory::openPrimaryDevice_7_1(openPrimaryDevice_7_1_cb _hidl_cb) {
+ return openDevice(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
+}
+#endif // V7.1
+
+template
+Return DevicesFactory::openDevice(const char* moduleName, Callback _hidl_cb) {
+ audio_hw_device_t* halDevice;
+ Result retval(Result::INVALID_ARGUMENTS);
+ sp result;
+ int halStatus = loadAudioInterface(moduleName, &halDevice);
+ if (halStatus == OK) {
+ result = new DeviceShim(halDevice);
+ retval = Result::OK;
+ } else if (halStatus == -EINVAL) {
+ retval = Result::NOT_INITIALIZED;
+ }
+ _hidl_cb(retval, result);
+ return Void();
+}
+
+// static
+int DevicesFactory::loadAudioInterface(const char* if_name, audio_hw_device_t** dev) {
+ const hw_module_t* mod;
+ int rc;
+
+ rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
+ if (rc) {
+ ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
+ if_name, strerror(-rc));
+ goto out;
+ }
+ rc = audio_hw_device_open(mod, dev);
+ if (rc) {
+ ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
+ if_name, strerror(-rc));
+ goto out;
+ }
+ if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
+ ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
+ rc = -EINVAL;
+ audio_hw_device_close(*dev);
+ goto out;
+ }
+ return OK;
+
+out:
+ *dev = NULL;
+ return rc;
+}
+
+IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name) {
+ return strcmp(name, "default") == 0 ? new DevicesFactory() : nullptr;
+}
+
+} // namespace implementation
+} // namespace CPP_VERSION
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/hal/DevicesFactory.h b/bluetooth/audio/hal/DevicesFactory.h
new file mode 100644
index 0000000..566bc8a
--- /dev/null
+++ b/bluetooth/audio/hal/DevicesFactory.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H
+#define ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H
+
+#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
+
+#include
+
+#include
+
+#include
+namespace android {
+namespace hardware {
+namespace audio {
+namespace CPP_VERSION {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::CPP_VERSION;
+
+struct DevicesFactory : public IDevicesFactory {
+#if MAJOR_VERSION == 2
+ Return openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) override;
+#elif MAJOR_VERSION >= 4
+ Return openDevice(const hidl_string& device, openDevice_cb _hidl_cb) override;
+ Return openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) override;
+#endif
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ Return openDevice_7_1(const hidl_string& device, openDevice_7_1_cb _hidl_cb) override;
+ Return openPrimaryDevice_7_1(openPrimaryDevice_7_1_cb _hidl_cb) override;
+#endif
+
+ private:
+ template
+ Return openDevice(const char* moduleName, Callback _hidl_cb);
+#if MAJOR_VERSION == 2
+ Return openDevice(const char* moduleName, openDevice_cb _hidl_cb);
+#endif
+
+ static int loadAudioInterface(const char* if_name, audio_hw_device_t** dev);
+};
+
+extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name);
+
+} // namespace implementation
+} // namespace CPP_VERSION
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H
diff --git a/bluetooth/audio/hal/HearingAidAudioProvider.cpp b/bluetooth/audio/hal/HearingAidAudioProvider.cpp
new file mode 100644
index 0000000..e8b01ac
--- /dev/null
+++ b/bluetooth/audio/hal/HearingAidAudioProvider.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 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
+#include
+#include
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+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(), data_mq_(nullptr) {
+ LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+ << " byte(s)";
+ std::unique_ptr data_mq(
+ new DataMQ(kDataMqSize, /* EventFlag */ true));
+ if (data_mq && data_mq->isValid()) {
+ data_mq_ = std::move(data_mq);
+ session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+ } else {
+ ALOGE_IF(!data_mq, "failed to allocate data MQ");
+ ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
+ }
+}
+bool HearingAidAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
+}
+
+ndk::ScopedAStatus HearingAidAudioProvider::startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const auto& pcm_config = audio_config.get();
+ if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << pcm_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return BluetoothAudioProvider::startSession(
+ host_if, audio_config, latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus HearingAidAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ if (data_mq_ == nullptr || !data_mq_->isValid()) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = data_mq_->dupeDesc();
+ auto desc = data_mq_->dupeDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/HearingAidAudioProvider.h b/bluetooth/audio/hal/HearingAidAudioProvider.h
new file mode 100644
index 0000000..a158c86
--- /dev/null
+++ b/bluetooth/audio/hal/HearingAidAudioProvider.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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 aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class HearingAidAudioProvider : public BluetoothAudioProvider {
+ public:
+ HearingAidAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes,
+ DataMQDesc* _aidl_return);
+
+ private:
+ // audio data queue for software encoding
+ std::unique_ptr data_mq_;
+
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.cpp
new file mode 100644
index 0000000..0e22e44
--- /dev/null
+++ b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 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 "BTAudioProviderLeAudioHW"
+
+#include "LeAudioOffloadAudioProvider.h"
+
+#include
+#include
+#include
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+}
+
+LeAudioOffloadBroadcastAudioProvider::LeAudioOffloadBroadcastAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ =
+ SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
+ : BluetoothAudioProvider() {}
+
+bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const auto& le_audio_config =
+ audio_config.get();
+ if (!BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
+ session_type_, le_audio_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
+ << le_audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return BluetoothAudioProvider::startSession(
+ host_if, audio_config, latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/LeAudioOffloadAudioProvider.h b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.h
new file mode 100644
index 0000000..614c794
--- /dev/null
+++ b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 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 aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+ LeAudioOffloadAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes,
+ DataMQDesc* _aidl_return);
+
+ private:
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadOutputAudioProvider();
+};
+
+class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadInputAudioProvider();
+};
+
+class LeAudioOffloadBroadcastAudioProvider
+ : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadBroadcastAudioProvider();
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/LeAudioSoftwareAudioProvider.cpp b/bluetooth/audio/hal/LeAudioSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..c16ff54
--- /dev/null
+++ b/bluetooth/audio/hal/LeAudioSoftwareAudioProvider.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 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 "BTAudioProviderLeAudioSW"
+
+#include "LeAudioSoftwareAudioProvider.h"
+
+#include
+#include
+#include
+
+#include
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr uint32_t kBufferOutCount = 2; // two frame buffer
+static constexpr uint32_t kBufferInCount = 2; // two frame buffer
+
+inline uint32_t channel_mode_to_channel_count(ChannelMode channel_mode) {
+ switch (channel_mode) {
+ case ChannelMode::MONO:
+ return 1;
+ case ChannelMode::STEREO:
+ return 2;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+LeAudioSoftwareOutputAudioProvider::LeAudioSoftwareOutputAudioProvider()
+ : LeAudioSoftwareAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+}
+
+LeAudioSoftwareInputAudioProvider::LeAudioSoftwareInputAudioProvider()
+ : LeAudioSoftwareAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH;
+}
+
+LeAudioSoftwareBroadcastAudioProvider::LeAudioSoftwareBroadcastAudioProvider()
+ : LeAudioSoftwareAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH;
+}
+
+LeAudioSoftwareAudioProvider::LeAudioSoftwareAudioProvider()
+ : BluetoothAudioProvider(), data_mq_(nullptr) {}
+
+bool LeAudioSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus LeAudioSoftwareAudioProvider::startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector& latency_modes, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const auto& pcm_config = audio_config.get();
+ if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << pcm_config.toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ uint32_t buffer_modifier = 0;
+ if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH)
+ buffer_modifier = kBufferOutCount;
+ else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH)
+ buffer_modifier = kBufferInCount;
+
+ // 24 bit audio stream is sent as unpacked
+ int bytes_per_sample =
+ (pcm_config.bitsPerSample == 24) ? 4 : (pcm_config.bitsPerSample / 8);
+
+ uint32_t data_mq_size =
+ (ceil(pcm_config.sampleRateHz) / 1000) *
+ channel_mode_to_channel_count(pcm_config.channelMode) * bytes_per_sample *
+ (pcm_config.dataIntervalUs / 1000) * buffer_modifier;
+ if (data_mq_size <= 0) {
+ LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
+ << ", SampleRateHz: " << pcm_config.sampleRateHz
+ << ", ChannelMode: " << toString(pcm_config.channelMode)
+ << ", BitsPerSample: "
+ << static_cast(pcm_config.bitsPerSample)
+ << ", BytesPerSample: " << bytes_per_sample
+ << ", DataIntervalUs: " << pcm_config.dataIntervalUs
+ << ", SessionType: " << toString(session_type_);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size
+ << " byte(s)";
+
+ std::unique_ptr temp_data_mq(
+ new DataMQ(data_mq_size, /* EventFlag */ true));
+ if (temp_data_mq == nullptr || !temp_data_mq->isValid()) {
+ ALOGE_IF(!temp_data_mq, "failed to allocate data MQ");
+ ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid");
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ data_mq_ = std::move(temp_data_mq);
+
+ return BluetoothAudioProvider::startSession(
+ host_if, audio_config, latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus LeAudioSoftwareAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ if (data_mq_ == nullptr || !data_mq_->isValid()) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = data_mq_->dupeDesc();
+ auto desc = data_mq_->dupeDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/hal/LeAudioSoftwareAudioProvider.h b/bluetooth/audio/hal/LeAudioSoftwareAudioProvider.h
new file mode 100644
index 0000000..21243ff
--- /dev/null
+++ b/bluetooth/audio/hal/LeAudioSoftwareAudioProvider.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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 aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class LeAudioSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+ LeAudioSoftwareAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr& host_if,
+ const AudioConfiguration& audio_config,
+ const std::vector