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

Commit ad2e7b90 authored by Eric Laurent's avatar Eric Laurent
Browse files

Fix various AAudio device selection issues

Bug: 65292224
- Audio policy manager should not use an unavailable device when an explicit
route is requested. This causes a device selection made by a client to
become sticky after device disconnection.

Bug: 64945845
- Remove spurious device change callback occuring after registering a
new client to audio server by creating a specific configuration event
for client registration.
- Do not keep strong references to device callback interfaces in
AudioTrack, AudioRecord and AudioSystem.
- Do not update selected device in AudioTrack and AudioRecord when
not active as the new device selection on the stream is because of other
clients activity which is not relevant to an inactive client.

Bug: 65693340
- Fix missing increment of SessionRoute ref count in getInputForAttr() for
MMAP inputs

Test: AAudio CTS tests

Change-Id: I2a01b02e8b064d352004f6065495fd99aee55745
parent b92c988f
Loading
Loading
Loading
Loading
+55 −25
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ AudioRecord::~AudioRecord()
        }
        // No lock here: worst case we remove a NULL callback which will be a nop
        if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
            AudioSystem::removeAudioDeviceCallback(this, mInput);
        }
        IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
        mAudioRecord.clear();
@@ -499,19 +499,26 @@ audio_port_handle_t AudioRecord::getInputDevice() {
    return mSelectedDeviceId;
}

audio_port_handle_t AudioRecord::getRoutedDeviceId() {
    AutoMutex lock(mLock);
    if (mInput == AUDIO_IO_HANDLE_NONE) {
        return AUDIO_PORT_HANDLE_NONE;
// must be called with mLock held
void AudioRecord::updateRoutedDeviceId_l()
{
    // if the record is inactive, do not update actual device as the input stream maybe routed
    // from a device not relevant to this client because of other active use cases.
    if (!mActive) {
        return;
    }
    // if the input stream does not have an active audio patch, use either the device initially
    // selected by audio policy manager or the last routed device
    if (mInput != AUDIO_IO_HANDLE_NONE) {
        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
        deviceId = mRoutedDeviceId;
    }
        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
            mRoutedDeviceId = deviceId;
    return deviceId;
        }
     }
}

audio_port_handle_t AudioRecord::getRoutedDeviceId() {
    AutoMutex lock(mLock);
    updateRoutedDeviceId_l();
    return mRoutedDeviceId;
}

// -------------------------------------------------------------------------
@@ -537,9 +544,6 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
        return NO_INIT;
    }

    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
    }
    audio_io_handle_t input;

    // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@@ -744,6 +748,15 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
    }
    mNotificationFramesAct = (uint32_t) notificationFrames;


    //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
    if (mDeviceCallback != 0 && mInput != input) {
        if (mInput != AUDIO_IO_HANDLE_NONE) {
            AudioSystem::removeAudioDeviceCallback(this, mInput);
        }
        AudioSystem::addAudioDeviceCallback(this, input);
    }

    // We retain a copy of the I/O handle, but don't own the reference
    mInput = input;
    mRefreshRemaining = true;
@@ -763,10 +776,6 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
    mDeathNotifier = new DeathNotifier(this);
    IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);

    if (mDeviceCallback != 0) {
        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
    }

    return NO_ERROR;

    // End of retry loop.
@@ -1238,7 +1247,7 @@ status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCa
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    if (mDeviceCallback == callback) {
    if (mDeviceCallback.unsafe_get() == callback.get()) {
        ALOGW("%s adding same callback!", __FUNCTION__);
        return INVALID_OPERATION;
    }
@@ -1246,9 +1255,9 @@ status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCa
    if (mInput != AUDIO_IO_HANDLE_NONE) {
        if (mDeviceCallback != 0) {
            ALOGW("%s callback already present!", __FUNCTION__);
            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
            AudioSystem::removeAudioDeviceCallback(this, mInput);
        }
        status = AudioSystem::addAudioDeviceCallback(callback, mInput);
        status = AudioSystem::addAudioDeviceCallback(this, mInput);
    }
    mDeviceCallback = callback;
    return status;
@@ -1262,17 +1271,38 @@ status_t AudioRecord::removeAudioDeviceCallback(
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    if (mDeviceCallback != callback) {
    if (mDeviceCallback.unsafe_get() != callback.get()) {
        ALOGW("%s removing different callback!", __FUNCTION__);
        return INVALID_OPERATION;
    }
    mDeviceCallback.clear();
    if (mInput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
        AudioSystem::removeAudioDeviceCallback(this, mInput);
    }
    mDeviceCallback = 0;
    return NO_ERROR;
}

void AudioRecord::onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                 audio_port_handle_t deviceId)
{
    sp<AudioSystem::AudioDeviceCallback> callback;
    {
        AutoMutex lock(mLock);
        if (audioIo != mInput) {
            return;
        }
        callback = mDeviceCallback.promote();
        // only update device if the record is active as route changes due to other use cases are
        // irrelevant for this client
        if (mActive) {
            mRoutedDeviceId = deviceId;
        }
    }
    if (callback.get() != nullptr) {
        callback->onAudioDeviceUpdate(mInput, mRoutedDeviceId);
    }
}

// =========================================================================

void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
+39 −17
Original line number Diff line number Diff line
@@ -493,14 +493,16 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
    if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;

    audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
    Vector < sp<AudioDeviceCallback> > callbacks;
    Vector < wp<AudioDeviceCallback> > callbacks;

    {
        Mutex::Autolock _l(mLock);

        switch (event) {
        case AUDIO_OUTPUT_OPENED:
        case AUDIO_INPUT_OPENED: {
        case AUDIO_OUTPUT_REGISTERED:
        case AUDIO_INPUT_OPENED:
        case AUDIO_INPUT_REGISTERED: {
            sp<AudioIoDescriptor> oldDesc = getIoDescriptor_l(ioDesc->mIoHandle);
            if (oldDesc == 0) {
                mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
@@ -511,13 +513,19 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even

            if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
                deviceId = ioDesc->getDeviceId();
                if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
                    if (ioIndex >= 0) {
                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
                    }
                }
            ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
                    "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
            }
            ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
                    "frameCount %zu deviceId %d",
                    event == AUDIO_OUTPUT_OPENED || event == AUDIO_OUTPUT_REGISTERED ?
                            "output" : "input",
                            event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED ?
                            "opened" : "registered",
                    ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
                    ioDesc->mFrameCount, ioDesc->getDeviceId());
            } break;
@@ -563,9 +571,23 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
        } break;
        }
    }
    bool callbackRemoved = false;
    // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
    for (size_t i = 0; i < callbacks.size(); i++) {
        callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
    for (size_t i = 0; i < callbacks.size(); ) {
        sp<AudioDeviceCallback> callback = callbacks[i].promote();
        if (callback.get() != nullptr) {
            callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
            i++;
        } else {
            callbacks.removeAt(i);
            callbackRemoved = true;
        }
    }
    // clean up callback list while we are here if some clients have disappeared without
    // unregistering their callback
    if (callbackRemoved) {
        Mutex::Autolock _l(mLock);
        mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
    }
}

@@ -618,17 +640,17 @@ sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_
}

status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
    Mutex::Autolock _l(mLock);
    Vector < sp<AudioDeviceCallback> > callbacks;
    Vector < wp<AudioDeviceCallback> > callbacks;
    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
    if (ioIndex >= 0) {
        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
    }

    for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
        if (callbacks[cbIndex] == callback) {
        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
            return INVALID_OPERATION;
        }
    }
@@ -639,18 +661,18 @@ status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
}

status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
    Mutex::Autolock _l(mLock);
    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
    if (ioIndex < 0) {
        return INVALID_OPERATION;
    }
    Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
    Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);

    size_t cbIndex;
    for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
        if (callbacks[cbIndex] == callback) {
        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
            break;
        }
    }
@@ -1128,7 +1150,7 @@ status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callb
}

status_t AudioSystem::addAudioDeviceCallback(
        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
    if (afc == 0) {
@@ -1145,7 +1167,7 @@ status_t AudioSystem::addAudioDeviceCallback(
}

status_t AudioSystem::removeAudioDeviceCallback(
        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
    if (afc == 0) {
+67 −28
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ AudioTrack::~AudioTrack()
        }
        // No lock here: worst case we remove a NULL callback which will be a nop
        if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
            AudioSystem::removeAudioDeviceCallback(this, mOutput);
        }
        IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
        mAudioTrack.clear();
@@ -1229,19 +1229,26 @@ audio_port_handle_t AudioTrack::getOutputDevice() {
    return mSelectedDeviceId;
}

audio_port_handle_t AudioTrack::getRoutedDeviceId() {
    AutoMutex lock(mLock);
    if (mOutput == AUDIO_IO_HANDLE_NONE) {
        return AUDIO_PORT_HANDLE_NONE;
// must be called with mLock held
void AudioTrack::updateRoutedDeviceId_l()
{
    // if the track is inactive, do not update actual device as the output stream maybe routed
    // to a device not relevant to this client because of other active use cases.
    if (mState != STATE_ACTIVE) {
        return;
    }
    // if the output stream does not have an active audio patch, use either the device initially
    // selected by audio policy manager or the last routed device
    if (mOutput != AUDIO_IO_HANDLE_NONE) {
        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
        deviceId = mRoutedDeviceId;
    }
        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
            mRoutedDeviceId = deviceId;
    return deviceId;
        }
    }
}

audio_port_handle_t AudioTrack::getRoutedDeviceId() {
    AutoMutex lock(mLock);
    updateRoutedDeviceId_l();
    return mRoutedDeviceId;
}

status_t AudioTrack::attachAuxEffect(int effectId)
@@ -1305,12 +1312,10 @@ status_t AudioTrack::createTrack_l()
        return NO_INIT;
    }

    if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
    }
    audio_io_handle_t output;
    audio_stream_type_t streamType = mStreamType;
    audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
    bool callbackAdded = false;

    // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
    // After fast request is denied, we will request again if IAudioTrack is re-created.
@@ -1515,12 +1520,14 @@ status_t AudioTrack::createTrack_l()
    sp<IMemory> iMem = track->getCblk();
    if (iMem == 0) {
        ALOGE("Could not get control block");
        return NO_INIT;
        status = NO_INIT;
        goto release;
    }
    void *iMemPointer = iMem->pointer();
    if (iMemPointer == NULL) {
        ALOGE("Could not get control block pointer");
        return NO_INIT;
        status = NO_INIT;
        goto release;
    }
    // invariant that mAudioTrack != 0 is true only after set() returns successfully
    if (mAudioTrack != 0) {
@@ -1582,6 +1589,15 @@ status_t AudioTrack::createTrack_l()
        }
    }

    //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
    if (mDeviceCallback != 0 && mOutput != output) {
        if (mOutput != AUDIO_IO_HANDLE_NONE) {
            AudioSystem::removeAudioDeviceCallback(this, mOutput);
        }
        AudioSystem::addAudioDeviceCallback(this, output);
        callbackAdded = true;
    }

    // We retain a copy of the I/O handle, but don't own the reference
    mOutput = output;
    mRefreshRemaining = true;
@@ -1597,7 +1613,8 @@ status_t AudioTrack::createTrack_l()
        buffers = mSharedBuffer->pointer();
        if (buffers == NULL) {
            ALOGE("Could not get buffer pointer");
            return NO_INIT;
            status = NO_INIT;
            goto release;
        }
    }

@@ -1642,15 +1659,15 @@ status_t AudioTrack::createTrack_l()
    mDeathNotifier = new DeathNotifier(this);
    IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);

    if (mDeviceCallback != 0) {
        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput);
    }

    return NO_ERROR;
    }

release:
    AudioSystem::releaseOutput(output, streamType, mSessionId);
    if (callbackAdded) {
        // note: mOutput is always valid is callbackAdded is true
        AudioSystem::removeAudioDeviceCallback(this, mOutput);
    }
    if (status == NO_ERROR) {
        status = NO_INIT;
    }
@@ -2851,7 +2868,7 @@ status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCal
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    if (mDeviceCallback == callback) {
    if (mDeviceCallback.unsafe_get() == callback.get()) {
        ALOGW("%s adding same callback!", __FUNCTION__);
        return INVALID_OPERATION;
    }
@@ -2859,9 +2876,9 @@ status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCal
    if (mOutput != AUDIO_IO_HANDLE_NONE) {
        if (mDeviceCallback != 0) {
            ALOGW("%s callback already present!", __FUNCTION__);
            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
            AudioSystem::removeAudioDeviceCallback(this, mOutput);
        }
        status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
        status = AudioSystem::addAudioDeviceCallback(this, mOutput);
    }
    mDeviceCallback = callback;
    return status;
@@ -2875,17 +2892,39 @@ status_t AudioTrack::removeAudioDeviceCallback(
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    if (mDeviceCallback != callback) {
    if (mDeviceCallback.unsafe_get() != callback.get()) {
        ALOGW("%s removing different callback!", __FUNCTION__);
        return INVALID_OPERATION;
    }
    mDeviceCallback.clear();
    if (mOutput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
        AudioSystem::removeAudioDeviceCallback(this, mOutput);
    }
    mDeviceCallback = 0;
    return NO_ERROR;
}


void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                 audio_port_handle_t deviceId)
{
    sp<AudioSystem::AudioDeviceCallback> callback;
    {
        AutoMutex lock(mLock);
        if (audioIo != mOutput) {
            return;
        }
        callback = mDeviceCallback.promote();
        // only update device if the track is active as route changes due to other use cases are
        // irrelevant for this client
        if (mState == STATE_ACTIVE) {
            mRoutedDeviceId = deviceId;
        }
    }
    if (callback.get() != nullptr) {
        callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
    }
}

status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
{
    if (msec == nullptr ||
+2 −0
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@
namespace android {

enum audio_io_config_event {
    AUDIO_OUTPUT_REGISTERED,
    AUDIO_OUTPUT_OPENED,
    AUDIO_OUTPUT_CLOSED,
    AUDIO_OUTPUT_CONFIG_CHANGED,
    AUDIO_INPUT_REGISTERED,
    AUDIO_INPUT_OPENED,
    AUDIO_INPUT_CLOSED,
    AUDIO_INPUT_CONFIG_CHANGED,
+14 −3
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ class AudioRecordClientProxy;

// ----------------------------------------------------------------------------

class AudioRecord : public RefBase
class AudioRecord : public AudioSystem::AudioDeviceCallback
{
public:

@@ -424,7 +424,12 @@ public:

     /* Returns the ID of the audio device actually used by the input to which this AudioRecord
      * is attached.
      * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input.
      * The device ID is relevant only if the AudioRecord is active.
      * When the AudioRecord is inactive, the device ID returned can be either:
      * - AUDIO_PORT_HANDLE_NONE if the AudioRecord is not attached to any output.
      * - The device ID used before paused or stopped.
      * - The device ID selected by audio policy manager of setOutputDevice() if the AudioRecord
      * has not been started yet.
      *
      * Parameters:
      *  none.
@@ -454,6 +459,10 @@ public:
            status_t removeAudioDeviceCallback(
                    const sp<AudioSystem::AudioDeviceCallback>& callback);

            // AudioSystem::AudioDeviceCallback> virtuals
            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                             audio_port_handle_t deviceId);

private:
    /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
     * additional non-contiguous frames that are predicted to be available immediately,
@@ -561,6 +570,8 @@ private:
            // FIXME enum is faster than strcmp() for parameter 'from'
            status_t restoreRecord_l(const char *from);

            void     updateRoutedDeviceId_l();

    sp<AudioRecordThread>   mAudioRecordThread;
    mutable Mutex           mLock;

@@ -665,7 +676,7 @@ private:
    audio_port_handle_t     mRoutedDeviceId;   // Device actually selected by audio policy manager:
                                              // May not match the app selection depending on other
                                              // activity and connected devices
    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
    audio_port_handle_t    mPortId;  // unique ID allocated by audio policy

};
Loading