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

Commit 24a9fb0d authored by Francois Gaffie's avatar Francois Gaffie Committed by Eric Laurent
Browse files

libaudioclient: force onAudioDeviceUpdate on registration



This CL forces the onAudioDeviceUpdate on register event.
It also fixes the loss of callback on AudioTrack or AudioRecord
client if received before ioHandle is assigned.

Test: audio smoke tests
Test: CTS for AudioTrack and AudioRouting

Change-Id: I119b5c407da68a5b55162550bea5fa7e724165d1
Signed-off-by: default avatarFrancois Gaffie <francois.gaffie@renault.com>
parent a6d5e8b3
Loading
Loading
Loading
Loading
+11 −6
Original line number Original line Diff line number Diff line
@@ -355,7 +355,10 @@ status_t AudioRecord::set(
    }
    }


    // create the IAudioRecord
    // create the IAudioRecord
    {
        AutoMutex lock(mLock);
        status = createRecord_l(0 /*epoch*/, mOpPackageName);
        status = createRecord_l(0 /*epoch*/, mOpPackageName);
    }


    ALOGV("%s(%d): status %d", __func__, mPortId, status);
    ALOGV("%s(%d): status %d", __func__, mPortId, status);


@@ -1358,12 +1361,14 @@ status_t AudioRecord::removeAudioDeviceCallback(
        ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
        ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }
    {
        AutoMutex lock(mLock);
        AutoMutex lock(mLock);
        if (mDeviceCallback.unsafe_get() != callback.get()) {
        if (mDeviceCallback.unsafe_get() != callback.get()) {
            ALOGW("%s(%d): removing different callback!", __func__, mPortId);
            ALOGW("%s(%d): removing different callback!", __func__, mPortId);
            return INVALID_OPERATION;
            return INVALID_OPERATION;
        }
        }
        mDeviceCallback.clear();
        mDeviceCallback.clear();
    }
    if (mInput != AUDIO_IO_HANDLE_NONE) {
    if (mInput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(this, mInput);
        AudioSystem::removeAudioDeviceCallback(this, mInput);
    }
    }
+36 −21
Original line number Original line Diff line number Diff line
@@ -522,8 +522,9 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
    if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
    if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;


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

    bool deviceValidOrChanged = false;
    Mutex::Autolock _l(mCallbacksLock);
    {
    {
        Mutex::Autolock _l(mLock);
        Mutex::Autolock _l(mLock);


@@ -546,6 +547,13 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
                    if (ioIndex >= 0) {
                    if (ioIndex >= 0) {
                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
                        deviceValidOrChanged = true;
                    }
                }
                if (event == AUDIO_OUTPUT_REGISTERED || event == AUDIO_INPUT_REGISTERED) {
                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
                    if ((ioIndex >= 0) && !mAudioDeviceCallbacks.valueAt(ioIndex).notifiedOnce()) {
                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
                    }
                    }
                }
                }
            }
            }
@@ -584,6 +592,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
            mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
            mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);


            if (deviceId != ioDesc->getDeviceId()) {
            if (deviceId != ioDesc->getDeviceId()) {
                deviceValidOrChanged = true;
                deviceId = ioDesc->getDeviceId();
                deviceId = ioDesc->getDeviceId();
                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
                if (ioIndex >= 0) {
                if (ioIndex >= 0) {
@@ -600,22 +609,28 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
        } break;
        } break;
        }
        }
    }
    }
    bool callbackRemoved = false;
    // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
    // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
    if (callbacks.size() != 0) {
        for (size_t i = 0; i < callbacks.size(); ) {
        for (size_t i = 0; i < callbacks.size(); ) {
            sp<AudioDeviceCallback> callback = callbacks[i].promote();
            sp<AudioDeviceCallback> callback = callbacks[i].promote();
            if (callback.get() != nullptr) {
            if (callback.get() != nullptr) {
                // Call the callback only if the device actually changed, the input or output was
                // opened or closed or the client was newly registered and the callback was never
                // called
                if (!callback->notifiedOnce() || deviceValidOrChanged) {
                    // Must be called without mLock held. May lead to dead lock if calling for
                    // example getRoutedDevice that updates the device and tries to acquire mLock.
                    callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
                    callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
                    callback->setNotifiedOnce();
                }
                i++;
                i++;
            } else {
            } else {
                callbacks.removeAt(i);
                callbacks.removeAt(i);
            callbackRemoved = true;
            }
            }
        }
        }
        callbacks.setNotifiedOnce();
        // clean up callback list while we are here if some clients have disappeared without
        // clean up callback list while we are here if some clients have disappeared without
    // unregistering their callback
        // unregistering their callback, or if cb was served for the first time since registered
    if (callbackRemoved) {
        Mutex::Autolock _l(mLock);
        mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
        mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
    }
    }
}
}
@@ -671,8 +686,8 @@ sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_
status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
{
    Mutex::Autolock _l(mLock);
    Mutex::Autolock _l(mCallbacksLock);
    Vector < wp<AudioDeviceCallback> > callbacks;
    AudioDeviceCallbacks callbacks;
    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
    if (ioIndex >= 0) {
    if (ioIndex >= 0) {
        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
@@ -684,7 +699,7 @@ status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
        }
        }
    }
    }
    callbacks.add(callback);
    callbacks.add(callback);

    callbacks.resetNotifiedOnce();
    mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
    mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
    return NO_ERROR;
    return NO_ERROR;
}
}
@@ -692,12 +707,12 @@ status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
{
    Mutex::Autolock _l(mLock);
    Mutex::Autolock _l(mCallbacksLock);
    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
    if (ioIndex < 0) {
    if (ioIndex < 0) {
        return INVALID_OPERATION;
        return INVALID_OPERATION;
    }
    }
    Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
    AudioDeviceCallbacks callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);


    size_t cbIndex;
    size_t cbIndex;
    for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
    for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
+11 −7
Original line number Original line Diff line number Diff line
@@ -621,8 +621,10 @@ status_t AudioTrack::set(
    }
    }


    // create the IAudioTrack
    // create the IAudioTrack
    {
        AutoMutex lock(mLock);
        status = createTrack_l();
        status = createTrack_l();

    }
    if (status != NO_ERROR) {
    if (status != NO_ERROR) {
        if (mAudioTrackThread != 0) {
        if (mAudioTrackThread != 0) {
            mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
            mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
@@ -2957,12 +2959,14 @@ status_t AudioTrack::removeAudioDeviceCallback(
        ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
        ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }
    {
        AutoMutex lock(mLock);
        AutoMutex lock(mLock);
        if (mDeviceCallback.unsafe_get() != callback.get()) {
        if (mDeviceCallback.unsafe_get() != callback.get()) {
        ALOGW("%s(%d): removing different callback!", __func__, mPortId);
            ALOGW("%s removing different callback!", __FUNCTION__);
            return INVALID_OPERATION;
            return INVALID_OPERATION;
        }
        }
        mDeviceCallback.clear();
        mDeviceCallback.clear();
    }
    if (mOutput != AUDIO_IO_HANDLE_NONE) {
    if (mOutput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(this, mOutput);
        AudioSystem::removeAudioDeviceCallback(this, mOutput);
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -677,7 +677,7 @@ private:
    sp<IMemory>             mCblkMemory;
    sp<IMemory>             mCblkMemory;
    audio_track_cblk_t*     mCblk;              // re-load after mLock.unlock()
    audio_track_cblk_t*     mCblk;              // re-load after mLock.unlock()
    sp<IMemory>             mBufferMemory;
    sp<IMemory>             mBufferMemory;
    audio_io_handle_t       mInput;             // returned by AudioSystem::getInput()
    audio_io_handle_t       mInput = AUDIO_IO_HANDLE_NONE; // from AudioSystem::getInputforAttr()


    int                     mPreviousPriority;  // before start()
    int                     mPreviousPriority;  // before start()
    SchedPolicy             mPreviousSchedulingGroup;
    SchedPolicy             mPreviousSchedulingGroup;
+30 −2
Original line number Original line Diff line number Diff line
@@ -398,6 +398,15 @@ public:


        virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
        virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                         audio_port_handle_t deviceId) = 0;
                                         audio_port_handle_t deviceId) = 0;
                bool notifiedOnce() const { return mNotifiedOnce; }
                void setNotifiedOnce() { mNotifiedOnce = true; }
    private:
                /**
                 * @brief mNotifiedOnce it forces the callback to be called at least once when
                 * registered with a VALID AudioDevice, and allows not to flood other listeners
                 * on this iohandle that already know the valid device.
                 */
                bool mNotifiedOnce = false;
    };
    };


    static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
    static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
@@ -443,8 +452,27 @@ private:
    private:
    private:
        Mutex                               mLock;
        Mutex                               mLock;
        DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> >   mIoDescriptors;
        DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> >   mIoDescriptors;
        DefaultKeyedVector<audio_io_handle_t, Vector < wp<AudioDeviceCallback> > >

                                                                        mAudioDeviceCallbacks;
        class AudioDeviceCallbacks : public Vector<wp<AudioDeviceCallback>>
        {
        public:
            /**
             * @brief notifiedOnce ensures that if a client adds a callback, it must at least be
             * called once with the device on which it will be routed to.
             * @return true if already notified or nobody waits for a callback, false otherwise.
             */
            bool notifiedOnce() const { return (size() == 0) || mNotifiedOnce; }
            void setNotifiedOnce() { mNotifiedOnce = true; }
            void resetNotifiedOnce() { mNotifiedOnce = false; }
        private:
            /**
             * @brief mNotifiedOnce it forces each callback to be called at least once when
             * registered with a VALID AudioDevice
             */
            bool mNotifiedOnce = false;
        };
        Mutex                               mCallbacksLock; // prevents race on Callbacks
        DefaultKeyedVector<audio_io_handle_t, AudioDeviceCallbacks> mAudioDeviceCallbacks;
        // cached values for recording getInputBufferSize() queries
        // cached values for recording getInputBufferSize() queries
        size_t                              mInBuffSize;    // zero indicates cache is invalid
        size_t                              mInBuffSize;    // zero indicates cache is invalid
        uint32_t                            mInSamplingRate;
        uint32_t                            mInSamplingRate;
Loading