Add Bluetooth Audio AIDL utils
Test: manual
Bug: 203490261
Change-Id: Ia299a61e89273ea1c9d132425598975418f57a03
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 4f712bf..974357e 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -32,5 +32,30 @@
"libhidlbase",
"liblog",
"libutils",
+ "libbluetooth_audio_session_aidl",
+ ],
+}
+
+cc_library_shared {
+ name: "libbluetooth_audio_session_aidl",
+ vendor: true,
+ srcs: [
+ "aidl_session/BluetoothAudioCodecs.cpp",
+ "aidl_session/BluetoothAudioSession.cpp",
+ "aidl_session/HidlToAidlMiddleware.cpp",
+ ],
+ export_include_dirs: ["aidl_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",
+ "libbinder_ndk",
+ "libfmq",
+ "liblog",
+ "android.hardware.bluetooth.audio-V1-ndk",
+ "libhidlbase",
],
}
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
new file mode 100644
index 0000000..92cd0f5
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -0,0 +1,489 @@
+/*
+ * 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 "BTAudioCodecsAidl"
+
+#include "BluetoothAudioCodecs.h"
+
+#include <aidl/android/hardware/bluetooth/audio/AacCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/AacObjectType.h>
+#include <aidl/android/hardware/bluetooth/audio/AptxCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacQualityIndex.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SbcCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
+ .sampleRateHz = {16000, 24000, 44100, 48000, 88200, 96000},
+ .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
+ .bitsPerSample = {16, 24, 32},
+ .dataIntervalUs = {},
+};
+
+static const SbcCapabilities kDefaultOffloadSbcCapability = {
+ .sampleRateHz = {44100},
+ .channelMode = {SbcChannelMode::MONO, SbcChannelMode::JOINT_STEREO},
+ .blockLength = {4, 8, 12, 16},
+ .numSubbands = {8},
+ .allocMethod = {SbcAllocMethod::ALLOC_MD_L},
+ .bitsPerSample = {16},
+ .minBitpool = 2,
+ .maxBitpool = 53};
+
+static const AacCapabilities kDefaultOffloadAacCapability = {
+ .objectType = {AacObjectType::MPEG2_LC},
+ .sampleRateHz = {44100},
+ .channelMode = {ChannelMode::STEREO},
+ .variableBitRateSupported = true,
+ .bitsPerSample = {16}};
+
+static const LdacCapabilities kDefaultOffloadLdacCapability = {
+ .sampleRateHz = {44100, 48000, 88200, 96000},
+ .channelMode = {LdacChannelMode::DUAL, LdacChannelMode::STEREO},
+ .qualityIndex = {LdacQualityIndex::HIGH},
+ .bitsPerSample = {16, 24, 32}};
+
+static const AptxCapabilities kDefaultOffloadAptxCapability = {
+ .sampleRateHz = {44100, 48000},
+ .channelMode = {ChannelMode::STEREO},
+ .bitsPerSample = {16},
+};
+
+static const AptxCapabilities kDefaultOffloadAptxHdCapability = {
+ .sampleRateHz = {44100, 48000},
+ .channelMode = {ChannelMode::STEREO},
+ .bitsPerSample = {24},
+};
+
+static const Lc3Capabilities kDefaultOffloadLc3Capability = {
+ .samplingFrequencyHz = {44100, 48000},
+ .frameDurationUs = {7500, 10000},
+ .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
+};
+
+const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
+ {.codecType = CodecType::SBC, .capabilities = {}},
+ {.codecType = CodecType::AAC, .capabilities = {}},
+ {.codecType = CodecType::LDAC, .capabilities = {}},
+ {.codecType = CodecType::APTX, .capabilities = {}},
+ {.codecType = CodecType::APTX_HD, .capabilities = {}},
+ {.codecType = CodecType::LC3, .capabilities = {}}};
+
+std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
+
+static const UnicastCapability kInvalidUnicastCapability = {
+ .codecType = CodecType::UNKNOWN};
+
+static const BroadcastCapability kInvalidBroadcastCapability = {
+ .codecType = CodecType::UNKNOWN};
+
+// Default Supported Codecs
+// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30
+static const Lc3Capabilities kLc3Capability_16_1 = {
+ .samplingFrequencyHz = {16000},
+ .frameDurationUs = {7500},
+ .octetsPerFrame = {30}};
+
+// Default Supported Codecs
+// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
+static const Lc3Capabilities kLc3Capability_16_2 = {
+ .samplingFrequencyHz = {16000},
+ .frameDurationUs = {10000},
+ .octetsPerFrame = {40}};
+
+// Default Supported Codecs
+// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
+static const Lc3Capabilities kLc3Capability_48_4 = {
+ .samplingFrequencyHz = {48000},
+ .frameDurationUs = {10000},
+ .octetsPerFrame = {120}};
+
+static const std::vector<Lc3Capabilities> supportedLc3CapabilityList = {
+ kLc3Capability_48_4, kLc3Capability_16_2, kLc3Capability_16_1};
+
+static AudioLocation stereoAudio = static_cast<AudioLocation>(
+ static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
+ static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
+static AudioLocation monoAudio = AudioLocation::UNKNOWN;
+
+// Stores the supported setting of audio location, connected device, and the
+// channel count for each device
+std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
+ supportedDeviceSetting = {std::make_tuple(stereoAudio, 2, 1),
+ std::make_tuple(monoAudio, 1, 2),
+ std::make_tuple(monoAudio, 1, 1)};
+
+template <class T>
+bool BluetoothAudioCodecs::ContainedInVector(
+ const std::vector<T>& vector, const typename identity<T>::type& target) {
+ return std::find(vector.begin(), vector.end(), target) != vector.end();
+}
+
+bool BluetoothAudioCodecs::IsOffloadSbcConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::sbcConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const SbcConfiguration sbc_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::sbcConfig>();
+
+ if (ContainedInVector(kDefaultOffloadSbcCapability.sampleRateHz,
+ sbc_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.blockLength,
+ sbc_data.blockLength) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.numSubbands,
+ sbc_data.numSubbands) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.bitsPerSample,
+ sbc_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.channelMode,
+ sbc_data.channelMode) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.allocMethod,
+ sbc_data.allocMethod) &&
+ sbc_data.minBitpool <= sbc_data.maxBitpool &&
+ kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool &&
+ kDefaultOffloadSbcCapability.maxBitpool >= sbc_data.maxBitpool) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::aacConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const AacConfiguration aac_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::aacConfig>();
+
+ if (ContainedInVector(kDefaultOffloadAacCapability.sampleRateHz,
+ aac_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadAacCapability.bitsPerSample,
+ aac_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadAacCapability.channelMode,
+ aac_data.channelMode) &&
+ ContainedInVector(kDefaultOffloadAacCapability.objectType,
+ aac_data.objectType) &&
+ (!aac_data.variableBitRateEnabled ||
+ kDefaultOffloadAacCapability.variableBitRateSupported)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLdacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() !=
+ CodecConfiguration::CodecSpecific::ldacConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const LdacConfiguration ldac_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::ldacConfig>();
+
+ if (ContainedInVector(kDefaultOffloadLdacCapability.sampleRateHz,
+ ldac_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadLdacCapability.bitsPerSample,
+ ldac_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadLdacCapability.channelMode,
+ ldac_data.channelMode) &&
+ ContainedInVector(kDefaultOffloadLdacCapability.qualityIndex,
+ ldac_data.qualityIndex)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAptxConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() !=
+ CodecConfiguration::CodecSpecific::aptxConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const AptxConfiguration aptx_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
+
+ if (ContainedInVector(kDefaultOffloadAptxCapability.sampleRateHz,
+ aptx_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadAptxCapability.bitsPerSample,
+ aptx_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadAptxCapability.channelMode,
+ aptx_data.channelMode)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAptxHdConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() !=
+ CodecConfiguration::CodecSpecific::aptxConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const AptxConfiguration aptx_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
+
+ if (ContainedInVector(kDefaultOffloadAptxHdCapability.sampleRateHz,
+ aptx_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadAptxHdCapability.bitsPerSample,
+ aptx_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadAptxHdCapability.channelMode,
+ aptx_data.channelMode)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLc3ConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::lc3Config) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const Lc3Configuration lc3_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::lc3Config>();
+
+ if (ContainedInVector(kDefaultOffloadLc3Capability.samplingFrequencyHz,
+ lc3_data.samplingFrequencyHz) &&
+ ContainedInVector(kDefaultOffloadLc3Capability.frameDurationUs,
+ lc3_data.frameDurationUs) &&
+ ContainedInVector(kDefaultOffloadLc3Capability.channelMode,
+ lc3_data.channelMode)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
+ const SessionType& session_type, const LeAudioConfiguration&) {
+ if (session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return false;
+ }
+ return true;
+}
+
+std::vector<PcmCapabilities>
+BluetoothAudioCodecs::GetSoftwarePcmCapabilities() {
+ return {kDefaultSoftwarePcmCapabilities};
+}
+
+std::vector<CodecCapabilities>
+BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(
+ const SessionType& session_type) {
+ if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return {};
+ }
+ std::vector<CodecCapabilities> offload_a2dp_codec_capabilities =
+ kDefaultOffloadA2dpCodecCapabilities;
+ for (auto& codec_capability : offload_a2dp_codec_capabilities) {
+ switch (codec_capability.codecType) {
+ case CodecType::SBC:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::sbcCapabilities>(
+ kDefaultOffloadSbcCapability);
+ break;
+ case CodecType::AAC:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::aacCapabilities>(
+ kDefaultOffloadAacCapability);
+ break;
+ case CodecType::LDAC:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::ldacCapabilities>(
+ kDefaultOffloadLdacCapability);
+ break;
+ case CodecType::APTX:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::aptxCapabilities>(
+ kDefaultOffloadAptxCapability);
+ break;
+ case CodecType::APTX_HD:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::aptxCapabilities>(
+ kDefaultOffloadAptxHdCapability);
+ break;
+ case CodecType::LC3:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::lc3Capabilities>(
+ kDefaultOffloadLc3Capability);
+ break;
+ case CodecType::UNKNOWN:
+ codec_capability = {};
+ break;
+ }
+ }
+ return offload_a2dp_codec_capabilities;
+}
+
+bool BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(
+ const PcmConfiguration& pcm_config) {
+ if (ContainedInVector(kDefaultSoftwarePcmCapabilities.sampleRateHz,
+ pcm_config.sampleRateHz) &&
+ ContainedInVector(kDefaultSoftwarePcmCapabilities.bitsPerSample,
+ pcm_config.bitsPerSample) &&
+ ContainedInVector(kDefaultSoftwarePcmCapabilities.channelMode,
+ pcm_config.channelMode)
+ // data interval is not checked for now
+ // && pcm_config.dataIntervalUs != 0
+ ) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << pcm_config.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+ const SessionType& session_type, const CodecConfiguration& codec_config) {
+ if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ LOG(ERROR) << __func__
+ << ": Invalid SessionType=" << toString(session_type);
+ return false;
+ }
+ const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config;
+ switch (codec_config.codecType) {
+ case CodecType::SBC:
+ if (IsOffloadSbcConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::AAC:
+ if (IsOffloadAacConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::LDAC:
+ if (IsOffloadLdacConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::APTX:
+ if (IsOffloadAptxConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::APTX_HD:
+ if (IsOffloadAptxHdConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::LC3:
+ if (IsOffloadLc3ConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::UNKNOWN:
+ break;
+ }
+ return false;
+}
+
+UnicastCapability composeUnicastLc3Capability(
+ AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount,
+ const Lc3Capabilities& capability) {
+ return {
+ .codecType = CodecType::LC3,
+ .supportedChannel = audioLocation,
+ .deviceCount = deviceCnt,
+ .channelCountPerDevice = channelCount,
+ .leAudioCodecCapabilities =
+ UnicastCapability::LeAudioCodecCapabilities(capability),
+ };
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
+ const SessionType& session_type) {
+ if (session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return std::vector<LeAudioCodecCapabilitiesSetting>(0);
+ }
+
+ if (kDefaultOffloadLeAudioCapabilities.empty()) {
+ for (auto [audioLocation, deviceCnt, channelCount] :
+ supportedDeviceSetting) {
+ for (auto capability : supportedLc3CapabilityList) {
+ UnicastCapability lc3Capability = composeUnicastLc3Capability(
+ audioLocation, deviceCnt, channelCount, capability);
+ UnicastCapability lc3MonoDecodeCapability =
+ composeUnicastLc3Capability(monoAudio, 1, 1, capability);
+
+ // Adds the capability for encode only
+ kDefaultOffloadLeAudioCapabilities.push_back(
+ {.unicastEncodeCapability = lc3Capability,
+ .unicastDecodeCapability = kInvalidUnicastCapability,
+ .broadcastCapability = kInvalidBroadcastCapability});
+
+ // Adds the capability for decode only
+ kDefaultOffloadLeAudioCapabilities.push_back(
+ {.unicastEncodeCapability = kInvalidUnicastCapability,
+ .unicastDecodeCapability = lc3Capability,
+ .broadcastCapability = kInvalidBroadcastCapability});
+
+ // Adds the capability for the case that encode and decode exist at the
+ // same time
+ kDefaultOffloadLeAudioCapabilities.push_back(
+ {.unicastEncodeCapability = lc3Capability,
+ .unicastDecodeCapability = lc3MonoDecodeCapability,
+ .broadcastCapability = kInvalidBroadcastCapability});
+ }
+ }
+ }
+
+ return kDefaultOffloadLeAudioCapabilities;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
new file mode 100644
index 0000000..c542ce5
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -0,0 +1,88 @@
+/*
+ * 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 <aidl/android/hardware/bluetooth/audio/CodecCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/Lc3Configuration.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioCodecs {
+ public:
+ static std::vector<PcmCapabilities> GetSoftwarePcmCapabilities();
+ static std::vector<CodecCapabilities> GetA2dpOffloadCodecCapabilities(
+ const SessionType& session_type);
+
+ static bool IsSoftwarePcmConfigurationValid(
+ const PcmConfiguration& pcm_config);
+ static bool IsOffloadCodecConfigurationValid(
+ const SessionType& session_type, const CodecConfiguration& codec_config);
+
+ static bool IsOffloadLeAudioConfigurationValid(
+ const SessionType& session_type, const Lc3Configuration& codec_config);
+
+ static bool IsOffloadLeAudioConfigurationValid(
+ const SessionType& session_type,
+ const LeAudioConfiguration& codec_config);
+
+ static std::vector<LeAudioCodecCapabilitiesSetting>
+ GetLeAudioOffloadCodecCapabilities(const SessionType& session_type);
+
+ private:
+ template <typename T>
+ struct identity {
+ typedef T type;
+ };
+ template <class T>
+ static bool ContainedInVector(const std::vector<T>& vector,
+ const typename identity<T>::type& target);
+ template <class T>
+ static bool ContainedInBitmask(const T& bitmask, const T& target);
+ static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield);
+ static bool IsOffloadSbcConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadAacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadLdacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadAptxConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadAptxHdConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadLc3ConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadLeAudioConfigurationValid(
+ const SessionType& session_type, const LeAudioCodecConfiguration&);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
new file mode 100644
index 0000000..95e473e
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -0,0 +1,581 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#define LOG_TAG "BTAudioSessionAidl"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_manager.h>
+
+#include "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr int kFmqSendTimeoutMs = 1000; // 1000 ms timeout for sending
+static constexpr int kFmqReceiveTimeoutMs =
+ 1000; // 1000 ms timeout for receiving
+static constexpr int kWritePollMs = 1; // polled non-blocking interval
+static constexpr int kReadPollMs = 1; // polled non-blocking interval
+
+const CodecConfiguration BluetoothAudioSession::kInvalidCodecConfiguration = {};
+const LeAudioConfiguration kInvalidLeAudioConfiguration = {};
+AudioConfiguration BluetoothAudioSession::invalidSoftwareAudioConfiguration =
+ {};
+AudioConfiguration BluetoothAudioSession::invalidOffloadAudioConfiguration = {};
+AudioConfiguration BluetoothAudioSession::invalidLeOffloadAudioConfig = {};
+
+BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
+ : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {
+ invalidSoftwareAudioConfiguration.set<AudioConfiguration::pcmConfig>(
+ kInvalidPcmConfiguration);
+ invalidOffloadAudioConfiguration.set<AudioConfiguration::a2dpConfig>(
+ kInvalidCodecConfiguration);
+ invalidLeOffloadAudioConfig.set<AudioConfiguration::leAudioConfig>(
+ kInvalidLeAudioConfiguration);
+}
+
+/***
+ *
+ * Callback methods
+ *
+ ***/
+
+void BluetoothAudioSession::OnSessionStarted(
+ const std::shared_ptr<IBluetoothAudioPort> stack_iface,
+ const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (stack_iface == nullptr) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", IBluetoothAudioPort Invalid";
+ } else if (!UpdateAudioConfig(audio_config)) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", AudioConfiguration=" << audio_config.toString()
+ << " Invalid";
+ } else if (!UpdateDataPath(mq_desc)) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << " MqDescriptor Invalid";
+ if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ audio_config_ = std::make_unique<AudioConfiguration>(
+ invalidOffloadAudioConfiguration);
+ } else {
+ audio_config_ = std::make_unique<AudioConfiguration>(
+ invalidSoftwareAudioConfiguration);
+ }
+ } else {
+ stack_iface_ = stack_iface;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", AudioConfiguration=" << audio_config.toString();
+ ReportSessionStatus();
+ }
+}
+
+void BluetoothAudioSession::OnSessionEnded() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ bool toggled = IsSessionReady();
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+ if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ audio_config_ =
+ std::make_unique<AudioConfiguration>(invalidOffloadAudioConfiguration);
+ } else {
+ audio_config_ =
+ std::make_unique<AudioConfiguration>(invalidSoftwareAudioConfiguration);
+ }
+ stack_iface_ = nullptr;
+ UpdateDataPath(nullptr);
+ if (toggled) {
+ ReportSessionStatus();
+ }
+}
+
+/***
+ *
+ * Util methods
+ *
+ ***/
+
+const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return invalidOffloadAudioConfiguration;
+ } else {
+ return invalidSoftwareAudioConfiguration;
+ }
+ switch (session_type_) {
+ case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ return invalidOffloadAudioConfiguration;
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ return invalidLeOffloadAudioConfig;
+ default:
+ return invalidSoftwareAudioConfiguration;
+ }
+ }
+ return *audio_config_;
+}
+
+void BluetoothAudioSession::ReportAudioConfigChanged(
+ const AudioConfiguration& audio_config) {
+ if (session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return;
+ }
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+ if (observers_.empty()) {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO port state observer";
+ return;
+ }
+ for (auto& observer : observers_) {
+ uint16_t cookie = observer.first;
+ std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
+ LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_)
+ << ", bluetooth_audio=0x"
+ << ::android::base::StringPrintf("%04x", cookie);
+ if (cb->audio_configuration_changed_cb_ != nullptr) {
+ cb->audio_configuration_changed_cb_(cookie);
+ }
+ }
+}
+
+bool BluetoothAudioSession::IsSessionReady() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+
+ bool is_mq_valid =
+ (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+ (data_mq_ != nullptr && data_mq_->isValid()));
+ return stack_iface_ != nullptr && is_mq_valid;
+}
+
+/***
+ *
+ * Status callback methods
+ *
+ ***/
+
+uint16_t BluetoothAudioSession::RegisterStatusCback(
+ const PortStatusCallbacks& callbacks) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ uint16_t cookie = ObserversCookieGetInitValue(session_type_);
+ uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
+
+ while (cookie < cookie_upper_bound) {
+ if (observers_.find(cookie) == observers_.end()) {
+ break;
+ }
+ ++cookie;
+ }
+ if (cookie >= cookie_upper_bound) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has " << observers_.size()
+ << " observers already (No Resource)";
+ return kObserversCookieUndefined;
+ }
+ std::shared_ptr<PortStatusCallbacks> cb =
+ std::make_shared<PortStatusCallbacks>();
+ *cb = callbacks;
+ observers_[cookie] = cb;
+ return cookie;
+}
+
+void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (observers_.erase(cookie) != 1) {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << " no such provider=0x"
+ << ::android::base::StringPrintf("%04x", cookie);
+ }
+}
+
+/***
+ *
+ * Stream methods
+ *
+ ***/
+
+bool BluetoothAudioSession::StartStream() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+ auto hal_retval = stack_iface_->startStream();
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ return false;
+ }
+ return true;
+}
+
+bool BluetoothAudioSession::SuspendStream() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+ auto hal_retval = stack_iface_->suspendStream();
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ return false;
+ }
+ return true;
+}
+
+void BluetoothAudioSession::StopStream() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ return;
+ }
+ auto hal_retval = stack_iface_->stopStream();
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ }
+}
+
+/***
+ *
+ * Private methods
+ *
+ ***/
+
+bool BluetoothAudioSession::UpdateDataPath(const DataMQDesc* mq_desc) {
+ if (mq_desc == nullptr) {
+ // usecase of reset by nullptr
+ data_mq_ = nullptr;
+ return true;
+ }
+ std::unique_ptr<DataMQ> temp_mq;
+ temp_mq.reset(new DataMQ(*mq_desc));
+ if (!temp_mq || !temp_mq->isValid()) {
+ data_mq_ = nullptr;
+ return false;
+ }
+ data_mq_ = std::move(temp_mq);
+ return true;
+}
+
+bool BluetoothAudioSession::UpdateAudioConfig(
+ const AudioConfiguration& audio_config) {
+ bool is_software_session =
+ (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
+ session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
+ bool is_offload_a2dp_session =
+ (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+ bool is_offload_le_audio_session =
+ (session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+ auto audio_config_tag = audio_config.getTag();
+ bool is_software_audio_config =
+ (is_software_session &&
+ audio_config_tag == AudioConfiguration::pcmConfig);
+ bool is_a2dp_offload_audio_config =
+ (is_offload_a2dp_session &&
+ audio_config_tag == AudioConfiguration::a2dpConfig);
+ bool is_le_audio_offload_audio_config =
+ (is_offload_le_audio_session &&
+ audio_config_tag == AudioConfiguration::leAudioConfig);
+ if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
+ !is_le_audio_offload_audio_config) {
+ return false;
+ }
+ audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+ return true;
+}
+
+void BluetoothAudioSession::ReportSessionStatus() {
+ // This is locked already by OnSessionStarted / OnSessionEnded
+ if (observers_.empty()) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO port state observer";
+ return;
+ }
+ for (auto& observer : observers_) {
+ uint16_t cookie = observer.first;
+ std::shared_ptr<PortStatusCallbacks> callback = observer.second;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " notify to bluetooth_audio=0x"
+ << ::android::base::StringPrintf("%04x", cookie);
+ callback->session_changed_cb_(cookie);
+ }
+}
+
+/***
+ *
+ * PCM methods
+ *
+ ***/
+
+size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
+ size_t bytes) {
+ if (buffer == nullptr || bytes <= 0) {
+ return 0;
+ }
+ size_t total_written = 0;
+ int timeout_ms = kFmqSendTimeoutMs;
+ do {
+ std::unique_lock<std::recursive_mutex> lock(mutex_);
+ if (!IsSessionReady()) {
+ break;
+ }
+ size_t num_bytes_to_write = data_mq_->availableToWrite();
+ if (num_bytes_to_write) {
+ if (num_bytes_to_write > (bytes - total_written)) {
+ num_bytes_to_write = bytes - total_written;
+ }
+
+ if (!data_mq_->write(
+ static_cast<const MQDataType*>(buffer) + total_written,
+ num_bytes_to_write)) {
+ LOG(ERROR) << "FMQ datapath writing " << total_written << "/" << bytes
+ << " failed";
+ return total_written;
+ }
+ total_written += num_bytes_to_write;
+ } else if (timeout_ms >= kWritePollMs) {
+ lock.unlock();
+ usleep(kWritePollMs * 1000);
+ timeout_ms -= kWritePollMs;
+ } else {
+ LOG(DEBUG) << "Data " << total_written << "/" << bytes << " overflow "
+ << (kFmqSendTimeoutMs - timeout_ms) << " ms";
+ return total_written;
+ }
+ } while (total_written < bytes);
+ return total_written;
+}
+
+size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
+ if (buffer == nullptr || bytes <= 0) {
+ return 0;
+ }
+ size_t total_read = 0;
+ int timeout_ms = kFmqReceiveTimeoutMs;
+ do {
+ std::unique_lock<std::recursive_mutex> lock(mutex_);
+ if (!IsSessionReady()) {
+ break;
+ }
+ size_t num_bytes_to_read = data_mq_->availableToRead();
+ if (num_bytes_to_read) {
+ if (num_bytes_to_read > (bytes - total_read)) {
+ num_bytes_to_read = bytes - total_read;
+ }
+ if (!data_mq_->read(static_cast<MQDataType*>(buffer) + total_read,
+ num_bytes_to_read)) {
+ LOG(ERROR) << "FMQ datapath reading " << total_read << "/" << bytes
+ << " failed";
+ return total_read;
+ }
+ total_read += num_bytes_to_read;
+ } else if (timeout_ms >= kReadPollMs) {
+ lock.unlock();
+ usleep(kReadPollMs * 1000);
+ timeout_ms -= kReadPollMs;
+ continue;
+ } else {
+ LOG(DEBUG) << "Data " << total_read << "/" << bytes << " overflow "
+ << (kFmqReceiveTimeoutMs - timeout_ms) << " ms";
+ return total_read;
+ }
+ } while (total_read < bytes);
+ return total_read;
+}
+
+/***
+ *
+ * Other methods
+ *
+ ***/
+
+void BluetoothAudioSession::ReportControlStatus(bool start_resp,
+ BluetoothAudioStatus status) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (observers_.empty()) {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO port state observer";
+ return;
+ }
+ for (auto& observer : observers_) {
+ uint16_t cookie = observer.first;
+ std::shared_ptr<PortStatusCallbacks> callback = observer.second;
+ LOG(INFO) << __func__ << " - status=" << toString(status)
+ << " for SessionType=" << toString(session_type_)
+ << ", bluetooth_audio=0x"
+ << ::android::base::StringPrintf("%04x", cookie)
+ << (start_resp ? " started" : " suspended");
+ callback->control_result_cb_(cookie, start_resp, status);
+ }
+}
+
+bool BluetoothAudioSession::GetPresentationPosition(
+ PresentationPosition& presentation_position) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+ bool retval = false;
+
+ if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ return false;
+ }
+ return retval;
+}
+
+void BluetoothAudioSession::UpdateSourceMetadata(
+ const struct source_metadata& source_metadata) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return;
+ }
+
+ ssize_t track_count = source_metadata.track_count;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
+ << track_count << " track(s)";
+ if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return;
+ }
+
+ SourceMetadata hal_source_metadata;
+ hal_source_metadata.tracks.resize(track_count);
+ for (int i = 0; i < track_count; i++) {
+ hal_source_metadata.tracks[i].usage =
+ static_cast<media::audio::common::AudioUsage>(
+ source_metadata.tracks[i].usage);
+ hal_source_metadata.tracks[i].contentType =
+ static_cast<media::audio::common::AudioContentType>(
+ source_metadata.tracks[i].content_type);
+ hal_source_metadata.tracks[i].gain = source_metadata.tracks[i].gain;
+ LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", usage=" << toString(hal_source_metadata.tracks[i].usage)
+ << ", content="
+ << toString(hal_source_metadata.tracks[i].contentType)
+ << ", gain=" << hal_source_metadata.tracks[i].gain;
+ }
+
+ auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ }
+}
+
+void BluetoothAudioSession::UpdateSinkMetadata(
+ const struct sink_metadata& sink_metadata) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return;
+ }
+
+ ssize_t track_count = sink_metadata.track_count;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
+ << track_count << " track(s)";
+ if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return;
+ }
+
+ SinkMetadata hal_sink_metadata;
+ hal_sink_metadata.tracks.resize(track_count);
+ for (int i = 0; i < track_count; i++) {
+ hal_sink_metadata.tracks[i].source =
+ static_cast<media::audio::common::AudioSource>(
+ sink_metadata.tracks[i].source);
+ hal_sink_metadata.tracks[i].gain = sink_metadata.tracks[i].gain;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", source=" << sink_metadata.tracks[i].source
+ << ", dest_device=" << sink_metadata.tracks[i].dest_device
+ << ", gain=" << sink_metadata.tracks[i].gain
+ << ", dest_device_address="
+ << sink_metadata.tracks[i].dest_device_address;
+ }
+
+ auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ }
+}
+
+bool BluetoothAudioSession::IsAidlAvailable() {
+ if (is_aidl_checked) return is_aidl_available;
+ is_aidl_available =
+ (AServiceManager_checkService(
+ kDefaultAudioProviderFactoryInterface.c_str()) != nullptr);
+ is_aidl_checked = true;
+ return is_aidl_available;
+}
+
+/***
+ *
+ * BluetoothAudioSessionInstance
+ *
+ ***/
+std::mutex BluetoothAudioSessionInstance::mutex_;
+std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+ BluetoothAudioSessionInstance::sessions_map_;
+
+std::shared_ptr<BluetoothAudioSession>
+BluetoothAudioSessionInstance::GetSessionInstance(
+ const SessionType& session_type) {
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ if (!sessions_map_.empty()) {
+ auto entry = sessions_map_.find(session_type);
+ if (entry != sessions_map_.end()) {
+ return entry->second;
+ }
+ }
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ std::make_shared<BluetoothAudioSession>(session_type);
+ sessions_map_[session_type] = session_ptr;
+ return session_ptr;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
new file mode 100644
index 0000000..85fd571
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -0,0 +1,227 @@
+/*
+ * 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 <aidl/android/hardware/audio/common/SinkMetadata.h>
+#include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hardware/audio.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using ::aidl::android::hardware::audio::common::SinkMetadata;
+using ::aidl::android::hardware::audio::common::SourceMetadata;
+
+using MQDataType = int8_t;
+using MQDataMode = SynchronizedReadWrite;
+using DataMQ = AidlMessageQueue<MQDataType, MQDataMode>;
+using DataMQDesc =
+ ::aidl::android::hardware::common::fmq::MQDescriptor<MQDataType,
+ MQDataMode>;
+
+static constexpr uint16_t kObserversCookieSize = 0x0010; // 0x0000 ~ 0x000f
+static constexpr uint16_t kObserversCookieUndefined =
+ (static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00);
+inline SessionType ObserversCookieGetSessionType(uint16_t cookie) {
+ return static_cast<SessionType>(cookie >> 8 & 0x00ff);
+}
+inline uint16_t ObserversCookieGetInitValue(SessionType session_type) {
+ return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
+}
+inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) {
+ return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
+ kObserversCookieSize;
+}
+
+/***
+ * This presents the callbacks of started / suspended and session changed,
+ * and the bluetooth_audio module uses to receive the status notification
+ ***/
+struct PortStatusCallbacks {
+ /***
+ * control_result_cb_ - when the Bluetooth stack reports results of
+ * streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
+ * this callback to report to the bluetooth_audio module.
+ * @param: cookie - indicates which bluetooth_audio output should handle
+ * @param: start_resp - this report is for startStream or not
+ * @param: status - the result of startStream
+ ***/
+ std::function<void(uint16_t cookie, bool start_resp,
+ BluetoothAudioStatus status)>
+ control_result_cb_;
+ /***
+ * session_changed_cb_ - when the Bluetooth stack start / end session, the
+ * BluetoothAudioProvider will invoke this callback to notify to the
+ * bluetooth_audio module.
+ * @param: cookie - indicates which bluetooth_audio output should handle
+ ***/
+ std::function<void(uint16_t cookie)> session_changed_cb_;
+ /***
+ * audio_configuration_changed_cb_ - when the Bluetooth stack change the audio
+ * configuration, the BluetoothAudioProvider will invoke this callback to
+ * notify to the bluetooth_audio module.
+ * @param: cookie - indicates which bluetooth_audio output should handle
+ ***/
+ std::function<void(uint16_t cookie)> audio_configuration_changed_cb_;
+};
+
+class BluetoothAudioSession {
+ public:
+ BluetoothAudioSession(const 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();
+
+ /***
+ * 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 std::shared_ptr<IBluetoothAudioPort> stack_iface,
+ const DataMQDesc* mq_desc,
+ const AudioConfiguration& audio_config);
+
+ /***
+ * The report function is used to report that the Bluetooth stack has ended
+ * the session, and will invoke session_changed_cb_ to notify registered
+ * bluetooth_audio outputs
+ ***/
+ void OnSessionEnded();
+
+ /***
+ * The report function is used to report that the Bluetooth stack has notified
+ * the result of startStream or suspendStream, and will invoke
+ * control_result_cb_ to notify registered bluetooth_audio outputs
+ ***/
+ void ReportControlStatus(bool start_resp, BluetoothAudioStatus status);
+
+ /***
+ * The control function helps the bluetooth_audio module to register
+ * PortStatusCallbacks
+ * @return: cookie - the assigned number to this bluetooth_audio output
+ ***/
+ uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks);
+
+ /***
+ * The control function helps the bluetooth_audio module to unregister
+ * PortStatusCallbacks
+ * @param: cookie - indicates which bluetooth_audio output is
+ ***/
+ void UnregisterStatusCback(uint16_t cookie);
+
+ /***
+ * The control function is for the bluetooth_audio module to get the current
+ * AudioConfiguration
+ ***/
+ const AudioConfiguration& GetAudioConfig();
+
+ /***
+ * The report function is used to report that the Bluetooth stack has notified
+ * the audio configuration changed, and will invoke
+ * audio_configuration_changed_cb_ to notify registered bluetooth_audio
+ * outputs
+ ***/
+ void ReportAudioConfigChanged(const AudioConfiguration& audio_config);
+
+ /***
+ * Those control functions are for the bluetooth_audio module to start,
+ * suspend, stop stream, to check position, and to update metadata.
+ ***/
+ bool StartStream();
+ bool SuspendStream();
+ void StopStream();
+ bool GetPresentationPosition(PresentationPosition& presentation_position);
+ void UpdateSourceMetadata(const struct source_metadata& source_metadata);
+ void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
+
+ // The control function writes stream to FMQ
+ size_t OutWritePcmData(const void* buffer, size_t bytes);
+ // The control function read stream from FMQ
+ size_t InReadPcmData(void* buffer, size_t bytes);
+
+ // Return if IBluetoothAudioProviderFactory implementation existed
+ static bool IsAidlAvailable();
+
+ static constexpr PcmConfiguration kInvalidPcmConfiguration = {};
+ // can't be constexpr because of non-literal type
+ static const CodecConfiguration kInvalidCodecConfiguration;
+
+ static AudioConfiguration invalidSoftwareAudioConfiguration;
+ static AudioConfiguration invalidOffloadAudioConfiguration;
+ static AudioConfiguration invalidLeOffloadAudioConfig;
+
+ private:
+ // using recursive_mutex to allow hwbinder to re-enter again.
+ std::recursive_mutex mutex_;
+ SessionType session_type_;
+
+ // audio control path to use for both software and offloading
+ std::shared_ptr<IBluetoothAudioPort> stack_iface_;
+ // audio data path (FMQ) for software encoding
+ std::unique_ptr<DataMQ> data_mq_;
+ // audio data configuration for both software and offloading
+ std::unique_ptr<AudioConfiguration> audio_config_;
+
+ // saving those registered bluetooth_audio's callbacks
+ std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
+ observers_;
+
+ bool UpdateDataPath(const DataMQDesc* mq_desc);
+ bool UpdateAudioConfig(const AudioConfiguration& audio_config);
+ // invoking the registered session_changed_cb_
+ void ReportSessionStatus();
+
+ static inline std::atomic<bool> is_aidl_checked = false;
+ static inline std::atomic<bool> is_aidl_available = false;
+ static inline const std::string kDefaultAudioProviderFactoryInterface =
+ std::string() + IBluetoothAudioProviderFactory::descriptor + "/default";
+};
+
+class BluetoothAudioSessionInstance {
+ public:
+ // The API is to fetch the specified session of A2DP / Hearing Aid
+ static std::shared_ptr<BluetoothAudioSession> GetSessionInstance(
+ const SessionType& session_type);
+
+ private:
+ static std::mutex mutex_;
+ static std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+ sessions_map_;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
new file mode 100644
index 0000000..a3ed428
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -0,0 +1,182 @@
+/*
+ * 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 "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionControl {
+ public:
+ /***
+ * The control API helps to check if session is ready or not
+ * @return: true if the Bluetooth stack has started th specified session
+ ***/
+ static bool IsSessionReady(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->IsSessionReady();
+ }
+
+ return false;
+ }
+
+ /***
+ * The control API helps the bluetooth_audio module to register
+ * PortStatusCallbacks
+ * @return: cookie - the assigned number to this bluetooth_audio output
+ ***/
+ static uint16_t RegisterControlResultCback(
+ const SessionType& session_type, const PortStatusCallbacks& cbacks) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->RegisterStatusCback(cbacks);
+ }
+ return kObserversCookieUndefined;
+ }
+
+ /***
+ * The control API helps the bluetooth_audio module to unregister
+ * PortStatusCallbacks
+ * @param: cookie - indicates which bluetooth_audio output is
+ ***/
+ static void UnregisterControlResultCback(const SessionType& session_type,
+ uint16_t cookie) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->UnregisterStatusCback(cookie);
+ }
+ }
+
+ /***
+ * The control API for the bluetooth_audio module to get current
+ * AudioConfiguration
+ ***/
+ static const AudioConfiguration GetAudioConfig(
+ const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->GetAudioConfig();
+ } else if (session_type ==
+ SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return BluetoothAudioSession::invalidOffloadAudioConfiguration;
+ } else {
+ return BluetoothAudioSession::invalidSoftwareAudioConfiguration;
+ }
+ }
+
+ /***
+ * Those control APIs for the bluetooth_audio module to start / suspend /
+ stop
+ * stream, to check position, and to update metadata.
+ ***/
+ static bool StartStream(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->StartStream();
+ }
+ return false;
+ }
+
+ static bool SuspendStream(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->SuspendStream();
+ }
+ return false;
+ }
+
+ static void StopStream(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->StopStream();
+ }
+ }
+
+ static bool GetPresentationPosition(
+ const SessionType& session_type,
+ PresentationPosition& presentation_position) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->GetPresentationPosition(presentation_position);
+ }
+ return false;
+ }
+
+ static void UpdateSourceMetadata(
+ const SessionType& session_type,
+ const struct source_metadata& source_metadata) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->UpdateSourceMetadata(source_metadata);
+ }
+ }
+
+ static void UpdateSinkMetadata(const SessionType& session_type,
+ const struct sink_metadata& sink_metadata) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->UpdateSinkMetadata(sink_metadata);
+ }
+ }
+
+ /***
+ * The control API writes stream to FMQ
+ ***/
+ static size_t OutWritePcmData(const SessionType& session_type,
+ const void* buffer, size_t bytes) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->OutWritePcmData(buffer, bytes);
+ }
+ return 0;
+ }
+
+ /***
+ * The control API reads stream from FMQ
+ ***/
+ static size_t InReadPcmData(const SessionType& session_type, void* buffer,
+ size_t bytes) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->InReadPcmData(buffer, bytes);
+ }
+ return 0;
+ }
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
new file mode 100644
index 0000000..18569c3
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
@@ -0,0 +1,87 @@
+/*
+ * 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 "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionReport {
+ public:
+ /***
+ * The API reports the Bluetooth stack has started the session, and will
+ * inform registered bluetooth_audio outputs
+ ***/
+ static void OnSessionStarted(
+ const SessionType& session_type,
+ const std::shared_ptr<IBluetoothAudioPort> host_iface,
+ const DataMQDesc* data_mq, const AudioConfiguration& audio_config) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->OnSessionStarted(host_iface, data_mq, audio_config);
+ }
+ }
+
+ /***
+ * The API reports the Bluetooth stack has ended the session, and will
+ * inform registered bluetooth_audio outputs
+ ***/
+ static void OnSessionEnded(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->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 SessionType& session_type,
+ const bool& start_resp,
+ BluetoothAudioStatus status) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->ReportControlStatus(start_resp, status);
+ }
+ }
+ /***
+ * The API reports the Bluetooth stack has replied the changed of the audio
+ * configuration, and will inform registered bluetooth_audio outputs
+ ***/
+ static void ReportAudioConfigChanged(const SessionType& session_type,
+ const AudioConfiguration& audio_config) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->ReportAudioConfigChanged(audio_config);
+ }
+ }
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
new file mode 100644
index 0000000..91e0238
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
@@ -0,0 +1,775 @@
+/*
+ * 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 "BtAudioNakahara"
+
+#include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <android-base/logging.h>
+
+#include <functional>
+#include <unordered_map>
+
+#include "../aidl_session/BluetoothAudioSession.h"
+#include "../aidl_session/BluetoothAudioSessionControl.h"
+#include "HidlToAidlMiddleware_2_0.h"
+#include "HidlToAidlMiddleware_2_1.h"
+#include "HidlToAidlMiddleware_2_2.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using HidlStatus = ::android::hardware::bluetooth::audio::V2_0::Status;
+using PcmConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using SampleRate_2_0 = ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ChannelMode_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using BitsPerSample_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using CodecConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using CodecType_2_0 = ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using SbcConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+using AacConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using LdacConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using AptxConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using SbcAllocMethod_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using SbcBlockLength_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using SbcChannelMode_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using SbcNumSubbands_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using AacObjectType_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using AacVarBitRate_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using LdacChannelMode_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using LdacQualityIndex_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+
+using PcmConfig_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::PcmParameters;
+using SampleRate_2_1 = ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+using Lc3CodecConfig_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration;
+using Lc3Config_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::Lc3Parameters;
+using Lc3FrameDuration_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::Lc3FrameDuration;
+
+using LeAudioConfig_2_2 =
+ ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
+using LeAudioMode_2_2 =
+ ::android::hardware::bluetooth::audio::V2_2::LeAudioMode;
+
+std::mutex legacy_callback_lock;
+std::unordered_map<
+ SessionType,
+ std::unordered_map<uint16_t, std::shared_ptr<PortStatusCallbacks_2_2>>>
+ legacy_callback_table;
+
+const static std::unordered_map<SessionType_2_0, SessionType>
+ session_type_2_0_to_aidl_map{
+ {SessionType_2_0::A2DP_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH},
+ {SessionType_2_0::A2DP_HARDWARE_OFFLOAD_DATAPATH,
+ SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
+ {SessionType_2_0::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH},
+ };
+
+const static std::unordered_map<SessionType_2_1, SessionType>
+ session_type_2_1_to_aidl_map{
+ {SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH},
+ {SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH,
+ SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
+ {SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH,
+ SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH},
+ };
+
+const static std::unordered_map<int32_t, SampleRate_2_0>
+ sample_rate_to_hidl_2_0_map{
+ {44100, SampleRate_2_0::RATE_44100},
+ {48000, SampleRate_2_0::RATE_48000},
+ {88200, SampleRate_2_0::RATE_88200},
+ {96000, SampleRate_2_0::RATE_96000},
+ {176400, SampleRate_2_0::RATE_176400},
+ {192000, SampleRate_2_0::RATE_192000},
+ {16000, SampleRate_2_0::RATE_16000},
+ {24000, SampleRate_2_0::RATE_24000},
+ };
+
+const static std::unordered_map<int32_t, SampleRate_2_1>
+ sample_rate_to_hidl_2_1_map{
+ {44100, SampleRate_2_1::RATE_44100},
+ {48000, SampleRate_2_1::RATE_48000},
+ {88200, SampleRate_2_1::RATE_88200},
+ {96000, SampleRate_2_1::RATE_96000},
+ {176400, SampleRate_2_1::RATE_176400},
+ {192000, SampleRate_2_1::RATE_192000},
+ {16000, SampleRate_2_1::RATE_16000},
+ {24000, SampleRate_2_1::RATE_24000},
+ {8000, SampleRate_2_1::RATE_8000},
+ {32000, SampleRate_2_1::RATE_32000},
+ };
+
+const static std::unordered_map<CodecType, CodecType_2_0>
+ codec_type_to_hidl_2_0_map{
+ {CodecType::UNKNOWN, CodecType_2_0::UNKNOWN},
+ {CodecType::SBC, CodecType_2_0::SBC},
+ {CodecType::AAC, CodecType_2_0::AAC},
+ {CodecType::APTX, CodecType_2_0::APTX},
+ {CodecType::APTX_HD, CodecType_2_0::APTX_HD},
+ {CodecType::LDAC, CodecType_2_0::LDAC},
+ {CodecType::LC3, CodecType_2_0::UNKNOWN},
+ };
+
+const static std::unordered_map<SbcChannelMode, SbcChannelMode_2_0>
+ sbc_channel_mode_to_hidl_2_0_map{
+ {SbcChannelMode::UNKNOWN, SbcChannelMode_2_0::UNKNOWN},
+ {SbcChannelMode::JOINT_STEREO, SbcChannelMode_2_0::JOINT_STEREO},
+ {SbcChannelMode::STEREO, SbcChannelMode_2_0::STEREO},
+ {SbcChannelMode::DUAL, SbcChannelMode_2_0::DUAL},
+ {SbcChannelMode::MONO, SbcChannelMode_2_0::MONO},
+ };
+
+const static std::unordered_map<int8_t, SbcBlockLength_2_0>
+ sbc_block_length_to_hidl_map{
+ {4, SbcBlockLength_2_0::BLOCKS_4},
+ {8, SbcBlockLength_2_0::BLOCKS_8},
+ {12, SbcBlockLength_2_0::BLOCKS_12},
+ {16, SbcBlockLength_2_0::BLOCKS_16},
+ };
+
+const static std::unordered_map<int8_t, SbcNumSubbands_2_0>
+ sbc_subbands_to_hidl_map{
+ {4, SbcNumSubbands_2_0::SUBBAND_4},
+ {8, SbcNumSubbands_2_0::SUBBAND_8},
+ };
+
+const static std::unordered_map<SbcAllocMethod, SbcAllocMethod_2_0>
+ sbc_alloc_method_to_hidl_map{
+ {SbcAllocMethod::ALLOC_MD_S, SbcAllocMethod_2_0::ALLOC_MD_S},
+ {SbcAllocMethod::ALLOC_MD_L, SbcAllocMethod_2_0::ALLOC_MD_L},
+ };
+
+const static std::unordered_map<AacObjectType, AacObjectType_2_0>
+ aac_object_type_to_hidl_map{
+ {AacObjectType::MPEG2_LC, AacObjectType_2_0::MPEG2_LC},
+ {AacObjectType::MPEG4_LC, AacObjectType_2_0::MPEG4_LC},
+ {AacObjectType::MPEG4_LTP, AacObjectType_2_0::MPEG4_LTP},
+ {AacObjectType::MPEG4_SCALABLE, AacObjectType_2_0::MPEG4_SCALABLE},
+ };
+
+const static std::unordered_map<LdacChannelMode, LdacChannelMode_2_0>
+ ldac_channel_mode_to_hidl_map{
+ {LdacChannelMode::UNKNOWN, LdacChannelMode_2_0::UNKNOWN},
+ {LdacChannelMode::STEREO, LdacChannelMode_2_0::STEREO},
+ {LdacChannelMode::DUAL, LdacChannelMode_2_0::DUAL},
+ {LdacChannelMode::MONO, LdacChannelMode_2_0::MONO},
+ };
+
+const static std::unordered_map<LdacQualityIndex, LdacQualityIndex_2_0>
+ ldac_qindex_to_hidl_map{
+ {LdacQualityIndex::HIGH, LdacQualityIndex_2_0::QUALITY_HIGH},
+ {LdacQualityIndex::MID, LdacQualityIndex_2_0::QUALITY_MID},
+ {LdacQualityIndex::LOW, LdacQualityIndex_2_0::QUALITY_LOW},
+ {LdacQualityIndex::ABR, LdacQualityIndex_2_0::QUALITY_ABR},
+ };
+
+const static std::unordered_map<LeAudioMode, LeAudioMode_2_2>
+ leaudio_mode_to_hidl_map{
+ {LeAudioMode::UNKNOWN, LeAudioMode_2_2::UNKNOWN},
+ {LeAudioMode::UNICAST, LeAudioMode_2_2::UNICAST},
+ {LeAudioMode::BROADCAST, LeAudioMode_2_2::BROADCAST},
+ };
+
+inline SessionType from_session_type_2_0(
+ const SessionType_2_0& session_type_hidl) {
+ auto it = session_type_2_0_to_aidl_map.find(session_type_hidl);
+ if (it != session_type_2_0_to_aidl_map.end()) return it->second;
+ return SessionType::UNKNOWN;
+}
+
+inline SessionType from_session_type_2_1(
+ const SessionType_2_1& session_type_hidl) {
+ auto it = session_type_2_1_to_aidl_map.find(session_type_hidl);
+ if (it != session_type_2_1_to_aidl_map.end()) return it->second;
+ return SessionType::UNKNOWN;
+}
+
+inline HidlStatus to_hidl_status(const BluetoothAudioStatus& status) {
+ switch (status) {
+ case BluetoothAudioStatus::SUCCESS:
+ return HidlStatus::SUCCESS;
+ case BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION:
+ return HidlStatus::UNSUPPORTED_CODEC_CONFIGURATION;
+ default:
+ return HidlStatus::FAILURE;
+ }
+}
+
+inline SampleRate_2_0 to_hidl_sample_rate_2_0(const int32_t sample_rate_hz) {
+ auto it = sample_rate_to_hidl_2_0_map.find(sample_rate_hz);
+ if (it != sample_rate_to_hidl_2_0_map.end()) return it->second;
+ return SampleRate_2_0::RATE_UNKNOWN;
+}
+
+inline SampleRate_2_1 to_hidl_sample_rate_2_1(const int32_t sample_rate_hz) {
+ auto it = sample_rate_to_hidl_2_1_map.find(sample_rate_hz);
+ if (it != sample_rate_to_hidl_2_1_map.end()) return it->second;
+ return SampleRate_2_1::RATE_UNKNOWN;
+}
+
+inline BitsPerSample_2_0 to_hidl_bits_per_sample(const int8_t bit_per_sample) {
+ switch (bit_per_sample) {
+ case 16:
+ return BitsPerSample_2_0::BITS_16;
+ case 24:
+ return BitsPerSample_2_0::BITS_24;
+ case 32:
+ return BitsPerSample_2_0::BITS_32;
+ default:
+ return BitsPerSample_2_0::BITS_UNKNOWN;
+ }
+}
+
+inline ChannelMode_2_0 to_hidl_channel_mode(const ChannelMode channel_mode) {
+ switch (channel_mode) {
+ case ChannelMode::MONO:
+ return ChannelMode_2_0::MONO;
+ case ChannelMode::STEREO:
+ return ChannelMode_2_0::STEREO;
+ default:
+ return ChannelMode_2_0::UNKNOWN;
+ }
+}
+
+inline PcmConfig_2_0 to_hidl_pcm_config_2_0(
+ const PcmConfiguration& pcm_config) {
+ PcmConfig_2_0 hidl_pcm_config;
+ hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_0(pcm_config.sampleRateHz);
+ hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
+ hidl_pcm_config.bitsPerSample =
+ to_hidl_bits_per_sample(pcm_config.bitsPerSample);
+ return hidl_pcm_config;
+}
+
+inline CodecType_2_0 to_hidl_codec_type_2_0(const CodecType codec_type) {
+ auto it = codec_type_to_hidl_2_0_map.find(codec_type);
+ if (it != codec_type_to_hidl_2_0_map.end()) return it->second;
+ return CodecType_2_0::UNKNOWN;
+}
+
+inline SbcConfig_2_0 to_hidl_sbc_config(const SbcConfiguration sbc_config) {
+ SbcConfig_2_0 hidl_sbc_config;
+ hidl_sbc_config.minBitpool = sbc_config.minBitpool;
+ hidl_sbc_config.maxBitpool = sbc_config.maxBitpool;
+ hidl_sbc_config.sampleRate = to_hidl_sample_rate_2_0(sbc_config.sampleRateHz);
+ hidl_sbc_config.bitsPerSample =
+ to_hidl_bits_per_sample(sbc_config.bitsPerSample);
+ if (sbc_channel_mode_to_hidl_2_0_map.find(sbc_config.channelMode) !=
+ sbc_channel_mode_to_hidl_2_0_map.end()) {
+ hidl_sbc_config.channelMode =
+ sbc_channel_mode_to_hidl_2_0_map.at(sbc_config.channelMode);
+ }
+ if (sbc_block_length_to_hidl_map.find(sbc_config.blockLength) !=
+ sbc_block_length_to_hidl_map.end()) {
+ hidl_sbc_config.blockLength =
+ sbc_block_length_to_hidl_map.at(sbc_config.blockLength);
+ }
+ if (sbc_subbands_to_hidl_map.find(sbc_config.numSubbands) !=
+ sbc_subbands_to_hidl_map.end()) {
+ hidl_sbc_config.numSubbands =
+ sbc_subbands_to_hidl_map.at(sbc_config.numSubbands);
+ }
+ if (sbc_alloc_method_to_hidl_map.find(sbc_config.allocMethod) !=
+ sbc_alloc_method_to_hidl_map.end()) {
+ hidl_sbc_config.allocMethod =
+ sbc_alloc_method_to_hidl_map.at(sbc_config.allocMethod);
+ }
+ return hidl_sbc_config;
+}
+
+inline AacConfig_2_0 to_hidl_aac_config(const AacConfiguration aac_config) {
+ AacConfig_2_0 hidl_aac_config;
+ hidl_aac_config.sampleRate = to_hidl_sample_rate_2_0(aac_config.sampleRateHz);
+ hidl_aac_config.bitsPerSample =
+ to_hidl_bits_per_sample(aac_config.bitsPerSample);
+ hidl_aac_config.channelMode = to_hidl_channel_mode(aac_config.channelMode);
+ if (aac_object_type_to_hidl_map.find(aac_config.objectType) !=
+ aac_object_type_to_hidl_map.end()) {
+ hidl_aac_config.objectType =
+ aac_object_type_to_hidl_map.at(aac_config.objectType);
+ }
+ hidl_aac_config.variableBitRateEnabled = aac_config.variableBitRateEnabled
+ ? AacVarBitRate_2_0::ENABLED
+ : AacVarBitRate_2_0::DISABLED;
+ return hidl_aac_config;
+}
+
+inline LdacConfig_2_0 to_hidl_ldac_config(const LdacConfiguration ldac_config) {
+ LdacConfig_2_0 hidl_ldac_config;
+ hidl_ldac_config.sampleRate =
+ to_hidl_sample_rate_2_0(ldac_config.sampleRateHz);
+ hidl_ldac_config.bitsPerSample =
+ to_hidl_bits_per_sample(ldac_config.bitsPerSample);
+ if (ldac_channel_mode_to_hidl_map.find(ldac_config.channelMode) !=
+ ldac_channel_mode_to_hidl_map.end()) {
+ hidl_ldac_config.channelMode =
+ ldac_channel_mode_to_hidl_map.at(ldac_config.channelMode);
+ }
+ if (ldac_qindex_to_hidl_map.find(ldac_config.qualityIndex) !=
+ ldac_qindex_to_hidl_map.end()) {
+ hidl_ldac_config.qualityIndex =
+ ldac_qindex_to_hidl_map.at(ldac_config.qualityIndex);
+ }
+ return hidl_ldac_config;
+}
+
+inline AptxConfig_2_0 to_hidl_aptx_config(const AptxConfiguration aptx_config) {
+ AptxConfig_2_0 hidl_aptx_config;
+ hidl_aptx_config.sampleRate =
+ to_hidl_sample_rate_2_0(aptx_config.sampleRateHz);
+ hidl_aptx_config.bitsPerSample =
+ to_hidl_bits_per_sample(aptx_config.bitsPerSample);
+ hidl_aptx_config.channelMode = to_hidl_channel_mode(aptx_config.channelMode);
+ return hidl_aptx_config;
+}
+
+inline CodecConfig_2_0 to_hidl_codec_config_2_0(
+ const CodecConfiguration& codec_config) {
+ CodecConfig_2_0 hidl_codec_config;
+ hidl_codec_config.codecType = to_hidl_codec_type_2_0(codec_config.codecType);
+ hidl_codec_config.encodedAudioBitrate =
+ static_cast<uint32_t>(codec_config.encodedAudioBitrate);
+ hidl_codec_config.peerMtu = static_cast<uint32_t>(codec_config.peerMtu);
+ hidl_codec_config.isScmstEnabled = codec_config.isScmstEnabled;
+ switch (codec_config.config.getTag()) {
+ case CodecConfiguration::CodecSpecific::sbcConfig:
+ hidl_codec_config.config.sbcConfig(to_hidl_sbc_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::sbcConfig>()));
+ break;
+ case CodecConfiguration::CodecSpecific::aacConfig:
+ hidl_codec_config.config.aacConfig(to_hidl_aac_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::aacConfig>()));
+ break;
+ case CodecConfiguration::CodecSpecific::ldacConfig:
+ hidl_codec_config.config.ldacConfig(to_hidl_ldac_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::ldacConfig>()));
+ break;
+ case CodecConfiguration::CodecSpecific::aptxConfig:
+ hidl_codec_config.config.aptxConfig(to_hidl_aptx_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::aptxConfig>()));
+ break;
+ default:
+ break;
+ }
+ return hidl_codec_config;
+}
+
+inline AudioConfig_2_0 to_hidl_audio_config_2_0(
+ const AudioConfiguration& audio_config) {
+ AudioConfig_2_0 hidl_audio_config;
+ if (audio_config.getTag() == AudioConfiguration::pcmConfig) {
+ hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_0(
+ audio_config.get<AudioConfiguration::pcmConfig>()));
+ } else if (audio_config.getTag() == AudioConfiguration::a2dpConfig) {
+ hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+ audio_config.get<AudioConfiguration::a2dpConfig>()));
+ }
+ return hidl_audio_config;
+}
+
+inline PcmConfig_2_1 to_hidl_pcm_config_2_1(
+ const PcmConfiguration& pcm_config) {
+ PcmConfig_2_1 hidl_pcm_config;
+ hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_1(pcm_config.sampleRateHz);
+ hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
+ hidl_pcm_config.bitsPerSample =
+ to_hidl_bits_per_sample(pcm_config.bitsPerSample);
+ hidl_pcm_config.dataIntervalUs =
+ static_cast<uint32_t>(pcm_config.dataIntervalUs);
+ return hidl_pcm_config;
+}
+
+inline Lc3Config_2_1 to_hidl_lc3_config_2_1(
+ const Lc3Configuration& lc3_config) {
+ Lc3Config_2_1 hidl_lc3_config;
+ hidl_lc3_config.pcmBitDepth = to_hidl_bits_per_sample(lc3_config.pcmBitDepth);
+ hidl_lc3_config.samplingFrequency =
+ to_hidl_sample_rate_2_1(lc3_config.samplingFrequencyHz);
+ if (lc3_config.samplingFrequencyHz == 10000)
+ hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_10000US;
+ else if (lc3_config.samplingFrequencyHz == 7500)
+ hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_7500US;
+ hidl_lc3_config.octetsPerFrame =
+ static_cast<uint32_t>(lc3_config.octetsPerFrame);
+ hidl_lc3_config.blocksPerSdu = static_cast<uint32_t>(lc3_config.blocksPerSdu);
+ return hidl_lc3_config;
+}
+
+inline Lc3CodecConfig_2_1 to_hidl_leaudio_config_2_1(
+ const LeAudioConfiguration& leaudio_config) {
+ auto& unicast_config =
+ leaudio_config.modeConfig
+ .get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
+
+ auto& le_codec_config = unicast_config.leAudioCodecConfig
+ .get<LeAudioCodecConfiguration::lc3Config>();
+
+ Lc3CodecConfig_2_1 hidl_lc3_codec_config;
+ hidl_lc3_codec_config.lc3Config = to_hidl_lc3_config_2_1(le_codec_config);
+
+ hidl_lc3_codec_config.audioChannelAllocation =
+ unicast_config.streamMap.size();
+
+ return hidl_lc3_codec_config;
+}
+
+inline LeAudioConfig_2_2 to_hidl_leaudio_config_2_2(
+ const LeAudioConfiguration& leaudio_config) {
+ LeAudioConfig_2_2 hidl_leaudio_config;
+ if (leaudio_mode_to_hidl_map.find(leaudio_config.mode) !=
+ leaudio_mode_to_hidl_map.end()) {
+ hidl_leaudio_config.mode = leaudio_mode_to_hidl_map.at(leaudio_config.mode);
+ }
+
+ if (leaudio_config.modeConfig.getTag() ==
+ LeAudioConfiguration::LeAudioModeConfig::unicastConfig) {
+ auto& unicast_config =
+ leaudio_config.modeConfig
+ .get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
+ ::android::hardware::bluetooth::audio::V2_2::UnicastConfig
+ hidl_unicast_config;
+ hidl_unicast_config.peerDelay =
+ static_cast<uint32_t>(unicast_config.peerDelay);
+
+ auto& lc3_config = unicast_config.leAudioCodecConfig
+ .get<LeAudioCodecConfiguration::lc3Config>();
+ hidl_unicast_config.lc3Config = to_hidl_lc3_config_2_1(lc3_config);
+
+ hidl_unicast_config.streamMap.resize(unicast_config.streamMap.size());
+ for (int i = 0; i < unicast_config.streamMap.size(); i++) {
+ hidl_unicast_config.streamMap[i].audioChannelAllocation =
+ static_cast<uint32_t>(
+ unicast_config.streamMap[i].audioChannelAllocation);
+ hidl_unicast_config.streamMap[i].streamHandle =
+ static_cast<uint16_t>(unicast_config.streamMap[i].streamHandle);
+ }
+ } else if (leaudio_config.modeConfig.getTag() ==
+ LeAudioConfiguration::LeAudioModeConfig::broadcastConfig) {
+ auto bcast_config =
+ leaudio_config.modeConfig
+ .get<LeAudioConfiguration::LeAudioModeConfig::broadcastConfig>();
+ ::android::hardware::bluetooth::audio::V2_2::BroadcastConfig
+ hidl_bcast_config;
+ hidl_bcast_config.streamMap.resize(bcast_config.streamMap.size());
+ for (int i = 0; i < bcast_config.streamMap.size(); i++) {
+ hidl_bcast_config.streamMap[i].audioChannelAllocation =
+ static_cast<uint32_t>(
+ bcast_config.streamMap[i].audioChannelAllocation);
+ hidl_bcast_config.streamMap[i].streamHandle =
+ static_cast<uint16_t>(bcast_config.streamMap[i].streamHandle);
+ hidl_bcast_config.streamMap[i].lc3Config = to_hidl_lc3_config_2_1(
+ bcast_config.streamMap[i]
+ .leAudioCodecConfig.get<LeAudioCodecConfiguration::lc3Config>());
+ }
+ }
+ return hidl_leaudio_config;
+}
+
+inline AudioConfig_2_1 to_hidl_audio_config_2_1(
+ const AudioConfiguration& audio_config) {
+ AudioConfig_2_1 hidl_audio_config;
+ switch (audio_config.getTag()) {
+ case AudioConfiguration::pcmConfig:
+ hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
+ audio_config.get<AudioConfiguration::pcmConfig>()));
+ break;
+ case AudioConfiguration::a2dpConfig:
+ hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+ audio_config.get<AudioConfiguration::a2dpConfig>()));
+ break;
+ case AudioConfiguration::leAudioConfig:
+ hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_config_2_1(
+ audio_config.get<AudioConfiguration::leAudioConfig>()));
+ break;
+ }
+ return hidl_audio_config;
+}
+
+inline AudioConfig_2_2 to_hidl_audio_config_2_2(
+ const AudioConfiguration& audio_config) {
+ AudioConfig_2_2 hidl_audio_config;
+ switch (audio_config.getTag()) {
+ case AudioConfiguration::pcmConfig:
+ hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
+ audio_config.get<AudioConfiguration::pcmConfig>()));
+ break;
+ case AudioConfiguration::a2dpConfig:
+ hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+ audio_config.get<AudioConfiguration::a2dpConfig>()));
+ break;
+ case AudioConfiguration::leAudioConfig:
+ hidl_audio_config.leAudioConfig(to_hidl_leaudio_config_2_2(
+ audio_config.get<AudioConfiguration::leAudioConfig>()));
+ break;
+ }
+ return hidl_audio_config;
+}
+
+/***
+ *
+ * 2.0
+ *
+ ***/
+
+bool HidlToAidlMiddleware_2_0::IsSessionReady(
+ const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::IsSessionReady(
+ from_session_type_2_0(session_type));
+}
+
+uint16_t HidlToAidlMiddleware_2_0::RegisterControlResultCback(
+ const SessionType_2_0& session_type,
+ const PortStatusCallbacks_2_0& cbacks) {
+ PortStatusCallbacks_2_2 callback_2_2{
+ .control_result_cb_ = cbacks.control_result_cb_,
+ .session_changed_cb_ = cbacks.session_changed_cb_,
+ };
+ return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+ static_cast<SessionType_2_1>(session_type), callback_2_2);
+}
+
+void HidlToAidlMiddleware_2_0::UnregisterControlResultCback(
+ const SessionType_2_0& session_type, uint16_t cookie) {
+ HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+ static_cast<SessionType_2_1>(session_type), cookie);
+}
+
+const AudioConfig_2_0 HidlToAidlMiddleware_2_0::GetAudioConfig(
+ const SessionType_2_0& session_type) {
+ return to_hidl_audio_config_2_0(BluetoothAudioSessionControl::GetAudioConfig(
+ from_session_type_2_0(session_type)));
+}
+
+bool HidlToAidlMiddleware_2_0::StartStream(
+ const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::StartStream(
+ from_session_type_2_0(session_type));
+}
+
+void HidlToAidlMiddleware_2_0::StopStream(const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::StopStream(
+ from_session_type_2_0(session_type));
+}
+
+bool HidlToAidlMiddleware_2_0::SuspendStream(
+ const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::SuspendStream(
+ from_session_type_2_0(session_type));
+}
+
+bool HidlToAidlMiddleware_2_0::GetPresentationPosition(
+ const SessionType_2_0& session_type, uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_readed, timespec* data_position) {
+ PresentationPosition presentation_position;
+ auto ret_val = BluetoothAudioSessionControl::GetPresentationPosition(
+ from_session_type_2_0(session_type), presentation_position);
+ if (remote_delay_report_ns)
+ *remote_delay_report_ns = presentation_position.remoteDeviceAudioDelayNanos;
+ if (total_bytes_readed)
+ *total_bytes_readed = presentation_position.transmittedOctets;
+ if (data_position)
+ *data_position = {
+ .tv_sec = static_cast<__kernel_old_time_t>(
+ presentation_position.transmittedOctetsTimestamp.tvSec),
+ .tv_nsec = static_cast<long>(
+ presentation_position.transmittedOctetsTimestamp.tvNSec)};
+ return ret_val;
+}
+
+void HidlToAidlMiddleware_2_0::UpdateTracksMetadata(
+ const SessionType_2_0& session_type,
+ const struct source_metadata* source_metadata) {
+ return BluetoothAudioSessionControl::UpdateSourceMetadata(
+ from_session_type_2_0(session_type), *source_metadata);
+}
+
+size_t HidlToAidlMiddleware_2_0::OutWritePcmData(
+ const SessionType_2_0& session_type, const void* buffer, size_t bytes) {
+ return BluetoothAudioSessionControl::OutWritePcmData(
+ from_session_type_2_0(session_type), buffer, bytes);
+}
+
+bool HidlToAidlMiddleware_2_0::IsAidlAvailable() {
+ return BluetoothAudioSession::IsAidlAvailable();
+}
+
+/***
+ *
+ * 2.1
+ *
+ ***/
+
+const AudioConfig_2_1 HidlToAidlMiddleware_2_1::GetAudioConfig(
+ const SessionType_2_1& session_type) {
+ return to_hidl_audio_config_2_1(BluetoothAudioSessionControl::GetAudioConfig(
+ from_session_type_2_1(session_type)));
+}
+
+/***
+ *
+ * 2.2
+ *
+ ***/
+
+bool HidlToAidlMiddleware_2_2::IsSessionReady(
+ const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::IsSessionReady(
+ from_session_type_2_1(session_type));
+}
+
+uint16_t HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+ const SessionType_2_1& session_type,
+ const PortStatusCallbacks_2_2& cbacks) {
+ LOG(INFO) << __func__ << ": " << toString(session_type);
+ auto aidl_session_type = from_session_type_2_1(session_type);
+ // Pass the exact reference to the lambda
+ auto& session_legacy_callback_table =
+ legacy_callback_table[aidl_session_type];
+ PortStatusCallbacks aidl_callbacks{};
+ if (cbacks.control_result_cb_) {
+ aidl_callbacks.control_result_cb_ =
+ [&session_legacy_callback_table](uint16_t cookie, bool start_resp,
+ const BluetoothAudioStatus& status) {
+ if (session_legacy_callback_table.find(cookie) ==
+ session_legacy_callback_table.end()) {
+ LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+ return;
+ }
+ auto& cback = session_legacy_callback_table[cookie];
+ cback->control_result_cb_(cookie, start_resp, to_hidl_status(status));
+ };
+ }
+ if (cbacks.session_changed_cb_) {
+ aidl_callbacks.session_changed_cb_ =
+ [&session_legacy_callback_table](uint16_t cookie) {
+ if (session_legacy_callback_table.find(cookie) ==
+ session_legacy_callback_table.end()) {
+ LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+ return;
+ }
+ auto& cback = session_legacy_callback_table[cookie];
+ cback->session_changed_cb_(cookie);
+ };
+ };
+ if (cbacks.audio_configuration_changed_cb_) {
+ aidl_callbacks.audio_configuration_changed_cb_ =
+ [&session_legacy_callback_table](uint16_t cookie) {
+ if (session_legacy_callback_table.find(cookie) ==
+ session_legacy_callback_table.end()) {
+ LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+ return;
+ }
+ auto& cback = session_legacy_callback_table[cookie];
+ cback->audio_configuration_changed_cb_(cookie);
+ };
+ };
+ auto cookie = BluetoothAudioSessionControl::RegisterControlResultCback(
+ aidl_session_type, aidl_callbacks);
+ {
+ std::lock_guard<std::mutex> guard(legacy_callback_lock);
+ session_legacy_callback_table[cookie] =
+ std::make_shared<PortStatusCallbacks_2_2>(cbacks);
+ }
+ return cookie;
+}
+
+void HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+ const SessionType_2_1& session_type, uint16_t cookie) {
+ LOG(INFO) << __func__ << ": " << toString(session_type);
+ auto aidl_session_type = from_session_type_2_1(session_type);
+ BluetoothAudioSessionControl::UnregisterControlResultCback(aidl_session_type,
+ cookie);
+ auto& session_callback_table = legacy_callback_table[aidl_session_type];
+ if (session_callback_table.find(cookie) != session_callback_table.end()) {
+ std::lock_guard<std::mutex> guard(legacy_callback_lock);
+ session_callback_table.erase(cookie);
+ }
+}
+
+const AudioConfig_2_2 HidlToAidlMiddleware_2_2::GetAudioConfig(
+ const SessionType_2_1& session_type) {
+ return to_hidl_audio_config_2_2(BluetoothAudioSessionControl::GetAudioConfig(
+ from_session_type_2_1(session_type)));
+}
+
+bool HidlToAidlMiddleware_2_2::StartStream(
+ const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::StartStream(
+ from_session_type_2_1(session_type));
+}
+
+bool HidlToAidlMiddleware_2_2::SuspendStream(
+ const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::SuspendStream(
+ from_session_type_2_1(session_type));
+}
+
+void HidlToAidlMiddleware_2_2::StopStream(const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::StopStream(
+ from_session_type_2_1(session_type));
+}
+
+void HidlToAidlMiddleware_2_2::UpdateSinkMetadata(
+ const SessionType_2_1& session_type,
+ const struct sink_metadata* sink_metadata) {
+ return BluetoothAudioSessionControl::UpdateSinkMetadata(
+ from_session_type_2_1(session_type), *sink_metadata);
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h
new file mode 100644
index 0000000..d10ee37
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.0/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SessionType;
+using PortStatusCallbacks_2_0 =
+ ::android::bluetooth::audio::PortStatusCallbacks;
+using AudioConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_0 {
+ public:
+ static bool IsAidlAvailable();
+
+ static bool IsSessionReady(const SessionType_2_0& session_type);
+
+ static uint16_t RegisterControlResultCback(
+ const SessionType_2_0& session_type,
+ const PortStatusCallbacks_2_0& cbacks);
+
+ static void UnregisterControlResultCback(const SessionType_2_0& session_type,
+ uint16_t cookie);
+
+ static const AudioConfig_2_0 GetAudioConfig(
+ const SessionType_2_0& session_type);
+
+ static bool StartStream(const SessionType_2_0& session_type);
+
+ static void StopStream(const SessionType_2_0& session_type);
+
+ static bool SuspendStream(const SessionType_2_0& session_type);
+
+ static bool GetPresentationPosition(const SessionType_2_0& session_type,
+ uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_readed,
+ timespec* data_position);
+
+ static void UpdateTracksMetadata(
+ const SessionType_2_0& session_type,
+ const struct source_metadata* source_metadata);
+
+ static size_t OutWritePcmData(const SessionType_2_0& session_type,
+ const void* buffer, size_t bytes);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h
new file mode 100644
index 0000000..82dce96
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.1/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::SessionType;
+using AudioConfig_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_1 {
+ public:
+ static const AudioConfig_2_1 GetAudioConfig(
+ const SessionType_2_1& session_type);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
new file mode 100644
index 0000000..149e404
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.2/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+#include "../session/BluetoothAudioSession_2_2.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::SessionType;
+using PortStatusCallbacks_2_0 =
+ ::android::bluetooth::audio::PortStatusCallbacks;
+using PortStatusCallbacks_2_2 =
+ ::android::bluetooth::audio::PortStatusCallbacks_2_2;
+using AudioConfig_2_2 =
+ ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_2 {
+ public:
+ static bool IsSessionReady(const SessionType_2_1& session_type);
+
+ static uint16_t RegisterControlResultCback(
+ const SessionType_2_1& session_type,
+ const PortStatusCallbacks_2_2& cbacks);
+
+ static void UnregisterControlResultCback(const SessionType_2_1& session_type,
+ uint16_t cookie);
+
+ static const AudioConfig_2_2 GetAudioConfig(
+ const SessionType_2_1& session_type);
+
+ static bool StartStream(const SessionType_2_1& session_type);
+
+ static bool SuspendStream(const SessionType_2_1& session_type);
+
+ static void StopStream(const SessionType_2_1& session_type);
+
+ static void UpdateSinkMetadata(const SessionType_2_1& session_type,
+ const struct sink_metadata* sink_metadata);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
index 2f3ddaf..6d5608b 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
@@ -21,10 +21,13 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+
namespace android {
namespace bluetooth {
namespace audio {
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
using ::android::hardware::audio::common::V5_0::AudioContentType;
using ::android::hardware::audio::common::V5_0::AudioUsage;
using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
@@ -149,6 +152,8 @@
// The function helps to check if this session is ready or not
// @return: true if the Bluetooth stack has started the specified session
bool BluetoothAudioSession::IsSessionReady() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::IsSessionReady(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
bool dataMQ_valid =
(session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
@@ -200,6 +205,9 @@
// @return: cookie - the assigned number to this bluetooth_audio output
uint16_t BluetoothAudioSession::RegisterStatusCback(
const PortStatusCallbacks& cbacks) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::RegisterControlResultCback(session_type_,
+ cbacks);
std::lock_guard<std::recursive_mutex> guard(mutex_);
uint16_t cookie = ObserversCookieGetInitValue(session_type_);
uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
@@ -227,6 +235,9 @@
// PortStatusCallbacks
// @param: cookie - indicates which bluetooth_audio output is
void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::UnregisterControlResultCback(session_type_,
+ cookie);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (observers_.erase(cookie) != 1) {
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
@@ -238,6 +249,9 @@
// The control function is for the bluetooth_audio module to get the current
// AudioConfiguration
const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return (audio_config_ =
+ HidlToAidlMiddleware_2_0::GetAudioConfig(session_type_));
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (IsSessionReady()) {
return audio_config_;
@@ -251,6 +265,8 @@
// Those control functions are for the bluetooth_audio module to start, suspend,
// stop stream, to check position, and to update metadata.
bool BluetoothAudioSession::StartStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::StartStream(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -267,6 +283,8 @@
}
bool BluetoothAudioSession::SuspendStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::SuspendStream(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -283,6 +301,8 @@
}
void BluetoothAudioSession::StopStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::StopStream(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
return;
@@ -297,6 +317,10 @@
bool BluetoothAudioSession::GetPresentationPosition(
uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed,
timespec* data_position) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::GetPresentationPosition(
+ session_type_, remote_delay_report_ns, total_bytes_readed,
+ data_position);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -330,6 +354,9 @@
void BluetoothAudioSession::UpdateTracksMetadata(
const struct source_metadata* source_metadata) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::UpdateTracksMetadata(session_type_,
+ source_metadata);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -374,6 +401,9 @@
// The control function writes stream to FMQ
size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
size_t bytes) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::OutWritePcmData(session_type_, buffer,
+ bytes);
if (buffer == nullptr || !bytes) return 0;
size_t totalWritten = 0;
int ms_timeout = kFmqSendTimeoutMs;
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
index bf1f9b5..276a291 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
@@ -21,9 +21,14 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+#include "../aidl_session/HidlToAidlMiddleware_2_1.h"
+
namespace android {
namespace bluetooth {
namespace audio {
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_1;
using SessionType_2_1 =
::android::hardware::bluetooth::audio::V2_1::SessionType;
using SessionType_2_0 =
@@ -72,6 +77,7 @@
} else {
session_type_2_1_ = (session_type);
}
+ raw_session_type_ = session_type;
}
std::shared_ptr<BluetoothAudioSession>
@@ -83,6 +89,8 @@
// AudioConfiguration
const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
BluetoothAudioSession_2_1::GetAudioConfig() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_1::GetAudioConfig(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (audio_session->IsSessionReady()) {
// If session is unknown it means it should be 2.0 type
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
index 5a35153..e634064 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
@@ -31,6 +31,7 @@
std::shared_ptr<BluetoothAudioSession> audio_session;
::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
+ ::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
// audio data configuration for both software and offloading
::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
index 60ac4ec..4613ddc 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
@@ -22,10 +22,15 @@
#include <android-base/stringprintf.h>
#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioPort.h>
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+#include "../aidl_session/HidlToAidlMiddleware_2_2.h"
+
namespace android {
namespace bluetooth {
namespace audio {
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_2;
using ::android::hardware::audio::common::V5_0::AudioSource;
using ::android::hardware::audio::common::V5_0::RecordTrackMetadata;
using ::android::hardware::audio::common::V5_0::SinkMetadata;
@@ -93,6 +98,7 @@
} else {
session_type_2_1_ = (session_type);
}
+ raw_session_type_ = session_type;
invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
invalidOffloadAudioConfiguration.codecConfig(
audio_session->kInvalidCodecConfiguration);
@@ -100,6 +106,8 @@
}
bool BluetoothAudioSession_2_2::IsSessionReady() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::IsSessionReady(raw_session_type_);
if (session_type_2_1_ !=
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
session_type_2_1_ !=
@@ -122,6 +130,9 @@
void BluetoothAudioSession_2_2::UpdateSinkMetadata(
const struct sink_metadata* sink_metadata) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::UpdateSinkMetadata(raw_session_type_,
+ sink_metadata);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
@@ -172,6 +183,8 @@
// AudioConfiguration
const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
BluetoothAudioSession_2_2::GetAudioConfig() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::GetAudioConfig(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (IsSessionReady()) {
auto audio_config_discriminator = audio_config_2_2_.getDiscriminator();
@@ -226,6 +239,8 @@
// Those control functions are for the bluetooth_audio module to start, suspend,
// stop stream, to check position, and to update metadata.
bool BluetoothAudioSession_2_2::StartStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::StartStream(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
@@ -242,6 +257,8 @@
}
bool BluetoothAudioSession_2_2::SuspendStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::SuspendStream(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
@@ -258,6 +275,8 @@
}
void BluetoothAudioSession_2_2::StopStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::StopStream(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
return;
@@ -395,6 +414,9 @@
// @return: cookie - the assigned number to this bluetooth_audio output
uint16_t BluetoothAudioSession_2_2::RegisterStatusCback(
const PortStatusCallbacks_2_2& cbacks) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+ raw_session_type_, cbacks);
if (session_type_2_1_ !=
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
session_type_2_1_ !=
@@ -432,6 +454,9 @@
// PortStatusCallbacks_2_2
// @param: cookie - indicates which bluetooth_audio output is
void BluetoothAudioSession_2_2::UnregisterStatusCback(uint16_t cookie) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+ raw_session_type_, cookie);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (session_type_2_1_ !=
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
index 3673fd8..b6f96ab 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
@@ -68,6 +68,7 @@
std::shared_ptr<BluetoothAudioSession_2_1> audio_session_2_1;
::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
+ ::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
// audio data configuration for both software and offloading
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration