libaudiohal@aidl: Implement calls to IBluetooth*
Match BT SCO, HFP, A2DP and LE parameters and translate
them into corresponding calls on IBluetooth* sub-interfaces
of IModule.
Bug: 278976019
Test: check logcat with AIDL enabled
Change-Id: I84457b9405a085197ab4770c6a101f98693b7b05
Merged-In: I84457b9405a085197ab4770c6a101f98693b7b05
diff --git a/media/libaudiohal/impl/ConversionHelperAidl.h b/media/libaudiohal/impl/ConversionHelperAidl.h
index db6b6cf..5534d13 100644
--- a/media/libaudiohal/impl/ConversionHelperAidl.h
+++ b/media/libaudiohal/impl/ConversionHelperAidl.h
@@ -20,6 +20,9 @@
#include <string_view>
#include <vector>
+#include <android-base/expected.h>
+#include <error/Result.h>
+#include <media/AudioParameter.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -51,4 +54,24 @@
const std::string mClassName;
};
+// 'action' must accept a value of type 'T' and return 'status_t'.
+// The function returns 'true' if the parameter was found, and the action has succeeded.
+// The function returns 'false' if the parameter was not found.
+// Any errors get propagated, if there are errors it means the parameter was found.
+template<typename T, typename F>
+error::Result<bool> filterOutAndProcessParameter(
+ AudioParameter& parameters, const String8& key, const F& action) {
+ if (parameters.containsKey(key)) {
+ T value;
+ status_t status = parameters.get(key, value);
+ if (status == OK) {
+ parameters.remove(key);
+ status = action(value);
+ if (status == OK) return true;
+ }
+ return base::unexpected(status);
+ }
+ return false;
+}
+
} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 3079d91..836dcf8 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -35,6 +35,7 @@
#include "StreamHalAidl.h"
using aidl::android::aidl_utils::statusTFromBinderStatus;
+using aidl::android::media::audio::common::Boolean;
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioConfig;
using aidl::android::media::audio::common::AudioDevice;
@@ -68,6 +69,9 @@
using aidl::android::hardware::audio::common::RecordTrackMetadata;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IBluetooth;
+using aidl::android::hardware::audio::core::IBluetoothA2dp;
+using aidl::android::hardware::audio::core::IBluetoothLe;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::ITelephony;
using aidl::android::hardware::audio::core::ModuleDebug;
@@ -124,7 +128,10 @@
DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module)
: ConversionHelperAidl("DeviceHalAidl"),
mInstance(instance), mModule(module),
- mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)) {
+ mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
+ mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
+ mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
+ mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
}
status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
@@ -265,15 +272,32 @@
return statusTFromBinderStatus(mModule->getMasterMute(state));
}
-status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
- TIME_CHECK();
+status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
if (!mModule) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
+ AudioParameter parameters(kvPairs);
+ ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
+
+ if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
+ ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
+ }
+ if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
+ ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
+ }
+ if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
+ ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
+ }
+ if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
+ ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
+ }
+
+ ALOGW_IF(parameters.size() != 0, "%s: unknown parameters, ignored: \"%s\"",
+ __func__, parameters.toString().c_str());
return OK;
}
status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
TIME_CHECK();
+ // FIXME(b/278976019): Support keyReconfigA2dpSupported via vendor plugin
values->clear();
if (!mModule) return NO_INIT;
ALOGE("%s not implemented yet", __func__);
@@ -1069,6 +1093,150 @@
return OK;
}
+status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter ¶meters) {
+ TIME_CHECK();
+ std::optional<bool> a2dpEnabled;
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
+ parameters, String8(AudioParameter::keyBtA2dpSuspended),
+ [&a2dpEnabled](const String8& trueOrFalse) {
+ if (trueOrFalse == AudioParameter::valueTrue) {
+ a2dpEnabled = false; // 'suspended' == true
+ return OK;
+ } else if (trueOrFalse == AudioParameter::valueFalse) {
+ a2dpEnabled = true; // 'suspended' == false
+ return OK;
+ }
+ ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
+ AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
+ return BAD_VALUE;
+ }));
+ // FIXME(b/278976019): Support keyReconfigA2dp via vendor plugin
+ if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
+ return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
+ }
+ return OK;
+}
+
+status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter ¶meters) {
+ TIME_CHECK();
+ IBluetooth::HfpConfig hfpConfig;
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
+ parameters, String8(AudioParameter::keyBtHfpEnable),
+ [&hfpConfig](const String8& trueOrFalse) {
+ if (trueOrFalse == AudioParameter::valueTrue) {
+ hfpConfig.isEnabled = Boolean{ .value = true };
+ return OK;
+ } else if (trueOrFalse == AudioParameter::valueFalse) {
+ hfpConfig.isEnabled = Boolean{ .value = false };
+ return OK;
+ }
+ ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
+ AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
+ return BAD_VALUE;
+ }));
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
+ parameters, String8(AudioParameter::keyBtHfpSamplingRate),
+ [&hfpConfig](int sampleRate) {
+ return sampleRate > 0 ?
+ hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
+ }));
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
+ parameters, String8(AudioParameter::keyBtHfpVolume),
+ [&hfpConfig](int volume0to15) {
+ if (volume0to15 >= 0 && volume0to15 <= 15) {
+ hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
+ return OK;
+ }
+ return BAD_VALUE;
+ }));
+ if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
+ IBluetooth::HfpConfig newHfpConfig;
+ return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
+ }
+ return OK;
+}
+
+status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter ¶meters) {
+ TIME_CHECK();
+ std::optional<bool> leEnabled;
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
+ parameters, String8(AudioParameter::keyBtLeSuspended),
+ [&leEnabled](const String8& trueOrFalse) {
+ if (trueOrFalse == AudioParameter::valueTrue) {
+ leEnabled = false; // 'suspended' == true
+ return OK;
+ } else if (trueOrFalse == AudioParameter::valueFalse) {
+ leEnabled = true; // 'suspended' == false
+ return OK;
+ }
+ ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
+ AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
+ return BAD_VALUE;
+ }));
+ if (mBluetoothLe != nullptr && leEnabled.has_value()) {
+ return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
+ }
+ return OK;
+}
+
+status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter ¶meters) {
+ TIME_CHECK();
+ IBluetooth::ScoConfig scoConfig;
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
+ parameters, String8(AudioParameter::keyBtSco),
+ [&scoConfig](const String8& onOrOff) {
+ if (onOrOff == AudioParameter::valueOn) {
+ scoConfig.isEnabled = Boolean{ .value = true };
+ return OK;
+ } else if (onOrOff == AudioParameter::valueOff) {
+ scoConfig.isEnabled = Boolean{ .value = false };
+ return OK;
+ }
+ ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
+ AudioParameter::keyBtSco, onOrOff.c_str());
+ return BAD_VALUE;
+ }));
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
+ parameters, String8(AudioParameter::keyBtScoHeadsetName),
+ [&scoConfig](const String8& name) {
+ scoConfig.debugName = name;
+ return OK;
+ }));
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
+ parameters, String8(AudioParameter::keyBtNrec),
+ [&scoConfig](const String8& onOrOff) {
+ if (onOrOff == AudioParameter::valueOn) {
+ scoConfig.isNrecEnabled = Boolean{ .value = true };
+ return OK;
+ } else if (onOrOff == AudioParameter::valueOff) {
+ scoConfig.isNrecEnabled = Boolean{ .value = false };
+ return OK;
+ }
+ ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
+ AudioParameter::keyBtNrec, onOrOff.c_str());
+ return BAD_VALUE;
+ }));
+ (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
+ parameters, String8(AudioParameter::keyBtScoWb),
+ [&scoConfig](const String8& onOrOff) {
+ if (onOrOff == AudioParameter::valueOn) {
+ scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
+ return OK;
+ } else if (onOrOff == AudioParameter::valueOff) {
+ scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
+ return OK;
+ }
+ ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
+ AudioParameter::keyBtScoWb, onOrOff.c_str());
+ return BAD_VALUE;
+ }));
+ if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
+ IBluetooth::ScoConfig newScoConfig;
+ return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
+ }
+ return OK;
+}
+
status_t DeviceHalAidl::findOrCreatePatch(
const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 7e1ee27..e29ae79 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -210,6 +210,10 @@
status_t createOrUpdatePortConfig(
const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
PortConfigs::iterator* result, bool *created);
+ status_t filterAndUpdateBtA2dpParameters(AudioParameter ¶meters);
+ status_t filterAndUpdateBtHfpParameters(AudioParameter ¶meters);
+ status_t filterAndUpdateBtLeParameters(AudioParameter ¶meters);
+ status_t filterAndUpdateBtScoParameters(AudioParameter ¶meters);
status_t findOrCreatePatch(
const std::set<int32_t>& sourcePortConfigIds,
const std::set<int32_t>& sinkPortConfigIds,
@@ -284,6 +288,9 @@
const std::string mInstance;
const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule;
const std::shared_ptr<::aidl::android::hardware::audio::core::ITelephony> mTelephony;
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetooth> mBluetooth;
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothA2dp> mBluetoothA2dp;
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothLe> mBluetoothLe;
Ports mPorts;
int32_t mDefaultInputPortId = -1;
int32_t mDefaultOutputPortId = -1;
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index eccdfe8..d1044dc 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -122,30 +122,6 @@
return OK;
}
-namespace {
-
-// 'action' must accept a value of type 'T' and return 'status_t'.
-// The function returns 'true' if the parameter was found, and the action has succeeded.
-// The function returns 'false' if the parameter was not found.
-// Any errors get propagated, if there are errors it means the parameter was found.
-template<typename T, typename F>
-error::Result<bool> filterOutAndProcessParameter(
- AudioParameter& parameters, const String8& key, const F& action) {
- if (parameters.containsKey(key)) {
- T value;
- status_t status = parameters.get(key, value);
- if (status == OK) {
- parameters.remove(key);
- status = action(value);
- if (status == OK) return true;
- }
- return base::unexpected(status);
- }
- return false;
-}
-
-} // namespace
-
status_t StreamHalAidl::setParameters(const String8& kvPairs) {
TIME_CHECK();
if (!mStream) return NO_INIT;
@@ -579,10 +555,10 @@
if (!mStream) return NO_INIT;
AudioParameter parameters(kvPairs);
- ALOGD("%s parameters: %s", __func__, parameters.toString().c_str());
+ ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
if (status_t status = filterAndUpdateOffloadMetadata(parameters); status != OK) {
- ALOGW("%s filtering or updating offload metadata failed: %d", __func__, status);
+ ALOGW("%s: filtering or updating offload metadata failed: %d", __func__, status);
}
return StreamHalAidl::setParameters(parameters.toString());