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

Commit 73d5ec40 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "AudioFlinger: Add IAfPatchPanel interface" into main

parents 83bd62b6 b6692eba
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -328,7 +328,6 @@ AudioFlinger::AudioFlinger()
      mTotalMemory(0),
      mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes),
      mGlobalEffectEnableTime(0),
      mPatchPanel(this),
      mPatchCommandThread(sp<PatchCommandThread>::make()),
      mDeviceEffectManager(sp<DeviceEffectManager>::make(*this)),
      mMelReporter(sp<MelReporter>::make(*this)),
@@ -934,7 +933,7 @@ NO_THREAD_SAFETY_ANALYSIS // conditional try lock
            dev->dump(fd, args);
        }

        mPatchPanel.dump(fd);
        mPatchPanel->dump(fd);

        mDeviceEffectManager->dump(fd);

@@ -1822,8 +1821,8 @@ void AudioFlinger::forwardParametersToDownstreamPatches_l(
        audio_io_handle_t upStream, const String8& keyValuePairs,
        const std::function<bool(const sp<IAfPlaybackThread>&)>& useThread)
{
    std::vector<PatchPanel::SoftwarePatch> swPatches;
    if (mPatchPanel.getDownstreamSoftwarePatches(upStream, &swPatches) != OK) return;
    std::vector<SoftwarePatch> swPatches;
    if (mPatchPanel->getDownstreamSoftwarePatches(upStream, &swPatches) != OK) return;
    ALOGV_IF(!swPatches.empty(), "%s found %zu downstream patches for stream ID %d",
            __func__, swPatches.size(), upStream);
    for (const auto& swPatch : swPatches) {
@@ -3077,7 +3076,7 @@ sp<IAfThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
            }
            mPlaybackThreads.add(*output, thread);
            struct audio_patch patch;
            mPatchPanel.notifyStreamOpened(outHwDev, *output, &patch);
            mPatchPanel->notifyStreamOpened(outHwDev, *output, &patch);
            if (thread->isMsdDevice()) {
                thread->setDownStreamPatch(&patch);
            }
@@ -3240,7 +3239,7 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
            ALOGD("closing mmapThread %p", mmapThread.get());
        }
        ioConfigChanged(AUDIO_OUTPUT_CLOSED, sp<AudioIoDescriptor>::make(output));
        mPatchPanel.notifyStreamClosed(output);
        mPatchPanel->notifyStreamClosed(output);
    }
    // The thread entity (active unit of execution) is no longer running here,
    // but the IAfThreadBase container still exists.
@@ -4329,7 +4328,7 @@ status_t AudioFlinger::createEffect(const media::CreateEffectRequest& request,
            sp<Client> client = registerPid(currentPid);
            ALOGV("%s device type %#x address %s", __func__, device.mType, device.getAddress());
            handle = mDeviceEffectManager->createEffect_l(
                    &descOut, device, client, effectClient, mPatchPanel.patches_l(),
                    &descOut, device, client, effectClient, mPatchPanel->patches_l(),
                    &enabledOut, &lStatus, probe, request.notifyFramesProcessed);
            if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
                // remove local strong reference to Client with mClientLock held
+3 −1
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@
#include "ResamplerBufferProvider.h"

// include AudioFlinger component interfaces
#include "IAfPatchPanel.h"  // this should be listed before other IAf* interfaces.
#include "IAfEffect.h"
#include "IAfThread.h"
#include "IAfTrack.h"
@@ -879,7 +880,8 @@ private:
    nsecs_t mGlobalEffectEnableTime;  // when a global effect was last enabled

    // protected by mLock
    PatchPanel mPatchPanel;
    const sp<IAfPatchPanel> mPatchPanel = IAfPatchPanel::create(this);

public:
    // TODO(b/288339104) access by getter.
    sp<EffectsFactoryHalInterface> mEffectsFactoryHal;
+251 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

namespace android {

class IAfPatchPanel;
class IAfPatchRecord;
class IAfPatchTrack;
class IAfPlaybackThread;
class IAfRecordThread;
class IAfThreadBase;

class SoftwarePatch {
public:
    SoftwarePatch(
            const sp<const IAfPatchPanel>& patchPanel,
            audio_patch_handle_t patchHandle,
            audio_io_handle_t playbackThreadHandle,
            audio_io_handle_t recordThreadHandle)
        : mPatchPanel(patchPanel),
          mPatchHandle(patchHandle),
          mPlaybackThreadHandle(playbackThreadHandle),
          mRecordThreadHandle(recordThreadHandle) {}
    SoftwarePatch(const SoftwarePatch&) = default;

    // Must be called under AudioFlinger::mLock
    status_t getLatencyMs_l(double* latencyMs) const;
    audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
    audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
    audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };

private:
    const sp<const IAfPatchPanel> mPatchPanel;
    const audio_patch_handle_t mPatchHandle;
    const audio_io_handle_t mPlaybackThreadHandle;
    const audio_io_handle_t mRecordThreadHandle;
};

class IAfPatchPanel : public virtual RefBase {
public:
    static sp<IAfPatchPanel> create(AudioFlinger* audioFlinger);

    // Extraction of inner Endpoint and Patch classes would require interfaces
    // (in the Endpoint case a templated interface) but that seems
    // excessive for now.  We keep them as inner classes until extraction
    // is needed.
    template <typename ThreadType, typename TrackType>
    class Endpoint final {
    public:
        Endpoint() = default;
        Endpoint(const Endpoint&) = delete;
        Endpoint& operator=(const Endpoint& other) noexcept {
            mThread = other.mThread;
            mCloseThread = other.mCloseThread;
            mHandle = other.mHandle;
            mTrack = other.mTrack;
            return *this;
        }
        Endpoint(Endpoint&& other) noexcept { swap(other); }
        Endpoint& operator=(Endpoint&& other) noexcept {
            swap(other);
            return *this;
        }
        ~Endpoint() {
            ALOGE_IF(
                    mHandle != AUDIO_PATCH_HANDLE_NONE,
                    "A non empty Patch Endpoint leaked, handle %d", mHandle);
        }

        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() const { return mThread; }
        sp<TrackType> track() const { return mTrack; }
        sp<const ThreadType> const_thread() const { return mThread; }
        sp<const TrackType> const_track() const { return mTrack; }

        void closeConnections(const sp<IAfPatchPanel>& panel) {
            if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
                panel->releaseAudioPatch(mHandle);
                mHandle = AUDIO_PATCH_HANDLE_NONE;
            }
            if (mThread != nullptr) {
                if (mTrack != nullptr) {
                    mThread->deletePatchTrack(mTrack);
                }
                if (mCloseThread) {
                    panel->closeThreadInternal_l(mThread);
                }
            }
        }
        audio_patch_handle_t* handlePtr() { return &mHandle; }
        void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
            mThread = thread;
            mCloseThread = closeThread;
        }
        template <typename T>
        void setTrackAndPeer(const sp<TrackType>& track, const sp<T>& peer, bool holdReference) {
            mTrack = track;
            mThread->addPatchTrack(mTrack);
            mTrack->setPeerProxy(peer, holdReference);
            mClearPeerProxy = holdReference;
        }
        void clearTrackPeer() {
            if (mClearPeerProxy && mTrack) mTrack->clearPeerProxy();
        }
        void stopTrack() {
            if (mTrack) mTrack->stop();
        }

        void swap(Endpoint& other) noexcept {
            using std::swap;
            swap(mThread, other.mThread);
            swap(mCloseThread, other.mCloseThread);
            swap(mClearPeerProxy, other.mClearPeerProxy);
            swap(mHandle, other.mHandle);
            swap(mTrack, other.mTrack);
        }

        friend void swap(Endpoint& a, Endpoint& b) noexcept { a.swap(b); }

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

    class Patch final {
    public:
        Patch(const struct audio_patch& patch, bool endpointPatch)
            : mAudioPatch(patch), mIsEndpointPatch(endpointPatch) {}
        Patch() = default;
        ~Patch();
        Patch(const Patch& other) noexcept {
            mAudioPatch = other.mAudioPatch;
            mHalHandle = other.mHalHandle;
            mPlayback = other.mPlayback;
            mRecord = other.mRecord;
            mThread = other.mThread;
            mIsEndpointPatch = other.mIsEndpointPatch;
        }
        Patch(Patch&& other) noexcept { swap(other); }
        Patch& operator=(Patch&& other) noexcept {
            swap(other);
            return *this;
        }

        void swap(Patch& other) noexcept {
            using std::swap;
            swap(mAudioPatch, other.mAudioPatch);
            swap(mHalHandle, other.mHalHandle);
            swap(mPlayback, other.mPlayback);
            swap(mRecord, other.mRecord);
            swap(mThread, other.mThread);
            swap(mIsEndpointPatch, other.mIsEndpointPatch);
        }

        friend void swap(Patch& a, Patch& b) noexcept { a.swap(b); }

        status_t createConnections(const sp<IAfPatchPanel>& panel);
        void clearConnections(const sp<IAfPatchPanel>& panel);
        bool isSoftware() const {
            return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
                   mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE;
        }

        void setThread(const sp<IAfThreadBase>& thread) { mThread = thread; }
        wp<IAfThreadBase> thread() const { return mThread; }

        // returns the latency of the patch (from record to playback).
        status_t getLatencyMs(double* latencyMs) const;

        String8 dump(audio_patch_handle_t myHandle) const;

        // Note that audio_patch::id is only unique within a HAL module
        struct audio_patch mAudioPatch;
        // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
        audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE;
        // below members are used by a software audio patch connecting a source device from a
        // 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
        // connects playback thread output to sink device
        Endpoint<IAfPlaybackThread, IAfPatchTrack> mPlayback;
        // connects source device to record thread input
        Endpoint<IAfRecordThread, IAfPatchRecord> mRecord;

        wp<IAfThreadBase> mThread;
        bool mIsEndpointPatch;
    };

    /* List connected audio ports and their attributes */
    virtual status_t listAudioPorts(unsigned int* num_ports, struct audio_port* ports) = 0;

    /* Get supported attributes for a given audio port */
    virtual status_t getAudioPort(struct audio_port_v7* port) = 0;

    /* Create a patch between several source and sink ports */
    virtual status_t createAudioPatch(
            const struct audio_patch* patch,
            audio_patch_handle_t* handle,
            bool endpointPatch = false) = 0;

    /* Release a patch */
    virtual status_t releaseAudioPatch(audio_patch_handle_t handle) = 0;

    /* List connected audio devices and they attributes */
    virtual status_t listAudioPatches(unsigned int* num_patches, struct audio_patch* patches) = 0;

    // Retrieves all currently estrablished software patches for a stream
    // opened on an intermediate module.
    virtual status_t getDownstreamSoftwarePatches(
            audio_io_handle_t stream, std::vector<SoftwarePatch>* patches) const = 0;

    // Notifies patch panel about all opened and closed streams.
    virtual void notifyStreamOpened(
            AudioHwDevice* audioHwDevice, audio_io_handle_t stream, struct audio_patch* patch) = 0;

    virtual void notifyStreamClosed(audio_io_handle_t stream) = 0;

    virtual void dump(int fd) const = 0;

    // Must be called under AudioFlinger::mLock

    virtual const std::map<audio_patch_handle_t, Patch>& patches_l() const = 0;

    virtual status_t getLatencyMs_l(audio_patch_handle_t patchHandle, double* latencyMs) const = 0;

    virtual void closeThreadInternal_l(const sp<IAfThreadBase>& thread) const = 0;
};

}  // namespace android
+38 −12
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ status_t AudioFlinger::listAudioPorts(unsigned int *num_ports,
                                struct audio_port *ports)
{
    Mutex::Autolock _l(mLock);
    return mPatchPanel.listAudioPorts(num_ports, ports);
    return mPatchPanel->listAudioPorts(num_ports, ports);
}

/* Get supported attributes for a given audio port */
@@ -63,7 +63,7 @@ status_t AudioFlinger::getAudioPort(struct audio_port_v7 *port) {
    }

    Mutex::Autolock _l(mLock);
    return mPatchPanel.getAudioPort(port);
    return mPatchPanel->getAudioPort(port);
}

/* Connect a patch between several source and sink ports */
@@ -76,14 +76,14 @@ status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
    }

    Mutex::Autolock _l(mLock);
    return mPatchPanel.createAudioPatch(patch, handle);
    return mPatchPanel->createAudioPatch(patch, handle);
}

/* Disconnect a patch */
status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
{
    Mutex::Autolock _l(mLock);
    return mPatchPanel.releaseAudioPatch(handle);
    return mPatchPanel->releaseAudioPatch(handle);
}

/* List connected audio ports and they attributes */
@@ -91,19 +91,44 @@ status_t AudioFlinger::listAudioPatches(unsigned int *num_patches,
                                  struct audio_patch *patches)
{
    Mutex::Autolock _l(mLock);
    return mPatchPanel.listAudioPatches(num_patches, patches);
    return mPatchPanel->listAudioPatches(num_patches, patches);
}

status_t AudioFlinger::PatchPanel::SoftwarePatch::getLatencyMs_l(double *latencyMs) const
/* static */
sp<IAfPatchPanel> IAfPatchPanel::create(AudioFlinger* audioFlinger) {
    return sp<AudioFlinger::PatchPanel>::make(audioFlinger);
}

status_t SoftwarePatch::getLatencyMs_l(double* latencyMs) const {
    return mPatchPanel->getLatencyMs_l(mPatchHandle, latencyMs);
}

status_t AudioFlinger::PatchPanel::getLatencyMs_l(
        audio_patch_handle_t patchHandle, double* latencyMs) const
{
    const auto& iter = mPatchPanel.mPatches.find(mPatchHandle);
    if (iter != mPatchPanel.mPatches.end()) {
    const auto& iter = mPatches.find(patchHandle);
    if (iter != mPatches.end()) {
        return iter->second.getLatencyMs(latencyMs);
    } else {
        return BAD_VALUE;
    }
}

void AudioFlinger::PatchPanel::closeThreadInternal_l(const sp<IAfThreadBase>& thread) const
{
    if (const auto recordThread = thread->asIAfRecordThread();
            recordThread) {
        mAudioFlinger.closeThreadInternal_l(recordThread);
    } else if (const auto playbackThread = thread->asIAfPlaybackThread();
            playbackThread) {
        mAudioFlinger.closeThreadInternal_l(playbackThread);
    } else {
        LOG_ALWAYS_FATAL("%s: Endpoints only accept IAfPlayback and IAfRecord threads, "
                "invalid thread, id: %d  type: %d",
                __func__, thread->id(), thread->type());
    }
}

/* List connected audio ports and their attributes */
status_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused,
                                struct audio_port *ports __unused)
@@ -482,7 +507,7 @@ AudioFlinger::PatchPanel::Patch::~Patch()
            mRecord.handle(), mPlayback.handle());
}

status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
status_t AudioFlinger::PatchPanel::Patch::createConnections(const sp<IAfPatchPanel>& panel)
{
    // create patch from source device to record thread input
    status_t status = panel->createAudioPatch(
@@ -646,7 +671,7 @@ status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
    return status;
}

void AudioFlinger::PatchPanel::Patch::clearConnections(PatchPanel *panel)
void AudioFlinger::PatchPanel::Patch::clearConnections(const sp<IAfPatchPanel>& panel)
{
    ALOGV("%s() mRecord.handle %d mPlayback.handle %d",
            __func__, mRecord.handle(), mPlayback.handle());
@@ -839,7 +864,7 @@ status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __

status_t AudioFlinger::PatchPanel::getDownstreamSoftwarePatches(
        audio_io_handle_t stream,
        std::vector<AudioFlinger::PatchPanel::SoftwarePatch> *patches) const
        std::vector<SoftwarePatch>* patches) const
{
    for (const auto& module : mInsertedModules) {
        if (module.second.streams.count(stream)) {
@@ -847,7 +872,8 @@ status_t AudioFlinger::PatchPanel::getDownstreamSoftwarePatches(
                const auto& patch_iter = mPatches.find(patchHandle);
                if (patch_iter != mPatches.end()) {
                    const Patch &patch = patch_iter->second;
                    patches->emplace_back(*this, patchHandle,
                    patches->emplace_back(sp<const IAfPatchPanel>::fromExisting(this),
                            patchHandle,
                            patch.mPlayback.const_thread()->id(),
                            patch.mRecord.const_thread()->id());
                } else {
+15 −178

File changed.

Preview size limit exceeded, changes collapsed.

Loading