Loading audio/7.0/IDevice.hal +9 −0 Original line number Diff line number Diff line Loading @@ -174,6 +174,9 @@ interface IDevice { * Creates an audio patch between several source and sink ports. The handle * is allocated by the HAL and must be unique for this audio HAL module. * * Optional method. HAL must support it if 'supportsAudioPatches' returns * 'true'. * * @param sources patch sources. * @param sinks patch sinks. * @return retval operation completion status. Loading @@ -189,6 +192,9 @@ interface IDevice { * as the HAL module can figure out a way of switching the route without * causing audio disruption. * * Optional method. HAL must support it if 'supportsAudioPatches' returns * 'true'. * * @param previousPatch handle of the previous patch to update. * @param sources new patch sources. * @param sinks new patch sinks. Loading @@ -204,6 +210,9 @@ interface IDevice { /** * Release an audio patch. * * Optional method. HAL must support it if 'supportsAudioPatches' returns * 'true'. * * @param patch patch handle. * @return retval operation completion status. */ Loading audio/core/all-versions/default/Device.cpp +13 −4 Original line number Diff line number Diff line Loading @@ -325,11 +325,17 @@ std::tuple<Result, AudioPatchHandle> Device::createOrUpdateAudioPatch( const hidl_vec<AudioPortConfig>& sinks) { Result retval(Result::NOT_SUPPORTED); if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch); std::unique_ptr<audio_port_config[]> halSources; HidlUtils::audioPortConfigsToHal(sources, &halSources); if (status_t status = HidlUtils::audioPortConfigsToHal(sources, &halSources); status != NO_ERROR) { return {analyzeStatus("audioPortConfigsToHal;sources", status), patch}; } std::unique_ptr<audio_port_config[]> halSinks; HidlUtils::audioPortConfigsToHal(sinks, &halSinks); audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch); if (status_t status = HidlUtils::audioPortConfigsToHal(sinks, &halSinks); status != NO_ERROR) { return {analyzeStatus("audioPortConfigsToHal;sinks", status), patch}; } retval = analyzeStatus("create_audio_patch", mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0], sinks.size(), &halSinks[0], &halPatch)); Loading Loading @@ -364,7 +370,10 @@ Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_c Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) { if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { struct audio_port_config halPortConfig; HidlUtils::audioPortConfigToHal(config, &halPortConfig); if (status_t status = HidlUtils::audioPortConfigToHal(config, &halPortConfig); status != NO_ERROR) { return analyzeStatus("audioPortConfigToHal", status); } return analyzeStatus("set_audio_port_config", mDevice->set_audio_port_config(mDevice, &halPortConfig)); } Loading audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +147 −12 Original line number Diff line number Diff line Loading @@ -298,6 +298,18 @@ INSTANTIATE_TEST_CASE_P( &DeviceConfigParameterToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputBufferSizeInvalidConfig); static const DeviceAddress& getValidInputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)}; return valid; } static const DeviceAddress& getValidOutputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)}; return valid; } static const DeviceAddress& getInvalidDeviceAddress() { static const DeviceAddress valid = {.deviceType = "random_string"}; return valid; Loading @@ -311,6 +323,141 @@ TEST_P(AudioHidlDeviceTest, SetConnectedStateInvalidDeviceAddress) { getDevice()->setConnectedState(getInvalidDeviceAddress(), false)); } static std::vector<AudioPortConfig>& generatePortConfigs(bool valid) { enum { // Note: This is for convenience when deriving "invalid" configs from "valid". PORT_CONF_MINIMAL, PORT_CONF_WITH_GAIN, PORT_CONF_EXT_DEVICE, PORT_CONF_EXT_MIX_SOURCE, PORT_CONF_EXT_MIX_SINK, PORT_CONF_EXT_SESSION }; static std::vector<AudioPortConfig> valids = [] { std::vector<AudioPortConfig> result; result.reserve(PORT_CONF_EXT_SESSION + 1); result.push_back(AudioPortConfig{}); AudioPortConfig configWithGain{}; configWithGain.gain.config(AudioGainConfig{ .index = 0, .mode = {toString(xsd::AudioGainMode::AUDIO_GAIN_MODE_JOINT)}, .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO), .rampDurationMs = 1}); configWithGain.gain.config().values.resize(1); configWithGain.gain.config().values[0] = 1000; result.push_back(std::move(configWithGain)); AudioPortConfig configWithPortExtDevice{}; configWithPortExtDevice.ext.device(getValidOutputDeviceAddress()); result.push_back(std::move(configWithPortExtDevice)); AudioPortConfig configWithPortExtMixSource{}; configWithPortExtMixSource.ext.mix({}); configWithPortExtMixSource.ext.mix().useCase.stream( toString(xsd::AudioStreamType::AUDIO_STREAM_VOICE_CALL)); result.push_back(std::move(configWithPortExtMixSource)); AudioPortConfig configWithPortExtMixSink{}; configWithPortExtMixSink.ext.mix({}); configWithPortExtMixSink.ext.mix().useCase.source( toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT)); result.push_back(std::move(configWithPortExtMixSink)); AudioPortConfig configWithPortExtSession{}; configWithPortExtSession.ext.session( static_cast<AudioSession>(AudioSessionConsts::OUTPUT_MIX)); result.push_back(std::move(configWithPortExtSession)); return result; }(); static std::vector<AudioPortConfig> invalids = [&] { std::vector<AudioPortConfig> result; AudioPortConfig invalidBaseChannelMask = valids[PORT_CONF_MINIMAL]; invalidBaseChannelMask.base.channelMask = "random_string"; result.push_back(std::move(invalidBaseChannelMask)); AudioPortConfig invalidBaseFormat = valids[PORT_CONF_MINIMAL]; invalidBaseFormat.base.format = "random_string"; result.push_back(std::move(invalidBaseFormat)); AudioPortConfig invalidGainMode = valids[PORT_CONF_WITH_GAIN]; invalidGainMode.gain.config().mode = {{"random_string"}}; result.push_back(std::move(invalidGainMode)); AudioPortConfig invalidGainChannelMask = valids[PORT_CONF_WITH_GAIN]; invalidGainChannelMask.gain.config().channelMask = "random_string"; result.push_back(std::move(invalidGainChannelMask)); AudioPortConfig invalidDeviceType = valids[PORT_CONF_EXT_DEVICE]; invalidDeviceType.ext.device().deviceType = "random_string"; result.push_back(std::move(invalidDeviceType)); AudioPortConfig invalidStreamType = valids[PORT_CONF_EXT_MIX_SOURCE]; invalidStreamType.ext.mix().useCase.stream() = "random_string"; result.push_back(std::move(invalidStreamType)); AudioPortConfig invalidSource = valids[PORT_CONF_EXT_MIX_SINK]; invalidSource.ext.mix().useCase.source() = "random_string"; result.push_back(std::move(invalidSource)); return result; }(); return valid ? valids : invalids; } TEST_P(AudioHidlDeviceTest, SetAudioPortConfigInvalidArguments) { doc::test("Check that invalid port configs are rejected by IDevice::setAudioPortConfig"); for (const auto& invalidConfig : generatePortConfigs(false /*valid*/)) { EXPECT_RESULT(invalidArgsOrNotSupported, getDevice()->setAudioPortConfig(invalidConfig)) << ::testing::PrintToString(invalidConfig); } } TEST_P(AudioPatchHidlTest, CreatePatchInvalidArguments) { doc::test("Check that invalid port configs are rejected by IDevice::createAudioPatch"); // Note that HAL actually might reject the proposed source / sink combo // due to other reasons than presence of invalid enum-strings. // TODO: Come up with a way to guarantee validity of a source / sink combo. for (const auto& validSource : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSink : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle; EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{validSource}, hidl_vec<AudioPortConfig>{invalidSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(validSource) << "; Sink: " << ::testing::PrintToString(invalidSink); } } for (const auto& validSink : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSource : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle; EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{invalidSource}, hidl_vec<AudioPortConfig>{validSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(invalidSource) << "; Sink: " << ::testing::PrintToString(validSink); } } } TEST_P(AudioPatchHidlTest, UpdatePatchInvalidArguments) { doc::test("Check that invalid port configs are rejected by IDevice::updateAudioPatch"); // Note that HAL actually might reject the proposed source / sink combo // due to other reasons than presence of invalid enum-strings. // TODO: Come up with a way to guarantee validity of a source / sink combo. for (const auto& validSource : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSink : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle{}; EXPECT_OK(getDevice()->updateAudioPatch(handle, hidl_vec<AudioPortConfig>{validSource}, hidl_vec<AudioPortConfig>{invalidSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(validSource) << "; Sink: " << ::testing::PrintToString(invalidSink); } } for (const auto& validSink : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSource : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle{}; EXPECT_OK(getDevice()->updateAudioPatch( handle, hidl_vec<AudioPortConfig>{invalidSource}, hidl_vec<AudioPortConfig>{validSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(invalidSource) << "; Sink: " << ::testing::PrintToString(validSink); } } } enum { PARAM_DEVICE_CONFIG, PARAM_ADDRESS, PARAM_METADATA }; enum { INDEX_SINK, INDEX_SOURCE }; using SinkOrSourceMetadata = std::variant<SinkMetadata, SourceMetadata>; Loading Loading @@ -362,18 +509,6 @@ class StreamOpenTest : public HidlTest, public ::testing::WithParamInterface<Str } }; static const DeviceAddress& getValidInputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)}; return valid; } static const DeviceAddress& getValidOutputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)}; return valid; } static const RecordTrackMetadata& getValidRecordTrackMetadata() { static const RecordTrackMetadata valid = { .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1}; Loading Loading
audio/7.0/IDevice.hal +9 −0 Original line number Diff line number Diff line Loading @@ -174,6 +174,9 @@ interface IDevice { * Creates an audio patch between several source and sink ports. The handle * is allocated by the HAL and must be unique for this audio HAL module. * * Optional method. HAL must support it if 'supportsAudioPatches' returns * 'true'. * * @param sources patch sources. * @param sinks patch sinks. * @return retval operation completion status. Loading @@ -189,6 +192,9 @@ interface IDevice { * as the HAL module can figure out a way of switching the route without * causing audio disruption. * * Optional method. HAL must support it if 'supportsAudioPatches' returns * 'true'. * * @param previousPatch handle of the previous patch to update. * @param sources new patch sources. * @param sinks new patch sinks. Loading @@ -204,6 +210,9 @@ interface IDevice { /** * Release an audio patch. * * Optional method. HAL must support it if 'supportsAudioPatches' returns * 'true'. * * @param patch patch handle. * @return retval operation completion status. */ Loading
audio/core/all-versions/default/Device.cpp +13 −4 Original line number Diff line number Diff line Loading @@ -325,11 +325,17 @@ std::tuple<Result, AudioPatchHandle> Device::createOrUpdateAudioPatch( const hidl_vec<AudioPortConfig>& sinks) { Result retval(Result::NOT_SUPPORTED); if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch); std::unique_ptr<audio_port_config[]> halSources; HidlUtils::audioPortConfigsToHal(sources, &halSources); if (status_t status = HidlUtils::audioPortConfigsToHal(sources, &halSources); status != NO_ERROR) { return {analyzeStatus("audioPortConfigsToHal;sources", status), patch}; } std::unique_ptr<audio_port_config[]> halSinks; HidlUtils::audioPortConfigsToHal(sinks, &halSinks); audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch); if (status_t status = HidlUtils::audioPortConfigsToHal(sinks, &halSinks); status != NO_ERROR) { return {analyzeStatus("audioPortConfigsToHal;sinks", status), patch}; } retval = analyzeStatus("create_audio_patch", mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0], sinks.size(), &halSinks[0], &halPatch)); Loading Loading @@ -364,7 +370,10 @@ Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_c Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) { if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { struct audio_port_config halPortConfig; HidlUtils::audioPortConfigToHal(config, &halPortConfig); if (status_t status = HidlUtils::audioPortConfigToHal(config, &halPortConfig); status != NO_ERROR) { return analyzeStatus("audioPortConfigToHal", status); } return analyzeStatus("set_audio_port_config", mDevice->set_audio_port_config(mDevice, &halPortConfig)); } Loading
audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +147 −12 Original line number Diff line number Diff line Loading @@ -298,6 +298,18 @@ INSTANTIATE_TEST_CASE_P( &DeviceConfigParameterToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputBufferSizeInvalidConfig); static const DeviceAddress& getValidInputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)}; return valid; } static const DeviceAddress& getValidOutputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)}; return valid; } static const DeviceAddress& getInvalidDeviceAddress() { static const DeviceAddress valid = {.deviceType = "random_string"}; return valid; Loading @@ -311,6 +323,141 @@ TEST_P(AudioHidlDeviceTest, SetConnectedStateInvalidDeviceAddress) { getDevice()->setConnectedState(getInvalidDeviceAddress(), false)); } static std::vector<AudioPortConfig>& generatePortConfigs(bool valid) { enum { // Note: This is for convenience when deriving "invalid" configs from "valid". PORT_CONF_MINIMAL, PORT_CONF_WITH_GAIN, PORT_CONF_EXT_DEVICE, PORT_CONF_EXT_MIX_SOURCE, PORT_CONF_EXT_MIX_SINK, PORT_CONF_EXT_SESSION }; static std::vector<AudioPortConfig> valids = [] { std::vector<AudioPortConfig> result; result.reserve(PORT_CONF_EXT_SESSION + 1); result.push_back(AudioPortConfig{}); AudioPortConfig configWithGain{}; configWithGain.gain.config(AudioGainConfig{ .index = 0, .mode = {toString(xsd::AudioGainMode::AUDIO_GAIN_MODE_JOINT)}, .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO), .rampDurationMs = 1}); configWithGain.gain.config().values.resize(1); configWithGain.gain.config().values[0] = 1000; result.push_back(std::move(configWithGain)); AudioPortConfig configWithPortExtDevice{}; configWithPortExtDevice.ext.device(getValidOutputDeviceAddress()); result.push_back(std::move(configWithPortExtDevice)); AudioPortConfig configWithPortExtMixSource{}; configWithPortExtMixSource.ext.mix({}); configWithPortExtMixSource.ext.mix().useCase.stream( toString(xsd::AudioStreamType::AUDIO_STREAM_VOICE_CALL)); result.push_back(std::move(configWithPortExtMixSource)); AudioPortConfig configWithPortExtMixSink{}; configWithPortExtMixSink.ext.mix({}); configWithPortExtMixSink.ext.mix().useCase.source( toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT)); result.push_back(std::move(configWithPortExtMixSink)); AudioPortConfig configWithPortExtSession{}; configWithPortExtSession.ext.session( static_cast<AudioSession>(AudioSessionConsts::OUTPUT_MIX)); result.push_back(std::move(configWithPortExtSession)); return result; }(); static std::vector<AudioPortConfig> invalids = [&] { std::vector<AudioPortConfig> result; AudioPortConfig invalidBaseChannelMask = valids[PORT_CONF_MINIMAL]; invalidBaseChannelMask.base.channelMask = "random_string"; result.push_back(std::move(invalidBaseChannelMask)); AudioPortConfig invalidBaseFormat = valids[PORT_CONF_MINIMAL]; invalidBaseFormat.base.format = "random_string"; result.push_back(std::move(invalidBaseFormat)); AudioPortConfig invalidGainMode = valids[PORT_CONF_WITH_GAIN]; invalidGainMode.gain.config().mode = {{"random_string"}}; result.push_back(std::move(invalidGainMode)); AudioPortConfig invalidGainChannelMask = valids[PORT_CONF_WITH_GAIN]; invalidGainChannelMask.gain.config().channelMask = "random_string"; result.push_back(std::move(invalidGainChannelMask)); AudioPortConfig invalidDeviceType = valids[PORT_CONF_EXT_DEVICE]; invalidDeviceType.ext.device().deviceType = "random_string"; result.push_back(std::move(invalidDeviceType)); AudioPortConfig invalidStreamType = valids[PORT_CONF_EXT_MIX_SOURCE]; invalidStreamType.ext.mix().useCase.stream() = "random_string"; result.push_back(std::move(invalidStreamType)); AudioPortConfig invalidSource = valids[PORT_CONF_EXT_MIX_SINK]; invalidSource.ext.mix().useCase.source() = "random_string"; result.push_back(std::move(invalidSource)); return result; }(); return valid ? valids : invalids; } TEST_P(AudioHidlDeviceTest, SetAudioPortConfigInvalidArguments) { doc::test("Check that invalid port configs are rejected by IDevice::setAudioPortConfig"); for (const auto& invalidConfig : generatePortConfigs(false /*valid*/)) { EXPECT_RESULT(invalidArgsOrNotSupported, getDevice()->setAudioPortConfig(invalidConfig)) << ::testing::PrintToString(invalidConfig); } } TEST_P(AudioPatchHidlTest, CreatePatchInvalidArguments) { doc::test("Check that invalid port configs are rejected by IDevice::createAudioPatch"); // Note that HAL actually might reject the proposed source / sink combo // due to other reasons than presence of invalid enum-strings. // TODO: Come up with a way to guarantee validity of a source / sink combo. for (const auto& validSource : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSink : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle; EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{validSource}, hidl_vec<AudioPortConfig>{invalidSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(validSource) << "; Sink: " << ::testing::PrintToString(invalidSink); } } for (const auto& validSink : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSource : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle; EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{invalidSource}, hidl_vec<AudioPortConfig>{validSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(invalidSource) << "; Sink: " << ::testing::PrintToString(validSink); } } } TEST_P(AudioPatchHidlTest, UpdatePatchInvalidArguments) { doc::test("Check that invalid port configs are rejected by IDevice::updateAudioPatch"); // Note that HAL actually might reject the proposed source / sink combo // due to other reasons than presence of invalid enum-strings. // TODO: Come up with a way to guarantee validity of a source / sink combo. for (const auto& validSource : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSink : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle{}; EXPECT_OK(getDevice()->updateAudioPatch(handle, hidl_vec<AudioPortConfig>{validSource}, hidl_vec<AudioPortConfig>{invalidSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(validSource) << "; Sink: " << ::testing::PrintToString(invalidSink); } } for (const auto& validSink : generatePortConfigs(true /*valid*/)) { for (const auto& invalidSource : generatePortConfigs(false /*valid*/)) { AudioPatchHandle handle{}; EXPECT_OK(getDevice()->updateAudioPatch( handle, hidl_vec<AudioPortConfig>{invalidSource}, hidl_vec<AudioPortConfig>{validSink}, returnIn(res, handle))); EXPECT_EQ(Result::INVALID_ARGUMENTS, res) << "Source: " << ::testing::PrintToString(invalidSource) << "; Sink: " << ::testing::PrintToString(validSink); } } } enum { PARAM_DEVICE_CONFIG, PARAM_ADDRESS, PARAM_METADATA }; enum { INDEX_SINK, INDEX_SOURCE }; using SinkOrSourceMetadata = std::variant<SinkMetadata, SourceMetadata>; Loading Loading @@ -362,18 +509,6 @@ class StreamOpenTest : public HidlTest, public ::testing::WithParamInterface<Str } }; static const DeviceAddress& getValidInputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)}; return valid; } static const DeviceAddress& getValidOutputDeviceAddress() { static const DeviceAddress valid = { .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)}; return valid; } static const RecordTrackMetadata& getValidRecordTrackMetadata() { static const RecordTrackMetadata valid = { .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1}; Loading