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

Commit a80b03f6 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Android (Google) Code Review
Browse files

Merge "PatchPanel: Cleanup and refactoring"

parents e57f2cd6 444ecc34
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2293,7 +2293,7 @@ void AudioFlinger::closeOutputFinish(const sp<PlaybackThread>& thread)
    delete out;
}

void AudioFlinger::closeOutputInternal_l(const sp<PlaybackThread>& thread)
void AudioFlinger::closeThreadInternal_l(const sp<PlaybackThread>& thread)
{
    mPlaybackThreads.removeItem(thread->mId);
    thread->exit();
@@ -2586,7 +2586,7 @@ void AudioFlinger::closeInputFinish(const sp<RecordThread>& thread)
    delete in;
}

void AudioFlinger::closeInputInternal_l(const sp<RecordThread>& thread)
void AudioFlinger::closeThreadInternal_l(const sp<RecordThread>& thread)
{
    mRecordThreads.removeItem(thread->mId);
    closeInputFinish(thread);
+2 −2
Original line number Diff line number Diff line
@@ -791,9 +791,9 @@ private:

    // for use from destructor
    status_t    closeOutput_nonvirtual(audio_io_handle_t output);
    void        closeOutputInternal_l(const sp<PlaybackThread>& thread);
    void        closeThreadInternal_l(const sp<PlaybackThread>& thread);
    status_t    closeInput_nonvirtual(audio_io_handle_t input);
    void        closeInputInternal_l(const sp<RecordThread>& thread);
    void        closeThreadInternal_l(const sp<RecordThread>& thread);
    void        setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId);

    status_t    checkStreamType(audio_stream_type_t stream) const;
+75 −113
Original line number Diff line number Diff line
@@ -125,18 +125,16 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa
        if (iter != mPatches.end()) {
            ALOGV("%s() removing patch handle %d", __func__, *handle);
            Patch &removedPatch = iter->second;
            halHandle = removedPatch.mHalHandle;
            // free resources owned by the removed patch if applicable
            // 1) if a software patch is present, release the playback and capture threads and
            // tracks created. This will also release the corresponding audio HAL patches
            if ((removedPatch.mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) ||
                    (removedPatch.mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE)) {
            if (removedPatch.isSoftware()) {
                removedPatch.clearConnections(this);
            }
            // 2) if the new patch and old patch source or sink are devices from different
            // hw modules,  clear the audio HAL patches now because they will not be updated
            // by call to create_audio_patch() below which will happen on a different HW module
            if (halHandle != AUDIO_PATCH_HANDLE_NONE) {
            if (removedPatch.mHalHandle != AUDIO_PATCH_HANDLE_NONE) {
                audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;
                const struct audio_patch &oldPatch = removedPatch.mAudioPatch;
                if (oldPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE &&
@@ -153,16 +151,12 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa
                    // these special patches are only created by the policy manager but just
                    // in case, systematically clear the HAL patch.
                    // Note that removedPatch.mAudioPatch.num_sinks cannot be 0 here because
                    // halHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
                    // removedPatch.mHalHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
                    hwModule = oldPatch.sinks[0].ext.device.hw_module;
                }
                if (hwModule != AUDIO_MODULE_HANDLE_NONE) {
                    ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(hwModule);
                    if (index >= 0) {
                        sp<DeviceHalInterface> hwDevice =
                                mAudioFlinger.mAudioHwDevs.valueAt(index)->hwDevice();
                        hwDevice->releaseAudioPatch(halHandle);
                    }
                sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(hwModule);
                if (hwDevice != 0) {
                    hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
                }
            }
            mPatches.erase(iter);
@@ -217,12 +211,14 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa

                    sp<ThreadBase> thread =
                            mAudioFlinger.checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
                    newPatch.mPlaybackThread = (MixerThread *)thread.get();
                    if (thread == 0) {
                        ALOGW("%s() cannot get playback thread", __func__);
                        status = INVALID_OPERATION;
                        goto exit;
                    }
                    // existing playback thread is reused, so it is not closed when patch is cleared
                    newPatch.mPlayback.setThread(
                            reinterpret_cast<PlaybackThread*>(thread.get()), false /*closeThread*/);
                } else {
                    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
                    audio_devices_t device = patch->sinks[0].ext.device.type;
@@ -235,13 +231,12 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa
                                                            device,
                                                            address,
                                                            AUDIO_OUTPUT_FLAG_NONE);
                    newPatch.mPlaybackThread = (PlaybackThread *)thread.get();
                    ALOGV("mAudioFlinger.openOutput_l() returned %p",
                                          newPatch.mPlaybackThread.get());
                    if (newPatch.mPlaybackThread == 0) {
                    ALOGV("mAudioFlinger.openOutput_l() returned %p", thread.get());
                    if (thread == 0) {
                        status = NO_MEMORY;
                        goto exit;
                    }
                    newPatch.mPlayback.setThread(reinterpret_cast<PlaybackThread*>(thread.get()));
                }
                audio_devices_t device = patch->sources[0].ext.device.type;
                String8 address = String8(patch->sources[0].ext.device.address);
@@ -251,18 +246,18 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa
                if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
                    config.sample_rate = patch->sources[0].sample_rate;
                } else {
                    config.sample_rate = newPatch.mPlaybackThread->sampleRate();
                    config.sample_rate = newPatch.mPlayback.thread()->sampleRate();
                }
                if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
                    config.channel_mask = patch->sources[0].channel_mask;
                } else {
                    config.channel_mask =
                        audio_channel_in_mask_from_count(newPatch.mPlaybackThread->channelCount());
                    config.channel_mask = audio_channel_in_mask_from_count(
                            newPatch.mPlayback.thread()->channelCount());
                }
                if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) {
                    config.format = patch->sources[0].format;
                } else {
                    config.format = newPatch.mPlaybackThread->format();
                    config.format = newPatch.mPlayback.thread()->format();
                }
                audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
                sp<ThreadBase> thread = mAudioFlinger.openInput_l(srcModule,
@@ -272,13 +267,13 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa
                                                                    address,
                                                                    AUDIO_SOURCE_MIC,
                                                                    AUDIO_INPUT_FLAG_NONE);
                newPatch.mRecordThread = (RecordThread *)thread.get();
                ALOGV("mAudioFlinger.openInput_l() returned %p inChannelMask %08x",
                      newPatch.mRecordThread.get(), config.channel_mask);
                if (newPatch.mRecordThread == 0) {
                      thread.get(), config.channel_mask);
                if (thread == 0) {
                    status = NO_MEMORY;
                    goto exit;
                }
                newPatch.mRecord.setThread(reinterpret_cast<RecordThread*>(thread.get()));
                status = newPatch.createConnections(this);
                if (status != NO_ERROR) {
                    goto exit;
@@ -369,6 +364,12 @@ exit:
    return status;
}

AudioFlinger::PatchPanel::Patch::~Patch()
{
    ALOGE_IF(isSoftware(), "Software patch connections leaked %d %d",
            mRecord.handle(), mPlayback.handle());
}

status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
{
    // create patch from source device to record thread input
@@ -377,32 +378,32 @@ status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
    subPatch.sources[0] = mAudioPatch.sources[0];
    subPatch.num_sinks = 1;

    mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
    mRecord.thread()->getAudioPortConfig(&subPatch.sinks[0]);
    subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;

    status_t status = panel->createAudioPatch(&subPatch, &mRecordPatchHandle);
    status_t status = panel->createAudioPatch(&subPatch, mRecord.handlePtr());
    if (status != NO_ERROR) {
        mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
        *mRecord.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
        return status;
    }

    // create patch from playback thread output to sink device
    if (mAudioPatch.num_sinks != 0) {
        mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
        mPlayback.thread()->getAudioPortConfig(&subPatch.sources[0]);
        subPatch.sinks[0] = mAudioPatch.sinks[0];
        status = panel->createAudioPatch(&subPatch, &mPlaybackPatchHandle);
        status = panel->createAudioPatch(&subPatch, mPlayback.handlePtr());
        if (status != NO_ERROR) {
            mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
            *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
            return status;
        }
    } else {
        mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
        *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
    }

    // use a pseudo LCM between input and output framecount
    size_t playbackFrameCount = mPlaybackThread->frameCount();
    size_t playbackFrameCount = mPlayback.thread()->frameCount();
    int playbackShift = __builtin_ctz(playbackFrameCount);
    size_t recordFramecount = mRecordThread->frameCount();
    size_t recordFramecount = mRecord.thread()->frameCount();
    int shift = __builtin_ctz(recordFramecount);
    if (playbackShift < shift) {
        shift = playbackShift;
@@ -412,14 +413,14 @@ status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
            __func__, playbackFrameCount, recordFramecount, frameCount);

    // create a special record track to capture from record thread
    uint32_t channelCount = mPlaybackThread->channelCount();
    uint32_t channelCount = mPlayback.thread()->channelCount();
    audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
    audio_channel_mask_t outChannelMask = mPlaybackThread->channelMask();
    uint32_t sampleRate = mPlaybackThread->sampleRate();
    audio_format_t format = mPlaybackThread->format();
    audio_channel_mask_t outChannelMask = mPlayback.thread()->channelMask();
    uint32_t sampleRate = mPlayback.thread()->sampleRate();
    audio_format_t format = mPlayback.thread()->format();

    mPatchRecord = new RecordThread::PatchRecord(
                                             mRecordThread.get(),
    sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
                                             mRecord.thread().get(),
                                             sampleRate,
                                             inChannelMask,
                                             format,
@@ -427,91 +428,47 @@ status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
                                             NULL,
                                             (size_t)0 /* bufferSize */,
                                             AUDIO_INPUT_FLAG_NONE);
    if (mPatchRecord == 0) {
        return NO_MEMORY;
    }
    status = mPatchRecord->initCheck();
    status = mRecord.checkTrack(tempRecordTrack.get());
    if (status != NO_ERROR) {
        return status;
    }
    mRecordThread->addPatchRecord(mPatchRecord);

    // create a special playback track to render to playback thread.
    // this track is given the same buffer as the PatchRecord buffer
    mPatchTrack = new PlaybackThread::PatchTrack(
                                           mPlaybackThread.get(),
    sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
                                           mPlayback.thread().get(),
                                           mAudioPatch.sources[1].ext.mix.usecase.stream,
                                           sampleRate,
                                           outChannelMask,
                                           format,
                                           frameCount,
                                           mPatchRecord->buffer(),
                                           mPatchRecord->bufferSize(),
                                           tempRecordTrack->buffer(),
                                           tempRecordTrack->bufferSize(),
                                           AUDIO_OUTPUT_FLAG_NONE);
    status = mPatchTrack->initCheck();
    status = mPlayback.checkTrack(tempPatchTrack.get());
    if (status != NO_ERROR) {
        return status;
    }
    mPlaybackThread->addPatchTrack(mPatchTrack);

    // tie playback and record tracks together
    mPatchRecord->setPeerProxy(mPatchTrack.get());
    mPatchTrack->setPeerProxy(mPatchRecord.get());
    mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack.get());
    mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack.get());

    // start capture and playback
    mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
    mPatchTrack->start();
    mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
    mPlayback.track()->start();

    return status;
}

void AudioFlinger::PatchPanel::Patch::clearConnections(PatchPanel *panel)
{
    ALOGV("%s() mRecordPatchHandle %d mPlaybackPatchHandle %d",
            __func__, mRecordPatchHandle, mPlaybackPatchHandle);

    if (mPatchRecord != 0) {
        mPatchRecord->stop();
    }
    if (mPatchTrack != 0) {
        mPatchTrack->stop();
    }
    if (mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
        panel->releaseAudioPatch(mRecordPatchHandle);
        mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
    }
    if (mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
        panel->releaseAudioPatch(mPlaybackPatchHandle);
        mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
    }
    if (mRecordThread != 0) {
        if (mPatchRecord != 0) {
            mRecordThread->deletePatchRecord(mPatchRecord);
        }
        panel->mAudioFlinger.closeInputInternal_l(mRecordThread);
    }
    if (mPlaybackThread != 0) {
        if (mPatchTrack != 0) {
            mPlaybackThread->deletePatchTrack(mPatchTrack);
        }
        // if num sources == 2 we are reusing an existing playback thread so we do not close it
        if (mAudioPatch.num_sources != 2) {
            panel->mAudioFlinger.closeOutputInternal_l(mPlaybackThread);
        }
    }
    if (mRecordThread != 0) {
        if (mPatchRecord != 0) {
            mPatchRecord.clear();
        }
        mRecordThread.clear();
    }
    if (mPlaybackThread != 0) {
        if (mPatchTrack != 0) {
            mPatchTrack.clear();
        }
        mPlaybackThread.clear();
    }

    ALOGV("%s() mRecord.handle %d mPlayback.handle %d",
            __func__, mRecord.handle(), mPlayback.handle());
    mRecord.stopTrack();
    mPlayback.stopTrack();
    mRecord.closeConnections(panel);
    mPlayback.closeConnections(panel);
}

/* Disconnect a patch */
@@ -527,18 +484,17 @@ status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle
    Patch &removedPatch = iter->second;
    const struct audio_patch &patch = removedPatch.mAudioPatch;

    switch (patch.sources[0].type) {
    const struct audio_port_config &src = patch.sources[0];
    switch (src.type) {
        case AUDIO_PORT_TYPE_DEVICE: {
            audio_module_handle_t srcModule = patch.sources[0].ext.device.hw_module;
            ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(srcModule);
            if (index < 0) {
                ALOGW("%s() bad src hw module %d", __func__, srcModule);
            sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(src.ext.device.hw_module);
            if (hwDevice == 0) {
                ALOGW("%s() bad src hw module %d", __func__, src.ext.device.hw_module);
                status = BAD_VALUE;
                break;
            }

            if (removedPatch.mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE ||
                    removedPatch.mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
            if (removedPatch.isSoftware()) {
                removedPatch.clearConnections(this);
                break;
            }
@@ -556,20 +512,16 @@ status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle
                }
                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
            } else {
                AudioHwDevice *audioHwDevice = mAudioFlinger.mAudioHwDevs.valueAt(index);
                sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
                status = hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
            }
        } break;
        case AUDIO_PORT_TYPE_MIX: {
            audio_module_handle_t srcModule =  patch.sources[0].ext.mix.hw_module;
            ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(srcModule);
            if (index < 0) {
                ALOGW("%s() bad src hw module %d", __func__, srcModule);
            if (findHwDeviceByModule(src.ext.mix.hw_module) == 0) {
                ALOGW("%s() bad src hw module %d", __func__, src.ext.mix.hw_module);
                status = BAD_VALUE;
                break;
            }
            audio_io_handle_t ioHandle = patch.sources[0].ext.mix.handle;
            audio_io_handle_t ioHandle = src.ext.mix.handle;
            sp<ThreadBase> thread = mAudioFlinger.checkPlaybackThread_l(ioHandle);
            if (thread == 0) {
                thread = mAudioFlinger.checkMmapThread_l(ioHandle);
@@ -597,4 +549,14 @@ status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __
    return NO_ERROR;
}

sp<DeviceHalInterface> AudioFlinger::PatchPanel::findHwDeviceByModule(audio_module_handle_t module)
{
    if (module == AUDIO_MODULE_HANDLE_NONE) return nullptr;
    ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(module);
    if (index < 0) {
        return nullptr;
    }
    return mAudioFlinger.mAudioHwDevs.valueAt(index)->hwDevice();
}

} // namespace android
+55 −9
Original line number Diff line number Diff line
@@ -43,12 +43,61 @@ public:
                                      struct audio_patch *patches);

private:
    template<typename ThreadType, typename TrackType>
    class Endpoint {
    public:
        status_t checkTrack(TrackType *trackOrNull) const {
            if (trackOrNull == nullptr) return NO_MEMORY;
            return trackOrNull->initCheck();
        }
        audio_patch_handle_t handle() const { return mHandle; }
        sp<ThreadType> thread() { return mThread; }
        sp<TrackType> track() { return mTrack; }

        void closeConnections(PatchPanel *panel) {
            if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
                panel->releaseAudioPatch(mHandle);
                mHandle = AUDIO_PATCH_HANDLE_NONE;
            }
            if (mThread != 0) {
                if (mTrack != 0) {
                    mThread->deletePatchTrack(mTrack);
                }
                if (mCloseThread) {
                    panel->mAudioFlinger.closeThreadInternal_l(mThread);
                }
            }
        }
        audio_patch_handle_t* handlePtr() { return &mHandle; }
        void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
            mThread = thread;
            mCloseThread = closeThread;
        }
        void setTrackAndPeer(const sp<TrackType>& track,
                             ThreadBase::PatchProxyBufferProvider *peer) {
            mTrack = track;
            mThread->addPatchTrack(mTrack);
            mTrack->setPeerProxy(peer);
        }
        void stopTrack() { if (mTrack) mTrack->stop(); }

    private:
        sp<ThreadType> mThread;
        bool mCloseThread = true;
        audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
        sp<TrackType> mTrack;
    };

    class Patch {
    public:
        explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
        ~Patch();

        status_t createConnections(PatchPanel *panel);
        void clearConnections(PatchPanel *panel);
        bool isSoftware() const {
            return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
                    mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }

        // Note that audio_patch::id is only unique within a HAL module
        struct audio_patch              mAudioPatch;
@@ -58,17 +107,14 @@ private:
        // given audio HW module to a sink device on an other audio HW module.
        // the objects are created by createConnections() and released by clearConnections()
        // playback thread is created if no existing playback thread can be used
        sp<PlaybackThread>              mPlaybackThread;
        sp<PlaybackThread::PatchTrack>  mPatchTrack;
        sp<RecordThread>                mRecordThread;
        sp<RecordThread::PatchRecord>   mPatchRecord;
        // handle for audio patch connecting source device to record thread input.
        audio_patch_handle_t            mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
        // handle for audio patch connecting playback thread output to sink device
        audio_patch_handle_t            mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;

        // connects playback thread output to sink device
        Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
        // connects source device to record thread input
        Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
    };

    sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);

    AudioFlinger &mAudioFlinger;
    std::map<audio_patch_handle_t, Patch> mPatches;
};
+2 −2
Original line number Diff line number Diff line
@@ -7840,13 +7840,13 @@ status_t AudioFlinger::RecordThread::releaseAudioPatch_l(const audio_patch_handl
    return status;
}

void AudioFlinger::RecordThread::addPatchRecord(const sp<PatchRecord>& record)
void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
{
    Mutex::Autolock _l(mLock);
    mTracks.add(record);
}

void AudioFlinger::RecordThread::deletePatchRecord(const sp<PatchRecord>& record)
void AudioFlinger::RecordThread::deletePatchTrack(const sp<PatchRecord>& record)
{
    Mutex::Autolock _l(mLock);
    destroyTrack_l(record);
Loading