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

Commit 2052c265 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge changes I5c22c345,I46a7f949,Ic2d89fa0

* changes:
  audio policy: check audio attributes with use case validator
  use case validator: add AOSP headers
  Add libaudiousecasevalidation library
parents 37420762 0d13feae
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1086,6 +1086,8 @@ status_t AudioSystem::getOutputForAttr(audio_attributes_t* attr,
            responseAidl.secondaryOutputs, aidl2legacy_int32_t_audio_io_handle_t));
    *isSpatialized = responseAidl.isSpatialized;
    *isBitPerfect = responseAidl.isBitPerfect;
    *attr = VALUE_OR_RETURN_STATUS(
            aidl2legacy_AudioAttributesInternal_audio_attributes_t(responseAidl.attr));

    return OK;
}
+3 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package android.media;

import android.media.audio.common.AudioConfigBase;
import android.media.audio.common.AudioStreamType;

import android.media.AudioAttributesInternal;
/**
 * {@hide}
 */
@@ -37,4 +37,6 @@ parcelable GetOutputForAttrResponse {
    /** The suggested audio config if fails to get an output. **/
    AudioConfigBase configBase;
    boolean isBitPerfect;
    /** The corrected audio attributes. **/
    AudioAttributesInternal attr;
}
+49 −0
Original line number Diff line number Diff line
package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "frameworks_av_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["frameworks_av_license"],
}

cc_library {
    name: "libaudiousecasevalidation",
    host_supported: true,
    srcs: [
        "UsecaseLookup.cpp",
        "UsecaseValidator.cpp",
    ],
    header_libs: [
        "liberror_headers",
    ],
    shared_libs: [
        "framework-permission-aidl-cpp",
        "libaudioutils",
        "libbase",
        "liblog",
    ],
    export_include_dirs: [
        "include",
    ],
    target: {
        darwin: {
            enabled: false,
        },
    },
}

cc_test_host {
    name: "libaudiousecasevalidation-test",
    srcs: [
        "tests/UsecaseValidator-test.cpp",
    ],
    header_libs: [
        "liberror_headers",
    ],
    shared_libs: [
        "framework-permission-aidl-cpp",
        "libaudiousecasevalidation",
        "libutils",
    ],
}
+94 −0
Original line number Diff line number Diff line
/*
 * 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 "UsecaseLookup"
// #define LOG_NDEBUG 0

#include "media/UsecaseLookup.h"

#include <utils/Log.h>

namespace android {
namespace media {

/**
 * Add streamId and outputFlags to stream list.
 */
void UsecaseLookup::addStream(STREAMID streamId, bool outputFlagGame) {
    ALOGV("%s streamId: %d outputFlagGame: %d", __func__, streamId, outputFlagGame);

    mutex_lock lock(m_mutex);
    m_streams[streamId] = outputFlagGame;
}

/**
 * Remove streamId from stream list.
 */
void UsecaseLookup::removeStream(STREAMID streamId) {
    ALOGV("%s streamId: %d ", __func__, streamId);

    mutex_lock lock(m_mutex);
    m_streams.erase(streamId);

    // Shouldn't happen but it might.
    for (auto it = m_tracks.begin(); it != m_tracks.end();) {
        if (it->second == streamId) {
            it = m_tracks.erase(it);
        } else {
            it++;
        }
    }
}

/**
 * Add streamId and portId to track list.
 */
void UsecaseLookup::addTrack(STREAMID streamId, PORTID portId) {
    ALOGV("%s streamId: %d portId: %d", __func__, streamId, portId);

    mutex_lock lock(m_mutex);

    if (m_tracks.find(portId) == m_tracks.end()) {
        m_tracks[portId] = streamId;
    }
}

/**
 * Remove streamId and portId from track list.
 */
void UsecaseLookup::removeTrack(STREAMID streamId, PORTID portId) {
    ALOGV("%s streamId: %d portId: %d", __func__, streamId, portId);

    mutex_lock lock(m_mutex);
    auto it = m_tracks.find(portId);

    if (it != m_tracks.end() && it->second == streamId) {
        m_tracks.erase(portId);
    }
}

/**
 * Check if stream list contains streamId with Game outputFlag.
 */
bool UsecaseLookup::isGameStream(STREAMID streamId) {
    ALOGV("%s streamId: %d ", __func__, streamId);
    mutex_lock lock(m_mutex);
    auto it = m_streams.find(streamId);

    return (it != m_streams.end()) ? it->second : false;
}

}  // namespace media
}  // namespace android
+143 −0
Original line number Diff line number Diff line
/*
 * 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 "UsecaseValidator"
// #define LOG_NDEBUG 0

#include <inttypes.h>

#include <utils/Log.h>

#include "media/UsecaseValidator.h"
#include "media/UsecaseLookup.h"

namespace android {
namespace media {
namespace {

class UsecaseValidatorImpl : public UsecaseValidator {
 public:
    UsecaseValidatorImpl() {}

    /**
     * Register a new mixer/stream.
     * Called when the stream is opened at the HAL and communicates
     * immutable stream attributes like flags, sampling rate, format.
     */
    status_t registerStream(audio_io_handle_t streamId,
                            const audio_config_base_t& audioConfig __attribute__((unused)),
                            const audio_output_flags_t outputFlags) override {
        ALOGV("%s output: %d flags: %#x", __func__, streamId, outputFlags);

        // Check if FAST or MMAP output flag has been set.
        bool outputFlagGame = outputFlags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
        m_lookup.addStream(streamId, outputFlagGame);
        return OK;
    };

    /**
     * Unregister a stream/mixer.
     * Called when the stream is closed.
     */
    status_t unregisterStream(audio_io_handle_t streamId) override {
        ALOGV("%s output: %d", __func__, streamId);

        m_lookup.removeStream(streamId);
        return OK;
    };

    /**
     * Indicates that some playback activity started on the stream.
     * Called each time an audio track starts or resumes.
     */
    error::Result<audio_attributes_t> startClient(audio_io_handle_t streamId,
            audio_port_handle_t portId, const content::AttributionSourceState& attributionSource,
            const audio_attributes_t& attributes,
            const AttributesChangedCallback *callback __attribute__((unused))) override {
        ALOGV("%s output: %d portId: %d usage: %d pid: %d package: %s",
                __func__, streamId, portId, attributes.usage, attributionSource.pid,
                attributionSource.packageName.value_or("").c_str());

        m_lookup.addTrack(streamId, portId);

        return verifyAudioAttributes(streamId, attributionSource, attributes);
    };

    /**
     * Indicates that some playback activity stopped on the stream.
     * Called each time an audio track stops or pauses.
     */
    status_t stopClient(audio_io_handle_t streamId, audio_port_handle_t portId) override {
        ALOGV("%s output: %d portId: %d", __func__, streamId, portId);

        m_lookup.removeTrack(streamId, portId);
        return OK;
    };

    /**
     * Called to verify and update audio attributes for a track that is connected
     * to the specified stream.
     */
    error::Result<audio_attributes_t> verifyAudioAttributes(audio_io_handle_t streamId,
            const content::AttributionSourceState& attributionSource,
            const audio_attributes_t& attributes) override {
        ALOGV("%s output: %d usage: %d pid: %d package: %s",
                __func__, streamId, attributes.usage, attributionSource.pid,
                attributionSource.packageName.value_or("").c_str());

        audio_attributes_t attrRet = attributes;

        // Check if attribute usage media or unknown has been set.
        bool isUsageValid = this->isUsageValid(attributes);

        if (isUsageValid && m_lookup.isGameStream(streamId)) {
            ALOGI("%s update usage: %d to AUDIO_USAGE_GAME for output: %d pid: %d package: %s",
                    __func__, attributes.usage, streamId, attributionSource.pid,
                    attributionSource.packageName.value_or("").c_str());
            // Set attribute usage Game.
            attrRet.usage = AUDIO_USAGE_GAME;
        }

        return {attrRet};
    };

 protected:
    /**
     * Check if attribute usage valid.
     */
    bool isUsageValid(const audio_attributes_t& attr) {
        ALOGV("isUsageValid attr.usage: %d", attr.usage);
        switch (attr.usage) {
            case AUDIO_USAGE_MEDIA:
            case AUDIO_USAGE_UNKNOWN:
                return true;
            default:
                break;
        }
        return false;
    }

 protected:
    UsecaseLookup m_lookup;
};

}  // namespace

std::unique_ptr<UsecaseValidator> createUsecaseValidator() {
    return std::make_unique<UsecaseValidatorImpl>();
}

}  // namespace media
}  // namespace android
Loading