From 8a6930870efed057f9841dd82130e927b711a2d4 Mon Sep 17 00:00:00 2001 From: Francois Gaffie Date: Tue, 8 Feb 2022 17:40:14 +0100 Subject: [PATCH] Update Default AudioControl AIDL HAL for version 2 - Add Gain Callback to notify unexpected gain changed from HAL (as currently done for Audio Focus). - Add dumpsys commands Bug: 154906631 Test: build and run VTS tests Signed-off-by: Francois Gaffie Change-Id: I6be9620feb19d766d43be7199be2e9cd6d63c644 Merged-In: I6be9620feb19d766d43be7199be2e9cd6d63c644 (cherry picked from commit 625a8984e8cdcfc908101a3b94e76b3a2f023eb6) --- .../audiocontrol/aidl/default/Android.bp | 3 +- .../aidl/default/AudioControl.cpp | 254 +++++++++++++++++- .../audiocontrol/aidl/default/AudioControl.h | 30 +++ .../aidl/default/audiocontrol-default.xml | 2 +- 4 files changed, 284 insertions(+), 5 deletions(-) diff --git a/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp index 1439cce606..6bf4b9d860 100644 --- a/automotive/audiocontrol/aidl/default/Android.bp +++ b/automotive/audiocontrol/aidl/default/Android.bp @@ -29,8 +29,9 @@ cc_binary { vendor: true, shared_libs: [ "android.hardware.audio.common@7.0-enums", + "android.hardware.audio.common-V1-ndk", "android.frameworks.automotive.powerpolicy-V1-ndk", - "android.hardware.automotive.audiocontrol-V1-ndk", + "android.hardware.automotive.audiocontrol-V2-ndk", "libbase", "libbinder_ndk", "libcutils", diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp index c0bc796cdf..a121f8be21 100644 --- a/automotive/audiocontrol/aidl/default/AudioControl.cpp +++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp @@ -30,6 +30,8 @@ #include #include +#include + #include namespace aidl::android::hardware::automotive::audiocontrol { @@ -147,6 +149,47 @@ ndk::ScopedAStatus AudioControl::onDevicesToMuteChange( return ndk::ScopedAStatus::ok(); } +template +static inline std::string toString(const std::vector& in_values) { + return std::accumulate(std::begin(in_values), std::end(in_values), std::string{}, + [](std::string& ls, const aidl_type& rs) { + return ls += (ls.empty() ? "" : ",") + rs.toString(); + }); +} +template +static inline std::string toEnumString(const std::vector& in_values) { + return std::accumulate(std::begin(in_values), std::end(in_values), std::string{}, + [](std::string& ls, const aidl_enum_type& rs) { + return ls += (ls.empty() ? "" : ",") + toString(rs); + }); +} + +ndk::ScopedAStatus AudioControl::onAudioFocusChangeWithMetaData( + const audiohalcommon::PlaybackTrackMetadata& in_playbackMetaData, int32_t in_zoneId, + AudioFocusChange in_focusChange) { + LOG(INFO) << "Focus changed: " << toString(in_focusChange).c_str() << " for metadata " + << in_playbackMetaData.toString().c_str() << " in zone " << in_zoneId; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus AudioControl::setAudioDeviceGainsChanged( + const std::vector& in_reasons, const std::vector& in_gains) { + LOG(INFO) << "Audio Device Gains changed: resons:" << toEnumString(in_reasons).c_str() + << " for devices: " << toString(in_gains).c_str(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus AudioControl::registerGainCallback( + const std::shared_ptr& in_callback) { + LOG(DEBUG) << ": " << __func__; + if (in_callback) { + std::atomic_store(&mAudioGainCallback, in_callback); + } else { + LOG(ERROR) << "Unexpected nullptr for audio gain callback resulting in no-op."; + } + return ndk::ScopedAStatus::ok(); +} + binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) { if (numArgs == 0) { return dumpsys(fd); @@ -159,6 +202,12 @@ binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) return cmdRequestFocus(fd, args, numArgs); } else if (EqualsIgnoreCase(option, "--abandon")) { return cmdAbandonFocus(fd, args, numArgs); + } else if (EqualsIgnoreCase(option, "--requestFocusWithMetaData")) { + return cmdRequestFocusWithMetaData(fd, args, numArgs); + } else if (EqualsIgnoreCase(option, "--abandonFocusWithMetaData")) { + return cmdAbandonFocusWithMetaData(fd, args, numArgs); + } else if (EqualsIgnoreCase(option, "--audioGainCallback")) { + return cmdOnAudioDeviceGainsChanged(fd, args, numArgs); } else { dprintf(fd, "Invalid option: %s\n", option.c_str()); return STATUS_BAD_VALUE; @@ -171,20 +220,49 @@ binder_status_t AudioControl::dumpsys(int fd) { } else { dprintf(fd, "Focus listener registered\n"); } + dprintf(fd, "AudioGainCallback %sregistered\n", (mAudioGainCallback == nullptr ? "NOT " : "")); return STATUS_OK; } binder_status_t AudioControl::cmdHelp(int fd) const { dprintf(fd, "Usage: \n\n"); - dprintf(fd, "[no args]: dumps focus listener status\n"); + dprintf(fd, "[no args]: dumps focus listener / gain callback registered status\n"); dprintf(fd, "--help: shows this help\n"); dprintf(fd, "--request : requests audio focus for specified " - "usage (string), audio zone ID (int), and focus gain type (int)\n"); + "usage (string), audio zone ID (int), and focus gain type (int)\n" + "Deprecated, use MetaData instead\n"); dprintf(fd, "--abandon : abandons audio focus for specified usage (string) and " - "audio zone ID (int)\n"); + "audio zone ID (int)\n" + "Deprecated, use MetaData instead\n"); dprintf(fd, "See audio_policy_configuration.xsd for valid AudioUsage values.\n"); + + dprintf(fd, + "--requestFocusWithMetaData : " + "requests audio focus for specified metadata, audio zone ID (int), " + "and focus gain type (int)\n"); + dprintf(fd, + "--abandonFocusWithMetaData : " + "abandons audio focus for specified metadata and audio zone ID (int)\n"); + dprintf(fd, + "--audioGainCallback [, ...]" + " [ ...]: fire audio " + "gain callback for audio zone ID (int), the given reasons (csv int) for given pairs " + "of device address (string) and gain index (int) \n"); + + dprintf(fd, + "Note on : specified as where (int)usage, " + "(int)content type and tags (string)string)\n"); + dprintf(fd, + "See android/media/audio/common/AudioUsageType.aidl for valid AudioUsage values.\n"); + dprintf(fd, + "See android/media/audio/common/AudioContentType.aidl for valid AudioContentType " + "values.\n"); + dprintf(fd, + "Tags are optional. If provided, it must follow the = pattern, where the " + "value is namespaced (for example com.google.strategy=VR).\n"); + return STATUS_OK; } @@ -266,4 +344,174 @@ binder_status_t AudioControl::cmdAbandonFocus(int fd, const char** args, uint32_ return STATUS_OK; } +binder_status_t AudioControl::parseMetaData(int fd, const std::string& metadataLiteral, + audiohalcommon::PlaybackTrackMetadata& trackMetadata) { + std::stringstream csvMetaData(metadataLiteral); + std::vector splitMetaData; + std::string attribute; + while (getline(csvMetaData, attribute, ',')) { + splitMetaData.push_back(attribute); + } + if (splitMetaData.size() != 2 && splitMetaData.size() != 3) { + dprintf(fd, + "Invalid metadata: %s, please provide as " + "where (int)usage, (int)content type and tags (string)string)\n", + metadataLiteral.c_str()); + return STATUS_BAD_VALUE; + } + int usage; + if (!safelyParseInt(splitMetaData[0], &usage)) { + dprintf(fd, "Non-integer usage provided with request: %s\n", splitMetaData[0].c_str()); + return STATUS_BAD_VALUE; + } + int contentType; + if (!safelyParseInt(splitMetaData[1], &contentType)) { + dprintf(fd, "Non-integer content type provided with request: %s\n", + splitMetaData[1].c_str()); + return STATUS_BAD_VALUE; + } + const std::string tags = (splitMetaData.size() == 3 ? splitMetaData[2] : ""); + + trackMetadata = {.usage = static_cast(usage), + .contentType = static_cast(contentType), + .tags = {tags}}; + return STATUS_OK; +} + +binder_status_t AudioControl::cmdRequestFocusWithMetaData(int fd, const char** args, + uint32_t numArgs) { + if (!checkCallerHasWritePermissions(fd)) { + return STATUS_PERMISSION_DENIED; + } + if (numArgs != 4) { + dprintf(fd, + "Invalid number of arguments: please provide:\n" + "--requestFocusWithMetaData : " + "requests audio focus for specified metadata, audio zone ID (int), " + "and focus gain type (int)\n"); + return STATUS_BAD_VALUE; + } + std::string metadataLiteral = std::string(args[1]); + audiohalcommon::PlaybackTrackMetadata trackMetadata{}; + auto status = parseMetaData(fd, metadataLiteral, trackMetadata); + if (status != STATUS_OK) { + return status; + } + + int zoneId; + if (!safelyParseInt(std::string(args[2]), &zoneId)) { + dprintf(fd, "Non-integer zoneId provided with request: %s\n", std::string(args[2]).c_str()); + return STATUS_BAD_VALUE; + } + + int focusGainValue; + if (!safelyParseInt(std::string(args[3]), &focusGainValue)) { + dprintf(fd, "Non-integer focusGain provided with request: %s\n", + std::string(args[3]).c_str()); + return STATUS_BAD_VALUE; + } + AudioFocusChange focusGain = AudioFocusChange(focusGainValue); + + if (mFocusListener == nullptr) { + dprintf(fd, "Unable to request focus - no focus listener registered\n"); + return STATUS_BAD_VALUE; + } + mFocusListener->requestAudioFocusWithMetaData(trackMetadata, zoneId, focusGain); + dprintf(fd, "Requested focus for metadata %s, zoneId %d, and focusGain %d\n", + trackMetadata.toString().c_str(), zoneId, focusGain); + return STATUS_OK; +} + +binder_status_t AudioControl::cmdAbandonFocusWithMetaData(int fd, const char** args, + uint32_t numArgs) { + if (!checkCallerHasWritePermissions(fd)) { + return STATUS_PERMISSION_DENIED; + } + if (numArgs != 3) { + dprintf(fd, + "Invalid number of arguments: please provide:\n" + "--abandonFocusWithMetaData : " + "abandons audio focus for specified metadata and audio zone ID (int)\n"); + return STATUS_BAD_VALUE; + } + std::string metadataLiteral = std::string(args[1]); + audiohalcommon::PlaybackTrackMetadata trackMetadata{}; + auto status = parseMetaData(fd, metadataLiteral, trackMetadata); + if (status != STATUS_OK) { + return status; + } + int zoneId; + if (!safelyParseInt(std::string(args[2]), &zoneId)) { + dprintf(fd, "Non-integer zoneId provided with request: %s\n", std::string(args[2]).c_str()); + return STATUS_BAD_VALUE; + } + if (mFocusListener == nullptr) { + dprintf(fd, "Unable to abandon focus - no focus listener registered\n"); + return STATUS_BAD_VALUE; + } + + mFocusListener->abandonAudioFocusWithMetaData(trackMetadata, zoneId); + dprintf(fd, "Abandoned focus for metadata %s and zoneId %d\n", trackMetadata.toString().c_str(), + zoneId); + return STATUS_OK; +} + +binder_status_t AudioControl::cmdOnAudioDeviceGainsChanged(int fd, const char** args, + uint32_t numArgs) { + if (!checkCallerHasWritePermissions(fd)) { + return STATUS_PERMISSION_DENIED; + } + if ((numArgs + 1) % 2 != 0) { + dprintf(fd, + "Invalid number of arguments: please provide\n" + "--audioGainCallback [, ...]" + " [ ...]: " + "fire audio gain callback for audio zone ID (int), " + "with the given reasons (csv int) for given pairs of device address (string) " + "and gain index (int) \n"); + return STATUS_BAD_VALUE; + } + int zoneId; + if (!safelyParseInt(string(args[1]), &zoneId)) { + dprintf(fd, "Non-integer zoneId provided with request: %s\n", std::string(args[1]).c_str()); + return STATUS_BAD_VALUE; + } + std::string reasonsLiteral = std::string(args[2]); + std::stringstream csvReasonsLiteral(reasonsLiteral); + std::vector reasons; + std::string reasonLiteral; + while (getline(csvReasonsLiteral, reasonLiteral, ',')) { + int reason; + if (!safelyParseInt(reasonLiteral, &reason)) { + dprintf(fd, "Invalid Reason(s) provided %s\n", reasonLiteral.c_str()); + return STATUS_BAD_VALUE; + } + reasons.push_back(static_cast(reason)); + } + + std::vector agcis{}; + for (uint32_t i = 3; i < numArgs; i += 2) { + std::string deviceAddress = std::string(args[i]); + int32_t index; + if (!safelyParseInt(std::string(args[i + 1]), &index)) { + dprintf(fd, "Non-integer index provided with request: %s\n", + std::string(args[i + 1]).c_str()); + return STATUS_BAD_VALUE; + } + AudioGainConfigInfo agci{zoneId, deviceAddress, index}; + agcis.push_back(agci); + } + if (mAudioGainCallback == nullptr) { + dprintf(fd, + "Unable to trig audio gain callback for reasons=%s and gains=%s\n" + " - no audio gain callback registered\n", + toEnumString(reasons).c_str(), toString(agcis).c_str()); + return STATUS_BAD_VALUE; + } + + mAudioGainCallback->onAudioDeviceGainsChanged(reasons, agcis); + dprintf(fd, "Fired audio gain callback for reasons=%s and gains=%s\n", + toEnumString(reasons).c_str(), toString(agcis).c_str()); + return STATUS_OK; +} } // namespace aidl::android::hardware::automotive::audiocontrol diff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h index cca9c44004..16b80e890c 100644 --- a/automotive/audiocontrol/aidl/default/AudioControl.h +++ b/automotive/audiocontrol/aidl/default/AudioControl.h @@ -17,12 +17,20 @@ #define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_AUDIOCONTROL_H #include +#include #include #include +#include #include +#include + +#include namespace aidl::android::hardware::automotive::audiocontrol { +namespace audiohalcommon = ::aidl::android::hardware::audio::common; +namespace audiomediacommon = ::aidl::android::media::audio::common; + class AudioControl : public BnAudioControl { public: ndk::ScopedAStatus onAudioFocusChange(const std::string& in_usage, int32_t in_zoneId, @@ -35,6 +43,15 @@ class AudioControl : public BnAudioControl { const std::shared_ptr& in_listener) override; ndk::ScopedAStatus setBalanceTowardRight(float in_value) override; ndk::ScopedAStatus setFadeTowardFront(float in_value) override; + ndk::ScopedAStatus onAudioFocusChangeWithMetaData( + const audiohalcommon::PlaybackTrackMetadata& in_playbackMetaData, int32_t in_zoneId, + AudioFocusChange in_focusChange) override; + ndk::ScopedAStatus setAudioDeviceGainsChanged( + const std::vector& in_reasons, + const std::vector& in_gains) override; + ndk::ScopedAStatus registerGainCallback( + const std::shared_ptr& in_callback) override; + binder_status_t dump(int fd, const char** args, uint32_t numArgs) override; private: @@ -44,9 +61,22 @@ class AudioControl : public BnAudioControl { // listener, then it should also include mutexes or make the listener atomic. std::shared_ptr mFocusListener; + /** + * @brief mAudioGainCallback will be used by this HAL instance to communicate e.g. with a single + * instance of CarAudioService to report unexpected gain changed. + */ + std::shared_ptr mAudioGainCallback = nullptr; + binder_status_t cmdHelp(int fd) const; binder_status_t cmdRequestFocus(int fd, const char** args, uint32_t numArgs); binder_status_t cmdAbandonFocus(int fd, const char** args, uint32_t numArgs); + binder_status_t cmdRequestFocusWithMetaData(int fd, const char** args, uint32_t numArgs); + binder_status_t cmdAbandonFocusWithMetaData(int fd, const char** args, uint32_t numArgs); + binder_status_t cmdOnAudioDeviceGainsChanged(int fd, const char** args, uint32_t numArgs); + + binder_status_t parseMetaData(int fd, const std::string& metadataLiteral, + audiohalcommon::PlaybackTrackMetadata& trackMetadata); + binder_status_t dumpsys(int fd); }; diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml index f95d05fe77..e82f6fada9 100644 --- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml +++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml @@ -1,4 +1,4 @@ - + android.hardware.automotive.audiocontrol IAudioControl/default