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

Commit f77236dc authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

Merge "Add AudioMix and AudioMixCollection to common policy element"

parents 53d68027 036e1e91
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \
    src/HwModule.cpp \
    src/IOProfile.cpp \
    src/AudioPort.cpp \
    src/AudioPolicyMix.cpp \
    src/AudioPatch.cpp \
    src/AudioInputDescriptor.cpp \
    src/AudioOutputDescriptor.cpp \
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 <utils/RefBase.h>
#include <media/AudioPolicy.h>
#include <utils/KeyedVector.h>
#include <hardware/audio.h>
#include <utils/String8.h>

namespace android {

class AudioOutputDescriptor;

/**
 * custom mix entry in mPolicyMixes
 */
class AudioPolicyMix : public RefBase {
public:
    AudioPolicyMix() {}

    const sp<AudioOutputDescriptor> &getOutput() const;

    void setOutput(sp<AudioOutputDescriptor> &output);

    void clearOutput();

    android::AudioMix &getMix();

    void setMix(AudioMix &mix);

private:
    AudioMix    mMix;                   // Audio policy mix descriptor
    sp<AudioOutputDescriptor> mOutput;  // Corresponding output stream
};


class AudioPolicyMixCollection : public DefaultKeyedVector<String8, sp<AudioPolicyMix> >
{
public:
    status_t getAudioPolicyMix(String8 address, sp<AudioPolicyMix> &policyMix) const;

    status_t registerMix(String8 address, AudioMix mix);

    status_t unregisterMix(String8 address);

    void closeOutput(sp<AudioOutputDescriptor> &desc);

    /**
     * Try to find an output descriptor for the given attributes.
     *
     * @param[in] attributes to consider for the research of output descriptor.
     * @param[out] desc to return if an output could be found.
     *
     * @return NO_ERROR if an output was found for the given attribute (in this case, the
     *                  descriptor output param is initialized), error code otherwise.
     */
    status_t getOutputForAttr(audio_attributes_t attributes, sp<AudioOutputDescriptor> &desc);

    audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                  audio_devices_t availableDeviceTypes,
                                                  AudioMix **policyMix);

    status_t getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix);
};

}; // namespace android
+193 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 "APM::AudioPolicyMix"
//#define LOG_NDEBUG 0

#include "AudioPolicyMix.h"
#include "HwModule.h"
#include "AudioPort.h"
#include "IOProfile.h"
#include "AudioGain.h"
#include <AudioOutputDescriptor.h>

namespace android {

void AudioPolicyMix::setOutput(sp<AudioOutputDescriptor> &output)
{
    mOutput = output;
}

const sp<AudioOutputDescriptor> &AudioPolicyMix::getOutput() const
{
    return mOutput;
}

void AudioPolicyMix::clearOutput()
{
    mOutput.clear();
}

void AudioPolicyMix::setMix(AudioMix &mix)
{
    mMix = mix;
}

android::AudioMix &AudioPolicyMix::getMix()
{
    return mMix;
}

status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix)
{
    ssize_t index = indexOfKey(address);
    if (index >= 0) {
        ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
        return BAD_VALUE;
    }
    sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
    policyMix->setMix(mix);
    add(address, policyMix);
    return NO_ERROR;
}

status_t AudioPolicyMixCollection::unregisterMix(String8 address)
{
    ssize_t index = indexOfKey(address);
    if (index < 0) {
        ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
        return BAD_VALUE;
    }

    removeItemsAt(index);
    return NO_ERROR;
}

status_t AudioPolicyMixCollection::getAudioPolicyMix(String8 address,
                                                     sp<AudioPolicyMix> &policyMix) const
{
    ssize_t index = indexOfKey(address);
    if (index < 0) {
        ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
        return BAD_VALUE;
    }
    policyMix = valueAt(index);
    return NO_ERROR;
}

void AudioPolicyMixCollection::closeOutput(sp<AudioOutputDescriptor> &desc)
{
    for (size_t i = 0; i < size(); i++) {
        sp<AudioPolicyMix> policyMix = valueAt(i);
        if (policyMix->getOutput() == desc) {
            policyMix->clearOutput();
        }
    }
}

status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes,
                                                    sp<AudioOutputDescriptor> &desc)
{
    for (size_t i = 0; i < size(); i++) {
        sp<AudioPolicyMix> policyMix = valueAt(i);
        AudioMix mix = policyMix->getMix();

        if (mix.mMixType == MIX_TYPE_PLAYERS) {
            for (size_t j = 0; j < mix.mCriteria.size(); j++) {
                if ((RULE_MATCH_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule &&
                     mix.mCriteria[j].mAttr.mUsage == attributes.usage) ||
                        (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule &&
                         mix.mCriteria[j].mAttr.mUsage != attributes.usage)) {
                    desc = policyMix->getOutput();
                    break;
                }
                if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
                        strncmp(attributes.tags + strlen("addr="),
                                mix.mRegistrationId.string(),
                                AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
                    desc = policyMix->getOutput();
                    break;
                }
            }
        } else if (mix.mMixType == MIX_TYPE_RECORDERS) {
            if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
                    strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
                    strncmp(attributes.tags + strlen("addr="),
                            mix.mRegistrationId.string(),
                            AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
                desc = policyMix->getOutput();
            }
        }
        if (desc != 0) {
            desc->mPolicyMix = &mix;
            return NO_ERROR;
        }
    }
    return BAD_VALUE;
}

audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                                        audio_devices_t availDevices,
                                                                        AudioMix **policyMix)
{
    for (size_t i = 0; i < size(); i++) {
        AudioMix mix = valueAt(i)->getMix();

        if (mix.mMixType != MIX_TYPE_RECORDERS) {
            continue;
        }
        for (size_t j = 0; j < mix.mCriteria.size(); j++) {
            if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule &&
                    mix.mCriteria[j].mAttr.mSource == inputSource) ||
               (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule &&
                    mix.mCriteria[j].mAttr.mSource != inputSource)) {
                if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
                    if (policyMix != NULL) {
                        *policyMix = &mix;
                    }
                    return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
                }
                break;
            }
        }
    }
    return AUDIO_DEVICE_NONE;
}

status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix)
{
    if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) {
        return BAD_VALUE;
    }
    String8 address(attr.tags + strlen("addr="));

    ssize_t index = indexOfKey(address);
    if (index < 0) {
        ALOGW("getInputForAttr() no policy for address %s", address.string());
        return BAD_VALUE;
    }
    sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
    AudioMix mix = audioPolicyMix->getMix();

    if (mix.mMixType != MIX_TYPE_PLAYERS) {
        ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
        return BAD_VALUE;
    }
    policyMix = &mix;
    return NO_ERROR;
}

}; //namespace android
+30 −92
Original line number Diff line number Diff line
@@ -707,46 +707,17 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
        }
        stream_type_to_audio_attributes(*stream, &attributes);
    }

    for (size_t i = 0; i < mPolicyMixes.size(); i++) {
    sp<AudioOutputDescriptor> desc;
        if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_PLAYERS) {
            for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
                if ((RULE_MATCH_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
                        mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage == attributes.usage) ||
                    (RULE_EXCLUDE_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
                        mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage != attributes.usage)) {
                    desc = mPolicyMixes[i]->mOutput;
                    break;
                }
                if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
                        strncmp(attributes.tags + strlen("addr="),
                                mPolicyMixes[i]->mMix.mRegistrationId.string(),
                                AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
                    desc = mPolicyMixes[i]->mOutput;
                    break;
                }
            }
        } else if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_RECORDERS) {
            if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
                    strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
                    strncmp(attributes.tags + strlen("addr="),
                            mPolicyMixes[i]->mMix.mRegistrationId.string(),
                            AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
                desc = mPolicyMixes[i]->mOutput;
            }
        }
        if (desc != 0) {
    if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) {
        ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
        if (!audio_is_linear_pcm(format)) {
            return BAD_VALUE;
        }
            desc->mPolicyMix = &mPolicyMixes[i]->mMix;
        *stream = streamTypefromAttributesInt(&attributes);
        *output = desc->mIoHandle;
        ALOGV("getOutputForAttr() returns output %d", *output);
        return NO_ERROR;
    }
    }
    if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
        ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
        return BAD_VALUE;
@@ -1286,19 +1257,13 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,

    if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
            strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
        device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
        address = String8(attr->tags + strlen("addr="));
        ssize_t index = mPolicyMixes.indexOfKey(address);
        if (index < 0) {
            ALOGW("getInputForAttr() no policy for address %s", address.string());
            return BAD_VALUE;
        status_t ret = mPolicyMixes.getInputMixForAttr(*attr, policyMix);
        if (ret != NO_ERROR) {
            return ret;
        }
        if (mPolicyMixes[index]->mMix.mMixType != MIX_TYPE_PLAYERS) {
            ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
            return BAD_VALUE;
        }
        policyMix = &mPolicyMixes[index]->mMix;
        *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
        device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
        address = String8(attr->tags + strlen("addr="));
    } else {
        device = getDeviceAndMixForInputSource(inputSource, &policyMix);
        if (device == AUDIO_DEVICE_NONE) {
@@ -1929,9 +1894,8 @@ status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)

    for (size_t i = 0; i < mixes.size(); i++) {
        String8 address = mixes[i].mRegistrationId;
        ssize_t index = mPolicyMixes.indexOfKey(address);
        if (index >= 0) {
            ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());

        if (mPolicyMixes.registerMix(address, mixes[i]) != NO_ERROR) {
            continue;
        }
        audio_config_t outputConfig = mixes[i].mFormat;
@@ -1944,9 +1908,7 @@ status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)
                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
        module->addInputProfile(address, &inputConfig,
                                 AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
        sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
        policyMix->mMix = mixes[i];
        mPolicyMixes.add(address, policyMix);

        if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
            setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                     AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
@@ -1979,14 +1941,11 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)

    for (size_t i = 0; i < mixes.size(); i++) {
        String8 address = mixes[i].mRegistrationId;
        ssize_t index = mPolicyMixes.indexOfKey(address);
        if (index < 0) {
            ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());

        if (mPolicyMixes.unregisterMix(address) != NO_ERROR) {
            continue;
        }

        mPolicyMixes.removeItemsAt(index);

        if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) ==
                                             AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
        {
@@ -3261,14 +3220,14 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de
                if (output != AUDIO_IO_HANDLE_NONE) {
                    addOutput(output, desc);
                    if (device_distinguishes_on_address(device) && address != "0") {
                        ssize_t index = mPolicyMixes.indexOfKey(address);
                        if (index >= 0) {
                            mPolicyMixes[index]->mOutput = desc;
                            desc->mPolicyMix = &mPolicyMixes[index]->mMix;
                        } else {
                        sp<AudioPolicyMix> policyMix;
                        if (mPolicyMixes.getAudioPolicyMix(address, policyMix) != NO_ERROR) {
                            ALOGE("checkOutputsForDevice() cannot find policy for address %s",
                                  address.string());
                        }
                        policyMix->setOutput(desc);
                        desc->mPolicyMix = &(policyMix->getMix());

                    } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
                        // no duplicated output for direct outputs and
                        // outputs used by dynamic policy mixes
@@ -3579,12 +3538,7 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output)
        ALOGW("closeOutput() unknown output %d", output);
        return;
    }

    for (size_t i = 0; i < mPolicyMixes.size(); i++) {
        if (mPolicyMixes[i]->mOutput == outputDesc) {
            mPolicyMixes[i]->mOutput.clear();
        }
    }
    mPolicyMixes.closeOutput(outputDesc);

    // look for duplicated outputs connected to the output being removed.
    for (size_t i = 0; i < mOutputs.size(); i++) {
@@ -4730,29 +4684,13 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                                  AudioMix **policyMix)
{
    audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
                                            ~AUDIO_DEVICE_BIT_IN;
    audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
    audio_devices_t selectedDeviceFromMix =
           mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);

    for (size_t i = 0; i < mPolicyMixes.size(); i++) {
        if (mPolicyMixes[i]->mMix.mMixType != MIX_TYPE_RECORDERS) {
            continue;
        }
        for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
            if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
                    mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource == inputSource) ||
               (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
                    mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource != inputSource)) {
                if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
                    if (policyMix != NULL) {
                        *policyMix = &mPolicyMixes[i]->mMix;
                    }
                    return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
    if (selectedDeviceFromMix != AUDIO_DEVICE_NONE) {
        return selectedDeviceFromMix;
    }
                break;
            }
        }
    }

    return getDeviceForInputSource(inputSource);
}

+2 −10
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <HwModule.h>
#include <AudioInputDescriptor.h>
#include <AudioOutputDescriptor.h>
#include <AudioPolicyMix.h>

namespace android {

@@ -474,16 +475,7 @@ protected:
        uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
        bool mBeaconMuted;              // has STREAM_TTS been muted

        // custom mix entry in mPolicyMixes
        class AudioPolicyMix : public RefBase {
        public:
            AudioPolicyMix() {}

            AudioMix    mMix;                   // Audio policy mix descriptor
            sp<AudioOutputDescriptor> mOutput;  // Corresponding output stream
        };
        DefaultKeyedVector<String8, sp<AudioPolicyMix> > mPolicyMixes; // list of registered mixes

        AudioPolicyMixCollection mPolicyMixes; // list of registered mixes

#ifdef AUDIO_POLICY_TEST
        Mutex   mLock;