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

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

audio policy: audio source automatic re-connection



When an audio source is started, if either the sink or the source
becomes unavailable, the audio source is stopped.
It implies that the client must listen to patch/ports to become
aware that the source has been stopped.

In order to prevent this, it is possible to allow automatic re-connection
of audio source as APM already keeps track of AudioSource.

In case of unavailability, source is only disconnected, not stopped to prevent
from removing from tracking list.

Test: adb shell /data/nativetest64/AudioPolicyEmulatorTests/AudioPolicyEmulatorTests --gtest_filter=*AudioSourceBridgingTest*

Signed-off-by: default avatarFrancois Gaffie <francois.gaffie@renault.com>
Change-Id: I414195a85a06c9212420e3b51bf2863f3e08c755
parent ff1eb523
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -198,10 +198,18 @@ public:

    ~SourceClientDescriptor() override = default;

    void connect(audio_patch_handle_t patchHandle, const sp<DeviceDescriptor>& sinkDevice) {
        mPatchHandle = patchHandle;
        mSinkDevice = sinkDevice;
    }
    void disconnect() {
        mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
        mSinkDevice = nullptr;
    }
    bool isConnected() const { return mPatchHandle != AUDIO_PATCH_HANDLE_NONE; }
    audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
    void setPatchHandle(audio_patch_handle_t patchHandle) { mPatchHandle = patchHandle; }

    sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
    sp<DeviceDescriptor> sinkDevice() const { return mSinkDevice; }
    wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
    void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
    wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
@@ -213,6 +221,7 @@ public:
 private:
    audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
    const sp<DeviceDescriptor> mSrcDevice;
    sp<DeviceDescriptor> mSinkDevice;
    wp<SwAudioOutputDescriptor> mSwOutput;
    wp<HwAudioOutputDescriptor> mHwOutput;
};
+30 −13
Original line number Diff line number Diff line
@@ -385,7 +385,11 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript
            DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
            updateCallRouting(newDevices);
        }

        // Reconnect Audio Source
        for (const auto &strategy : mEngine->getOrderedProductStrategies()) {
            auto attributes = mEngine->getAllAttributesForProductStrategy(strategy).front();
            checkAudioSourceForAttributes(attributes);
        }
        if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
            cleanUpForDevice(device);
        }
@@ -4273,18 +4277,21 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>

    // make sure we only have one patch per source.
    disconnectAudioSource(sourceDesc);
    sourceDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);

    audio_attributes_t attributes = sourceDesc->attributes();
    sp<DeviceDescriptor> srcDevice = sourceDesc->srcDevice();

    // May the device (dynamic) have been disconnected/reconnected, id has changed.
    sp<DeviceDescriptor> srcDevice = mAvailableInputDevices.getDevice(
                sourceDesc->srcDevice()->type(),
                String8(sourceDesc->srcDevice()->address().c_str()),
                AUDIO_FORMAT_DEFAULT);
    DeviceVector sinkDevices =
            mEngine->getOutputDevicesForAttributes(attributes, nullptr, false /*fromCache*/);
    ALOG_ASSERT(!sinkDevices.isEmpty(), "connectAudioSource(): no device found for attributes");
    sp<DeviceDescriptor> sinkDevice = sinkDevices.itemAt(0);
    ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available",
                __FUNCTION__, sinkDevice->toString().c_str());

    if (!mAvailableOutputDevices.contains(sinkDevice)) {
        ALOGE("%s Device %s not available", __func__, sinkDevice->toString().c_str());
        return INVALID_OPERATION;
    }
    PatchBuilder patchBuilder;
    patchBuilder.addSink(sinkDevice).addSource(srcDevice);
    audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
@@ -4294,7 +4301,7 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
        ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
        return INVALID_OPERATION;
    }
    sourceDesc->setPatchHandle(handle);
    sourceDesc->connect(handle, sinkDevice);
    // SW Bridge? (@todo: HW bridge, keep track of HwOutput for device selection "reconsideration")
    sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
    if (swOutput != 0) {
@@ -4591,6 +4598,10 @@ bool AudioPolicyManager::isCallScreenModeSupported()
status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
    ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
    if (!sourceDesc->isConnected()) {
        ALOGV("%s port Id %d already disconnected", __FUNCTION__, sourceDesc->portId());
        return NO_ERROR;
    }
    sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
    if (swOutput != 0) {
        status_t status = stopSource(swOutput, sourceDesc);
@@ -4610,7 +4621,9 @@ status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescript
            ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
        }
    }
    return releaseAudioPatchInternal(sourceDesc->getPatchHandle());
    status_t status = releaseAudioPatchInternal(sourceDesc->getPatchHandle());
    sourceDesc->disconnect();
    return status;
}

sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput(
@@ -6476,9 +6489,9 @@ void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc
{
    for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--)  {
        sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
        if (sourceDesc->srcDevice()->equals(deviceDesc)) {
            ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->portId());
            stopAudioSource(sourceDesc->portId());
        if (sourceDesc->isConnected() && (sourceDesc->srcDevice()->equals(deviceDesc) ||
                                          sourceDesc->sinkDevice()->equals(deviceDesc))) {
            disconnectAudioSource(sourceDesc);
        }
    }

@@ -6492,10 +6505,14 @@ void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc
                release = true;
            }
        }
        const char *address = deviceDesc->address().c_str();
        for (size_t j = 0; j < patchDesc->mPatch.num_sinks && !release; j++)  {
            const struct audio_port_config *sink = &patchDesc->mPatch.sinks[j];
            if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
                    sink->ext.device.type == deviceDesc->type()) {
                    sink->ext.device.type == deviceDesc->type() &&
                    (strnlen(address, AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0
                     || strncmp(sink->ext.device.address, address,
                                 AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
                release = true;
            }
        }