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

Commit 572e61da authored by Ping Tsai's avatar Ping Tsai Committed by MugaChi
Browse files

audio policy: handle errors for usb broadcast device connection

When the USB is quickly connected and then disconnected, the broadcast device may not have enough time to read the USB info, preventing the dynamic profile from being created and causing routing errors. Therefore, when the usb broadcast device connection fails, setDeviceConnectionState will be interrupted

Bug: 360284877
Test:
Atest AudioPolicyManagerTestDeviceConnectionFailed

Change-Id: I3bd31f1455cfaf9f1041cf079b92b6b407c3a74e
parent 6f2b31f5
Loading
Loading
Loading
Loading
+22 −9
Original line number Diff line number Diff line
@@ -122,17 +122,16 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
    }
}

void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
status_t AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
                                                        media::DeviceConnectedState state)
{
    audio_port_v7 devicePort;
    device->toAudioPort(&devicePort);
    if (status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
            status != OK) {
        ALOGE("Error %d while setting connected state %d for device %s",
                status, static_cast<int>(state),
                device->getDeviceTypeAddr().toString(false).c_str());
    }
    status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
    ALOGE_IF(status != OK, "Error %d while setting connected state %d for device %s", status,
             static_cast<int>(state), device->getDeviceTypeAddr().toString(false).c_str());

    return status;
}

status_t AudioPolicyManager::setDeviceConnectionStateInt(
@@ -213,7 +212,14 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript

            // Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
            // parameters on newly connected devices (instead of opening the outputs...)
            broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
            if (broadcastDeviceConnectionState(
                        device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
                mAvailableOutputDevices.remove(device);
                mHwModules.cleanUpForDevice(device);
                ALOGE("%s() device %s format %x connection failed", __func__,
                      device->toString().c_str(), device->getEncodedFormat());
                return INVALID_OPERATION;
            }

            if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
                mAvailableOutputDevices.remove(device);
@@ -398,7 +404,14 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript

            // Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
            // parameters on newly connected devices (instead of opening the inputs...)
            broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
            if (broadcastDeviceConnectionState(
                        device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
                mAvailableInputDevices.remove(device);
                mHwModules.cleanUpForDevice(device);
                ALOGE("%s() device %s format %x connection failed", __func__,
                      device->toString().c_str(), device->getEncodedFormat());
                return INVALID_OPERATION;
            }
            // Propagate device availability to Engine
            setEngineDeviceConnectionState(device, state);

+2 −2
Original line number Diff line number Diff line
@@ -1077,7 +1077,7 @@ private:
        // It can give a chance to HAL implementer to retrieve dynamic capabilities associated
        // to this device for example.
        // TODO avoid opening stream to retrieve capabilities of a profile.
        void broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
        status_t broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
                                                media::DeviceConnectedState state);

        // updates device caching and output for streams that can influence the
+48 −0
Original line number Diff line number Diff line
@@ -2648,8 +2648,29 @@ class AudioPolicyManagerTestClientOpenFails : public AudioPolicyManagerTestClien

    void setSimulateFailure(bool simulateFailure) { mSimulateFailure = simulateFailure; }

    void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
        if (status != NO_ERROR) {
            // simulate device connect status
            mSimulateBroadcastDeviceStatus[device] = status;
        } else {
            // remove device connection fixed status
            mSimulateBroadcastDeviceStatus.erase(device);
        }
    }

    status_t setDeviceConnectedState(const struct audio_port_v7* port,
                                     media::DeviceConnectedState state) override {
        if (mSimulateBroadcastDeviceStatus.find(port->ext.device.type) !=
            mSimulateBroadcastDeviceStatus.end()) {
            // If a simulated status exists, return a status value
            return mSimulateBroadcastDeviceStatus[port->ext.device.type];
        }
        return AudioPolicyManagerTestClient::setDeviceConnectedState(port, state);
    }

  private:
    bool mSimulateFailure = false;
    std::map<audio_devices_t, status_t> mSimulateBroadcastDeviceStatus;
};

}  // namespace
@@ -2670,6 +2691,9 @@ class AudioPolicyManagerTestDeviceConnectionFailed :
    void setSimulateOpenFailure(bool simulateFailure) {
        mFullClient->setSimulateFailure(simulateFailure); }

    void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
        mFullClient->setSimulateBroadcastDeviceStatus(device, status); }

    static const std::string sBluetoothConfig;

  private:
@@ -2713,6 +2737,30 @@ TEST_P(AudioPolicyManagerTestDeviceConnectionFailed, SetDeviceConnectedStateHasA
    }
}

TEST_P(AudioPolicyManagerTestDeviceConnectionFailed, BroadcastDeviceFailure) {
    const audio_devices_t type = std::get<0>(GetParam());
    const std::string name = std::get<1>(GetParam());
    const std::string address = std::get<2>(GetParam());
    const audio_format_t format = std::get<3>(GetParam());

    // simulate broadcastDeviceConnectionState return failure
    setSimulateBroadcastDeviceStatus(type, INVALID_OPERATION);
    ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
            address.c_str(), name.c_str(), format));

    // if broadcast is fail, device should not be added to available devices list
    if (audio_is_output_device(type)) {
        auto availableDevices = mManager->getAvailableOutputDevices();
        EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
    } else if (audio_is_input_device(type)) {
        auto availableDevices = mManager->getAvailableInputDevices();
        EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
    }

    setSimulateBroadcastDeviceStatus(type, NO_ERROR);
}

INSTANTIATE_TEST_CASE_P(
        DeviceConnectionFailure,
        AudioPolicyManagerTestDeviceConnectionFailed,