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

Commit 592dd7bf authored by Eric Laurent's avatar Eric Laurent
Browse files

audiopolicy: refactor playback activity ref counting

Playback activity ref couting is now based on active state
of PlaybackClientDescriptor.

The active reference count per stream on each output is still
used because it provides a simple implementation for duplicated output.

Test: CTS tests for AudioTrack and Routing
Test: manual audio smoke test

Change-Id: Ifadb1d24131581461aace14a5b25e7c7582c57cb
parent 8f42ea1f
Loading
Loading
Loading
Loading
+10 −7
Original line number Diff line number Diff line
@@ -59,7 +59,10 @@ public:
                           audio_devices_t device,
                           uint32_t delayMs,
                           bool force);
    virtual void changeRefCount(audio_stream_type_t stream, int delta);
    virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
            uint32_t streamActiveCount(audio_stream_type_t stream) const
                            { return mActiveCount[stream]; }
            void setClientActive(const sp<TrackClientDescriptor>& client, bool active);

    bool isActive(uint32_t inPastMs = 0) const;
    bool isStreamActive(audio_stream_type_t stream,
@@ -84,15 +87,17 @@ public:

    sp<AudioPort> mPort;
    audio_devices_t mDevice;                   // current device this output is routed to
    uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
    nsecs_t mStopTime[AUDIO_STREAM_CNT];
    float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume in dB
    int mMuteCount[AUDIO_STREAM_CNT];     // mute request counter
    bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
                                        // device selection. See checkDeviceMuteStrategies()
    AudioPolicyClientInterface *mClientInterface;
    AudioMix *mPolicyMix;             // non NULL when used by a dynamic policy

protected:
    uint32_t mActiveCount[AUDIO_STREAM_CNT]; // number of streams of each type active on this output
    uint32_t mGlobalActiveCount;  // non-client-specific active count
    audio_patch_handle_t mPatchHandle;
    audio_port_handle_t mId;
    TrackClientMap mClients;
@@ -116,7 +121,7 @@ public:
    virtual bool isFixedVolume(audio_devices_t device);
    virtual sp<AudioOutputDescriptor> subOutput1() { return mOutput1; }
    virtual sp<AudioOutputDescriptor> subOutput2() { return mOutput2; }
    virtual void changeRefCount(audio_stream_type_t stream, int delta);
    virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
    virtual bool setVolume(float volume,
                           audio_stream_type_t stream,
                           audio_devices_t device,
@@ -134,10 +139,10 @@ public:
                          audio_output_flags_t flags,
                          audio_io_handle_t *output);
            // Called when a stream is about to be started
            // Note: called before changeRefCount(1);
            // Note: called before setClientActive(true);
            status_t start();
            // Called after a stream is stopped.
            // Note: called after changeRefCount(-1);
            // Note: called after setClientActive(false);
            void stop();
            void close();
            status_t openDuplicating(const sp<SwAudioOutputDescriptor>& output1,
@@ -148,12 +153,10 @@ public:
    audio_io_handle_t mIoHandle;           // output handle
    uint32_t mLatency;                  //
    audio_output_flags_t mFlags;   //
    AudioMix *mPolicyMix;             // non NULL when used by a dynamic policy
    sp<SwAudioOutputDescriptor> mOutput1;    // used by duplicated outputs: first output
    sp<SwAudioOutputDescriptor> mOutput2;    // used by duplicated outputs: second output
    uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
    audio_session_t mDirectClientSession; // session id of the direct output client
    uint32_t mGlobalRefCount;  // non-stream-specific ref count
};

// Audio output driven by an input device directly.
+57 −47
Original line number Diff line number Diff line
@@ -34,12 +34,12 @@ namespace android {

AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
                                             AudioPolicyClientInterface *clientInterface)
    : mPort(port), mDevice(AUDIO_DEVICE_NONE),
      mClientInterface(clientInterface), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0)
    : mPort(port), mDevice(AUDIO_DEVICE_NONE), mClientInterface(clientInterface),
      mPolicyMix(NULL), mGlobalActiveCount(0), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0)
{
    // clear usage count for all stream types
    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
        mRefCount[i] = 0;
        mActiveCount[i] = 0;
        mCurVolume[i] = -1.0;
        mMuteCount[i] = 0;
        mStopTime[i] = 0;
@@ -103,17 +103,51 @@ bool AudioOutputDescriptor::sharesHwModuleWith(
    }
}

void AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
void AudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
                                                                   int delta)
{
    if ((delta + (int)mRefCount[stream]) < 0) {
        ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d",
              delta, stream, mRefCount[stream]);
        mRefCount[stream] = 0;
    if ((delta + (int)mActiveCount[stream]) < 0) {
        ALOGW("%s invalid delta %d for stream %d, active count %d",
              __FUNCTION__, delta, stream, mActiveCount[stream]);
        mActiveCount[stream] = 0;
        return;
    }
    mRefCount[stream] += delta;
    ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
    mActiveCount[stream] += delta;
    ALOGV("%s stream %d, count %d", __FUNCTION__, stream, mActiveCount[stream]);
}

void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& client, bool active)
{
    if (mClients.find(client->portId()) == mClients.end()
        || active == client->active()) {
        return;
    }

    changeStreamActiveCount(client->stream(), active ? 1 : -1);

    // Handle non-client-specific activity ref count
    int32_t oldGlobalActiveCount = mGlobalActiveCount;
    if (!active && mGlobalActiveCount < 1) {
        ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
        mGlobalActiveCount = 1;
    }
    mGlobalActiveCount += active ? 1 : -1;

    if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
        {
            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
                                                            MIX_STATE_MIXING);
        }
    } else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
        {
            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
                                                            MIX_STATE_IDLE);
        }
    }

    client->setActive(active);
}

bool AudioOutputDescriptor::isActive(uint32_t inPastMs) const
@@ -137,7 +171,7 @@ bool AudioOutputDescriptor::isStreamActive(audio_stream_type_t stream,
                                           uint32_t inPastMs,
                                           nsecs_t sysTime) const
{
    if (mRefCount[stream] != 0) {
    if (mActiveCount[stream] != 0) {
        return true;
    }
    if (inPastMs == 0) {
@@ -231,11 +265,11 @@ status_t AudioOutputDescriptor::dump(int fd)
    result.append(buffer);
    snprintf(buffer, SIZE, " Devices %08x\n", device());
    result.append(buffer);
    snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
    snprintf(buffer, SIZE, " Stream volume activeCount muteCount\n");
    result.append(buffer);
    for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
        snprintf(buffer, SIZE, " %02d     %.03f     %02d          %02d\n",
                 i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
                 i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
        result.append(buffer);
    }

@@ -261,9 +295,9 @@ SwAudioOutputDescriptor::SwAudioOutputDescriptor(const sp<IOProfile>& profile,
                                                 AudioPolicyClientInterface *clientInterface)
    : AudioOutputDescriptor(profile, clientInterface),
    mProfile(profile), mIoHandle(AUDIO_IO_HANDLE_NONE), mLatency(0),
    mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
    mFlags((audio_output_flags_t)0),
    mOutput1(0), mOutput2(0), mDirectOpenCount(0),
    mDirectClientSession(AUDIO_SESSION_NONE), mGlobalRefCount(0)
    mDirectClientSession(AUDIO_SESSION_NONE)
{
    if (profile != NULL) {
        mFlags = (audio_output_flags_t)profile->getFlags();
@@ -327,40 +361,16 @@ uint32_t SwAudioOutputDescriptor::latency()
    }
}

void SwAudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
void SwAudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
                                                                   int delta)
{
    // forward usage count change to attached outputs
    if (isDuplicated()) {
        mOutput1->changeRefCount(stream, delta);
        mOutput2->changeRefCount(stream, delta);
    }
    AudioOutputDescriptor::changeRefCount(stream, delta);

    // handle stream-independent ref count
    uint32_t oldGlobalRefCount = mGlobalRefCount;
    if ((delta + (int)mGlobalRefCount) < 0) {
        ALOGW("changeRefCount() invalid delta %d globalRefCount %d", delta, mGlobalRefCount);
        mGlobalRefCount = 0;
    } else {
        mGlobalRefCount += delta;
    }
    if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
        {
            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
                    MIX_STATE_MIXING);
        }

    } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
        {
            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
                    MIX_STATE_IDLE);
        mOutput1->changeStreamActiveCount(stream, delta);
        mOutput2->changeStreamActiveCount(stream, delta);
    }
    AudioOutputDescriptor::changeStreamActiveCount(stream, delta);
}
}


bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
{
@@ -537,7 +547,7 @@ void SwAudioOutputDescriptor::close()

        LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
                            __FUNCTION__, mProfile->curOpenCount);
        // do not call stop() here as stop() is supposed to be called after changeRefCount(-1)
        // do not call stop() here as stop() is supposed to be called after setClientActive(false)
        // and we don't know how many streams are still active at this time
        if (isActive()) {
            mProfile->curActiveCount--;
@@ -737,7 +747,7 @@ bool SwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgno
        }
        for (size_t i = 0; i < size(); i++) {
            const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
            if (outputDesc->mRefCount[s] != 0) {
            if (outputDesc->streamActiveCount((audio_stream_type_t)s)!= 0) {
                return true;
            }
        }
@@ -802,7 +812,7 @@ bool HwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgno
        }
        for (size_t i = 0; i < size(); i++) {
            const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
            if (outputDesc->mRefCount[s] != 0) {
            if (outputDesc->streamActiveCount((audio_stream_type_t)s) != 0) {
                return true;
            }
        }
+8 −12
Original line number Diff line number Diff line
@@ -1034,8 +1034,6 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice(
            }
            return AUDIO_IO_HANDLE_NONE;
        }
        outputDesc->mRefCount[stream] = 0;
        outputDesc->mStopTime[stream] = 0;
        outputDesc->mDirectOpenCount = 1;
        outputDesc->mDirectClientSession = session;

@@ -1394,8 +1392,7 @@ status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outp
    // increment usage count for this stream on the requested output:
    // NOTE that the usage count is the same for duplicated output and hardware output which is
    // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
    outputDesc->changeRefCount(stream, 1);
    client->setActive(true);
    outputDesc->setClientActive(client, true);

    if (client->hasPreferredDevice(true)) {
        device = getNewOutputDevice(outputDesc, false /*fromCache*/);
@@ -1408,7 +1405,7 @@ status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outp
        selectOutputForMusicEffects();
    }

    if (outputDesc->mRefCount[stream] == 1 || device != AUDIO_DEVICE_NONE) {
    if (outputDesc->streamActiveCount(stream) == 1 || device != AUDIO_DEVICE_NONE) {
        // starting an output being rerouted?
        if (device == AUDIO_DEVICE_NONE) {
            device = getNewOutputDevice(outputDesc, false /*fromCache*/);
@@ -1537,8 +1534,8 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu

    handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);

    if (outputDesc->mRefCount[stream] > 0) {
        if (outputDesc->mRefCount[stream] == 1) {
    if (outputDesc->streamActiveCount(stream) > 0) {
        if (outputDesc->streamActiveCount(stream) == 1) {
            // 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) &&
@@ -1557,11 +1554,10 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu
        }

        // decrement usage count of this stream on the output
        outputDesc->changeRefCount(stream, -1);
        client->setActive(false);
        outputDesc->setClientActive(client, false);

        // store time at which the stream was stopped - see isStreamActive()
        if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) {
        if (outputDesc->streamActiveCount(stream) == 0 || forceDeviceUpdate) {
            outputDesc->mStopTime[stream] = systemTime();
            audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
            // delay the device switch by twice the latency because stopOutput() is executed when
@@ -4621,8 +4617,8 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output)
            // the other output.
            bool wasActive = outputDesc2->isActive();
            for (int j = 0; j < AUDIO_STREAM_CNT; j++) {
                int refCount = dupOutputDesc->mRefCount[j];
                outputDesc2->changeRefCount((audio_stream_type_t)j,-refCount);
                int activeCount = dupOutputDesc->streamActiveCount((audio_stream_type_t)j);
                outputDesc2->changeStreamActiveCount((audio_stream_type_t)j,-activeCount);
            }
            // stop() will be a no op if the output is still active but is needed in case all
            // active streams refcounts where cleared above