Audio: Add VTS tests for invalid enum-strings, Part 1

Add tests that try passing invalid enum-string values to HAL
methods taking enum-strings. Fix issues found in the default
wrapper.

Interface updates:

- Update AudioConfig structure to indicate whether
  AudioOffloadInfo is specified.

- Add return value to IStreamIn.updateSinkMetadata
  and IStreamOut.updateSourceMetadata to provide indication
  of invalid arguments.

- Specify the behavior of IDevice.open{Input|Output}Stream
  in the case of invalid arguments vs. rejected config.

Bug: 142480271
Test: atest VtsHalAudioV6_0TargetTest
Test: atest VtsHalAudioV7_0TargetTest
      with side-loaded V7 default wrapper
Change-Id: I6bd7be3869cc7a8d5d00506565bbf0b3a050b630
diff --git a/audio/7.0/IDevice.hal b/audio/7.0/IDevice.hal
index e30e545..d9e0ad2 100644
--- a/audio/7.0/IDevice.hal
+++ b/audio/7.0/IDevice.hal
@@ -103,6 +103,11 @@
      * If the stream can not be opened with the proposed audio config,
      * HAL must provide suggested values for the audio config.
      *
+     * Note: INVALID_ARGUMENTS is returned both in the case when the
+     * HAL can not use the provided config and in the case when
+     * the value of any argument is invalid. In the latter case the
+     * HAL must provide a default initialized suggested config.
+     *
      * @param ioHandle handle assigned by AudioFlinger.
      * @param device device type and (if needed) address.
      * @param config stream configuration.
@@ -111,7 +116,8 @@
                              May be used by implementations to configure hardware effects.
      * @return retval operation completion status.
      * @return outStream created output stream.
-     * @return suggestedConfig in case of invalid parameters, suggested config.
+     * @return suggestedConfig in the case of rejection of the proposed config,
+     *                         a config suggested by the HAL.
      */
     openOutputStream(
             AudioIoHandle ioHandle,
@@ -128,6 +134,11 @@
      * If the stream can not be opened with the proposed audio config,
      * HAL must provide suggested values for the audio config.
      *
+     * Note: INVALID_ARGUMENTS is returned both in the case when the
+     * HAL can not use the provided config and in the case when
+     * the value of any argument is invalid. In the latter case the
+     * HAL must provide a default initialized suggested config.
+     *
      * @param ioHandle handle assigned by AudioFlinger.
      * @param device device type and (if needed) address.
      * @param config stream configuration.
@@ -136,7 +147,8 @@
      *                     May be used by implementations to configure processing effects.
      * @return retval operation completion status.
      * @return inStream in case of success, created input stream.
-     * @return suggestedConfig in case of invalid parameters, suggested config.
+     * @return suggestedConfig in the case of rejection of the proposed config,
+     *                         a config suggested by the HAL.
      */
     openInputStream(
             AudioIoHandle ioHandle,
diff --git a/audio/7.0/IStreamIn.hal b/audio/7.0/IStreamIn.hal
index 0a3f24b..bf9ae52 100644
--- a/audio/7.0/IStreamIn.hal
+++ b/audio/7.0/IStreamIn.hal
@@ -41,6 +41,18 @@
     setGain(float gain) generates (Result retval);
 
     /**
+     * Called when the metadata of the stream's sink has been changed.
+     * Optional method
+     *
+     * @param sinkMetadata Description of the audio that is suggested by the clients.
+     * @return retval operation completion status.
+     *        If any of the metadata fields contains an invalid value,
+     *        returns INVALID_ARGUMENTS.
+     *        If method isn't supported by the HAL returns NOT_SUPPORTED.
+     */
+    updateSinkMetadata(SinkMetadata sinkMetadata) generates (Result retval);
+
+    /**
      * Commands that can be executed on the driver reader thread.
      */
     enum ReadCommand : int32_t {
@@ -82,12 +94,6 @@
     };
 
     /**
-     * Called when the metadata of the stream's sink has been changed.
-     * @param sinkMetadata Description of the audio that is suggested by the clients.
-     */
-    updateSinkMetadata(SinkMetadata sinkMetadata);
-
-    /**
      * Set up required transports for receiving audio buffers from the driver.
      *
      * The transport consists of three message queues:
diff --git a/audio/7.0/IStreamOut.hal b/audio/7.0/IStreamOut.hal
index 38d750f..4daab26 100644
--- a/audio/7.0/IStreamOut.hal
+++ b/audio/7.0/IStreamOut.hal
@@ -45,6 +45,18 @@
     setVolume(float left, float right) generates (Result retval);
 
     /**
+     * Called when the metadata of the stream's source has been changed.
+     * Optional method
+     *
+     * @param sourceMetadata Description of the audio that is played by the clients.
+     * @return retval operation completion status.
+     *        If any of the metadata fields contains an invalid value,
+     *        returns INVALID_ARGUMENTS.
+     *        If method isn't supported by the HAL returns NOT_SUPPORTED.
+     */
+    updateSourceMetadata(SourceMetadata sourceMetadata) generates (Result retval);
+
+    /**
      * Commands that can be executed on the driver writer thread.
      */
     enum WriteCommand : int32_t {
@@ -77,12 +89,6 @@
     };
 
     /**
-     * Called when the metadata of the stream's source has been changed.
-     * @param sourceMetadata Description of the audio that is played by the clients.
-     */
-    updateSourceMetadata(SourceMetadata sourceMetadata);
-
-    /**
      * Set up required transports for passing audio buffers to the driver.
      *
      * The transport consists of three message queues:
diff --git a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
index b7c1cc9..c0042db 100644
--- a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
+++ b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
@@ -212,12 +212,11 @@
     return isOutputDevice(stringToAudioDevice(device));
 }
 
-static inline bool isVendorExtension(const std::string& device) {
+static inline bool isVendorExtension(const std::string& s) {
     // Must match the "vendorExtension" rule from the XSD file.
     static const std::string vendorPrefix = "VX_";
-    return device.size() > vendorPrefix.size() &&
-           device.substr(0, vendorPrefix.size()) == vendorPrefix &&
-           std::all_of(device.begin() + vendorPrefix.size(), device.end(),
+    return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix &&
+           std::all_of(s.begin() + vendorPrefix.size(), s.end(),
                        [](unsigned char c) { return c == '_' || std::isalnum(c); });
 }
 
diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal
index b14ebd4..ed6d94f 100644
--- a/audio/common/7.0/types.hal
+++ b/audio/common/7.0/types.hal
@@ -270,7 +270,10 @@
  */
 struct AudioConfig {
     AudioConfigBase base;
-    AudioOffloadInfo offloadInfo;
+    safe_union OffloadInfo {
+        Monostate unspecified;
+        AudioOffloadInfo info;
+    } offloadInfo;
     uint64_t frameCount;
 };
 
@@ -278,7 +281,8 @@
  * AudioTag is an additional use case qualifier complementing
  * AudioUsage and AudioContentType. Tags are set by vendor specific applications
  * and must be prefixed by "VX_". Vendor must namespace their tag
- * names to avoid conflicts.
+ * names to avoid conflicts. See 'vendorExtension' in audio_policy_configuration.xsd
+ * for a formal definition.
  */
 typedef string AudioTag;
 
diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp
index c985a70..de19faf 100644
--- a/audio/common/all-versions/default/7.0/HidlUtils.cpp
+++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp
@@ -21,6 +21,7 @@
 #include <log/log.h>
 
 #include <android_audio_policy_configuration_V7_0-enums.h>
+#include <common/all-versions/HidlSupport.h>
 #include <common/all-versions/VersionUtils.h>
 
 #include "HidlUtils.h"
@@ -306,7 +307,12 @@
     audio_config_base_t halConfigBase = {halConfig.sample_rate, halConfig.channel_mask,
                                          halConfig.format};
     CONVERT_CHECKED(audioConfigBaseFromHal(halConfigBase, isInput, &config->base), result);
-    CONVERT_CHECKED(audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo), result);
+    if (halConfig.offload_info.sample_rate != 0) {
+        config->offloadInfo.info({});
+        CONVERT_CHECKED(
+                audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo.info()),
+                result);
+    }
     config->frameCount = halConfig.frame_count;
     return result;
 }
@@ -319,7 +325,11 @@
     halConfig->sample_rate = halConfigBase.sample_rate;
     halConfig->channel_mask = halConfigBase.channel_mask;
     halConfig->format = halConfigBase.format;
-    CONVERT_CHECKED(audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info), result);
+    if (config.offloadInfo.getDiscriminator() ==
+        AudioConfig::OffloadInfo::hidl_discriminator::info) {
+        CONVERT_CHECKED(audioOffloadInfoToHal(config.offloadInfo.info(), &halConfig->offload_info),
+                        result);
+    }
     halConfig->frame_count = config.frameCount;
     return result;
 }
@@ -800,6 +810,47 @@
     return result;
 }
 
+status_t HidlUtils::audioTagsFromHal(const char* halTags, hidl_vec<AudioTag>* tags) {
+    std::vector<std::string> strTags = utils::splitString(halTags, sAudioTagSeparator);
+    status_t result = NO_ERROR;
+    tags->resize(strTags.size());
+    size_t to = 0;
+    for (size_t from = 0; from < strTags.size(); ++from) {
+        if (xsd::isVendorExtension(strTags[from])) {
+            (*tags)[to++] = strTags[from];
+        } else {
+            result = BAD_VALUE;
+        }
+    }
+    if (to != strTags.size()) {
+        tags->resize(to);
+    }
+    return result;
+}
+
+status_t HidlUtils::audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags) {
+    memset(halTags, 0, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
+    status_t result = NO_ERROR;
+    std::ostringstream halTagsBuffer;
+    bool hasValue = false;
+    for (const auto& tag : tags) {
+        if (hasValue) {
+            halTagsBuffer << sAudioTagSeparator;
+        }
+        if (xsd::isVendorExtension(tag) && strchr(tag.c_str(), sAudioTagSeparator) == nullptr) {
+            halTagsBuffer << tag;
+            hasValue = true;
+        } else {
+            result = BAD_VALUE;
+        }
+    }
+    std::string fullHalTags{std::move(halTagsBuffer.str())};
+    strncpy(halTags, fullHalTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
+    CONVERT_CHECKED(fullHalTags.length() <= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE ? NO_ERROR : BAD_VALUE,
+                    result);
+    return result;
+}
+
 status_t HidlUtils::deviceAddressFromHal(audio_devices_t halDeviceType,
                                          const char* halDeviceAddress, DeviceAddress* device) {
     status_t result = NO_ERROR;
diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h
index d8b7ba4..8e9275c 100644
--- a/audio/common/all-versions/default/HidlUtils.h
+++ b/audio/common/all-versions/default/HidlUtils.h
@@ -109,6 +109,8 @@
                                            AudioStreamType* streamType);
     static status_t audioStreamTypeToHal(const AudioStreamType& streamType,
                                          audio_stream_type_t* halStreamType);
+    static status_t audioTagsFromHal(const char* halTags, hidl_vec<AudioTag>* tags);
+    static status_t audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags);
 
   private:
     static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask,
diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
index 22571c0..fef88b4 100644
--- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp
+++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
@@ -589,16 +589,29 @@
     config.base.sampleRateHz = 44100;
     config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
     config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
-    config.offloadInfo.base = config.base;
-    config.offloadInfo.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC);
-    config.offloadInfo.bitRatePerSecond = 320;
-    config.offloadInfo.durationMicroseconds = -1;
-    config.offloadInfo.bitWidth = 16;
-    config.offloadInfo.bufferSize = 1024;
-    config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA);
-    config.offloadInfo.encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM;
-    config.offloadInfo.contentId = 42;
-    config.offloadInfo.syncId = 13;
+    audio_config_t halConfig;
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(config, &halConfig));
+    AudioConfig configBack;
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, &configBack));
+    EXPECT_EQ(config, configBack);
+}
+
+TEST(HidlUtils, ConvertConfigWithOffloadInfo) {
+    AudioConfig config = {};
+    config.base.sampleRateHz = 44100;
+    config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+    config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+    config.offloadInfo.info(
+            AudioOffloadInfo{.base = config.base,
+                             .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
+                             .bitRatePerSecond = 320,
+                             .durationMicroseconds = -1,
+                             .bitWidth = 16,
+                             .bufferSize = 1024,
+                             .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+                             .encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM,
+                             .contentId = 42,
+                             .syncId = 13});
     audio_config_t halConfig;
     EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(config, &halConfig));
     AudioConfig configBack;
@@ -707,3 +720,43 @@
     EXPECT_EQ(NO_ERROR, HidlUtils::audioPortToHal(portBack, &halPortBack));
     EXPECT_TRUE(audio_ports_v7_are_equal(&halPort, &halPortBack));
 }
+
+TEST(HidlUtils, ConvertInvalidAudioTags) {
+    char halTag[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
+
+    hidl_vec<AudioTag> emptyTag = {{""}};
+    EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(emptyTag, halTag));
+
+    hidl_vec<AudioTag> longTag = {{std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE + 1, 'A')}};
+    EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(longTag, halTag));
+
+    hidl_vec<AudioTag> tagSeparator = {
+            {std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1, HidlUtils::sAudioTagSeparator)}};
+    EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(tagSeparator, halTag));
+
+    hidl_vec<AudioTag> notExtensions = {{"random string", "VX_", "VX_GOOGLE_$$"}};
+    EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(notExtensions, halTag));
+}
+
+TEST(HidlUtils, ConvertAudioTags) {
+    hidl_vec<AudioTag> emptyTags;
+    char halEmptyTags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(emptyTags, halEmptyTags));
+    hidl_vec<AudioTag> emptyTagsBack;
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halEmptyTags, &emptyTagsBack));
+    EXPECT_EQ(emptyTags, emptyTagsBack);
+
+    hidl_vec<AudioTag> oneTag = {{"VX_GOOGLE_VR"}};
+    char halOneTag[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(oneTag, halOneTag));
+    hidl_vec<AudioTag> oneTagBack;
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halOneTag, &oneTagBack));
+    EXPECT_EQ(oneTag, oneTagBack);
+
+    hidl_vec<AudioTag> twoTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}};
+    char halTwoTags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(twoTags, halTwoTags));
+    hidl_vec<AudioTag> twoTagsBack;
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halTwoTags, &twoTagsBack));
+    EXPECT_EQ(twoTags, twoTagsBack);
+}
diff --git a/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h b/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h
index b514a43..d7802cf 100644
--- a/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h
+++ b/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h
@@ -20,6 +20,9 @@
 
 #include <hidl/HidlSupport.h>
 #include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
 
 namespace android::hardware::audio::common::utils {
 
@@ -29,6 +32,16 @@
     return std::find(values.begin(), values.end(), e) != values.end();
 }
 
+static inline std::vector<std::string> splitString(const std::string& s, char separator) {
+    std::istringstream iss(s);
+    std::string t;
+    std::vector<std::string> result;
+    while (std::getline(iss, t, separator)) {
+        result.push_back(std::move(t));
+    }
+    return result;
+}
+
 } // namespace android::hardware::audio::common::utils
 
 #endif  // android_hardware_audio_common_HidlSupport_H_
diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp
index 8e0a140..f1752cc 100644
--- a/audio/core/all-versions/default/Conversions.cpp
+++ b/audio/core/all-versions/default/Conversions.cpp
@@ -32,14 +32,10 @@
 
 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
 
-#if MAJOR_VERSION <= 6
-std::string deviceAddressToHal(const DeviceAddress& address) {
-    audio_devices_t halDevice;
-    char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
-    (void)deviceAddressToHal(address, &halDevice, halAddress);
-    return halAddress;
-}
-#endif
+#define CONVERT_CHECKED(expr, result)                   \
+    if (status_t status = (expr); status != NO_ERROR) { \
+        result = status;                                \
+    }
 
 status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType,
                             char* halDeviceAddress) {
@@ -97,6 +93,52 @@
     }
     return status;
 }
+
+status_t sinkMetadataToHal(const SinkMetadata& sinkMetadata,
+                           std::vector<record_track_metadata>* halTracks) {
+    status_t result = NO_ERROR;
+    if (halTracks != nullptr) {
+        halTracks->reserve(sinkMetadata.tracks.size());
+    }
+    for (auto& metadata : sinkMetadata.tracks) {
+        record_track_metadata halTrackMetadata{.gain = metadata.gain};
+        CONVERT_CHECKED(HidlUtils::audioSourceToHal(metadata.source, &halTrackMetadata.source),
+                        result);
+#if MAJOR_VERSION >= 5
+        if (metadata.destination.getDiscriminator() ==
+            RecordTrackMetadata::Destination::hidl_discriminator::device) {
+            CONVERT_CHECKED(
+                    deviceAddressToHal(metadata.destination.device(), &halTrackMetadata.dest_device,
+                                       halTrackMetadata.dest_device_address),
+                    result);
+        }
+#endif
+        if (halTracks != nullptr) {
+            halTracks->push_back(std::move(halTrackMetadata));
+        }
+    }
+    return result;
+}
+
+status_t sourceMetadataToHal(const SourceMetadata& sourceMetadata,
+                             std::vector<playback_track_metadata_t>* halTracks) {
+    status_t result = NO_ERROR;
+    if (halTracks != nullptr) {
+        halTracks->reserve(sourceMetadata.tracks.size());
+    }
+    for (auto& metadata : sourceMetadata.tracks) {
+        playback_track_metadata_t halTrackMetadata{.gain = metadata.gain};
+        CONVERT_CHECKED(HidlUtils::audioUsageToHal(metadata.usage, &halTrackMetadata.usage),
+                        result);
+        CONVERT_CHECKED(HidlUtils::audioContentTypeToHal(metadata.contentType,
+                                                         &halTrackMetadata.content_type),
+                        result);
+        if (halTracks != nullptr) {
+            halTracks->push_back(std::move(halTrackMetadata));
+        }
+    }
+    return result;
+}
 #endif  // MAJOR_VERSION >= 4
 
 #if MAJOR_VERSION >= 7
@@ -135,6 +177,50 @@
     }
     return success;
 }
+
+status_t sinkMetadataToHalV7(const SinkMetadata& sinkMetadata,
+                             std::vector<record_track_metadata_v7_t>* halTracks) {
+    std::vector<record_track_metadata> bases;
+    status_t result = sinkMetadataToHal(sinkMetadata, halTracks != nullptr ? &bases : nullptr);
+    if (halTracks != nullptr) {
+        halTracks->reserve(bases.size());
+    }
+    auto baseIter = std::make_move_iterator(bases.begin());
+    for (auto& metadata : sinkMetadata.tracks) {
+        record_track_metadata_v7_t halTrackMetadata;
+        CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(metadata.channelMask,
+                                                         &halTrackMetadata.channel_mask),
+                        result);
+        CONVERT_CHECKED(HidlUtils::audioTagsToHal(metadata.tags, halTrackMetadata.tags), result);
+        if (halTracks != nullptr) {
+            halTrackMetadata.base = std::move(*baseIter++);
+            halTracks->push_back(std::move(halTrackMetadata));
+        }
+    }
+    return result;
+}
+
+status_t sourceMetadataToHalV7(const SourceMetadata& sourceMetadata,
+                               std::vector<playback_track_metadata_v7_t>* halTracks) {
+    std::vector<playback_track_metadata_t> bases;
+    status_t result = sourceMetadataToHal(sourceMetadata, halTracks != nullptr ? &bases : nullptr);
+    if (halTracks != nullptr) {
+        halTracks->reserve(bases.size());
+    }
+    auto baseIter = std::make_move_iterator(bases.begin());
+    for (auto& metadata : sourceMetadata.tracks) {
+        playback_track_metadata_v7_t halTrackMetadata;
+        CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(metadata.channelMask,
+                                                         &halTrackMetadata.channel_mask),
+                        result);
+        CONVERT_CHECKED(HidlUtils::audioTagsToHal(metadata.tags, halTrackMetadata.tags), result);
+        if (halTracks != nullptr) {
+            halTrackMetadata.base = std::move(*baseIter++);
+            halTracks->push_back(std::move(halTrackMetadata));
+        }
+    }
+    return result;
+}
 #endif
 
 }  // namespace implementation
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index bb69f0b..05c1066 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -135,13 +135,14 @@
 
 Return<void> Device::getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
     audio_config_t halConfig;
-    HidlUtils::audioConfigToHal(config, &halConfig);
-    size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
     Result retval(Result::INVALID_ARGUMENTS);
     uint64_t bufferSize = 0;
-    if (halBufferSize != 0) {
-        retval = Result::OK;
-        bufferSize = halBufferSize;
+    if (HidlUtils::audioConfigToHal(config, &halConfig) == NO_ERROR) {
+        size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
+        if (halBufferSize != 0) {
+            retval = Result::OK;
+            bufferSize = halBufferSize;
+        }
     }
     _hidl_cb(retval, bufferSize);
     return Void();
@@ -153,7 +154,9 @@
                                                                 const AudioOutputFlags& flags,
                                                                 AudioConfig* suggestedConfig) {
     audio_config_t halConfig;
-    HidlUtils::audioConfigToHal(config, &halConfig);
+    if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) {
+        return {Result::INVALID_ARGUMENTS, nullptr};
+    }
     audio_stream_out_t* halStream;
     audio_devices_t halDevice;
     char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
@@ -186,7 +189,9 @@
         int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
         const AudioInputFlags& flags, AudioSource source, AudioConfig* suggestedConfig) {
     audio_config_t halConfig;
-    HidlUtils::audioConfigToHal(config, &halConfig);
+    if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) {
+        return {Result::INVALID_ARGUMENTS, nullptr};
+    }
     audio_stream_in_t* halStream;
     audio_devices_t halDevice;
     char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
@@ -248,6 +253,14 @@
 #endif
                                       const SourceMetadata& sourceMetadata,
                                       openOutputStream_cb _hidl_cb) {
+#if MAJOR_VERSION <= 6
+    if (status_t status = sourceMetadataToHal(sourceMetadata, nullptr); status != NO_ERROR) {
+#else
+    if (status_t status = sourceMetadataToHalV7(sourceMetadata, nullptr); status != NO_ERROR) {
+#endif
+        _hidl_cb(analyzeStatus("sourceMetadataToHal", status), nullptr, AudioConfig{});
+        return Void();
+    }
     AudioConfig suggestedConfig;
     auto [result, streamOut] =
         openOutputStreamImpl(ioHandle, device, config, flags, &suggestedConfig);
@@ -271,7 +284,15 @@
         // This should never happen, the framework must not create as stream
         // if there is no client
         ALOGE("openInputStream called without tracks connected");
-        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, AudioConfig());
+        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, AudioConfig{});
+        return Void();
+    }
+#if MAJOR_VERSION <= 6
+    if (status_t status = sinkMetadataToHal(sinkMetadata, nullptr); status != NO_ERROR) {
+#else
+    if (status_t status = sinkMetadataToHalV7(sinkMetadata, nullptr); status != NO_ERROR) {
+#endif
+        _hidl_cb(analyzeStatus("sinkMetadataToHal", status), nullptr, AudioConfig{});
         return Void();
     }
     // Pick the first one as the main.
diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp
index c74079d..f964cbb 100644
--- a/audio/core/all-versions/default/Stream.cpp
+++ b/audio/core/all-versions/default/Stream.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "StreamHAL"
 
 #include "core/default/Stream.h"
+#include "common/all-versions/HidlSupport.h"
 #include "common/all-versions/default/EffectMap.h"
 #include "core/default/Conversions.h"
 #include "core/default/Util.h"
@@ -37,6 +38,7 @@
 namespace implementation {
 
 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
+using ::android::hardware::audio::common::utils::splitString;
 
 Stream::Stream(bool isInput, audio_stream_t* stream) : mIsInput(isInput), mStream(stream) {
     (void)mIsInput;  // prevent 'unused field' warnings in pre-V7 versions.
@@ -220,7 +222,7 @@
     // Ensure that the separator is one character, despite that it's defined as a C string.
     static_assert(sizeof(AUDIO_PARAMETER_VALUE_LIST_SEPARATOR) == 2);
     std::vector<std::string> halFormats =
-            util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+            splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
     hidl_vec<AudioFormat> formats;
     (void)HidlUtils::audioFormatsFromHal(halFormats, &formats);
     std::vector<AudioProfile> tempProfiles;
@@ -235,7 +237,7 @@
         result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context);
         if (result != Result::OK) break;
         std::vector<std::string> halSampleRates =
-                util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+                splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
         hidl_vec<uint32_t> sampleRates;
         sampleRates.resize(halSampleRates.size());
         for (size_t i = 0; i < sampleRates.size(); ++i) {
@@ -245,7 +247,7 @@
         result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context);
         if (result != Result::OK) break;
         std::vector<std::string> halChannelMasks =
-                util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+                splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
         hidl_vec<AudioChannelMask> channelMasks;
         (void)HidlUtils::audioChannelMasksFromHal(halChannelMasks, &channelMasks);
         // Create a profile.
diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp
index a673554..39a4c27 100644
--- a/audio/core/all-versions/default/StreamIn.cpp
+++ b/audio/core/all-versions/default/StreamIn.cpp
@@ -478,87 +478,59 @@
 }
 
 #if MAJOR_VERSION >= 4
-
-record_track_metadata StreamIn::convertRecordTrackMetadata(
-        const RecordTrackMetadata& trackMetadata) {
-    record_track_metadata halTrackMetadata = {.gain = trackMetadata.gain};
-    (void)HidlUtils::audioSourceToHal(trackMetadata.source, &halTrackMetadata.source);
-#if MAJOR_VERSION >= 5
-    if (trackMetadata.destination.getDiscriminator() ==
-        RecordTrackMetadata::Destination::hidl_discriminator::device) {
-        (void)deviceAddressToHal(trackMetadata.destination.device(), &halTrackMetadata.dest_device,
-                                 halTrackMetadata.dest_device_address);
-    }
-#endif
-    return halTrackMetadata;
-}
-
-void StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) {
+Result StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata,
+                                      bool abortOnConversionFailure) {
     std::vector<record_track_metadata> halTracks;
-    halTracks.reserve(sinkMetadata.tracks.size());
-    for (auto& metadata : sinkMetadata.tracks) {
-        halTracks.push_back(convertRecordTrackMetadata(metadata));
+    if (status_t status = sinkMetadataToHal(sinkMetadata, &halTracks);
+        status != NO_ERROR && abortOnConversionFailure) {
+        return Stream::analyzeStatus("sinkMetadataToHal", status);
     }
     const sink_metadata_t halMetadata = {
         .track_count = halTracks.size(),
         .tracks = halTracks.data(),
     };
     mStream->update_sink_metadata(mStream, &halMetadata);
+    return Result::OK;
 }
 
 #if MAJOR_VERSION >= 7
-record_track_metadata_v7 StreamIn::convertRecordTrackMetadataV7(
-        const RecordTrackMetadata& trackMetadata) {
-    record_track_metadata_v7 halTrackMetadata;
-    halTrackMetadata.base = convertRecordTrackMetadata(trackMetadata);
-    (void)HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask,
-                                           &halTrackMetadata.channel_mask);
-    std::string halTags;
-    for (const auto& tag : trackMetadata.tags) {
-        if (&tag != &trackMetadata.tags[0]) {
-            halTags += HidlUtils::sAudioTagSeparator;
-        }
-        halTags += tag.c_str();
-    }
-    strncpy(halTrackMetadata.tags, halTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
-    return halTrackMetadata;
-}
-
-void StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
+Result StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
     std::vector<record_track_metadata_v7> halTracks;
-    halTracks.reserve(sinkMetadata.tracks.size());
-    for (auto& metadata : sinkMetadata.tracks) {
-        halTracks.push_back(convertRecordTrackMetadataV7(metadata));
+    if (status_t status = sinkMetadataToHalV7(sinkMetadata, &halTracks); status != NO_ERROR) {
+        return Stream::analyzeStatus("sinkMetadataToHal", status);
     }
     const sink_metadata_v7_t halMetadata = {
             .track_count = halTracks.size(),
             .tracks = halTracks.data(),
     };
     mStream->update_sink_metadata_v7(mStream, &halMetadata);
+    return Result::OK;
 }
 #endif  //  MAJOR_VERSION >= 7
 
+#if MAJOR_VERSION <= 6
 Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
-#if MAJOR_VERSION < 7
     if (mStream->update_sink_metadata == nullptr) {
         return Void();  // not supported by the HAL
     }
-    doUpdateSinkMetadata(sinkMetadata);
-#else
-    if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
-        if (mStream->update_sink_metadata == nullptr) {
-            return Void();  // not supported by the HAL
-        }
-        doUpdateSinkMetadata(sinkMetadata);
-    } else {
-        if (mStream->update_sink_metadata_v7 == nullptr) {
-            return Void();  // not supported by the HAL
-        }
-        doUpdateSinkMetadataV7(sinkMetadata);
-    }
-#endif  //  MAJOR_VERSION < 7
+    (void)doUpdateSinkMetadata(sinkMetadata, false /*abortOnConversionFailure*/);
     return Void();
 }
+#elif MAJOR_VERSION >= 7
+Return<Result> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
+    if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
+        if (mStream->update_sink_metadata == nullptr) {
+            return Result::NOT_SUPPORTED;
+        }
+        return doUpdateSinkMetadata(sinkMetadata, true /*abortOnConversionFailure*/);
+    } else {
+        if (mStream->update_sink_metadata_v7 == nullptr) {
+            return Result::NOT_SUPPORTED;
+        }
+        return doUpdateSinkMetadataV7(sinkMetadata);
+    }
+}
+#endif
 
 Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) {
     Result retval = Result::NOT_SUPPORTED;
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 2451b9e..0ff9182 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "StreamOutHAL"
 
 #include "core/default/StreamOut.h"
+#include "core/default/Conversions.h"
 #include "core/default/Util.h"
 
 //#define LOG_NDEBUG 0
@@ -585,81 +586,59 @@
 }
 
 #if MAJOR_VERSION >= 4
-playback_track_metadata StreamOut::convertPlaybackTrackMetadata(
-        const PlaybackTrackMetadata& trackMetadata) {
-    playback_track_metadata_t halTrackMetadata = {.gain = trackMetadata.gain};
-    (void)HidlUtils::audioUsageToHal(trackMetadata.usage, &halTrackMetadata.usage);
-    (void)HidlUtils::audioContentTypeToHal(trackMetadata.contentType,
-                                           &halTrackMetadata.content_type);
-    return halTrackMetadata;
-}
-
-void StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) {
+Result StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata,
+                                         bool abortOnConversionFailure) {
     std::vector<playback_track_metadata_t> halTracks;
-    halTracks.reserve(sourceMetadata.tracks.size());
-    for (auto& metadata : sourceMetadata.tracks) {
-        halTracks.push_back(convertPlaybackTrackMetadata(metadata));
+    if (status_t status = sourceMetadataToHal(sourceMetadata, &halTracks);
+        status != NO_ERROR && abortOnConversionFailure) {
+        return Stream::analyzeStatus("sourceMetadataToHal", status);
     }
     const source_metadata_t halMetadata = {
         .track_count = halTracks.size(),
         .tracks = halTracks.data(),
     };
     mStream->update_source_metadata(mStream, &halMetadata);
+    return Result::OK;
 }
 
 #if MAJOR_VERSION >= 7
-playback_track_metadata_v7 StreamOut::convertPlaybackTrackMetadataV7(
-        const PlaybackTrackMetadata& trackMetadata) {
-    playback_track_metadata_v7 halTrackMetadata;
-    halTrackMetadata.base = convertPlaybackTrackMetadata(trackMetadata);
-    (void)HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask,
-                                           &halTrackMetadata.channel_mask);
-    std::string halTags;
-    for (const auto& tag : trackMetadata.tags) {
-        if (&tag != &trackMetadata.tags[0]) {
-            halTags += HidlUtils::sAudioTagSeparator;
-        }
-        halTags += tag.c_str();
-    }
-    strncpy(halTrackMetadata.tags, halTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
-    return halTrackMetadata;
-}
-
-void StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
+Result StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
     std::vector<playback_track_metadata_v7> halTracks;
-    halTracks.reserve(sourceMetadata.tracks.size());
-    for (auto& metadata : sourceMetadata.tracks) {
-        halTracks.push_back(convertPlaybackTrackMetadataV7(metadata));
+    if (status_t status = sourceMetadataToHalV7(sourceMetadata, &halTracks); status != NO_ERROR) {
+        return Stream::analyzeStatus("sourceMetadataToHal", status);
     }
     const source_metadata_v7_t halMetadata = {
             .track_count = halTracks.size(),
             .tracks = halTracks.data(),
     };
     mStream->update_source_metadata_v7(mStream, &halMetadata);
+    return Result::OK;
 }
 #endif  //  MAJOR_VERSION >= 7
 
+#if MAJOR_VERSION <= 6
 Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
-#if MAJOR_VERSION < 7
     if (mStream->update_source_metadata == nullptr) {
         return Void();  // not supported by the HAL
     }
-    doUpdateSourceMetadata(sourceMetadata);
-#else
-    if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
-        if (mStream->update_source_metadata == nullptr) {
-            return Void();  // not supported by the HAL
-        }
-        doUpdateSourceMetadata(sourceMetadata);
-    } else {
-        if (mStream->update_source_metadata_v7 == nullptr) {
-            return Void();  // not supported by the HAL
-        }
-        doUpdateSourceMetadataV7(sourceMetadata);
-    }
-#endif  //  MAJOR_VERSION < 7
+    (void)doUpdateSourceMetadata(sourceMetadata, false /*abortOnConversionFailure*/);
     return Void();
 }
+#elif MAJOR_VERSION >= 7
+Return<Result> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
+    if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
+        if (mStream->update_source_metadata == nullptr) {
+            return Result::NOT_SUPPORTED;
+        }
+        return doUpdateSourceMetadata(sourceMetadata, true /*abortOnConversionFailure*/);
+    } else {
+        if (mStream->update_source_metadata_v7 == nullptr) {
+            return Result::NOT_SUPPORTED;
+        }
+        return doUpdateSourceMetadataV7(sourceMetadata);
+    }
+}
+#endif
 
 Return<Result> StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t /*programId*/) {
     return Result::NOT_SUPPORTED;  // TODO: propagate to legacy
diff --git a/audio/core/all-versions/default/include/core/default/Conversions.h b/audio/core/all-versions/default/include/core/default/Conversions.h
index 2372771..61720d5 100644
--- a/audio/core/all-versions/default/include/core/default/Conversions.h
+++ b/audio/core/all-versions/default/include/core/default/Conversions.h
@@ -35,12 +35,6 @@
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 using namespace ::android::hardware::audio::CPP_VERSION;
 
-#if MAJOR_VERSION <= 6
-// Temporary version for compatibility with forks of the default implementation.
-// Will be removed, do not use!
-std::string deviceAddressToHal(const DeviceAddress& address);
-#endif
-
 status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType,
                             char* halDeviceAddress);
 status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDeviceAddress,
@@ -49,6 +43,10 @@
 #if MAJOR_VERSION >= 4
 bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst,
                                     const struct audio_microphone_characteristic_t& src);
+status_t sinkMetadataToHal(const SinkMetadata& sinkMetadata,
+                           std::vector<record_track_metadata>* halTracks);
+status_t sourceMetadataToHal(const SourceMetadata& sourceMetadata,
+                             std::vector<playback_track_metadata_t>* halTracks);
 #endif
 
 #if MAJOR_VERSION <= 6
@@ -69,6 +67,11 @@
 #else
 bool audioInputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_input_flags_t* halFlags);
 bool audioOutputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_output_flags_t* halFlags);
+// Overloading isn't convenient when passing a nullptr.
+status_t sinkMetadataToHalV7(const SinkMetadata& sinkMetadata,
+                             std::vector<record_track_metadata_v7_t>* halTracks);
+status_t sourceMetadataToHalV7(const SourceMetadata& sourceMetadata,
+                               std::vector<playback_track_metadata_v7_t>* halTracks);
 #endif
 
 }  // namespace implementation
diff --git a/audio/core/all-versions/default/include/core/default/StreamIn.h b/audio/core/all-versions/default/include/core/default/StreamIn.h
index 512da55..ccb5eed 100644
--- a/audio/core/all-versions/default/include/core/default/StreamIn.h
+++ b/audio/core/all-versions/default/include/core/default/StreamIn.h
@@ -114,9 +114,13 @@
     Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
     Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
 #if MAJOR_VERSION >= 4
+#if MAJOR_VERSION <= 6
     Return<void> updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
-    Return<void> getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override;
+#else
+    Return<Result> updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
 #endif
+    Return<void> getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override;
+#endif  // MAJOR_VERSION >= 4
 #if MAJOR_VERSION >= 5
     Return<Result> setMicrophoneDirection(MicrophoneDirection direction) override;
     Return<Result> setMicrophoneFieldDimension(float zoom) override;
@@ -126,13 +130,11 @@
 
   private:
 #if MAJOR_VERSION >= 4
-    record_track_metadata convertRecordTrackMetadata(const RecordTrackMetadata& trackMetadata);
-    void doUpdateSinkMetadata(const SinkMetadata& sinkMetadata);
+    Result doUpdateSinkMetadata(const SinkMetadata& sinkMetadata, bool abortOnConversionFailure);
 #if MAJOR_VERSION >= 7
-    record_track_metadata_v7 convertRecordTrackMetadataV7(const RecordTrackMetadata& trackMetadata);
-    void doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata);
+    Result doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata);
 #endif
-#endif
+#endif  // MAJOR_VERSION >= 4
 
     const sp<Device> mDevice;
     audio_stream_in_t* mStream;
diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h
index 8da940d..b7f211e 100644
--- a/audio/core/all-versions/default/include/core/default/StreamOut.h
+++ b/audio/core/all-versions/default/include/core/default/StreamOut.h
@@ -123,9 +123,13 @@
     Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
     Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
 #if MAJOR_VERSION >= 4
-    Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
     Return<Result> selectPresentation(int32_t presentationId, int32_t programId) override;
+#if MAJOR_VERSION <= 6
+    Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
+#else
+    Return<Result> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
 #endif
+#endif  // MAJOR_VERSION >= 4
 #if MAJOR_VERSION >= 6
     Return<void> getDualMonoMode(getDualMonoMode_cb _hidl_cb) override;
     Return<Result> setDualMonoMode(DualMonoMode mode) override;
@@ -144,15 +148,12 @@
 
   private:
 #if MAJOR_VERSION >= 4
-    playback_track_metadata convertPlaybackTrackMetadata(
-            const PlaybackTrackMetadata& trackMetadata);
-    void doUpdateSourceMetadata(const SourceMetadata& sourceMetadata);
+    Result doUpdateSourceMetadata(const SourceMetadata& sourceMetadata,
+                                  bool abortOnConversionFailure);
 #if MAJOR_VERSION >= 7
-    playback_track_metadata_v7 convertPlaybackTrackMetadataV7(
-            const PlaybackTrackMetadata& trackMetadata);
-    void doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata);
+    Result doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata);
 #endif
-#endif
+#endif  // MAJOR_VERSION >= 4
 
     const sp<Device> mDevice;
     audio_stream_out_t* mStream;
diff --git a/audio/core/all-versions/default/include/core/default/Util.h b/audio/core/all-versions/default/include/core/default/Util.h
index 3d629cd..78ae03e 100644
--- a/audio/core/all-versions/default/include/core/default/Util.h
+++ b/audio/core/all-versions/default/include/core/default/Util.h
@@ -20,8 +20,6 @@
 #include PATH(android/hardware/audio/FILE_VERSION/types.h)
 
 #include <algorithm>
-#include <sstream>
-#include <string>
 #include <vector>
 
 #include <system/audio.h>
@@ -72,16 +70,6 @@
     return analyzeStatus(status);
 }
 
-static inline std::vector<std::string> splitString(const std::string& s, char separator) {
-    std::istringstream iss(s);
-    std::string t;
-    std::vector<std::string> result;
-    while (std::getline(iss, t, separator)) {
-        result.push_back(std::move(t));
-    }
-    return result;
-}
-
 }  // namespace util
 }  // namespace implementation
 }  // namespace CPP_VERSION
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index c53ae8d..5076dcf 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -237,26 +237,14 @@
 
 TEST_P(InputStreamTest, updateSinkMetadata) {
     doc::test("The HAL should not crash on metadata change");
-
 #if MAJOR_VERSION <= 6
     hidl_enum_range<AudioSource> range;
-#elif MAJOR_VERSION >= 7
-    xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioSource> range;
-#endif
     // Test all possible track configuration
     for (auto source : range) {
         for (float volume : {0.0, 0.5, 1.0}) {
-#if MAJOR_VERSION <= 6
             const SinkMetadata metadata = {{{.source = source, .gain = volume}}};
-#elif MAJOR_VERSION >= 7
-            const SinkMetadata metadata = {
-                    {{.source = toString(source),
-                      .gain = volume,
-                      .tags = {},
-                      .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}};
-#endif
             ASSERT_OK(stream->updateSinkMetadata(metadata))
-                << "source=" << toString(source) << ", volume=" << volume;
+                    << "source=" << toString(source) << ", volume=" << volume;
         }
     }
 
@@ -264,9 +252,30 @@
 
     // Set no metadata as if all stream track had stopped
     ASSERT_OK(stream->updateSinkMetadata({}));
-
     // Restore initial
     ASSERT_OK(stream->updateSinkMetadata(initMetadata));
+
+#elif MAJOR_VERSION >= 7
+    xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioSource> range;
+    // Test all possible track configuration
+    for (auto source : range) {
+        for (float volume : {0.0, 0.5, 1.0}) {
+            const SinkMetadata metadata = {
+                    {{.source = toString(source),
+                      .gain = volume,
+                      .tags = {},
+                      .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}};
+            ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata(metadata))
+                    << "source=" << toString(source) << ", volume=" << volume;
+        }
+    }
+    // Do not test concurrent capture as this is not officially supported
+
+    // Set no metadata as if all stream track had stopped
+    ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata({}));
+    // Restore initial
+    ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata(initMetadata));
+#endif
 }
 
 TEST_P(OutputStreamTest, SelectPresentation) {
@@ -276,44 +285,55 @@
 
 TEST_P(OutputStreamTest, updateSourceMetadata) {
     doc::test("The HAL should not crash on metadata change");
-
 #if MAJOR_VERSION <= 6
     hidl_enum_range<AudioUsage> usageRange;
     hidl_enum_range<AudioContentType> contentRange;
-#elif MAJOR_VERSION >= 7
-    xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioUsage> usageRange;
-    xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioContentType> contentRange;
-#endif
     // Test all possible track configuration
     for (auto usage : usageRange) {
         for (auto content : contentRange) {
             for (float volume : {0.0, 0.5, 1.0}) {
-#if MAJOR_VERSION <= 6
                 const SourceMetadata metadata = {{{usage, content, volume}}};
-#elif MAJOR_VERSION >= 7
-                const SourceMetadata metadata = {
-                        {{toString(usage),
-                          toString(content),
-                          {} /* tags */,
-                          toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
-                          volume}}};
-#endif
                 ASSERT_OK(stream->updateSourceMetadata(metadata))
                     << "usage=" << toString(usage) << ", content=" << toString(content)
                     << ", volume=" << volume;
             }
         }
     }
-
-    // clang-format off
     // Set many track of different configuration
+    // clang-format off
     ASSERT_OK(stream->updateSourceMetadata(
-#if MAJOR_VERSION <= 6
         {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 0.1},
           {AudioUsage::VOICE_COMMUNICATION, AudioContentType::SPEECH, 1.0},
           {AudioUsage::ALARM, AudioContentType::SONIFICATION, 0.0},
           {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}}
+    ));
+    // clang-format on
+    // Set no metadata as if all stream track had stopped
+    ASSERT_OK(stream->updateSourceMetadata({}));
+    // Restore initial
+    ASSERT_OK(stream->updateSourceMetadata(initMetadata));
 #elif MAJOR_VERSION >= 7
+    xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioUsage> usageRange;
+    xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioContentType> contentRange;
+    // Test all possible track configuration
+    for (auto usage : usageRange) {
+        for (auto content : contentRange) {
+            for (float volume : {0.0, 0.5, 1.0}) {
+                const SourceMetadata metadata = {
+                        {{toString(usage),
+                          toString(content),
+                          {} /* tags */,
+                          toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
+                          volume}}};
+                ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(metadata))
+                        << "usage=" << toString(usage) << ", content=" << toString(content)
+                        << ", volume=" << volume;
+            }
+        }
+    }
+    // Set many track of different configuration
+    // clang-format off
+    ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(
         {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
                       toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
                       {},
@@ -334,15 +354,13 @@
                       {},
                       toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO),
                       0.3}}}
-#endif
     ));
     // clang-format on
-
     // Set no metadata as if all stream track had stopped
-    ASSERT_OK(stream->updateSourceMetadata({}));
-
+    ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata({}));
     // Restore initial
-    ASSERT_OK(stream->updateSourceMetadata(initMetadata));
+    ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(initMetadata));
+#endif
 }
 
 TEST_P(AudioPrimaryHidlTest, setMode) {
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 5ad38de..94fa92a 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -18,84 +18,110 @@
 #include "5.0/AudioPrimaryHidlHalTest.cpp"
 
 #if MAJOR_VERSION <= 6
-const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
-    static std::vector<DeviceConfigParameter> parameters = [] {
-        std::vector<DeviceConfigParameter> result;
-        for (const auto& device : getDeviceParameters()) {
-            auto module =
-                    getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
-            for (const auto& ioProfile : module->getOutputProfiles()) {
-                for (const auto& profile : ioProfile->getAudioProfiles()) {
-                    const auto& channels = profile->getChannels();
-                    const auto& sampleRates = profile->getSampleRates();
-                    auto configs = ConfigHelper::combineAudioConfig(
-                            std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
-                            std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
-                            profile->getFormat());
-                    auto flags = ioProfile->getFlags();
-                    for (auto& config : configs) {
-                        // Some combinations of flags declared in the config file require special
-                        // treatment.
-                        if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-                            config.offloadInfo.sampleRateHz = config.sampleRateHz;
-                            config.offloadInfo.channelMask = config.channelMask;
-                            config.offloadInfo.format = config.format;
-                            config.offloadInfo.streamType = AudioStreamType::MUSIC;
-                            config.offloadInfo.bitRatePerSecond = 320;
-                            config.offloadInfo.durationMicroseconds = -1;
-                            config.offloadInfo.bitWidth = 16;
-                            config.offloadInfo.bufferSize = 256;  // arbitrary value
-                            config.offloadInfo.usage = AudioUsage::MEDIA;
-                            result.emplace_back(device, config,
-                                                AudioOutputFlag(AudioOutputFlag::COMPRESS_OFFLOAD |
-                                                                AudioOutputFlag::DIRECT));
-                        } else {
-                            if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {  // ignore the flag
-                                flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY;
-                            }
-                            result.emplace_back(device, config, AudioOutputFlag(flags));
+static std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(
+        bool oneProfilePerDevice) {
+    std::vector<DeviceConfigParameter> result;
+    for (const auto& device : getDeviceParameters()) {
+        auto module =
+                getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+        for (const auto& ioProfile : module->getOutputProfiles()) {
+            for (const auto& profile : ioProfile->getAudioProfiles()) {
+                const auto& channels = profile->getChannels();
+                const auto& sampleRates = profile->getSampleRates();
+                auto configs = ConfigHelper::combineAudioConfig(
+                        std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+                        std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+                        profile->getFormat());
+                auto flags = ioProfile->getFlags();
+                for (auto& config : configs) {
+                    // Some combinations of flags declared in the config file require special
+                    // treatment.
+                    if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                        config.offloadInfo.sampleRateHz = config.sampleRateHz;
+                        config.offloadInfo.channelMask = config.channelMask;
+                        config.offloadInfo.format = config.format;
+                        config.offloadInfo.streamType = AudioStreamType::MUSIC;
+                        config.offloadInfo.bitRatePerSecond = 320;
+                        config.offloadInfo.durationMicroseconds = -1;
+                        config.offloadInfo.bitWidth = 16;
+                        config.offloadInfo.bufferSize = 256;  // arbitrary value
+                        config.offloadInfo.usage = AudioUsage::MEDIA;
+                        result.emplace_back(device, config,
+                                            AudioOutputFlag(AudioOutputFlag::COMPRESS_OFFLOAD |
+                                                            AudioOutputFlag::DIRECT));
+                    } else {
+                        if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {  // ignore the flag
+                            flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY;
                         }
+                        result.emplace_back(device, config, AudioOutputFlag(flags));
                     }
+                    if (oneProfilePerDevice) break;
                 }
+                if (oneProfilePerDevice) break;
             }
+            if (oneProfilePerDevice) break;
         }
-        return result;
-    }();
+    }
+    return result;
+}
+
+const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateOutputDeviceConfigParameters(false);
     return parameters;
 }
 
-const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
-    static std::vector<DeviceConfigParameter> parameters = [] {
-        std::vector<DeviceConfigParameter> result;
-        for (const auto& device : getDeviceParameters()) {
-            auto module =
-                    getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
-            for (const auto& ioProfile : module->getInputProfiles()) {
-                for (const auto& profile : ioProfile->getAudioProfiles()) {
-                    const auto& channels = profile->getChannels();
-                    const auto& sampleRates = profile->getSampleRates();
-                    auto configs = ConfigHelper::combineAudioConfig(
-                            std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
-                            std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
-                            profile->getFormat());
-                    for (const auto& config : configs) {
-                        result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags()));
-                    }
+const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateOutputDeviceConfigParameters(true);
+    return parameters;
+}
+
+static std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(
+        bool oneProfilePerDevice) {
+    std::vector<DeviceConfigParameter> result;
+    for (const auto& device : getDeviceParameters()) {
+        auto module =
+                getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+        for (const auto& ioProfile : module->getInputProfiles()) {
+            for (const auto& profile : ioProfile->getAudioProfiles()) {
+                const auto& channels = profile->getChannels();
+                const auto& sampleRates = profile->getSampleRates();
+                auto configs = ConfigHelper::combineAudioConfig(
+                        std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+                        std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+                        profile->getFormat());
+                for (const auto& config : configs) {
+                    result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags()));
+                    if (oneProfilePerDevice) break;
                 }
+                if (oneProfilePerDevice) break;
             }
+            if (oneProfilePerDevice) break;
         }
-        return result;
-    }();
+    }
+    return result;
+}
+
+const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateInputDeviceConfigParameters(false);
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateInputDeviceConfigParameters(true);
     return parameters;
 }
 #endif  // MAJOR_VERSION <= 6
 
-TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
-    doc::test("Verify that a device can't be closed if there are streams opened");
+class SingleOutputConfigTest : public AudioHidlTestWithDeviceConfigParameter {};
+TEST_P(SingleOutputConfigTest, CloseDeviceWithOpenedOutputStreams) {
+    doc::test("Verify that a device can't be closed if there are output streams opened");
 #if MAJOR_VERSION <= 6
     DeviceAddress address{.device = AudioDevice::OUT_DEFAULT};
     SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
-    auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
 #elif MAJOR_VERSION >= 7
     DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
     SourceMetadata initMetadata = {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
@@ -103,9 +129,9 @@
                                      {} /* tags */,
                                      toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
                                      1 /* gain */}}};
-    hidl_vec<AudioInOutFlag> flags;
 #endif
-    AudioConfig config{};
+    const AudioConfig& config = getConfig();
+    auto flags = getOutputFlags();
     sp<IStreamOut> stream;
     StreamHelper<IStreamOut> helper(stream);
     AudioConfig suggestedConfig{};
@@ -120,16 +146,17 @@
     ASSERT_OK(getDevice()->close());
     ASSERT_TRUE(resetDevice());
 }
+INSTANTIATE_TEST_CASE_P(SingleOutputConfig, SingleOutputConfigTest,
+                        ::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
+                        &DeviceConfigParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SingleOutputConfig);
 
-TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
-    doc::test("Verify that a device can't be closed if there are streams opened");
-    if (!getCachedPolicyConfig().haveInputProfilesInModule(getDeviceName())) {
-        GTEST_SKIP() << "Device doesn't have input profiles";
-    }
+class SingleInputConfigTest : public AudioHidlTestWithDeviceConfigParameter {};
+TEST_P(SingleInputConfigTest, CloseDeviceWithOpenedInputStreams) {
+    doc::test("Verify that a device can't be closed if there are input streams opened");
 #if MAJOR_VERSION <= 6
     DeviceAddress address{.device = AudioDevice::IN_DEFAULT};
     SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
-    auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
 #elif MAJOR_VERSION >= 7
     DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
     SinkMetadata initMetadata = {
@@ -137,9 +164,9 @@
               .gain = 1,
               .tags = {},
               .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}};
-    hidl_vec<AudioInOutFlag> flags;
 #endif
-    AudioConfig config{};
+    const AudioConfig& config = getConfig();
+    auto flags = getInputFlags();
     sp<IStreamIn> stream;
     StreamHelper<IStreamIn> helper(stream);
     AudioConfig suggestedConfig{};
@@ -154,6 +181,10 @@
     ASSERT_OK(getDevice()->close());
     ASSERT_TRUE(resetDevice());
 }
+INSTANTIATE_TEST_CASE_P(SingleInputConfig, SingleInputConfigTest,
+                        ::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
+                        &DeviceConfigParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SingleInputConfig);
 
 TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) {
     doc::test("Verify that passing an invalid handle to updateAudioPatch is checked");
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 6bb7995..2ed578d 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -25,7 +25,6 @@
     for (auto channelMask : channelMasks) {
         for (auto sampleRate : sampleRates) {
             AudioConfig config{};
-            // leave offloadInfo to 0
             config.base.channelMask = toString(channelMask);
             config.base.sampleRateHz = sampleRate;
             config.base.format = format;
@@ -35,56 +34,158 @@
     return configs;
 }
 
+static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
+        const xsd::MixPorts::MixPort& mixPort) {
+    static const std::vector<AudioInOutFlag> offloadFlags = {
+            toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+            toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
+    std::vector<AudioInOutFlag> flags;
+    bool isOffload = false;
+    if (mixPort.hasFlags()) {
+        auto xsdFlags = mixPort.getFlags();
+        isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
+                              xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
+                    xsdFlags.end();
+        if (!isOffload) {
+            for (auto flag : xsdFlags) {
+                if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
+                    flags.push_back(toString(flag));
+                }
+            }
+        } else {
+            flags = offloadFlags;
+        }
+    }
+    return {flags, isOffload};
+}
+
+static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) {
+    return AudioOffloadInfo{
+            .base = base,
+            .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
+            .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+            .bitRatePerSecond = 320,
+            .durationMicroseconds = -1,
+            .bitWidth = 16,
+            .bufferSize = 256  // arbitrary value
+    };
+}
+
+static std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(
+        bool oneProfilePerDevice) {
+    std::vector<DeviceConfigParameter> result;
+    for (const auto& device : getDeviceParameters()) {
+        auto module =
+                getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+        if (!module || !module->getFirstMixPorts()) break;
+        for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+            if (mixPort.getRole() != xsd::Role::source) continue;  // not an output profile
+            auto [flags, isOffload] = generateOutFlags(mixPort);
+            for (const auto& profile : mixPort.getProfile()) {
+                auto configs = combineAudioConfig(profile.getChannelMasks(),
+                                                  profile.getSamplingRates(), profile.getFormat());
+                for (auto& config : configs) {
+                    // Some combinations of flags declared in the config file require special
+                    // treatment.
+                    if (isOffload) {
+                        config.offloadInfo.info(generateOffloadInfo(config.base));
+                    }
+                    result.emplace_back(device, config, flags);
+                    if (oneProfilePerDevice) break;
+                }
+                if (oneProfilePerDevice) break;
+            }
+            if (oneProfilePerDevice) break;
+        }
+    }
+    return result;
+}
+
 const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
-    static std::vector<DeviceConfigParameter> parameters = [] {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateOutputDeviceConfigParameters(false);
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateOutputDeviceConfigParameters(true);
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters(
+        bool generateInvalidFlags = true) {
+    static std::vector<DeviceConfigParameter> parameters = [&] {
         std::vector<DeviceConfigParameter> result;
-        const std::vector<AudioInOutFlag> offloadFlags = {
-                toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
-                toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
         for (const auto& device : getDeviceParameters()) {
             auto module =
                     getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
             if (!module || !module->getFirstMixPorts()) break;
+            bool hasRegularConfig = false, hasOffloadConfig = false;
             for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
                 if (mixPort.getRole() != xsd::Role::source) continue;  // not an output profile
-                std::vector<AudioInOutFlag> flags;
-                bool isOffload = false;
-                if (mixPort.hasFlags()) {
-                    auto xsdFlags = mixPort.getFlags();
-                    isOffload =
-                            std::find(xsdFlags.begin(), xsdFlags.end(),
-                                      xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
-                            xsdFlags.end();
-                    if (!isOffload) {
-                        for (auto flag : xsdFlags) {
-                            if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
-                                flags.push_back(toString(flag));
-                            }
-                        }
-                    } else {
-                        flags = offloadFlags;
-                    }
-                }
+                auto [validFlags, isOffload] = generateOutFlags(mixPort);
+                if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue;
                 for (const auto& profile : mixPort.getProfile()) {
-                    auto configs =
-                            combineAudioConfig(profile.getChannelMasks(),
-                                               profile.getSamplingRates(), profile.getFormat());
-                    for (auto& config : configs) {
-                        // Some combinations of flags declared in the config file require special
-                        // treatment.
+                    if (!profile.hasFormat() || !profile.hasSamplingRates() ||
+                        !profile.hasChannelMasks())
+                        continue;
+                    AudioConfigBase validBase = {
+                            profile.getFormat(),
+                            static_cast<uint32_t>(profile.getSamplingRates()[0]),
+                            toString(profile.getChannelMasks()[0])};
+                    {
+                        AudioConfig config{.base = validBase};
+                        config.base.channelMask = "random_string";
                         if (isOffload) {
-                            config.offloadInfo.base = config.base;
-                            config.offloadInfo.streamType =
-                                    toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC);
-                            config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA);
-                            config.offloadInfo.bitRatePerSecond = 320;
-                            config.offloadInfo.durationMicroseconds = -1;
-                            config.offloadInfo.bitWidth = 16;
-                            config.offloadInfo.bufferSize = 256;  // arbitrary value
+                            config.offloadInfo.info(generateOffloadInfo(validBase));
                         }
+                        result.emplace_back(device, config, validFlags);
+                    }
+                    {
+                        AudioConfig config{.base = validBase};
+                        config.base.format = "random_string";
+                        if (isOffload) {
+                            config.offloadInfo.info(generateOffloadInfo(validBase));
+                        }
+                        result.emplace_back(device, config, validFlags);
+                    }
+                    if (generateInvalidFlags) {
+                        AudioConfig config{.base = validBase};
+                        if (isOffload) {
+                            config.offloadInfo.info(generateOffloadInfo(validBase));
+                        }
+                        std::vector<AudioInOutFlag> flags = {"random_string", ""};
                         result.emplace_back(device, config, flags);
                     }
+                    if (isOffload) {
+                        {
+                            AudioConfig config{.base = validBase};
+                            config.offloadInfo.info(generateOffloadInfo(validBase));
+                            config.offloadInfo.info().base.channelMask = "random_string";
+                        }
+                        {
+                            AudioConfig config{.base = validBase};
+                            config.offloadInfo.info(generateOffloadInfo(validBase));
+                            config.offloadInfo.info().base.format = "random_string";
+                        }
+                        {
+                            AudioConfig config{.base = validBase};
+                            config.offloadInfo.info(generateOffloadInfo(validBase));
+                            config.offloadInfo.info().streamType = "random_string";
+                        }
+                        {
+                            AudioConfig config{.base = validBase};
+                            config.offloadInfo.info(generateOffloadInfo(validBase));
+                            config.offloadInfo.info().usage = "random_string";
+                        }
+                        hasOffloadConfig = true;
+                    } else {
+                        hasRegularConfig = true;
+                    }
+                    break;
                 }
+                if (hasOffloadConfig && hasRegularConfig) break;
             }
         }
         return result;
@@ -92,32 +193,346 @@
     return parameters;
 }
 
+static std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(
+        bool oneProfilePerDevice) {
+    std::vector<DeviceConfigParameter> result;
+    for (const auto& device : getDeviceParameters()) {
+        auto module =
+                getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+        if (!module || !module->getFirstMixPorts()) break;
+        for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+            if (mixPort.getRole() != xsd::Role::sink) continue;  // not an input profile
+            std::vector<AudioInOutFlag> flags;
+            if (mixPort.hasFlags()) {
+                std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
+                               std::back_inserter(flags), [](auto flag) { return toString(flag); });
+            }
+            for (const auto& profile : mixPort.getProfile()) {
+                auto configs = combineAudioConfig(profile.getChannelMasks(),
+                                                  profile.getSamplingRates(), profile.getFormat());
+                for (const auto& config : configs) {
+                    result.emplace_back(device, config, flags);
+                    if (oneProfilePerDevice) break;
+                }
+                if (oneProfilePerDevice) break;
+            }
+            if (oneProfilePerDevice) break;
+        }
+    }
+    return result;
+}
+
 const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
-    static std::vector<DeviceConfigParameter> parameters = [] {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateInputDeviceConfigParameters(false);
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters =
+            generateInputDeviceConfigParameters(true);
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
+        bool generateInvalidFlags = true) {
+    static std::vector<DeviceConfigParameter> parameters = [&] {
         std::vector<DeviceConfigParameter> result;
         for (const auto& device : getDeviceParameters()) {
             auto module =
                     getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
             if (!module || !module->getFirstMixPorts()) break;
+            bool hasConfig = false;
             for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
                 if (mixPort.getRole() != xsd::Role::sink) continue;  // not an input profile
-                std::vector<AudioInOutFlag> flags;
+                std::vector<AudioInOutFlag> validFlags;
                 if (mixPort.hasFlags()) {
                     std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
-                                   std::back_inserter(flags),
+                                   std::back_inserter(validFlags),
                                    [](auto flag) { return toString(flag); });
                 }
                 for (const auto& profile : mixPort.getProfile()) {
-                    auto configs =
-                            combineAudioConfig(profile.getChannelMasks(),
-                                               profile.getSamplingRates(), profile.getFormat());
-                    for (const auto& config : configs) {
+                    if (!profile.hasFormat() || !profile.hasSamplingRates() ||
+                        !profile.hasChannelMasks())
+                        continue;
+                    AudioConfigBase validBase = {
+                            profile.getFormat(),
+                            static_cast<uint32_t>(profile.getSamplingRates()[0]),
+                            toString(profile.getChannelMasks()[0])};
+                    {
+                        AudioConfig config{.base = validBase};
+                        config.base.channelMask = "random_string";
+                        result.emplace_back(device, config, validFlags);
+                    }
+                    {
+                        AudioConfig config{.base = validBase};
+                        config.base.format = "random_string";
+                        result.emplace_back(device, config, validFlags);
+                    }
+                    if (generateInvalidFlags) {
+                        AudioConfig config{.base = validBase};
+                        std::vector<AudioInOutFlag> flags = {"random_string", ""};
                         result.emplace_back(device, config, flags);
                     }
+                    hasConfig = true;
+                    break;
                 }
+                if (hasConfig) break;
             }
         }
         return result;
     }();
     return parameters;
 }
+
+class InvalidInputConfigNoFlagsTest : public AudioHidlTestWithDeviceConfigParameter {};
+TEST_P(InvalidInputConfigNoFlagsTest, InputBufferSizeTest) {
+    doc::test("Verify that invalid config is rejected by IDevice::getInputBufferSize method.");
+    uint64_t bufferSize;
+    ASSERT_OK(getDevice()->getInputBufferSize(getConfig(), returnIn(res, bufferSize)));
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, res);
+}
+INSTANTIATE_TEST_CASE_P(
+        InputBufferSizeInvalidConfig, InvalidInputConfigNoFlagsTest,
+        ::testing::ValuesIn(getInputDeviceInvalidConfigParameters(false /*generateInvalidFlags*/)),
+        &DeviceConfigParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputBufferSizeInvalidConfig);
+
+enum { PARAM_DEVICE_CONFIG, PARAM_ADDRESS, PARAM_METADATA };
+enum { INDEX_SINK, INDEX_SOURCE };
+using SinkOrSourceMetadata = std::variant<SinkMetadata, SourceMetadata>;
+using StreamOpenParameter = std::tuple<DeviceConfigParameter, DeviceAddress, SinkOrSourceMetadata>;
+
+static std::string StreamOpenParameterToString(
+        const ::testing::TestParamInfo<StreamOpenParameter>& info) {
+    return DeviceConfigParameterToString(::testing::TestParamInfo<DeviceConfigParameter>{
+                   std::get<PARAM_DEVICE_CONFIG>(info.param), info.index}) +
+           "__" +
+           SanitizeStringForGTestName(
+                   ::testing::PrintToString(std::get<PARAM_ADDRESS>(info.param))) +
+           "__" +
+           SanitizeStringForGTestName(std::visit(
+                   [](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
+                   std::get<PARAM_METADATA>(info.param)));
+}
+
+class StreamOpenTest : public HidlTest, public ::testing::WithParamInterface<StreamOpenParameter> {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
+        ASSERT_TRUE(getDevice() != nullptr);
+    }
+    const std::string& getFactoryName() const override {
+        return std::get<PARAM_FACTORY_NAME>(
+                std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam())));
+    }
+    const std::string& getDeviceName() const override {
+        return std::get<PARAM_DEVICE_NAME>(
+                std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam())));
+    }
+    const AudioConfig& getConfig() const {
+        return std::get<PARAM_CONFIG>(std::get<PARAM_DEVICE_CONFIG>(GetParam()));
+    }
+    const hidl_vec<AudioInOutFlag> getFlags() const {
+        return std::get<PARAM_FLAGS>(std::get<PARAM_DEVICE_CONFIG>(GetParam()));
+    }
+    const DeviceAddress& getDeviceAddress() const { return std::get<PARAM_ADDRESS>(GetParam()); }
+    bool isParamForInputStream() const {
+        return std::get<PARAM_METADATA>(GetParam()).index() == INDEX_SINK;
+    }
+    const SinkMetadata& getSinkMetadata() const {
+        return std::get<INDEX_SINK>(std::get<PARAM_METADATA>(GetParam()));
+    }
+    const SourceMetadata& getSourceMetadata() const {
+        return std::get<INDEX_SOURCE>(std::get<PARAM_METADATA>(GetParam()));
+    }
+};
+
+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;
+}
+
+static const RecordTrackMetadata& getValidRecordTrackMetadata() {
+    static const RecordTrackMetadata valid = {
+            .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1};
+    return valid;
+}
+
+static const RecordTrackMetadata& getValidRecordTrackMetadataWithDest() {
+    static const RecordTrackMetadata valid = {
+            .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
+            .gain = 1,
+            .destination = [] {
+                RecordTrackMetadata::Destination dest;
+                dest.device(getValidOutputDeviceAddress());
+                return dest;
+            }()};
+    return valid;
+}
+
+static const RecordTrackMetadata& getInvalidSourceRecordTrackMetadata() {
+    static const RecordTrackMetadata invalid = {.source = "random_string", .gain = 1};
+    return invalid;
+}
+
+static const RecordTrackMetadata& getRecordTrackMetadataWithInvalidDest() {
+    static const RecordTrackMetadata invalid = {
+            .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
+            .gain = 1,
+            .destination = [] {
+                RecordTrackMetadata::Destination dest;
+                dest.device(getInvalidDeviceAddress());
+                return dest;
+            }()};
+    return invalid;
+}
+
+static const PlaybackTrackMetadata& getValidPlaybackTrackMetadata() {
+    static const PlaybackTrackMetadata valid = {
+            .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+            .contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
+            .gain = 1};
+    return valid;
+}
+
+static const PlaybackTrackMetadata& getInvalidUsagePlaybackTrackMetadata() {
+    static const PlaybackTrackMetadata invalid = {
+            .usage = "random_string",
+            .contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
+            .gain = 1};
+    return invalid;
+}
+
+static const PlaybackTrackMetadata& getInvalidContentTypePlaybackTrackMetadata() {
+    static const PlaybackTrackMetadata invalid = {
+            .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+            .contentType = "random_string",
+            .gain = 1};
+    return invalid;
+}
+
+static const std::vector<SourceMetadata>& getInvalidSourceMetadatas() {
+    static const std::vector<SourceMetadata> invalids = {
+            SourceMetadata{.tracks = {{getInvalidUsagePlaybackTrackMetadata()}}},
+            SourceMetadata{.tracks = {{getInvalidContentTypePlaybackTrackMetadata()}}},
+            SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
+                                       getInvalidUsagePlaybackTrackMetadata()}}},
+            SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
+                                       getInvalidContentTypePlaybackTrackMetadata()}}}};
+    return invalids;
+}
+static const std::vector<SinkMetadata>& getInvalidSinkMetadatas() {
+    static const std::vector<SinkMetadata> invalids = {
+            SinkMetadata{.tracks = {{getInvalidSourceRecordTrackMetadata()}}},
+            SinkMetadata{.tracks = {{getRecordTrackMetadataWithInvalidDest()}}},
+            SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
+                                     getInvalidSourceRecordTrackMetadata()}}},
+            SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
+                                     getRecordTrackMetadataWithInvalidDest()}}}};
+    return invalids;
+}
+template <typename T>
+static inline std::vector<SinkOrSourceMetadata> wrapMetadata(const std::vector<T>& metadata) {
+    return std::vector<SinkOrSourceMetadata>{metadata.begin(), metadata.end()};
+}
+
+TEST_P(StreamOpenTest, OpenInputOrOutputStreamTest) {
+    doc::test(
+            "Verify that invalid arguments are rejected by "
+            "IDevice::open{Input|Output}Stream method.");
+    AudioConfig suggestedConfig{};
+    if (isParamForInputStream()) {
+        sp<IStreamIn> stream;
+        ASSERT_OK(getDevice()->openInputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(),
+                                               getFlags(), getSinkMetadata(),
+                                               returnIn(res, stream, suggestedConfig)));
+        ASSERT_TRUE(stream == nullptr);
+    } else {
+        sp<IStreamOut> stream;
+        ASSERT_OK(getDevice()->openOutputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(),
+                                                getFlags(), getSourceMetadata(),
+                                                returnIn(res, stream, suggestedConfig)));
+        ASSERT_TRUE(stream == nullptr);
+    }
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, res);
+    EXPECT_EQ(AudioConfig{}, suggestedConfig);
+}
+INSTANTIATE_TEST_CASE_P(
+        InputStreamInvalidConfig, StreamOpenTest,
+        ::testing::Combine(::testing::ValuesIn(getInputDeviceInvalidConfigParameters()),
+                           ::testing::Values(getValidInputDeviceAddress()),
+                           ::testing::Values(SinkMetadata{
+                                   .tracks = {{getValidRecordTrackMetadata(),
+                                               getValidRecordTrackMetadataWithDest()}}})),
+        &StreamOpenParameterToString);
+INSTANTIATE_TEST_CASE_P(
+        InputStreamInvalidAddress, StreamOpenTest,
+        ::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
+                           ::testing::Values(getInvalidDeviceAddress()),
+                           ::testing::Values(SinkMetadata{
+                                   .tracks = {{getValidRecordTrackMetadata(),
+                                               getValidRecordTrackMetadataWithDest()}}})),
+        &StreamOpenParameterToString);
+INSTANTIATE_TEST_CASE_P(
+        InputStreamInvalidMetadata, StreamOpenTest,
+        ::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
+                           ::testing::Values(getValidInputDeviceAddress()),
+                           ::testing::ValuesIn(wrapMetadata(getInvalidSinkMetadatas()))),
+        &StreamOpenParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidConfig);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidAddress);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidMetadata);
+
+INSTANTIATE_TEST_CASE_P(
+        OutputStreamInvalidConfig, StreamOpenTest,
+        ::testing::Combine(::testing::ValuesIn(getOutputDeviceInvalidConfigParameters()),
+                           ::testing::Values(getValidOutputDeviceAddress()),
+                           ::testing::Values(SourceMetadata{
+                                   .tracks = {{getValidPlaybackTrackMetadata()}}})),
+        &StreamOpenParameterToString);
+INSTANTIATE_TEST_CASE_P(
+        OutputStreamInvalidAddress, StreamOpenTest,
+        ::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
+                           ::testing::Values(getInvalidDeviceAddress()),
+                           ::testing::Values(SourceMetadata{
+                                   .tracks = {{getValidPlaybackTrackMetadata()}}})),
+        &StreamOpenParameterToString);
+INSTANTIATE_TEST_CASE_P(
+        OutputStreamInvalidMetadata, StreamOpenTest,
+        ::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
+                           ::testing::Values(getValidOutputDeviceAddress()),
+                           ::testing::ValuesIn(wrapMetadata(getInvalidSourceMetadatas()))),
+        &StreamOpenParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidConfig);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidAddress);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidMetadata);
+
+TEST_P(OutputStreamTest, UpdateInvalidSourceMetadata) {
+    doc::test("Verify that invalid metadata is rejected by IStreamOut::updateSourceMetadata");
+    for (const auto& metadata : getInvalidSourceMetadatas()) {
+        ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSourceMetadata(metadata))
+                << ::testing::PrintToString(metadata);
+    }
+}
+
+TEST_P(InputStreamTest, UpdateInvalidSinkMetadata) {
+    doc::test("Verify that invalid metadata is rejected by IStreamIn::updateSinkMetadata");
+    for (const auto& metadata : getInvalidSinkMetadatas()) {
+        ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSinkMetadata(metadata))
+                << ::testing::PrintToString(metadata);
+    }
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index a16a0fb..f145b60 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -522,7 +522,9 @@
 
 #if MAJOR_VERSION >= 6
 const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters();
+const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters();
 const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters();
+const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters();
 #endif
 
 #if MAJOR_VERSION >= 4
@@ -883,7 +885,7 @@
         AudioHidlTestWithDeviceConfigParameter::TearDown();
     }
 
-   protected:
+  protected:
     AudioConfig audioConfig;
     DeviceAddress address = {};
     sp<Stream> stream;
@@ -973,7 +975,7 @@
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
 #if MAJOR_VERSION <= 6
         address.device = AudioDevice::IN_DEFAULT;
-#elif MAJOR_VERSION <= 7
+#elif MAJOR_VERSION >= 7
         address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
 #endif
         const AudioConfig& config = getConfig();
@@ -988,7 +990,7 @@
 
    protected:
 #if MAJOR_VERSION == 2
-    const AudioSource initMetadata = AudioSource::DEFAULT;
+     const AudioSource initMetadata = AudioSource::DEFAULT;
 #elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
      const SinkMetadata initMetadata = {{ {.source = AudioSource::DEFAULT, .gain = 1 } }};
 #elif MAJOR_VERSION >= 7