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

Commit c722f30e authored by Eric Laurent's avatar Eric Laurent Committed by Jean-Michel Trivi
Browse files

audio policy: suppport for dynamic source

Completed support for dynamic sources:
- remote submix input device is dynamically connected/disconnected
when corresponding AudioTrack starts/stops.

Also do not create a duplicated output for mixes used by dynamic policies.

Bug: 16006090.
Change-Id: Ib5b5a2159fcac9d9f410a5a2f1c64d7ebad79f72
parent 7e45789f
Loading
Loading
Loading
Loading
+97 −43
Original line number Diff line number Diff line
@@ -899,14 +899,13 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
                            mPolicyMixes[i]->mMix.mRegistrationId.string(),
                            AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
                desc = mPolicyMixes[i]->mOutput;
                break;
            }
        }
        if (desc != 0) {
            if (!audio_is_linear_pcm(format)) {
                return BAD_VALUE;
            }
            desc->mPolicyMixAddress = mPolicyMixes[i]->mMix.mRegistrationId;
            desc->mPolicyMix = &mPolicyMixes[i]->mMix;
            *stream = streamTypefromAttributesInt(&attributes);
            *output = desc->mIoHandle;
            ALOGV("getOutputForAttr() returns output %d", *output);
@@ -1227,8 +1226,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
    if (outputDesc->mRefCount[stream] == 1) {
        // starting an output being rerouted?
        audio_devices_t newDevice;
        if (outputDesc->mPolicyMixAddress != String8("")
                && outputDesc->mPolicyMixAddress != String8("0")) {
        if (outputDesc->mPolicyMix != NULL) {
            newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
        } else {
            newDevice = getNewOutputDevice(output, false /*fromCache*/);
@@ -1275,6 +1273,16 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
        // update the outputs if starting an output with a stream that can affect notification
        // routing
        handleNotificationRoutingForStream(stream);

        // Automatically enable the remote submix input when output is started on a re routing mix
        // of type MIX_TYPE_RECORDERS
        if (audio_is_remote_submix_device(newDevice) && outputDesc->mPolicyMix != NULL &&
                outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
                setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                        AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                        outputDesc->mPolicyMix->mRegistrationId);
        }

        if (waitMs > muteWaitMs) {
            usleep((waitMs - muteWaitMs) * 2 * 1000);
        }
@@ -1309,6 +1317,16 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
        outputDesc->changeRefCount(stream, -1);
        // store time at which the stream was stopped - see isStreamActive()
        if (outputDesc->mRefCount[stream] == 0) {
            // Automatically disable the remote submix input when output is stopped on a
            // re routing mix of type MIX_TYPE_RECORDERS
            if (audio_is_remote_submix_device(outputDesc->mDevice) &&
                    outputDesc->mPolicyMix != NULL &&
                    outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
                setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                        AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                        outputDesc->mPolicyMix->mRegistrationId);
            }

            outputDesc->mStopTime[stream] = systemTime();
            audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
            // delay the device switch by twice the latency because stopOutput() is executed when
@@ -1406,6 +1424,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
    String8 address = String8("");
    bool isSoundTrigger = false;
    audio_source_t halInputSource = attr->source;
    AudioMix *policyMix = NULL;

    if (attr->source == AUDIO_SOURCE_REMOTE_SUBMIX &&
            strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
@@ -1416,13 +1435,22 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
            ALOGW("getInputForAttr() no policy for address %s", address.string());
            return BAD_VALUE;
        }
        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;
    } else {
        device = getDeviceForInputSource(attr->source, &address);

        device = getDeviceForInputSource(attr->source, &policyMix);
        if (device == AUDIO_DEVICE_NONE) {
            ALOGW("getInputForAttr() could not find device for source %d", attr->source);
            return BAD_VALUE;
        }
        if (policyMix != NULL) {
            address = policyMix->mRegistrationId;
        } else if (audio_is_remote_submix_device(device)) {
            address = String8("0");
        }
        // adapt channel selection to input source
        switch (attr->source) {
        case AUDIO_SOURCE_VOICE_UPLINK:
@@ -1507,8 +1535,9 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
    inputDesc->mFormat = format;
    inputDesc->mChannelMask = channelMask;
    inputDesc->mDevice = device;
    inputDesc->mSessions.add(session, address);
    inputDesc->mSessions.add(session);
    inputDesc->mIsSoundTrigger = isSoundTrigger;
    inputDesc->mPolicyMix = policyMix;

    addInput(*input, inputDesc);
    mpClientInterface->onAudioPortListUpdate();
@@ -1526,7 +1555,7 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
    }
    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);

    index = inputDesc->mSessions.indexOfKey(session);
    index = inputDesc->mSessions.indexOf(session);
    if (index < 0) {
        ALOGW("startInput() unknown session %d on input %d", session, input);
        return BAD_VALUE;
@@ -1544,8 +1573,8 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
            sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
            if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
                ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
                stopInput(activeInput, activeDesc->mSessions.keyAt(0));
                releaseInput(activeInput, activeDesc->mSessions.keyAt(0));
                stopInput(activeInput, activeDesc->mSessions.itemAt(0));
                releaseInput(activeInput, activeDesc->mSessions.itemAt(0));
            } else {
                ALOGE("startInput(%d) failed: other input %d already started", input, activeInput);
                return INVALID_OPERATION;
@@ -1559,12 +1588,21 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
        }
        setInputDevice(input, getNewInputDevice(input), true /* force */);

        // Automatically enable the remote submix output when input is started.
        // automatically enable the remote submix output when input is started if not
        // used by a policy mix of type MIX_TYPE_RECORDERS
        // For remote submix (a virtual device), we open only one input per capture request.
        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
            String8 address = String8("");
            if (inputDesc->mPolicyMix == NULL) {
                address = String8("0");
            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
                address = inputDesc->mPolicyMix->mRegistrationId;
            }
            if (address != "") {
                setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                        AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                    inputDesc->mSessions.valueAt(index));
                        address);
            }
        }
    }

@@ -1585,7 +1623,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
    }
    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);

    index = inputDesc->mSessions.indexOfKey(session);
    index = inputDesc->mSessions.indexOf(session);
    if (index < 0) {
        ALOGW("stopInput() unknown session %d on input %d", session, input);
        return BAD_VALUE;
@@ -1599,11 +1637,20 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
    inputDesc->mRefCount--;
    if (inputDesc->mRefCount == 0) {

        // automatically disable the remote submix output when input is stopped
        // automatically disable the remote submix output when input is stopped if not
        // used by a policy mix of type MIX_TYPE_RECORDERS
        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
            String8 address = String8("");
            if (inputDesc->mPolicyMix == NULL) {
                address = String8("0");
            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
                address = inputDesc->mPolicyMix->mRegistrationId;
            }
            if (address != "") {
                setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                                         AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                    inputDesc->mSessions.valueAt(index));
                                         address);
            }
        }

        resetInputDevice(input);
@@ -1627,12 +1674,12 @@ void AudioPolicyManager::releaseInput(audio_io_handle_t input,
    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
    ALOG_ASSERT(inputDesc != 0);

    index = inputDesc->mSessions.indexOfKey(session);
    index = inputDesc->mSessions.indexOf(session);
    if (index < 0) {
        ALOGW("releaseInput() unknown session %d on input %d", session, input);
        return;
    }
    inputDesc->mSessions.removeItem(session);
    inputDesc->mSessions.remove(session);
    if (inputDesc->mOpenRefCount == 0) {
        ALOGW("releaseInput() invalid open ref count %d", inputDesc->mOpenRefCount);
        return;
@@ -1961,10 +2008,9 @@ bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream,
        const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
        if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
                outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
            // only consider empty or "0" address to only qualify the screen mirroring case
            // as "remote playback" (vs rerouting when the output is going to a dynamic policy)
            if (outputDesc->mPolicyMixAddress == String8("")
                    || outputDesc->mPolicyMixAddress == String8("0")) {
            // do not consider re routing (when the output is going to a dynamic policy)
            // as "remote playback"
            if (outputDesc->mPolicyMix == NULL) {
                return true;
            }
        }
@@ -2046,9 +2092,15 @@ status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)
        sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
        policyMix->mMix = mixes[i];
        mPolicyMixes.add(address, policyMix);
        if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
            setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                     AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                     address.string());
        } else {
            setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                                     AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                     address.string());
        }
    }
    return NO_ERROR;
}
@@ -2080,9 +2132,13 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)

        mPolicyMixes.removeItemsAt(index);

        if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) ==
                                             AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
        {
            setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                     AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                     address.string());
        }

        if (getDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address.string()) ==
                                             AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
@@ -3543,12 +3599,14 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de
                        ssize_t index = mPolicyMixes.indexOfKey(address);
                        if (index >= 0) {
                            mPolicyMixes[index]->mOutput = desc;
                            desc->mPolicyMix = &mPolicyMixes[index]->mMix;
                        } else {
                            ALOGE("checkOutputsForDevice() cannot find policy for address %s",
                                  address.string());
                        }
                    }
                    if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
                    } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
                        // no duplicated output for direct outputs and
                        // outputs used by dynamic policy mixes
                        audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;

                        // set initial stream volume for device
@@ -5014,7 +5072,7 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi
}

audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource,
                                                            String8 *address)
                                                            AudioMix **policyMix)
{
    uint32_t device = AUDIO_DEVICE_NONE;
    audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
@@ -5030,8 +5088,8 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input
               (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 (address != NULL) {
                        *address = mPolicyMixes[i]->mMix.mRegistrationId;
                    if (policyMix != NULL) {
                        *policyMix = &mPolicyMixes[i]->mMix;
                    }
                    return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
                }
@@ -5127,9 +5185,6 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input
    case AUDIO_SOURCE_REMOTE_SUBMIX:
        if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
            device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
            if (address != NULL) {
                *address = "0";
            }
        }
        break;
     case AUDIO_SOURCE_FM_TUNER:
@@ -5571,8 +5626,7 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
        ssize_t index = mOutputs.indexOfKey(output);
        if (index >= 0) {
            sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
            if (outputDesc->mPolicyMixAddress != String8("")
                    && outputDesc->mPolicyMixAddress != String8("0")) {
            if (outputDesc->mPolicyMix != NULL) {
                ALOGV("max gain when rerouting for output=%d", output);
                volume = 1.0f;
            }
@@ -5761,7 +5815,7 @@ uint32_t AudioPolicyManager::getMaxEffectsMemory()
AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
        const sp<IOProfile>& profile)
    : mId(0), mIoHandle(0), mLatency(0),
    mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMixAddress(String8("")),
    mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
    mPatchHandle(0),
    mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
{
@@ -5957,7 +6011,7 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)

AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
    : mId(0), mIoHandle(0),
      mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0),
      mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
      mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false)
{
    if (profile != NULL) {
+4 −5
Original line number Diff line number Diff line
@@ -497,7 +497,7 @@ protected:
            uint32_t mLatency;                  //
            audio_output_flags_t mFlags;   //
            audio_devices_t mDevice;                   // current device this output is routed to
            String8 mPolicyMixAddress;            // non empty or "0" when used by a dynamic policy
            AudioMix *mPolicyMix;             // non NULL when used by a dynamic policy
            audio_patch_handle_t mPatchHandle;
            uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
            nsecs_t mStopTime[AUDIO_STREAM_CNT];
@@ -523,6 +523,7 @@ protected:
            audio_port_handle_t           mId;
            audio_io_handle_t             mIoHandle;       // input handle
            audio_devices_t               mDevice;         // current device this input is routed to
            AudioMix                      *mPolicyMix;     // non NULL when used by a dynamic policy
            audio_patch_handle_t          mPatchHandle;
            uint32_t                      mRefCount;       // number of AudioRecord clients using
                                                           // this input
@@ -530,9 +531,7 @@ protected:
            audio_source_t                mInputSource;    // input source selected by application
                                                           //(mediarecorder.h)
            const sp<IOProfile>           mProfile;        // I/O profile this output derives from
                                          // audio sessions attached to this input and the
                                          // corresponding device address
            DefaultKeyedVector<audio_session_t, String8> mSessions;
            SortedVector<audio_session_t> mSessions;       // audio sessions attached to this input
            bool                          mIsSoundTrigger; // used by a soundtrigger capture

            virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -612,7 +611,7 @@ protected:

        // select input device corresponding to requested audio source
        virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource,
                                                        String8 *address = NULL);
                                                        AudioMix **policyMix = NULL);

        // return io handle of active input or 0 if no input is active
        //    Only considers inputs from physical devices (e.g. main mic, headset mic) when