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

Commit b1ddbb0c authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

libaudiohal@aidl: Implement setConnectedState

Implement the following methods in DeviceHalAidl:
 - getAudioPort (both overloads)
 - setAudioPortConfig
 - setConnectedState

Add DeviceHalInterface::setSimulateDeviceConnections.
This method only works for the AIDL HAL and allows
testing external device connections in unit tests.
Plumb setSimulateDeviceConnections via the audio
framework to expose to libaudioclient tests.

Make conversions to/from AudioDevice and legacy
to use a corresponding variant for the address.
Fix invalid addresses in audiopolicy_tests.

Bug: 273252382
Test: atest audiopolicy_tests
Test: atest audiosystem_tests
Test: atest audio_aidl_conversion_tests
Change-Id: I9ed13b3a464496740f00a6553b1e03a3f884db74
parent 5edc5ed2
Loading
Loading
Loading
Loading
+129 −20
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

#include <stdio.h>

#include <algorithm>
#include <map>
#include <utility>
@@ -570,7 +572,6 @@ const detail::AudioDevicePairs& getAudioDevicePairs() {
                GET_DEVICE_DESC_CONNECTION(BT_LE));
        return pairs;
    }();
#undef GET_DEVICE_DESC_CONNECTION
    return pairs;
}

@@ -998,55 +999,161 @@ ConversionResult<AudioDeviceDescription> legacy2aidl_audio_devices_t_AudioDevice
    }
}

AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& description) {
    using Tag = AudioDeviceAddress::Tag;
    if (std::string connection = description.connection;
            connection == GET_DEVICE_DESC_CONNECTION(BT_A2DP) ||
            // Note: BT LE Broadcast uses a "group id".
            (description.type != AudioDeviceType::OUT_BROADCAST &&
                    connection == GET_DEVICE_DESC_CONNECTION(BT_LE)) ||
            connection == GET_DEVICE_DESC_CONNECTION(BT_SCO) ||
            connection == GET_DEVICE_DESC_CONNECTION(WIRELESS)) {
        return Tag::mac;
    } else if (connection == GET_DEVICE_DESC_CONNECTION(IP_V4)) {
        return Tag::ipv4;
    } else if (connection == GET_DEVICE_DESC_CONNECTION(USB)) {
        return Tag::alsa;
    }
    return Tag::id;
}

::android::status_t aidl2legacy_AudioDevice_audio_device(
        const AudioDevice& aidl,
        audio_devices_t* legacyType, char* legacyAddress) {
    *legacyType = VALUE_OR_RETURN_STATUS(
            aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
    return aidl2legacy_string(
                    aidl.address.get<AudioDeviceAddress::id>(),
                    legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN);
    std::string stringAddress;
    RETURN_STATUS_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
                    aidl, legacyType, &stringAddress));
    return aidl2legacy_string(stringAddress, legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN);
}

::android::status_t aidl2legacy_AudioDevice_audio_device(
        const AudioDevice& aidl,
        audio_devices_t* legacyType, String8* legacyAddress) {
    *legacyType = VALUE_OR_RETURN_STATUS(
            aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
    *legacyAddress = VALUE_OR_RETURN_STATUS(aidl2legacy_string_view_String8(
                    aidl.address.get<AudioDeviceAddress::id>()));
    std::string stringAddress;
    RETURN_STATUS_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
                    aidl, legacyType, &stringAddress));
    *legacyAddress = VALUE_OR_RETURN_STATUS(aidl2legacy_string_view_String8(stringAddress));
    return OK;
}

::android::status_t aidl2legacy_AudioDevice_audio_device(
        const AudioDevice& aidl,
        audio_devices_t* legacyType, std::string* legacyAddress) {
    using Tag = AudioDeviceAddress::Tag;
    *legacyType = VALUE_OR_RETURN_STATUS(
            aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
    *legacyAddress = aidl.address.get<AudioDeviceAddress::id>();
    char addressBuffer[AUDIO_DEVICE_MAX_ADDRESS_LEN]{};
    // 'aidl.address' can be empty even when the connection type is not.
    // This happens for device ports that act as "blueprints". In this case
    // we pass an empty string using the 'id' variant.
    switch (aidl.address.getTag()) {
        case Tag::mac: {
            const std::vector<uint8_t>& mac = aidl.address.get<AudioDeviceAddress::mac>();
            if (mac.size() != 6) return BAD_VALUE;
            snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
                    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
        } break;
        case Tag::ipv4: {
            const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>();
            if (ipv4.size() != 4) return BAD_VALUE;
            snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%u.%u.%u.%u",
                    ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
        } break;
        case Tag::ipv6: {
            const std::vector<int32_t>& ipv6 = aidl.address.get<AudioDeviceAddress::ipv6>();
            if (ipv6.size() != 8) return BAD_VALUE;
            snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN,
                    "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
                    ipv6[0], ipv6[1], ipv6[2], ipv6[3], ipv6[4], ipv6[5], ipv6[6], ipv6[7]);
        } break;
        case Tag::alsa: {
            const std::vector<int32_t>& alsa = aidl.address.get<AudioDeviceAddress::alsa>();
            if (alsa.size() != 2) return BAD_VALUE;
            snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "card=%d;device=%d",
                    alsa[0], alsa[1]);
        } break;
        case Tag::id: {
            RETURN_STATUS_IF_ERROR(aidl2legacy_string(aidl.address.get<AudioDeviceAddress::id>(),
                            addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN));
        } break;
    }
    *legacyAddress = addressBuffer;
    return OK;
}

ConversionResult<AudioDevice> legacy2aidl_audio_device_AudioDevice(
        audio_devices_t legacyType, const char* legacyAddress) {
    AudioDevice aidl;
    aidl.type = VALUE_OR_RETURN(
            legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
    const std::string aidl_id = VALUE_OR_RETURN(
    const std::string stringAddress = VALUE_OR_RETURN(
            legacy2aidl_string(legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN));
    aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(aidl_id);
    return aidl;
    return legacy2aidl_audio_device_AudioDevice(legacyType, stringAddress);
}

ConversionResult<AudioDevice>
legacy2aidl_audio_device_AudioDevice(
        audio_devices_t legacyType, const String8& legacyAddress) {
    const std::string stringAddress = VALUE_OR_RETURN(legacy2aidl_String8_string(legacyAddress));
    return legacy2aidl_audio_device_AudioDevice(legacyType, stringAddress);
}

ConversionResult<AudioDevice>
legacy2aidl_audio_device_AudioDevice(
        audio_devices_t legacyType, const std::string& legacyAddress) {
    using Tag = AudioDeviceAddress::Tag;
    AudioDevice aidl;
    aidl.type = VALUE_OR_RETURN(
            legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
    const std::string aidl_id = VALUE_OR_RETURN(
            legacy2aidl_String8_string(legacyAddress));
    aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(aidl_id);
    // 'legacyAddress' can be empty even when the connection type is not.
    // This happens for device ports that act as "blueprints". In this case
    // we pass an empty string using the 'id' variant.
    if (!legacyAddress.empty()) {
        switch (suggestDeviceAddressTag(aidl.type)) {
            case Tag::mac: {
                std::vector<uint8_t> mac(6);
                int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
                        &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
                if (status != mac.size()) {
                    ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str());
                    return unexpected(BAD_VALUE);
                }
                aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::mac>(std::move(mac));
            } break;
            case Tag::ipv4: {
                std::vector<uint8_t> ipv4(4);
                int status = sscanf(legacyAddress.c_str(), "%hhu.%hhu.%hhu.%hhu",
                        &ipv4[0], &ipv4[1], &ipv4[2], &ipv4[3]);
                if (status != ipv4.size()) {
                    ALOGE("%s: malformed IPv4 address: \"%s\"", __func__, legacyAddress.c_str());
                    return unexpected(BAD_VALUE);
                }
                aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::ipv4>(std::move(ipv4));
            } break;
            case Tag::ipv6: {
                std::vector<int32_t> ipv6(8);
                int status = sscanf(legacyAddress.c_str(), "%X:%X:%X:%X:%X:%X:%X:%X",
                        &ipv6[0], &ipv6[1], &ipv6[2], &ipv6[3], &ipv6[4], &ipv6[5], &ipv6[6],
                        &ipv6[7]);
                if (status != ipv6.size()) {
                    ALOGE("%s: malformed IPv6 address: \"%s\"", __func__, legacyAddress.c_str());
                    return unexpected(BAD_VALUE);
                }
                aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::ipv6>(std::move(ipv6));
            } break;
            case Tag::alsa: {
                std::vector<int32_t> alsa(2);
                int status = sscanf(legacyAddress.c_str(), "card=%d;device=%d", &alsa[0], &alsa[1]);
                if (status != alsa.size()) {
                    ALOGE("%s: malformed ALSA address: \"%s\"", __func__, legacyAddress.c_str());
                    return unexpected(BAD_VALUE);
                }
                aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::alsa>(std::move(alsa));
            } break;
            case Tag::id: {
                aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(legacyAddress);
            } break;
        }
    } else {
        aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(legacyAddress);
    }
    return aidl;
}

@@ -3025,6 +3132,8 @@ legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfos(

}  // namespace android

#undef GET_DEVICE_DESC_CONNECTION

#if defined(BACKEND_NDK)
}  // aidl
#endif
+5 −0
Original line number Diff line number Diff line
@@ -190,6 +190,9 @@ ConversionResult<audio_devices_t> aidl2legacy_AudioDeviceDescription_audio_devic
ConversionResult<media::audio::common::AudioDeviceDescription>
legacy2aidl_audio_devices_t_AudioDeviceDescription(audio_devices_t legacy);

media::audio::common::AudioDeviceAddress::Tag suggestDeviceAddressTag(
        const media::audio::common::AudioDeviceDescription& description);

::android::status_t aidl2legacy_AudioDevice_audio_device(
        const media::audio::common::AudioDevice& aidl, audio_devices_t* legacyType,
        char* legacyAddress);
@@ -204,6 +207,8 @@ ConversionResult<media::audio::common::AudioDevice> legacy2aidl_audio_device_Aud
        audio_devices_t legacyType, const char* legacyAddress);
ConversionResult<media::audio::common::AudioDevice> legacy2aidl_audio_device_AudioDevice(
        audio_devices_t legacyType, const ::android::String8& legacyAddress);
ConversionResult<media::audio::common::AudioDevice> legacy2aidl_audio_device_AudioDevice(
        audio_devices_t legacyType, const std::string& legacyAddress);

ConversionResult<audio_extra_audio_descriptor>
aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor(
+6 −0
Original line number Diff line number Diff line
@@ -264,6 +264,12 @@ status_t AudioSystem::setMode(audio_mode_t mode) {
    return af->setMode(mode);
}

status_t AudioSystem::setSimulateDeviceConnections(bool enabled) {
    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
    if (af == 0) return PERMISSION_DENIED;
    return af->setSimulateDeviceConnections(enabled);
}

status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
    if (af == 0) return PERMISSION_DENIED;
+8 −0
Original line number Diff line number Diff line
@@ -816,6 +816,10 @@ status_t AudioFlingerClientAdapter::setDeviceConnectedState(
    return statusTFromBinderStatus(mDelegate->setDeviceConnectedState(aidlPort, connected));
}

status_t AudioFlingerClientAdapter::setSimulateDeviceConnections(bool enabled) {
    return statusTFromBinderStatus(mDelegate->setSimulateDeviceConnections(enabled));
}

status_t AudioFlingerClientAdapter::setRequestedLatencyMode(
        audio_io_handle_t output, audio_latency_mode_t mode) {
    int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
@@ -1370,6 +1374,10 @@ Status AudioFlingerServerAdapter::setDeviceConnectedState(
    return Status::fromStatusT(mDelegate->setDeviceConnectedState(&portLegacy, connected));
}

Status AudioFlingerServerAdapter::setSimulateDeviceConnections(bool enabled) {
    return Status::fromStatusT(mDelegate->setSimulateDeviceConnections(enabled));
}

Status AudioFlingerServerAdapter::setRequestedLatencyMode(
        int32_t output, media::audio::common::AudioLatencyMode modeAidl) {
    audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
+3 −0
Original line number Diff line number Diff line
@@ -229,6 +229,9 @@ interface IAudioFlingerService {

    void setDeviceConnectedState(in AudioPortFw devicePort, boolean connected);

    // Used for tests only. Requires AIDL HAL to work.
    void setSimulateDeviceConnections(boolean enabled);

    /**
     * Requests a given latency mode (See AudioLatencyMode.aidl) on an output stream.
     * This can be used when some use case on a given mixer/stream can only be enabled
Loading