Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1253974 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Cherrypicker Worker
Browse files

System-side vendor extension for handling vendor parameters

A mechanism for handling vendor parameters of the Core Audio HAL
is introduced. It is realized by means of a system side interface
'IHalAdapterVendorExtension' which can be implemented by the
vendor in order to provide bidirectional translation between raw
key-value pairs and structured VendorParameter parcelables.

If an instance of 'IHalAdapterVendorExtension' is provided
(for example, via a system ext partition), the audio framework
will use it in order to process parameters that do not map
to methods and fields of AOSP Core Audio HAL interfaces,
and call 'IModule|IStreamCommon.get|setVendorParameters'.

Bug: 274433842
Bug: 278976019
Test: atest CoreAudioHalAidlTest
(cherry picked from https://android-review.googlesource.com/q/commit:e7a26adc8d891328fcce5fb14bbc988aa962f128)
Merged-In: I8e77238d85cfa91bd7b53e20ad42bd195160fb04
Change-Id: I8e77238d85cfa91bd7b53e20ad42bd195160fb04
parent baab5014
Loading
Loading
Loading
Loading
+24 −0
Original line number Original line Diff line number Diff line
@@ -102,3 +102,27 @@ cc_library_headers {
        },
        },
    },
    },
}
}

aidl_interface {
    name: "av-audio-types-aidl",
    unstable: true,
    host_supported: true,
    vendor_available: true,
    double_loadable: true,
    local_include_dir: "aidl",
    srcs: [
        "aidl/android/media/audio/IHalAdapterVendorExtension.aidl",
    ],
    imports: [
        "android.hardware.audio.core-V1",
    ],
    backend: {
        // The C++ backend is disabled transitively due to use of FMQ by the audio core HAL.
        cpp: {
            enabled: false,
        },
        java: {
            sdk_version: "module_current",
        },
    },
}
+136 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media.audio;

import android.hardware.audio.core.VendorParameter;

/**
 * This interface is used by the HAL adapter of the Audio Server. Implementation
 * is optional. Vendors may provide an implementation on the system_ext
 * partition. The default instance of this interface, if provided, must be
 * registered prior to the moment when the audio server connects to HAL modules.
 *
 * {@hide}
 */
interface IHalAdapterVendorExtension {
    enum ParameterScope {
        MODULE = 0,
        STREAM = 1,
    }

    /**
     * Parse raw parameter keys into vendor parameter ids.
     *
     * This method prepares arguments for a call to the 'getVendorParameters'
     * method of an 'IModule' or an 'IStreamCommon' interface instance,
     * depending on the provided scope.
     *
     * The client calls this method in order to prepare arguments for a call to
     * the particular Core HAL interface. The result returned by the HAL is then
     * processed using the 'processVendorParameters' method. It is not required
     * to maintain a 1:1 correspondence between the provided raw keys and the
     * elements of the parsed result. If the returned list is empty, the call of
     * 'getVendorParameters' is skipped. The implementation can either ignore
     * keys which it does not recognize, or throw an error. The latter is
     * preferred as it can help in discovering malformed key names.
     *
     * @param scope The scope of all raw parameter keys.
     * @param rawKeys Raw parameter keys, joined into a string using a semicolon
     *                (';') as the delimiter.
     * @return A list of vendor parameter IDs, see android.hardware.audio.core.VendorParameter.
     * @throws EX_ILLEGAL_ARGUMENT If the implementation can not parse the raw keys
     *                             and prefers to signal an error.
     */
    @utf8InCpp String[] parseVendorParameterIds(
            ParameterScope scope, in @utf8InCpp String rawKeys);

    /**
     * Parse raw parameter key-value pairs into vendor parameters.
     *
     * This method prepares arguments for a call to the 'setVendorParameters'
     * method of an 'IModule' or an 'IStreamCommon' interface instance,
     * depending on the provided scope.
     *
     * The vendor parameters returned using 'syncParameters' argument is then
     * used to call the 'setVendorParameters' method with 'async = false', and
     * 'asyncParameters' is used in a subsequent call to the same method, but
     * with 'async = true'. It is not required to maintain a 1:1 correspondence
     * between the provided key-value pairs and the elements of parsed
     * results. If any of the returned lists of vendor parameters is empty, then
     * the corresponding call is skipped. The implementation can either ignore
     * keys which it does not recognize, and invalid values, or throw an
     * error. The latter is preferred as it can help in discovering malformed
     * key names and values.
     *
     * @param scope The scope of all raw key-value pairs.
     * @param rawKeys Raw key-value pairs, separated by the "equals" sign ('='),
     *                joined into a string using a semicolon (';') as the delimiter.
     * @param syncParameters A list of vendor parameters to be set synchronously.
     * @param asyncParameters A list of vendor parameters to be set asynchronously.
     * @throws EX_ILLEGAL_ARGUMENT If the implementation can not parse raw key-value
     *                             pairs and prefers to signal an error.
     */
    void parseVendorParameters(
            ParameterScope scope, in @utf8InCpp String rawKeysAndValues,
            out VendorParameter[] syncParameters, out VendorParameter[] asyncParameters);

    /**
     * Parse raw value of the parameter for BT A2DP reconfiguration.
     *
     * This method may return any number of vendor parameters (including zero)
     * which will be passed to the 'IBluetoothA2dp.reconfigureOffload' method.
     *
     * @param rawValue An unparsed value of the legacy parameter.
     * @return A list of vendor parameters.
     * @throws EX_ILLEGAL_ARGUMENT If the implementation can not parse the raw value.
     */
    VendorParameter[] parseBluetoothA2dpReconfigureOffload(in @utf8InCpp String rawValue);

    /**
     * Parse raw value of the parameter for BT LE reconfiguration.
     *
     * This method may return any number of vendor parameters (including zero)
     * which will be passed to the 'IBluetoothLe.reconfigureOffload' method.
     *
     * @param rawValue An unparsed value of the legacy parameter.
     * @return A list of vendor parameters.
     * @throws EX_ILLEGAL_ARGUMENT If the implementation can not parse the raw value.
     */
    VendorParameter[] parseBluetoothLeReconfigureOffload(in @utf8InCpp String rawValue);

    /**
     * Process vendor parameters returned by the Audio Core HAL.
     *
     * This processes the result returned from a call to the
     * 'getVendorParameters' method of an 'IModule' or an 'IStreamCommon'
     * interface instance, depending on the provided scope.
     *
     * See 'parseVendorParameterIds' method for the flow description.  It is not
     * required to maintain a 1:1 correspondence between the elements of the
     * provided list and the emitted key-value pairs. The returned string with
     * raw key-value pairs is passed back to the framework.
     *
     * @param scope The scope of vendor parameters.
     * @param parameters Vendor parameters, see android.hardware.audio.core.VendorParameter.
     * @return Key-value pairs, separated by the "equals" sign ('='),
     *         joined into a string using a semicolon (';') as the delimiter.
     * @throws EX_ILLEGAL_ARGUMENT If the implementation can not emit raw key-value
     *                             pairs and prefers to signal an error.
     */
    @utf8InCpp String processVendorParameters(
            ParameterScope scope, in VendorParameter[] parameters);
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -257,6 +257,7 @@ cc_defaults {
    shared_libs: [
    shared_libs: [
        "android.hardware.common-V2-ndk",
        "android.hardware.common-V2-ndk",
        "android.hardware.common.fmq-V1-ndk",
        "android.hardware.common.fmq-V1-ndk",
        "av-audio-types-aidl-ndk",
        "libaudio_aidl_conversion_common_cpp",
        "libaudio_aidl_conversion_common_cpp",
        "libaudio_aidl_conversion_common_ndk",
        "libaudio_aidl_conversion_common_ndk",
        "libaudio_aidl_conversion_common_ndk_cpp",
        "libaudio_aidl_conversion_common_ndk_cpp",
@@ -315,6 +316,7 @@ cc_library_shared {
filegroup {
filegroup {
    name: "core_audio_hal_aidl_src_files",
    name: "core_audio_hal_aidl_src_files",
    srcs: [
    srcs: [
        "ConversionHelperAidl.cpp",
        "DeviceHalAidl.cpp",
        "DeviceHalAidl.cpp",
        "DevicesFactoryHalAidl.cpp",
        "DevicesFactoryHalAidl.cpp",
        "StreamHalAidl.cpp",
        "StreamHalAidl.cpp",
+125 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2023 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 "ConversionHelperAidl"

#include <memory>

#include <media/AidlConversionUtil.h>
#include <utils/Log.h>

#include "ConversionHelperAidl.h"

using aidl::android::aidl_utils::statusTFromBinderStatus;
using aidl::android::hardware::audio::core::VendorParameter;
using aidl::android::media::audio::IHalAdapterVendorExtension;

namespace android {

status_t parseAndGetVendorParameters(
        std::shared_ptr<IHalAdapterVendorExtension> vendorExt,
        const VendorParametersRecipient& recipient,
        const AudioParameter& parameterKeys,
        String8* values) {
    using ParameterScope = IHalAdapterVendorExtension::ParameterScope;
    if (parameterKeys.size() == 0) return OK;
    const String8 rawKeys = parameterKeys.keysToString();
    if (vendorExt == nullptr) {
        ALOGW("%s: unknown parameters, ignored: \"%s\"", __func__, rawKeys.c_str());
        return OK;
    }

    std::vector<std::string> parameterIds;
    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(vendorExt->parseVendorParameterIds(
                            ParameterScope(recipient.index()),
                            std::string(rawKeys.c_str()), &parameterIds)));
    if (parameterIds.empty()) return OK;

    std::vector<VendorParameter> parameters;
    if (recipient.index() == static_cast<int>(ParameterScope::MODULE)) {
        auto module = std::get<static_cast<int>(ParameterScope::MODULE)>(recipient);
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(module->getVendorParameters(
                                parameterIds, &parameters)));
    } else if (recipient.index() == static_cast<int>(ParameterScope::STREAM)) {
        auto stream = std::get<static_cast<int>(ParameterScope::STREAM)>(recipient);
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(stream->getVendorParameters(
                                parameterIds, &parameters)));
    } else {
        LOG_ALWAYS_FATAL("%s: unexpected recipient variant index: %zu",
                __func__, recipient.index());
    }
    if (!parameters.empty()) {
        std::string vendorParameters;
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(vendorExt->processVendorParameters(
                                ParameterScope(recipient.index()),
                                parameters, &vendorParameters)));
        // Re-parse the vendor-provided string to ensure that it is correct.
        AudioParameter reparse(String8(vendorParameters.c_str()));
        if (reparse.size() != 0) {
            if (!values->empty()) {
                values->append(";");
            }
            values->append(reparse.toString().c_str());
        }
    }
    return OK;
}

status_t parseAndSetVendorParameters(
        std::shared_ptr<IHalAdapterVendorExtension> vendorExt,
        const VendorParametersRecipient& recipient,
        const AudioParameter& parameters) {
    using ParameterScope = IHalAdapterVendorExtension::ParameterScope;
    if (parameters.size() == 0) return OK;
    const String8 rawKeysAndValues = parameters.toString();
    if (vendorExt == nullptr) {
        ALOGW("%s: unknown parameters, ignored: \"%s\"", __func__, rawKeysAndValues.c_str());
        return OK;
    }

    std::vector<VendorParameter> syncParameters, asyncParameters;
    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(vendorExt->parseVendorParameters(
                            ParameterScope(recipient.index()),
                            std::string(rawKeysAndValues.c_str()),
                            &syncParameters, &asyncParameters)));
    if (recipient.index() == static_cast<int>(ParameterScope::MODULE)) {
        auto module = std::get<static_cast<int>(ParameterScope::MODULE)>(recipient);
        if (!syncParameters.empty()) {
            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(module->setVendorParameters(
                                    syncParameters, false /*async*/)));
        }
        if (!asyncParameters.empty()) {
            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(module->setVendorParameters(
                                    asyncParameters, true /*async*/)));
        }
    } else if (recipient.index() == static_cast<int>(ParameterScope::STREAM)) {
        auto stream = std::get<static_cast<int>(ParameterScope::STREAM)>(recipient);
        if (!syncParameters.empty()) {
            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(stream->setVendorParameters(
                                    syncParameters, false /*async*/)));
        }
        if (!asyncParameters.empty()) {
            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(stream->setVendorParameters(
                                    asyncParameters, true /*async*/)));
        }
    } else {
        LOG_ALWAYS_FATAL("%s: unexpected recipient variant index: %zu",
                __func__, recipient.index());
    }
    return OK;
}

} // namespace android
+18 −0
Original line number Original line Diff line number Diff line
@@ -18,8 +18,12 @@


#include <string>
#include <string>
#include <string_view>
#include <string_view>
#include <variant>
#include <vector>
#include <vector>


#include <aidl/android/hardware/audio/core/IModule.h>
#include <aidl/android/hardware/audio/core/IStreamCommon.h>
#include <aidl/android/media/audio/IHalAdapterVendorExtension.h>
#include <android-base/expected.h>
#include <android-base/expected.h>
#include <error/Result.h>
#include <error/Result.h>
#include <media/AudioParameter.h>
#include <media/AudioParameter.h>
@@ -74,4 +78,18 @@ error::Result<bool> filterOutAndProcessParameter(
    return false;
    return false;
}
}


// Must use the same order of elements as IHalAdapterVendorExtension::ParameterScope.
using VendorParametersRecipient = std::variant<
        std::shared_ptr<::aidl::android::hardware::audio::core::IModule>,
        std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon>>;
status_t parseAndGetVendorParameters(
        std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension> vendorExt,
        const VendorParametersRecipient& recipient,
        const AudioParameter& parameterKeys,
        String8* values);
status_t parseAndSetVendorParameters(
        std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension> vendorExt,
        const VendorParametersRecipient& recipient,
        const AudioParameter& parameters);

}  // namespace android
}  // namespace android
Loading