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

Commit a444666e authored by Eric Laurent's avatar Eric Laurent Committed by android-build-merger
Browse files

Merge "audio: improve audio routing callbacks" into qt-dev

am: 9f5591ac

Change-Id: I33c26881df9668bac78dc1b2a257e5c44d8c8e28
parents 21c26f83 9f5591ac
Loading
Loading
Loading
Loading
+10 −10
Original line number Diff line number Diff line
@@ -177,7 +177,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(this, mInput);
            AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
        }
        IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
        mAudioRecord.clear();
@@ -790,14 +790,13 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String
    mAudioRecord = record;
    mCblkMemory = output.cblk;
    mBufferMemory = output.buffers;
    mPortId = output.portId;
    IPCThreadState::self()->flushCommands();

    mCblk = cblk;
    // note that output.frameCount is the (possibly revised) value of mReqFrameCount
    if (output.frameCount < mReqFrameCount || (mReqFrameCount == 0 && output.frameCount == 0)) {
        ALOGW("%s(%d): Requested frameCount %zu but received frameCount %zu",
              __func__, mPortId,
              __func__, output.portId,
              mReqFrameCount,  output.frameCount);
    }

@@ -805,19 +804,20 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String
    // The computation is done on server side.
    if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) {
        ALOGW("%s(%d): Server adjusted notificationFrames from %u to %zu for frameCount %zu",
                __func__, mPortId,
                __func__, output.portId,
                mNotificationFramesReq, output.notificationFrameCount, output.frameCount);
    }
    mNotificationFramesAct = (uint32_t)output.notificationFrameCount;

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

    mPortId = output.portId;
    // We retain a copy of the I/O handle, but don't own the reference
    mInput = output.inputId;
    mRefreshRemaining = true;
@@ -1332,9 +1332,9 @@ status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCa
    if (mInput != AUDIO_IO_HANDLE_NONE) {
        if (mDeviceCallback != 0) {
            ALOGW("%s(%d): callback already present!", __func__, mPortId);
            AudioSystem::removeAudioDeviceCallback(this, mInput);
            AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
        }
        status = AudioSystem::addAudioDeviceCallback(this, mInput);
        status = AudioSystem::addAudioDeviceCallback(this, mInput, mPortId);
    }
    mDeviceCallback = callback;
    return status;
@@ -1354,7 +1354,7 @@ status_t AudioRecord::removeAudioDeviceCallback(
    }
    mDeviceCallback.clear();
    if (mInput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(this, mInput);
        AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
    }
    return NO_ERROR;
}
+57 −74
Original line number Diff line number Diff line
@@ -523,12 +523,10 @@ 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>> callbacksToCall;
    std::vector<sp<AudioDeviceCallback>> callbacksToCall;
    {
        Mutex::Autolock _l(mLock);
        bool deviceValidOrChanged = false;
        bool sendCallbacks = false;
        ssize_t ioIndex = -1;
        auto callbacks = std::map<audio_port_handle_t, wp<AudioDeviceCallback>>();

        switch (event) {
        case AUDIO_OUTPUT_OPENED:
@@ -546,17 +544,11 @@ 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) {
                    ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
                    if (ioIndex >= 0) {
                        sendCallbacks = true;
                        deviceValidOrChanged = true;
                    auto it = mAudioDeviceCallbacks.find(ioDesc->mIoHandle);
                    if (it != mAudioDeviceCallbacks.end()) {
                        callbacks = it->second;
                    }
                }
                if (event == AUDIO_OUTPUT_REGISTERED || event == AUDIO_INPUT_REGISTERED) {
                    ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
                    sendCallbacks = (ioIndex >= 0)
                            && !mAudioDeviceCallbackProxies.valueAt(ioIndex).notifiedOnce();
                }
            }
            ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
                    "frameCount %zu deviceId %d",
@@ -578,7 +570,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
                  event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle);

            mIoDescriptors.removeItem(ioDesc->mIoHandle);
            mAudioDeviceCallbackProxies.removeItem(ioDesc->mIoHandle);
            mAudioDeviceCallbacks.erase(ioDesc->mIoHandle);
            } break;

        case AUDIO_OUTPUT_CONFIG_CHANGED:
@@ -593,10 +585,11 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
            mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);

            if (deviceId != ioDesc->getDeviceId()) {
                deviceValidOrChanged = true;
                deviceId = ioDesc->getDeviceId();
                ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
                sendCallbacks = ioIndex >= 0;
                auto it = mAudioDeviceCallbacks.find(ioDesc->mIoHandle);
                if (it != mAudioDeviceCallbacks.end()) {
                    callbacks = it->second;
                }
            }
            ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x "
                    "channel mask %#x frameCount %zu frameCountHAL %zu deviceId %d",
@@ -606,35 +599,40 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
                    ioDesc->getDeviceId());

        } break;
        case AUDIO_CLIENT_STARTED: {
            sp<AudioIoDescriptor> oldDesc = getIoDescriptor_l(ioDesc->mIoHandle);
            if (oldDesc == 0) {
                ALOGW("ioConfigChanged() start client on unknown io! %d", ioDesc->mIoHandle);
                break;
            }

        // sendCallbacks true =>  ioDesc->mIoHandle and deviceId are valid
        if (sendCallbacks) {
            AudioDeviceCallbackProxies &callbackProxies =
                mAudioDeviceCallbackProxies.editValueAt(ioIndex);
            for (size_t i = 0; i < callbackProxies.size(); ) {
                sp<AudioDeviceCallback> callback = callbackProxies[i]->callback();
                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 (!callbackProxies[i]->notifiedOnce() || deviceValidOrChanged) {
                        callbacksToCall.add(callback);
                        callbackProxies[i]->setNotifiedOnce();
                    }
                    i++;
                } else {
                    callbackProxies.removeAt(i);
            ALOGV("ioConfigChanged() AUDIO_CLIENT_STARTED  io %d port %d num callbacks %zu",
                ioDesc->mIoHandle, ioDesc->mPortId, mAudioDeviceCallbacks.size());
            oldDesc->mPatch = ioDesc->mPatch;
            auto it = mAudioDeviceCallbacks.find(ioDesc->mIoHandle);
            if (it != mAudioDeviceCallbacks.end()) {
                auto cbks = it->second;
                auto it2 = cbks.find(ioDesc->mPortId);
                if (it2 != cbks.end()) {
                   callbacks.emplace(ioDesc->mPortId, it2->second);
                   deviceId = oldDesc->getDeviceId();
                }
            }
            callbackProxies.setNotifiedOnce();
        } break;
        }

        for (auto wpCbk : callbacks) {
            sp<AudioDeviceCallback> spCbk = wpCbk.second.promote();
            if (spCbk != nullptr) {
                callbacksToCall.push_back(spCbk);
            }
        }
    }

    // Callbacks 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.
    for (size_t i = 0; i < callbacksToCall.size(); i++) {
        callbacksToCall[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
    for (auto cb  : callbacksToCall) {
        // If callbacksToCall is not empty, it implies ioDesc->mIoHandle and deviceId are valid
        cb->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
    }
}

@@ -687,51 +685,34 @@ sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_
}

status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo,
        audio_port_handle_t portId)
{
    ALOGV("%s audioIo %d portId %d", __func__, audioIo, portId);
    Mutex::Autolock _l(mLock);
    AudioDeviceCallbackProxies callbackProxies;
    ssize_t ioIndex = mAudioDeviceCallbackProxies.indexOfKey(audioIo);
    if (ioIndex >= 0) {
        callbackProxies = mAudioDeviceCallbackProxies.valueAt(ioIndex);
    }

    for (size_t cbIndex = 0; cbIndex < callbackProxies.size(); cbIndex++) {
        sp<AudioDeviceCallback> cbk = callbackProxies[cbIndex]->callback();
        if (cbk.get() == callback.unsafe_get()) {
    auto& callbacks = mAudioDeviceCallbacks.emplace(audioIo, std::map<audio_port_handle_t, wp<AudioDeviceCallback>>()).first->second;
    auto result = callbacks.try_emplace(portId, callback);
    if (!result.second) {
        return INVALID_OPERATION;
    }
    }
    callbackProxies.add(new AudioDeviceCallbackProxy(callback));
    callbackProxies.resetNotifiedOnce();
    mAudioDeviceCallbackProxies.replaceValueFor(audioIo, callbackProxies);
    return NO_ERROR;
}

status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback __unused, audio_io_handle_t audioIo,
        audio_port_handle_t portId)
{
    ALOGV("%s audioIo %d portId %d", __func__, audioIo, portId);
    Mutex::Autolock _l(mLock);
    ssize_t ioIndex = mAudioDeviceCallbackProxies.indexOfKey(audioIo);
    if (ioIndex < 0) {
    auto it = mAudioDeviceCallbacks.find(audioIo);
    if (it == mAudioDeviceCallbacks.end()) {
        return INVALID_OPERATION;
    }
    AudioDeviceCallbackProxies callbackProxies = mAudioDeviceCallbackProxies.valueAt(ioIndex);
    size_t cbIndex;
    for (cbIndex = 0; cbIndex < callbackProxies.size(); cbIndex++) {
        sp<AudioDeviceCallback> cbk = callbackProxies[cbIndex]->callback();
        if (cbk.get() == callback.unsafe_get()) {
            break;
        }
    }
    if (cbIndex == callbackProxies.size()) {
    if (it->second.erase(portId) == 0) {
        return INVALID_OPERATION;
    }
    callbackProxies.removeAt(cbIndex);
    if (callbackProxies.size() != 0) {
        mAudioDeviceCallbackProxies.replaceValueFor(audioIo, callbackProxies);
    } else {
        mAudioDeviceCallbackProxies.removeItem(audioIo);
    if (it->second.size() == 0) {
        mAudioDeviceCallbacks.erase(audioIo);
    }
    return NO_ERROR;
}
@@ -1271,13 +1252,14 @@ status_t AudioSystem::removeAudioVolumeGroupCallback(const sp<AudioVolumeGroupCa
}

status_t AudioSystem::addAudioDeviceCallback(
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo,
        audio_port_handle_t portId)
{
    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
    if (afc == 0) {
        return NO_INIT;
    }
    status_t status = afc->addAudioDeviceCallback(callback, audioIo);
    status_t status = afc->addAudioDeviceCallback(callback, audioIo, portId);
    if (status == NO_ERROR) {
        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
        if (af != 0) {
@@ -1288,13 +1270,14 @@ status_t AudioSystem::addAudioDeviceCallback(
}

status_t AudioSystem::removeAudioDeviceCallback(
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo,
        audio_port_handle_t portId)
{
    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
    if (afc == 0) {
        return NO_INIT;
    }
    return afc->removeAudioDeviceCallback(callback, audioIo);
    return afc->removeAudioDeviceCallback(callback, audioIo, portId);
}

audio_port_handle_t AudioSystem::getDeviceIdForIo(audio_io_handle_t audioIo)
+11 −9
Original line number Diff line number Diff line
@@ -309,7 +309,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(this, mOutput);
            AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
        }
        IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
        mAudioTrack.clear();
@@ -1495,7 +1495,6 @@ status_t AudioTrack::createTrack_l()
    mAfFrameCount = output.afFrameCount;
    mAfSampleRate = output.afSampleRate;
    mAfLatency = output.afLatencyMs;
    mPortId = output.portId;

    mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;

@@ -1543,14 +1542,15 @@ status_t AudioTrack::createTrack_l()
    mFlags = output.flags;

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

    mPortId = output.portId;
    // We retain a copy of the I/O handle, but don't own the reference
    mOutput = output.outputId;
    mRefreshRemaining = true;
@@ -1615,7 +1615,7 @@ status_t AudioTrack::createTrack_l()
exit:
    if (status != NO_ERROR && callbackAdded) {
        // note: mOutput is always valid is callbackAdded is true
        AudioSystem::removeAudioDeviceCallback(this, mOutput);
        AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
    }

    mStatus = status;
@@ -2922,6 +2922,7 @@ uint32_t AudioTrack::getUnderrunFrames() const

status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
{

    if (callback == 0) {
        ALOGW("%s(%d): adding NULL callback!", __func__, mPortId);
        return BAD_VALUE;
@@ -2935,9 +2936,9 @@ status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCal
    if (mOutput != AUDIO_IO_HANDLE_NONE) {
        if (mDeviceCallback != 0) {
            ALOGW("%s(%d): callback already present!", __func__, mPortId);
            AudioSystem::removeAudioDeviceCallback(this, mOutput);
            AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
        }
        status = AudioSystem::addAudioDeviceCallback(this, mOutput);
        status = AudioSystem::addAudioDeviceCallback(this, mOutput, mPortId);
    }
    mDeviceCallback = callback;
    return status;
@@ -2957,7 +2958,7 @@ status_t AudioTrack::removeAudioDeviceCallback(
    }
    mDeviceCallback.clear();
    if (mOutput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(this, mOutput);
        AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
    }
    return NO_ERROR;
}
@@ -2979,6 +2980,7 @@ void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
            mRoutedDeviceId = deviceId;
        }
    }

    if (callback.get() != nullptr) {
        callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
    }
+2 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ public:
        data.writeInt64(ioDesc->mFrameCount);
        data.writeInt64(ioDesc->mFrameCountHAL);
        data.writeInt32(ioDesc->mLatency);
        data.writeInt32(ioDesc->mPortId);
        remote()->transact(IO_CONFIG_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
    }
};
@@ -76,6 +77,7 @@ status_t BnAudioFlingerClient::onTransact(
            ioDesc->mFrameCount = data.readInt64();
            ioDesc->mFrameCountHAL = data.readInt64();
            ioDesc->mLatency = data.readInt32();
            ioDesc->mPortId = data.readInt32();
            ioConfigChanged(event, ioDesc);
            return NO_ERROR;
        } break;
+3 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ enum audio_io_config_event {
    AUDIO_INPUT_OPENED,
    AUDIO_INPUT_CLOSED,
    AUDIO_INPUT_CONFIG_CHANGED,
    AUDIO_CLIENT_STARTED,
};

// audio input/output descriptor used to cache output configurations in client process to avoid
@@ -37,7 +38,7 @@ public:
    AudioIoDescriptor() :
        mIoHandle(AUDIO_IO_HANDLE_NONE),
        mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(AUDIO_CHANNEL_NONE),
        mFrameCount(0), mFrameCountHAL(0), mLatency(0)
        mFrameCount(0), mFrameCountHAL(0), mLatency(0), mPortId(AUDIO_PORT_HANDLE_NONE)
    {
        memset(&mPatch, 0, sizeof(struct audio_patch));
    }
@@ -66,6 +67,7 @@ public:
    size_t                  mFrameCount;
    size_t                  mFrameCountHAL;
    uint32_t                mLatency;   // only valid for output
    audio_port_handle_t     mPortId;    // valid for event AUDIO_CLIENT_STARTED
};


Loading