audio policy: enhancing type conversion helper

This patch updates the conversion helper class (string to/from policy
common types) by adding direction agnostic helper for channels and
formats.
It also adds the support of device category and stream type parsing.

Change-Id: I75d5a77d78bc3aeb2389b424bfb41febbf020f1a
Signed-off-by: François Gaffie <francois.gaffie@intel.com>
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 4b73e3c..1a1cbb2 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -18,6 +18,10 @@
 
 #include <system/audio.h>
 
+static const uint32_t gDynamicRate = 0;
+static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
+static const audio_channel_mask_t gDynamicChannelMask = AUDIO_CHANNEL_NONE;
+
 // For mixed output and inputs, the policy will use max mixer sampling rates.
 // Do not limit sampling rate otherwise
 #define MAX_MIXER_SAMPLING_RATE 192000
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
index 85db863..9b96770 100644
--- a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -16,123 +16,218 @@
 
 #pragma once
 
+#include "policy.h"
+#include <Volume.h>
 #include <system/audio.h>
 #include <convert/convert.h>
 #include <utils/Log.h>
 #include <string>
 #include <utils/Vector.h>
+#include <utils/SortedVector.h>
 
 namespace android {
 
-/**
- * As far as we do not have real type (only typedef on uint32_t for some types, we
- * will need this trick to handle template specialization.
- */
-class Devices;
-class InputFlags;
-class OutputFlags;
-class Formats;
-class OutputChannel;
-class InputChannel;
-class ChannelIndex;
-class GainMode;
-
 #define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
                                     // "formats" in outputs descriptors indicating that supported
                                     // values should be queried after opening the output.
 
+struct SampleRateTraits
+{
+    typedef uint32_t Type;
+    typedef Vector<Type> Collection;
+};
+struct DeviceTraits
+{
+    typedef audio_devices_t Type;
+    typedef Vector<Type> Collection;
+};
+struct OutputFlagTraits
+{
+    typedef audio_output_flags_t Type;
+    typedef Vector<Type> Collection;
+};
+struct InputFlagTraits
+{
+    typedef audio_input_flags_t Type;
+    typedef Vector<Type> Collection;
+};
+struct FormatTraits
+{
+    typedef audio_format_t Type;
+    typedef Vector<Type> Collection;
+};
+struct ChannelTraits
+{
+    typedef audio_channel_mask_t Type;
+    typedef Vector<Type> Collection;
+};
+struct OutputChannelTraits : public ChannelTraits {};
+struct InputChannelTraits : public ChannelTraits {};
+struct ChannelIndexTraits : public ChannelTraits {};
+struct GainModeTraits
+{
+    typedef audio_gain_mode_t Type;
+    typedef Vector<Type> Collection;
+};
+struct StreamTraits
+{
+  typedef audio_stream_type_t Type;
+  typedef Vector<Type> Collection;
+};
+struct DeviceCategoryTraits
+{
+  typedef device_category Type;
+  typedef Vector<Type> Collection;
+};
 template <typename T>
-static void collectionFromString(const std::string &str, Vector<T> &collection)
+struct DefaultTraits
+{
+  typedef T Type;
+  typedef Vector<Type> Collection;
+};
+
+template <class Traits>
+static void collectionFromString(const std::string &str, typename Traits::Collection &collection,
+                                 const char *del = "|")
 {
     char *literal = strdup(str.c_str());
-    for (const char *cstr = strtok(literal, "|"); cstr != NULL; cstr = strtok(NULL, "|")) {
-        T value;
-        if (utilities::convertTo<std::string, T>(cstr, value)) {
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type value;
+        if (utilities::convertTo<std::string, typename Traits::Type >(cstr, value)) {
             collection.add(value);
         }
     }
     free(literal);
 }
 
-template <typename T, typename SupportedType>
+template <class Traits>
 class TypeConverter
 {
 public:
-    static bool toString(const T &value, std::string &str);
+    static bool toString(const typename Traits::Type &value, std::string &str);
 
-    static bool fromString(const std::string &str, T &result);
+    static bool fromString(const std::string &str, typename Traits::Type &result);
 
-    static void collectionFromString(const std::string &str, Vector<T> &collection);
+    static void collectionFromString(const std::string &str,
+                                     typename Traits::Collection &collection,
+                                     const char *del = "|");
 
-    static uint32_t maskFromString(const std::string &str);
+    static uint32_t maskFromString(const std::string &str, const char *del = "|");
 
 protected:
     struct Table {
         const char *literal;
-        T value;
+        typename Traits::Type value;
     };
 
     static const Table mTable[];
     static const size_t mSize;
 };
 
-typedef TypeConverter<audio_devices_t, Devices> DeviceConverter;
-typedef TypeConverter<audio_output_flags_t, OutputFlags> OutputFlagConverter;
-typedef TypeConverter<audio_input_flags_t, InputFlags> InputFlagConverter;
-typedef TypeConverter<audio_format_t, Formats> FormatConverter;
-typedef TypeConverter<audio_channel_mask_t, OutputChannel> OutputChannelConverter;
-typedef TypeConverter<audio_channel_mask_t, InputChannel> InputChannelConverter;
-typedef TypeConverter<audio_channel_mask_t, ChannelIndex> ChannelIndexConverter;
-typedef TypeConverter<audio_gain_mode_t, GainMode> GainModeConverter;
+typedef TypeConverter<DeviceTraits> DeviceConverter;
+typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;
+typedef TypeConverter<InputFlagTraits> InputFlagConverter;
+typedef TypeConverter<FormatTraits> FormatConverter;
+typedef TypeConverter<OutputChannelTraits> OutputChannelConverter;
+typedef TypeConverter<InputChannelTraits> InputChannelConverter;
+typedef TypeConverter<ChannelIndexTraits> ChannelIndexConverter;
+typedef TypeConverter<GainModeTraits> GainModeConverter;
+typedef TypeConverter<StreamTraits> StreamTypeConverter;
+typedef TypeConverter<DeviceCategoryTraits> DeviceCategoryConverter;
 
-static Vector<uint32_t> samplingRatesFromString(const std::string &samplingRates)
+static SampleRateTraits::Collection samplingRatesFromString(const std::string &samplingRates,
+                                                            const char *del = "|")
 {
-    Vector<uint32_t> samplingRateCollection;
+    SampleRateTraits::Collection samplingRateCollection;
     // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
     // rates should be read from the output stream after it is opened for the first time
     if (samplingRates == DYNAMIC_VALUE_TAG) {
-        samplingRateCollection.add(0);
+        samplingRateCollection.add(gDynamicRate);
     } else {
-        collectionFromString<uint32_t>(samplingRates, samplingRateCollection);
+        collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
     }
     return samplingRateCollection;
 }
 
-static Vector<audio_format_t> formatsFromString(const std::string &formats)
+static FormatTraits::Collection formatsFromString(const std::string &formats, const char *del = "|")
 {
-    Vector<audio_format_t> formatCollection;
+    FormatTraits::Collection formatCollection;
     // by convention, "0' in the first entry in mFormats indicates the supported formats
     // should be read from the output stream after it is opened for the first time
     if (formats == DYNAMIC_VALUE_TAG) {
-        formatCollection.add(AUDIO_FORMAT_DEFAULT);
+        formatCollection.add(gDynamicFormat);
     } else {
-        FormatConverter::collectionFromString(formats, formatCollection);
+        FormatConverter::collectionFromString(formats, formatCollection, del);
     }
     return formatCollection;
 }
 
-static Vector<audio_channel_mask_t> inputChannelMasksFromString(const std::string &inChannels)
+static audio_format_t formatFromString(const std::string &literalFormat)
 {
-    Vector <audio_channel_mask_t> inputChannelMaskCollection;
-    if (inChannels == DYNAMIC_VALUE_TAG) {
-        inputChannelMaskCollection.add(0);
+    audio_format_t format;
+    // by convention, "0' in the first entry in literalFormat indicates the supported formats
+    // should be read from the output stream after it is opened for the first time
+    if (literalFormat == DYNAMIC_VALUE_TAG) {
+        return gDynamicFormat;
     } else {
-        InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection);
-        ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection);
+        FormatConverter::fromString(literalFormat, format);
+    }
+    return format;
+}
+
+static audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
+{
+    audio_channel_mask_t channels;
+    // by convention, "0' in the first entry in literalChannels indicates the supported channels
+    // should be read from the output stream after it is opened for the first time
+    if (literalChannels == DYNAMIC_VALUE_TAG) {
+        return gDynamicChannelMask;
+    }
+    if (!OutputChannelConverter::fromString(literalChannels, channels) ||
+            !InputChannelConverter::fromString(literalChannels, channels)) {
+        return AUDIO_CHANNEL_INVALID;
+    }
+    return channels;
+}
+
+static ChannelTraits::Collection channelMasksFromString(const std::string &channels,
+                                                        const char *del = "|")
+{
+    ChannelTraits::Collection channelMaskCollection;
+    if (channels == DYNAMIC_VALUE_TAG) {
+        channelMaskCollection.add(gDynamicChannelMask);
+    } else {
+        OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+        InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+        ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
+    }
+    return channelMaskCollection;
+}
+
+static InputChannelTraits::Collection inputChannelMasksFromString(const std::string &inChannels,
+                                                                  const char *del = "|")
+{
+    InputChannelTraits::Collection inputChannelMaskCollection;
+    if (inChannels == DYNAMIC_VALUE_TAG) {
+        inputChannelMaskCollection.add(gDynamicChannelMask);
+    } else {
+        InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+        ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
     }
     return inputChannelMaskCollection;
 }
 
-static Vector<audio_channel_mask_t> outputChannelMasksFromString(const std::string &outChannels)
+static OutputChannelTraits::Collection outputChannelMasksFromString(const std::string &outChannels,
+                                                                    const char *del = "|")
 {
-    Vector <audio_channel_mask_t> outputChannelMaskCollection;
+    OutputChannelTraits::Collection outputChannelMaskCollection;
     // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
     // masks should be read from the output stream after it is opened for the first time
     if (outChannels == DYNAMIC_VALUE_TAG) {
-        outputChannelMaskCollection.add(0);
+        outputChannelMaskCollection.add(gDynamicChannelMask);
     } else {
-        OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection);
-        ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection);
+        OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+        ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
     }
     return outputChannelMaskCollection;
 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
index d66f6bf..0397f97 100644
--- a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -166,7 +166,6 @@
 const size_t InputChannelConverter::mSize = sizeof(InputChannelConverter::mTable) /
         sizeof(InputChannelConverter::mTable[0]);
 
-
 template <>
 const ChannelIndexConverter::Table ChannelIndexConverter::mTable[] = {
     "AUDIO_CHANNEL_INDEX_MASK_1", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_1),
@@ -194,9 +193,41 @@
 const size_t GainModeConverter::mSize = sizeof(GainModeConverter::mTable) /
         sizeof(GainModeConverter::mTable[0]);
 
+template <>
+const DeviceCategoryConverter::Table DeviceCategoryConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_HEADSET),
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_SPEAKER),
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EARPIECE),
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EXT_MEDIA)
+};
 
-template <typename T, typename SupportedType>
-bool TypeConverter<T, SupportedType>::toString(const T &value, std::string &str)
+template<>
+const size_t DeviceCategoryConverter::mSize = sizeof(DeviceCategoryConverter::mTable) /
+        sizeof(DeviceCategoryConverter::mTable[0]);
+
+template <>
+const StreamTypeConverter::Table StreamTypeConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_VOICE_CALL),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_SYSTEM),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_RING),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_MUSIC),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ALARM),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_NOTIFICATION),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_BLUETOOTH_SCO ),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ENFORCED_AUDIBLE),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DTMF),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_TTS),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ACCESSIBILITY),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_REROUTING),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH)
+};
+
+template<>
+const size_t StreamTypeConverter::mSize = sizeof(StreamTypeConverter::mTable) /
+        sizeof(StreamTypeConverter::mTable[0]);
+
+template <class Traits>
+bool TypeConverter<Traits>::toString(const typename Traits::Type &value, std::string &str)
 {
     for (size_t i = 0; i < mSize; i++) {
         if (mTable[i].value == value) {
@@ -207,8 +238,8 @@
     return false;
 }
 
-template <typename T, typename SupportedType>
-bool TypeConverter<T, SupportedType>::fromString(const std::string &str, T &result)
+template <class Traits>
+bool TypeConverter<Traits>::fromString(const std::string &str, typename Traits::Type &result)
 {
     for (size_t i = 0; i < mSize; i++) {
         if (strcmp(mTable[i].literal, str.c_str()) == 0) {
@@ -220,14 +251,15 @@
     return false;
 }
 
-template <typename T, typename SupportedType>
-void TypeConverter<T, SupportedType>::collectionFromString(const std::string &str,
-                                                           Vector<T> &collection)
+template <class Traits>
+void TypeConverter<Traits>::collectionFromString(const std::string &str,
+                                                 typename Traits::Collection &collection,
+                                                 const char *del)
 {
     char *literal = strdup(str.c_str());
 
-    for (const char *cstr = strtok(literal, "|"); cstr != NULL; cstr = strtok(NULL, "|")) {
-        T value;
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type value;
         if (fromString(cstr, value)) {
             collection.add(value);
         }
@@ -235,13 +267,13 @@
     free(literal);
 }
 
-template <typename T, typename SupportedType>
-uint32_t TypeConverter<T, SupportedType>::maskFromString(const std::string &str)
+template <class Traits>
+uint32_t TypeConverter<Traits>::maskFromString(const std::string &str, const char *del)
 {
     char *literal = strdup(str.c_str());
     uint32_t value = 0;
-    for (const char *cstr = strtok(literal, "|"); cstr != NULL; cstr = strtok(NULL, "|")) {
-        T type;
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type type;
         if (fromString(cstr, type)) {
             value |= static_cast<uint32_t>(type);
         }
@@ -250,14 +282,16 @@
     return value;
 }
 
-template class TypeConverter<audio_devices_t, Devices>;
-template class TypeConverter<audio_output_flags_t, OutputFlags>;
-template class TypeConverter<audio_input_flags_t, InputFlags>;
-template class TypeConverter<audio_format_t, Formats>;
-template class TypeConverter<audio_channel_mask_t, OutputChannel>;
-template class TypeConverter<audio_channel_mask_t, InputChannel>;
-template class TypeConverter<audio_channel_mask_t, ChannelIndex>;
-template class TypeConverter<audio_gain_mode_t, GainMode>;
+template class TypeConverter<DeviceTraits>;
+template class TypeConverter<OutputFlagTraits>;
+template class TypeConverter<InputFlagTraits>;
+template class TypeConverter<FormatTraits>;
+template class TypeConverter<OutputChannelTraits>;
+template class TypeConverter<InputChannelTraits>;
+template class TypeConverter<ChannelIndexTraits>;
+template class TypeConverter<GainModeTraits>;
+template class TypeConverter<StreamTraits>;
+template class TypeConverter<DeviceCategoryTraits>;
 
 }; // namespace android