Merge "Define SENSOR_TYPE_PICK_UP_GESTURE." into lmp-dev
diff --git a/include/hardware/audio.h b/include/hardware/audio.h
index 7ff5b78..95111dd 100644
--- a/include/hardware/audio.h
+++ b/include/hardware/audio.h
@@ -579,7 +579,8 @@
                              audio_io_handle_t handle,
                              audio_devices_t devices,
                              struct audio_config *config,
-                             struct audio_stream_in **stream_in);
+                             struct audio_stream_in **stream_in,
+                             audio_input_flags_t flags);
 
     void (*close_input_stream)(struct audio_hw_device *dev,
                                struct audio_stream_in *stream_in);
diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h
index f647ab3..882bade 100644
--- a/include/hardware/hwcomposer.h
+++ b/include/hardware/hwcomposer.h
@@ -678,16 +678,24 @@
      * total number of configurations available for the display is returned in
      * *numConfigs. If *numConfigs is zero on entry, then configs may be NULL.
      *
-     * HWC_DEVICE_API_VERSION_1_1 does not provide a way to choose a config.
-     * For displays that support multiple configurations, the h/w composer
-     * implementation should choose one and report it as the first config in
-     * the list. Reporting the not-chosen configs is not required.
+     * Hardware composers implementing HWC_DEVICE_API_VERSION_1_3 or prior
+     * shall choose one configuration to activate and report it as the first
+     * entry in the returned list. Reporting the inactive configurations is not
+     * required.
      *
-     * Returns 0 on success or -errno on error. If disp is a hotpluggable
-     * display type and no display is connected, an error should be returned.
+     * HWC_DEVICE_API_VERSION_1_4 and later provide configuration management
+     * through SurfaceFlinger, and hardware composers implementing these APIs
+     * must also provide getActiveConfig and setActiveConfig. Hardware composers
+     * implementing these API versions may choose not to activate any
+     * configuration, leaving configuration selection to higher levels of the
+     * framework.
+     *
+     * Returns 0 on success or a negative error code on error. If disp is a
+     * hotpluggable display type and no display is connected, an error shall be
+     * returned.
      *
      * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_1 and later.
-     * It should be NULL for previous versions.
+     * It shall be NULL for previous versions.
      */
     int (*getDisplayConfigs)(struct hwc_composer_device_1* dev, int disp,
             uint32_t* configs, size_t* numConfigs);
@@ -704,19 +712,54 @@
      * array will have one less value than the attributes array.
      *
      * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_1 and later.
-     * It should be NULL for previous versions.
+     * It shall be NULL for previous versions.
      *
      * If disp is a hotpluggable display type and no display is connected,
      * or if config is not a valid configuration for the display, a negative
-     * value should be returned.
+     * error code shall be returned.
      */
     int (*getDisplayAttributes)(struct hwc_composer_device_1* dev, int disp,
             uint32_t config, const uint32_t* attributes, int32_t* values);
 
     /*
+     * (*getActiveConfig)() returns the index of the configuration that is
+     * currently active on the connected display. The index is relative to
+     * the list of configuration handles returned by getDisplayConfigs. If there
+     * is no active configuration, -1 shall be returned.
+     *
+     * Returns the configuration index on success or -1 on error.
+     *
+     * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_4 and later.
+     * It shall be NULL for previous versions.
+     */
+    int (*getActiveConfig)(struct hwc_composer_device_1* dev, int disp);
+
+    /*
+     * (*setActiveConfig)() instructs the hardware composer to switch to the
+     * display configuration at the given index in the list of configuration
+     * handles returned by getDisplayConfigs.
+     *
+     * If this function returns without error, any subsequent calls to
+     * getActiveConfig shall return the index set by this function until one
+     * of the following occurs:
+     *   1) Another successful call of this function
+     *   2) The display is disconnected
+     *
+     * Returns 0 on success or a negative error code on error. If disp is a
+     * hotpluggable display type and no display is connected, or if index is
+     * outside of the range of hardware configurations returned by
+     * getDisplayConfigs, an error shall be returned.
+     *
+     * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_4 and later.
+     * It shall be NULL for previous versions.
+     */
+    int (*setActiveConfig)(struct hwc_composer_device_1* dev, int disp,
+            int index);
+
+    /*
      * Reserved for future use. Must be NULL.
      */
-    void* reserved_proc[4];
+    void* reserved_proc[2];
 
 } hwc_composer_device_1_t;
 
diff --git a/modules/audio/audio_hw.c b/modules/audio/audio_hw.c
index 2f44d95..ef070c1 100644
--- a/modules/audio/audio_hw.c
+++ b/modules/audio/audio_hw.c
@@ -327,7 +327,8 @@
                                   audio_io_handle_t handle,
                                   audio_devices_t devices,
                                   struct audio_config *config,
-                                  struct audio_stream_in **stream_in)
+                                  struct audio_stream_in **stream_in,
+                                  audio_input_flags_t flags __unused)
 {
     struct stub_audio_device *ladev = (struct stub_audio_device *)dev;
     struct stub_stream_in *in;
diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp
index c7e4305..9e824b1 100644
--- a/modules/audio_remote_submix/audio_hw.cpp
+++ b/modules/audio_remote_submix/audio_hw.cpp
@@ -1373,7 +1373,8 @@
                                   audio_io_handle_t handle,
                                   audio_devices_t devices,
                                   struct audio_config *config,
-                                  struct audio_stream_in **stream_in)
+                                  struct audio_stream_in **stream_in,
+                                  audio_input_flags_t flags __unused)
 {
     struct submix_audio_device *rsxadev = audio_hw_device_get_submix_audio_device(dev);
     struct submix_stream_in *in;
diff --git a/modules/consumerir/consumerir.c b/modules/consumerir/consumerir.c
index 83eba75..87039cc 100644
--- a/modules/consumerir/consumerir.c
+++ b/modules/consumerir/consumerir.c
@@ -32,8 +32,8 @@
     {.min = 56000, .max = 56000},
 };
 
-static int consumerir_transmit(struct consumerir_device *dev,
-   int carrier_freq, int pattern[], int pattern_len)
+static int consumerir_transmit(struct consumerir_device *dev __unused,
+   int carrier_freq, const int pattern[], int pattern_len)
 {
     int total_time = 0;
     long i;
@@ -48,12 +48,12 @@
     return 0;
 }
 
-static int consumerir_get_num_carrier_freqs(struct consumerir_device *dev)
+static int consumerir_get_num_carrier_freqs(struct consumerir_device *dev __unused)
 {
     return ARRAY_SIZE(consumerir_freqs);
 }
 
-static int consumerir_get_carrier_freqs(struct consumerir_device *dev,
+static int consumerir_get_carrier_freqs(struct consumerir_device *dev __unused,
     size_t len, consumerir_freq_range_t *ranges)
 {
     size_t to_copy = ARRAY_SIZE(consumerir_freqs);
diff --git a/modules/usbaudio/audio_hw.c b/modules/usbaudio/audio_hw.c
index 2085268..8fbd528 100644
--- a/modules/usbaudio/audio_hw.c
+++ b/modules/usbaudio/audio_hw.c
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "usb_audio_hw"
 /*#define LOG_NDEBUG 0*/
+/*#define LOG_PCM_PARAMS 0*/
 
 #include <errno.h>
 #include <inttypes.h>
@@ -36,6 +37,8 @@
 
 #include <tinyalsa/asoundlib.h>
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
 /* This is the default configuration to hand to The Framework on the initial
  * adev_open_output_stream(). Actual device attributes will be used on the subsequent
  * adev_open_output_stream() after the card and device number have been set in out_set_parameters()
@@ -69,18 +72,22 @@
     .stop_threshold = (IN_PERIOD_SIZE * IN_PERIOD_COUNT),
 };
 
+struct audio_device_profile {
+    int card;
+    int device;
+    int direction; /* PCM_OUT or PCM_IN */
+};
+
 struct audio_device {
     struct audio_hw_device hw_device;
 
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
 
     /* output */
-    int out_card;
-    int out_device;
+    struct audio_device_profile out_profile;
 
     /* input */
-    int in_card;
-    int in_device;
+    struct audio_device_profile in_profile;
 
     bool standby;
 };
@@ -93,6 +100,7 @@
     bool standby;
 
     struct audio_device *dev;           /* hardware information */
+    struct audio_device_profile * profile;
 
     void * conversion_buffer;           /* any conversions are put into here
                                          * they could come from here too if
@@ -116,6 +124,8 @@
 
     struct audio_device *dev;
 
+    struct audio_device_profile * profile;
+
     struct audio_config hal_pcm_config;
 
     /* this is the format the framework thinks it's using. We may need to convert from the actual
@@ -221,7 +231,7 @@
  *   in_buff_channels Specifies the number of channels in the input buffer.
  *   out_buff points to the buffer to receive converted PCM16 samples.
  *   out_buff_channels Specifies the number of channels in the output buffer.
- *   num_in_samples size of input buffer in SAMPLES
+ *   num_in_bytes size of input buffer in BYTES
  * returns
  *   the number of BYTES of output data.
  * NOTE
@@ -231,16 +241,18 @@
  * support 4-channel devices.
  * TODO Move this to a utilities module.
  */
-static size_t expand_channels_16(const short* in_buff, int in_buff_chans,
-                                 short* out_buff, int out_buff_chans,
-                                 size_t num_in_samples)
+static size_t expand_channels_16(const int16_t* in_buff, int in_buff_chans,
+                                 int16_t* out_buff, int out_buff_chans,
+                                 size_t num_in_bytes)
 {
     /*
      * Move from back to front so that the conversion can be done in-place
      * i.e. in_buff == out_buff
      * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
      */
-    int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans;
+    size_t num_in_samples = num_in_bytes / sizeof(int16_t);
+
+    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans;
 
     short* dst_ptr = out_buff + num_out_samples - 1;
     size_t src_index;
@@ -257,7 +269,7 @@
     }
 
     /* return number of *bytes* generated */
-    return num_out_samples * sizeof(short);
+    return num_out_samples * sizeof(int16_t);
 }
 
 /*
@@ -267,7 +279,7 @@
  *   in_buff_channels Specifies the number of channels in the input buffer.
  *   out_buff points to the buffer to receive converted PCM16 samples.
  *   out_buff_channels Specifies the number of channels in the output buffer.
- *   num_in_samples size of input buffer in SAMPLES
+ *   num_in_bytes size of input buffer in BYTES
  * returns
  *   the number of BYTES of output data.
  * NOTE
@@ -277,24 +289,26 @@
  * support 4-channel devices.
  * TODO Move this to a utilities module.
  */
-static size_t contract_channels_16(short* in_buff, int in_buff_chans,
-                                   short* out_buff, int out_buff_chans,
-                                   size_t num_in_samples)
+static size_t contract_channels_16(const int16_t* in_buff, size_t in_buff_chans,
+                                   int16_t* out_buff, size_t out_buff_chans,
+                                   size_t num_in_bytes)
 {
     /*
      * Move from front to back so that the conversion can be done in-place
      * i.e. in_buff == out_buff
      * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
      */
-    int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans;
+    size_t num_in_samples = num_in_bytes / sizeof(int16_t);
 
-    int num_skip_samples = in_buff_chans - out_buff_chans;
+    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans;
 
-    short* dst_ptr = out_buff;
-    short* src_ptr = in_buff;
+    size_t num_skip_samples = in_buff_chans - out_buff_chans;
+
+    int16_t* dst_ptr = out_buff;
+    const int16_t* src_ptr = in_buff;
     size_t src_index;
     for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) {
-        int dst_offset;
+        size_t dst_offset;
         for (dst_offset = 0; dst_offset < out_buff_chans; dst_offset++) {
             *dst_ptr++ = *src_ptr++;
         }
@@ -302,7 +316,169 @@
     }
 
     /* return number of *bytes* generated */
-    return num_out_samples * sizeof(short);
+    return num_out_samples * sizeof(int16_t);
+}
+
+/*
+ * Convert a buffer of N-channel, interleaved PCM32 samples to M-channel PCM32 channels
+ * (where N < M).
+ *   in_buff points to the buffer of PCM32 samples
+ *   in_buff_channels Specifies the number of channels in the input buffer.
+ *   out_buff points to the buffer to receive converted PCM32 samples.
+ *   out_buff_channels Specifies the number of channels in the output buffer.
+ *   num_in_bytes size of input buffer in BYTES
+ * returns
+ *   the number of BYTES of output data.
+ * NOTE
+ *   channels > N are filled with silence.
+ *   This conversion is safe to do in-place (in_buff == out_buff)
+ * We are doing this since we *always* present to The Framework as STEREO device, but need to
+ * support 4-channel devices.
+ * TODO Move this to a utilities module.
+ */
+static size_t expand_channels_32(const int32_t* in_buff, size_t in_buff_chans,
+                                 int32_t* out_buff, size_t out_buff_chans,
+                                 size_t num_in_bytes)
+{
+    /*
+     * Move from back to front so that the conversion can be done in-place
+     * i.e. in_buff == out_buff
+     * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
+     */
+    size_t num_in_samples = num_in_bytes / sizeof(int32_t);
+
+    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans;
+
+    int32_t* dst_ptr = out_buff + num_out_samples - 1;
+    const int32_t* src_ptr = in_buff + num_in_samples - 1;
+    size_t num_zero_chans = out_buff_chans - in_buff_chans;
+    size_t src_index;
+    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) {
+        size_t dst_offset;
+        for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) {
+            *dst_ptr-- = 0;
+        }
+        for (; dst_offset < out_buff_chans; dst_offset++) {
+            *dst_ptr-- = *src_ptr--;
+        }
+    }
+
+    /* return number of *bytes* generated */
+    return num_out_samples * sizeof(int32_t);
+}
+
+/*
+ * Convert a buffer of N-channel, interleaved PCM32 samples to M-channel PCM16 channels
+ * (where N > M).
+ *   in_buff points to the buffer of PCM32 samples
+ *   in_buff_channels Specifies the number of channels in the input buffer.
+ *   out_buff points to the buffer to receive converted PCM16 samples.
+ *   out_buff_channels Specifies the number of channels in the output buffer.
+ *   num_in_bytes size of input buffer in BYTES
+ * returns
+ *   the number of BYTES of output data.
+ * NOTE
+ *   channels > N are thrown away.
+ *   This conversion is safe to do in-place (in_buff == out_buff)
+ * We are doing this since we *always* present to The Framework as STEREO device, but need to
+ * support 4-channel devices.
+ * TODO Move this to a utilities module.
+ */
+static size_t contract_channels_32(const int32_t* in_buff, size_t in_buff_chans,
+                                   int32_t* out_buff, size_t out_buff_chans,
+                                   size_t num_in_bytes)
+{
+    /*
+     * Move from front to back so that the conversion can be done in-place
+     * i.e. in_buff == out_buff
+     * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
+     */
+    size_t num_in_samples = num_in_bytes / sizeof(int32_t);
+
+    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans;
+
+    size_t num_skip_samples = in_buff_chans - out_buff_chans;
+
+    int32_t* dst_ptr = out_buff;
+    const int32_t* src_ptr = in_buff;
+    size_t src_index;
+    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) {
+        size_t dst_offset;
+        for (dst_offset = 0; dst_offset < out_buff_chans; dst_offset++) {
+            *dst_ptr++ = *src_ptr++;
+        }
+        src_ptr += num_skip_samples;
+    }
+
+    /* return number of *bytes* generated */
+    return num_out_samples * sizeof(int32_t);
+}
+
+static size_t contract_channels(const void* in_buff, size_t in_buff_chans,
+                                void* out_buff, size_t out_buff_chans,
+                                unsigned sample_size_in_bytes, size_t num_in_bytes)
+{
+    switch (sample_size_in_bytes) {
+    case 2:
+        return contract_channels_16((const int16_t*)in_buff, in_buff_chans,
+                                    (int16_t*)out_buff, out_buff_chans,
+                                    num_in_bytes);
+
+    /* TODO - do this conversion when we have a device to test it with */
+    case 3:
+        ALOGE("24-bit channel contraction not supported.");
+        return 0;
+
+    case 4:
+        return contract_channels_32((const int32_t*)in_buff, in_buff_chans,
+                                    (int32_t*)out_buff, out_buff_chans,
+                                    num_in_bytes);
+
+    default:
+        return 0;
+    }
+}
+
+static size_t expand_channels(const void* in_buff, size_t in_buff_chans,
+                                void* out_buff, size_t out_buff_chans,
+                                unsigned sample_size_in_bytes, size_t num_in_bytes)
+{
+    switch (sample_size_in_bytes) {
+    case 2:
+        return expand_channels_16((const int16_t*)in_buff, in_buff_chans,
+                                  (int16_t*)out_buff, out_buff_chans,
+                                  num_in_bytes);
+
+    /* TODO - do this conversion when we have a device to test it with */
+    case 3:
+        ALOGE("24-bit channel expansion not supported.");
+        return 0;
+
+    case 4:
+        return expand_channels_32((const int32_t*)in_buff, in_buff_chans,
+                                  (int32_t*)out_buff, out_buff_chans,
+                                  num_in_bytes);
+
+    default:
+        return 0;
+    }
+}
+
+static size_t adjust_channels(const void* in_buff, size_t in_buff_chans,
+                              void* out_buff, size_t out_buff_chans,
+                              unsigned sample_size_in_bytes, size_t num_in_bytes)
+{
+    if (out_buff_chans > in_buff_chans) {
+        return expand_channels(in_buff, in_buff_chans, out_buff,  out_buff_chans,
+                               sample_size_in_bytes, num_in_bytes);
+    } else if (out_buff_chans < in_buff_chans) {
+        return contract_channels(in_buff, in_buff_chans, out_buff,  out_buff_chans,
+                                 sample_size_in_bytes, num_in_bytes);
+    } else if (in_buff != out_buff) {
+        memcpy(out_buff, in_buff, num_in_bytes);
+    }
+
+    return num_in_bytes;
 }
 
 /*
@@ -467,7 +643,7 @@
     return (mask->bits[0] & 0x0004) != 0;
 }
 
-static int get_format_for_mask(struct pcm_mask* mask)
+static audio_format_t get_format_for_mask(struct pcm_mask* mask)
 {
     int num_slots = sizeof(mask->bits)/ sizeof(mask->bits[0]);
     int bits_per_slot = sizeof(mask->bits[0]) * 8;
@@ -495,87 +671,140 @@
 }
 
 /*
- * Maps from bit position in pcm_mask to AUDIO_ format constants.
+ * Maps from bit position in pcm_mask to PCM_ format constants.
  */
-static int const pcm_format_value_map[] = {
+static int8_t const pcm_format_value_map[] = {
     PCM_FORMAT_S8,          /* 00 - SNDRV_PCM_FORMAT_S8 */
-    0,                      /* 01 - SNDRV_PCM_FORMAT_U8 */
+    PCM_FORMAT_INVALID,     /* 01 - SNDRV_PCM_FORMAT_U8 */
     PCM_FORMAT_S16_LE,      /* 02 - SNDRV_PCM_FORMAT_S16_LE */
-    0,                      /* 03 - SNDRV_PCM_FORMAT_S16_BE */
-    0,                      /* 04 - SNDRV_PCM_FORMAT_U16_LE */
-    0,                      /* 05 - SNDRV_PCM_FORMAT_U16_BE */
+    PCM_FORMAT_INVALID,     /* 03 - SNDRV_PCM_FORMAT_S16_BE */
+    PCM_FORMAT_INVALID,     /* 04 - SNDRV_PCM_FORMAT_U16_LE */
+    PCM_FORMAT_INVALID,     /* 05 - SNDRV_PCM_FORMAT_U16_BE */
     PCM_FORMAT_S24_3LE,     /* 06 - SNDRV_PCM_FORMAT_S24_LE */
-    0,                      /* 07 - SNDRV_PCM_FORMAT_S24_BE */
-    0,                      /* 08 - SNDRV_PCM_FORMAT_U24_LE */
-    0,                      /* 09 - SNDRV_PCM_FORMAT_U24_BE */
+    PCM_FORMAT_INVALID,     /* 07 - SNDRV_PCM_FORMAT_S24_BE */
+    PCM_FORMAT_INVALID,     /* 08 - SNDRV_PCM_FORMAT_U24_LE */
+    PCM_FORMAT_INVALID,     /* 09 - SNDRV_PCM_FORMAT_U24_BE */
     PCM_FORMAT_S32_LE,      /* 10 - SNDRV_PCM_FORMAT_S32_LE */
-    0,                      /* 11 - SNDRV_PCM_FORMAT_S32_BE */
-    0,                      /* 12 - SNDRV_PCM_FORMAT_U32_LE */
-    0,                      /* 13 - SNDRV_PCM_FORMAT_U32_BE */
-    0,                      /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */
-    0,                      /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */
-    0,                      /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */
-    0,                      /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */
-    0,                      /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */
-    0,                      /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */
-    0,                      /* 20 - SNDRV_PCM_FORMAT_MU_LAW */
-    0,                      /* 21 - SNDRV_PCM_FORMAT_A_LAW */
-    0,                      /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */
-    0,                      /* 23 - SNDRV_PCM_FORMAT_MPEG */
-    0,                      /* 24 - SNDRV_PCM_FORMAT_GSM */
-    0,                      /* 25 -> 30 (not assigned) */
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,                      /* 31 - SNDRV_PCM_FORMAT_SPECIAL */
+    PCM_FORMAT_INVALID,     /* 11 - SNDRV_PCM_FORMAT_S32_BE */
+    PCM_FORMAT_INVALID,     /* 12 - SNDRV_PCM_FORMAT_U32_LE */
+    PCM_FORMAT_INVALID,     /* 13 - SNDRV_PCM_FORMAT_U32_BE */
+    PCM_FORMAT_INVALID,     /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */
+    PCM_FORMAT_INVALID,     /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */
+    PCM_FORMAT_INVALID,     /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */
+    PCM_FORMAT_INVALID,     /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */
+    PCM_FORMAT_INVALID,     /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */
+    PCM_FORMAT_INVALID,     /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */
+    PCM_FORMAT_INVALID,     /* 20 - SNDRV_PCM_FORMAT_MU_LAW */
+    PCM_FORMAT_INVALID,     /* 21 - SNDRV_PCM_FORMAT_A_LAW */
+    PCM_FORMAT_INVALID,     /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */
+    PCM_FORMAT_INVALID,     /* 23 - SNDRV_PCM_FORMAT_MPEG */
+    PCM_FORMAT_INVALID,     /* 24 - SNDRV_PCM_FORMAT_GSM */
+    PCM_FORMAT_INVALID,     /* 25 -> 30 (not assigned) */
+    PCM_FORMAT_INVALID,
+    PCM_FORMAT_INVALID,
+    PCM_FORMAT_INVALID,
+    PCM_FORMAT_INVALID,
+    PCM_FORMAT_INVALID,
+    PCM_FORMAT_INVALID,     /* 31 - SNDRV_PCM_FORMAT_SPECIAL */
     PCM_FORMAT_S24_3LE,     /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ /* ??? */
-    0,                      /* 33 - SNDRV_PCM_FORMAT_S24_3BE */
-    0,                      /* 34 - SNDRV_PCM_FORMAT_U24_3LE */
-    0,                      /* 35 - SNDRV_PCM_FORMAT_U24_3BE */
-    0,                      /* 36 - SNDRV_PCM_FORMAT_S20_3LE */
-    0,                      /* 37 - SNDRV_PCM_FORMAT_S20_3BE */
-    0,                      /* 38 - SNDRV_PCM_FORMAT_U20_3LE */
-    0,                      /* 39 - SNDRV_PCM_FORMAT_U20_3BE */
-    0,                      /* 40 - SNDRV_PCM_FORMAT_S18_3LE */
-    0,                      /* 41 - SNDRV_PCM_FORMAT_S18_3BE */
-    0,                      /* 42 - SNDRV_PCM_FORMAT_U18_3LE */
-    0,                      /* 43 - SNDRV_PCM_FORMAT_U18_3BE */
-    0,                      /* 44 - SNDRV_PCM_FORMAT_G723_24 */
-    0,                      /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */
-    0,                      /* 46 - SNDRV_PCM_FORMAT_G723_40 */
-    0,                      /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */
-    0,                      /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */
-    0                       /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */
+    PCM_FORMAT_INVALID,     /* 33 - SNDRV_PCM_FORMAT_S24_3BE */
+    PCM_FORMAT_INVALID,     /* 34 - SNDRV_PCM_FORMAT_U24_3LE */
+    PCM_FORMAT_INVALID,     /* 35 - SNDRV_PCM_FORMAT_U24_3BE */
+    PCM_FORMAT_INVALID,     /* 36 - SNDRV_PCM_FORMAT_S20_3LE */
+    PCM_FORMAT_INVALID,     /* 37 - SNDRV_PCM_FORMAT_S20_3BE */
+    PCM_FORMAT_INVALID,     /* 38 - SNDRV_PCM_FORMAT_U20_3LE */
+    PCM_FORMAT_INVALID,     /* 39 - SNDRV_PCM_FORMAT_U20_3BE */
+    PCM_FORMAT_INVALID,     /* 40 - SNDRV_PCM_FORMAT_S18_3LE */
+    PCM_FORMAT_INVALID,     /* 41 - SNDRV_PCM_FORMAT_S18_3BE */
+    PCM_FORMAT_INVALID,     /* 42 - SNDRV_PCM_FORMAT_U18_3LE */
+    PCM_FORMAT_INVALID,     /* 43 - SNDRV_PCM_FORMAT_U18_3BE */
+    PCM_FORMAT_INVALID,     /* 44 - SNDRV_PCM_FORMAT_G723_24 */
+    PCM_FORMAT_INVALID,     /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */
+    PCM_FORMAT_INVALID,     /* 46 - SNDRV_PCM_FORMAT_G723_40 */
+    PCM_FORMAT_INVALID,     /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */
+    PCM_FORMAT_INVALID,     /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */
+    PCM_FORMAT_INVALID      /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */
 };
 
+/*
+ * Scans the provided format mask and returns the first non-8 bit sample
+ * format supported by the devices.
+ */
 static int get_pcm_format_for_mask(struct pcm_mask* mask) {
     int num_slots = sizeof(mask->bits)/ sizeof(mask->bits[0]);
     int bits_per_slot = sizeof(mask->bits[0]) * 8;
 
-    int table_size = sizeof(pcm_format_value_map) / sizeof(pcm_format_value_map[0]);
+    int table_size = ARRAY_SIZE(pcm_format_value_map);
 
     int slot_index, bit_index, table_index;
     table_index = 0;
     int num_written = 0;
-    for (slot_index = 0; slot_index < num_slots; slot_index++) {
+    for (slot_index = 0; slot_index < num_slots && table_index < table_size; slot_index++) {
         unsigned bit_mask = 1;
-        for (bit_index = 0; bit_index < bits_per_slot; bit_index++) {
+        for (bit_index = 0; bit_index < bits_per_slot  && table_index < table_size; bit_index++) {
             if ((mask->bits[slot_index] & bit_mask) != 0) {
-                /* just return the first one */
-                return table_index < table_size
-                           ? pcm_format_value_map[table_index]
-                           : AUDIO_FORMAT_INVALID;
+                /* TODO - we don't want a low-level function to be making this decision */
+                if (table_index != 0) { /* Don't pick 8-bit */
+                    /* just return the first one */
+                    return (int)pcm_format_value_map[table_index];
+                }
             }
             bit_mask <<= 1;
             table_index++;
         }
     }
 
-    return 0; // is this right?
+    return PCM_FORMAT_INVALID;
 }
 
+static bool test_out_sample_rate(struct audio_device_profile* dev_profile, unsigned rate) {
+    struct pcm_config local_config = cached_output_hardware_config;
+    local_config.rate = rate;
+
+    bool works = false; /* let's be pessimistic */
+    struct pcm * pcm =
+        pcm_open(dev_profile->card, dev_profile->device, dev_profile->direction, &local_config);
+
+    if (pcm != NULL) {
+        works = pcm_is_ready(pcm);
+        pcm_close(pcm);
+    }
+
+    return works;
+}
+
+/* sort these highest -> lowest */
+static const unsigned std_sample_rates[] =
+    {48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000};
+
+static char* enum_std_sample_rates(struct audio_device_profile* dev_profile,
+                                   unsigned min, unsigned max)
+{
+    char buffer[128];
+    buffer[0] = '\0';
+    int buffSize = ARRAY_SIZE(buffer);
+
+    char numBuffer[32];
+
+    int numEntries = 0;
+    unsigned index;
+    for(index = 0; index < ARRAY_SIZE(std_sample_rates); index++) {
+        if (std_sample_rates[index] >= min && std_sample_rates[index] <= max &&
+            test_out_sample_rate(dev_profile, std_sample_rates[index])) {
+            if (numEntries++ != 0) {
+                strncat(buffer, "|", buffSize);
+            }
+            snprintf(numBuffer, sizeof(numBuffer), "%u", std_sample_rates[index]);
+            strncat(buffer, numBuffer, buffSize);
+        }
+    }
+
+    return strdup(buffer);
+}
+
+/*
+ * Logging
+ */
 static void log_pcm_mask(const char* mask_name, struct pcm_mask* mask) {
     char buff[512];
     char bit_buff[32];
@@ -665,23 +894,30 @@
 /*
  * Reads and decodes configuration info from the specified ALSA card/device
  */
-static int read_alsa_device_config(int card, int device, int io_type, struct pcm_config * config)
+static int read_alsa_device_config(struct audio_device_profile * dev_profile,
+                                   struct pcm_config * config)
 {
-    ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",card, device, io_type);
+    ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",
+          dev_profile->card, dev_profile->device, dev_profile->direction);
 
-    if (card < 0 || device < 0) {
+    if (dev_profile->card < 0 || dev_profile->device < 0) {
         return -EINVAL;
     }
 
-    struct pcm_params * alsa_hw_params = pcm_params_get(card, device, io_type);
+    struct pcm_params * alsa_hw_params =
+        pcm_params_get(dev_profile->card, dev_profile->device, dev_profile->direction);
     if (alsa_hw_params == NULL) {
         return -EINVAL;
     }
 
+    int ret = 0;
+
     /*
      * This Logging will be useful when testing new USB devices.
      */
-    /* log_pcm_params(alsa_hw_params); */
+#ifdef LOG_PCM_PARAMS
+    log_pcm_params(alsa_hw_params);
+#endif
 
     config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
     config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
@@ -695,8 +931,15 @@
     }
     config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS);
 
-    config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
-    return 0;
+    int format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
+    if (format == PCM_FORMAT_INVALID) {
+        ret = -EINVAL;
+    } else {
+        config->format = format;
+    }
+
+    pcm_params_free(alsa_hw_params);
+    return ret;
 }
 
 /*
@@ -772,7 +1015,6 @@
     ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
 
     struct stream_out *out = (struct stream_out *)stream;
-    struct audio_device *adev = out->dev;
     struct str_parms *parms;
     char value[32];
     int param_val;
@@ -780,45 +1022,41 @@
     int ret_value = 0;
 
     parms = str_parms_create_str(kvpairs);
-    pthread_mutex_lock(&adev->lock);
+    pthread_mutex_lock(&out->dev->lock);
+    pthread_mutex_lock(&out->lock);
 
     bool recache_device_params = false;
     param_val = str_parms_get_str(parms, "card", value, sizeof(value));
     if (param_val >= 0) {
-        adev->out_card = atoi(value);
+        out->profile->card = atoi(value);
         recache_device_params = true;
     }
 
     param_val = str_parms_get_str(parms, "device", value, sizeof(value));
     if (param_val >= 0) {
-        adev->out_device = atoi(value);
+        out->profile->device = atoi(value);
         recache_device_params = true;
     }
 
-    if (recache_device_params && adev->out_card >= 0 && adev->out_device >= 0) {
-        ret_value = read_alsa_device_config(adev->out_card, adev->out_device, PCM_OUT,
-                                            &cached_output_hardware_config);
+    if (recache_device_params && out->profile->card >= 0 && out->profile->device >= 0) {
+        ret_value = read_alsa_device_config(out->profile, &cached_output_hardware_config);
         output_hardware_config_is_cached = (ret_value == 0);
     }
 
-    pthread_mutex_unlock(&adev->lock);
+    pthread_mutex_unlock(&out->lock);
+    pthread_mutex_unlock(&out->dev->lock);
     str_parms_destroy(parms);
 
     return ret_value;
 }
 
-/*TODO it seems like both out_get_parameters() and in_get_parameters()
-  could be written in terms of a get_device_parameters(io_type) */
-
-static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+static char * device_get_parameters(struct audio_device_profile * dev_profile, const char *keys)
 {
-    ALOGV("usb:audio_hw::out out_get_parameters() keys:%s", keys);
+    ALOGV("usb:audio_hw::device_get_parameters() keys:%s", keys);
 
-    struct stream_out *out = (struct stream_out *) stream;
-    struct audio_device *adev = out->dev;
-
-    if (adev->out_card < 0 || adev->out_device < 0)
+    if (dev_profile->card < 0 || dev_profile->device < 0) {
         return strdup("");
+    }
 
     unsigned min, max;
 
@@ -830,58 +1068,74 @@
     int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
     char* result_str = NULL;
 
-    struct pcm_params * alsa_hw_params = pcm_params_get(adev->out_card, adev->out_device, PCM_OUT);
+    struct pcm_params * alsa_hw_params =
+        pcm_params_get(dev_profile->card, dev_profile->device, dev_profile->direction);
 
     // These keys are from hardware/libhardware/include/audio.h
     // supported sample rates
     if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
-        // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
-        // if they are different, return a list containing those two values, otherwise just the one.
         min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
         max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
-        num_written = snprintf(buffer, buffer_size, "%u", min);
-        if (min != max) {
-            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
-        }
-        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
-                          buffer);
+
+        char* rates_list = enum_std_sample_rates(dev_profile, min, max);
+        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, rates_list);
+        free(rates_list);
     }  // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
 
     // supported channel counts
     if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
-        // Similarly for output channels count
-        /* TODO - This is wrong, we need format strings, not numbers (another CL) */
-        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
-        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
-        num_written = snprintf(buffer, buffer_size, "%u", min);
-        if (min != max) {
-            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
-        }
-        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, buffer);
+        // TODO remove this hack when it is superceeded by proper multi-channel support
+        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
+                          dev_profile->direction == PCM_OUT
+                                          ? "AUDIO_CHANNEL_OUT_STEREO"
+                                          : "AUDIO_CHANNEL_IN_STEREO");
     }  // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
 
     // supported sample formats
     if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
-        char * format_params =
-            get_format_str_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
-        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_params);
-        free(format_params);
+        // TODO remove this hack when we have support for input in non PCM16 formats
+        if (dev_profile->direction == PCM_IN) {
+            str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, "AUDIO_FORMAT_PCM_16_BIT");
+        } else {
+            struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT);
+            char * format_params = get_format_str_for_mask(format_mask);
+            str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_params);
+            free(format_params);
+        }
     }  // AUDIO_PARAMETER_STREAM_SUP_FORMATS
 
+    pcm_params_free(alsa_hw_params);
+
     result_str = str_parms_to_str(result);
 
     // done with these...
     str_parms_destroy(query);
     str_parms_destroy(result);
 
-    ALOGV("usb:audio_hw::out out_get_parameters() = %s", result_str);
+    ALOGV("usb:audio_hw::device_get_parameters = %s", result_str);
 
     return result_str;
 }
 
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    ALOGV("usb:audio_hw::out out_get_parameters() keys:%s", keys);
+
+    struct stream_out *out = (struct stream_out *) stream;
+    pthread_mutex_lock(&out->dev->lock);
+    pthread_mutex_lock(&out->lock);
+
+    char * params_str =  device_get_parameters(out->profile, keys);
+
+    pthread_mutex_unlock(&out->lock);
+    pthread_mutex_unlock(&out->dev->lock);
+
+    return params_str;
+}
+
 static uint32_t out_get_latency(const struct audio_stream_out *stream)
 {
-    struct stream_out *out = (struct stream_out *) stream;
+    // struct stream_out *out = (struct stream_out *) stream;
 
     /*TODO Do we need a term here for the USB latency (as reported in the USB descriptors)? */
     uint32_t latency = (cached_output_hardware_config.period_size
@@ -898,13 +1152,13 @@
 /* must be called with hw device and output stream mutexes locked */
 static int start_output_stream(struct stream_out *out)
 {
-    struct audio_device *adev = out->dev;
     int return_val = 0;
 
     ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
-          adev->out_card, adev->out_device);
+          out->profile->card, out->profile->device);
 
-    out->pcm = pcm_open(adev->out_card, adev->out_device, PCM_OUT, &cached_output_hardware_config);
+    out->pcm = pcm_open(out->profile->card, out->profile->device, PCM_OUT,
+                        &cached_output_hardware_config);
 
     if (out->pcm == NULL) {
         return -ENOMEM;
@@ -955,10 +1209,12 @@
     int num_device_channels = cached_output_hardware_config.channels;
     int num_req_channels = 2; /* always, for now */
     if (num_device_channels != num_req_channels) {
+        audio_format_t audio_format = out_get_format(&(out->stream.common));
+        unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
         num_write_buff_bytes =
-                expand_channels_16(write_buff, num_req_channels,
-                                   out->conversion_buffer, num_device_channels,
-                                   num_write_buff_bytes / sizeof(short));
+             adjust_channels(write_buff, num_req_channels,
+                             out->conversion_buffer, num_device_channels,
+                             sample_size_in_bytes, num_write_buff_bytes);
         write_buff = out->conversion_buffer;
     }
 
@@ -1041,6 +1297,9 @@
 
     out->dev = adev;
 
+    out->profile = &(adev->out_profile);
+    out->profile->direction = PCM_OUT;
+
     if (output_hardware_config_is_cached) {
         config->sample_rate = cached_output_hardware_config.rate;
 
@@ -1207,7 +1466,6 @@
     ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs);
 
     struct stream_in *in = (struct stream_in *)stream;
-    struct audio_device *adev = in->dev;
     struct str_parms *parms;
     char value[32];
     int param_val;
@@ -1215,112 +1473,49 @@
     int ret_value = 0;
 
     parms = str_parms_create_str(kvpairs);
-    pthread_mutex_lock(&adev->lock);
+    pthread_mutex_lock(&in->dev->lock);
+    pthread_mutex_lock(&in->lock);
 
     bool recache_device_params = false;
 
     // Card/Device
     param_val = str_parms_get_str(parms, "card", value, sizeof(value));
     if (param_val >= 0) {
-        adev->in_card = atoi(value);
+        in->profile->card = atoi(value);
         recache_device_params = true;
     }
 
     param_val = str_parms_get_str(parms, "device", value, sizeof(value));
     if (param_val >= 0) {
-        adev->in_device = atoi(value);
+        in->profile->device = atoi(value);
         recache_device_params = true;
     }
 
-    if (recache_device_params && adev->in_card >= 0 && adev->in_device >= 0) {
-        ret_value = read_alsa_device_config(adev->in_card, adev->in_device,
-                                            PCM_IN, &(cached_input_hardware_config));
+    if (recache_device_params && in->profile->card >= 0 && in->profile->device >= 0) {
+        ret_value = read_alsa_device_config(in->profile, &cached_input_hardware_config);
         input_hardware_config_is_cached = (ret_value == 0);
     }
 
-    pthread_mutex_unlock(&adev->lock);
+    pthread_mutex_unlock(&in->lock);
+    pthread_mutex_unlock(&in->dev->lock);
     str_parms_destroy(parms);
 
     return ret_value;
 }
 
-/*TODO it seems like both out_get_parameters() and in_get_parameters()
-   could be written in terms of a get_device_parameters(io_type) */
-
 static char * in_get_parameters(const struct audio_stream *stream, const char *keys) {
     ALOGV("usb:audio_hw::in in_get_parameters() keys:%s", keys);
 
     struct stream_in *in = (struct stream_in *)stream;
-    struct audio_device *adev = in->dev;
+    pthread_mutex_lock(&in->dev->lock);
+    pthread_mutex_lock(&in->lock);
 
-    if (adev->in_card < 0 || adev->in_device < 0)
-        return strdup("");
+    char * params_str  = device_get_parameters(in->profile, keys);
 
-    struct pcm_params * alsa_hw_params = pcm_params_get(adev->in_card, adev->in_device, PCM_IN);
-    if (alsa_hw_params == NULL)
-        return strdup("");
+    pthread_mutex_unlock(&in->lock);
+    pthread_mutex_unlock(&in->dev->lock);
 
-    struct str_parms *query = str_parms_create_str(keys);
-    struct str_parms *result = str_parms_create();
-
-    int num_written = 0;
-    char buffer[256];
-    int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
-    char* result_str = NULL;
-
-    unsigned min, max;
-
-    // These keys are from hardware/libhardware/include/audio.h
-    // supported sample rates
-    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
-        // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
-        // if they are different, return a list containing those two values, otherwise just the one.
-        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
-        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
-        num_written = snprintf(buffer, buffer_size, "%u", min);
-        if (min != max) {
-            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
-        }
-        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, buffer);
-    }  // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
-
-    // supported channel counts
-    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
-        // Similarly for output channels count
-        // TODO This is wrong, we need format strings, not numbers (another CL)
-        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
-        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
-        num_written = snprintf(buffer, buffer_size, "%u", min);
-        if (min != max) {
-            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
-        }
-        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_CHANNELS, buffer);
-    }  // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
-
-    // supported sample formats
-    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
-        struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT);
-        char * format_params = get_format_str_for_mask(format_mask);
-        if (!mask_has_pcm_16(format_mask)) {
-            /* For now, always support PCM_16 and convert locally if necessary */
-            char buff[256];
-            snprintf(buff, sizeof(buff), "AUDIO_FORMAT_PCM_16_BIT|%s", format_params);
-            free(format_params);
-            str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buff);
-        } else {
-            str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_params);
-        }
-    }  // AUDIO_PARAMETER_STREAM_SUP_FORMATS
-
-    result_str = str_parms_to_str(result);
-
-    // done with these...
-    str_parms_destroy(query);
-    str_parms_destroy(result);
-
-    ALOGV("usb:audio_hw::in in_get_parameters() = %s", result_str);
-
-    return result_str;
+    return params_str;
 }
 
 static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
@@ -1340,13 +1535,13 @@
 
 /* must be called with hw device and output stream mutexes locked */
 static int start_input_stream(struct stream_in *in) {
-    struct audio_device *adev = in->dev;
     int return_val = 0;
 
     ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)",
-          adev->in_card, adev->in_device);
+          in->profile->card, in->profile->device);
 
-    in->pcm = pcm_open(adev->in_card, adev->in_device, PCM_IN, &cached_input_hardware_config);
+    in->pcm = pcm_open(in->profile->card, in->profile->device, PCM_IN,
+                       &cached_input_hardware_config);
     if (in->pcm == NULL) {
         ALOGE("usb:audio_hw pcm_open() in->pcm == NULL");
         return -ENOMEM;
@@ -1436,16 +1631,14 @@
         if (num_device_channels != num_req_channels) {
             out_buff = buffer;
             /* Num Channels conversion */
-            if (num_device_channels < num_req_channels) {
+            if (num_device_channels != num_req_channels) {
+                audio_format_t audio_format = in_get_format(&(in->stream.common));
+                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
+
                 num_read_buff_bytes =
-                    expand_channels_16(read_buff, num_device_channels,
-                                       out_buff, num_req_channels,
-                                       num_read_buff_bytes / sizeof(short));
-            } else {
-                num_read_buff_bytes =
-                    contract_channels_16(read_buff, num_device_channels,
-                                         out_buff, num_req_channels,
-                                         num_read_buff_bytes / sizeof(short));
+                    adjust_channels(read_buff, num_device_channels,
+                                    out_buff, num_req_channels,
+                                    sample_size_in_bytes, num_read_buff_bytes);
             }
         }
     }
@@ -1466,7 +1659,8 @@
                                   audio_io_handle_t handle,
                                   audio_devices_t devices,
                                   struct audio_config *config,
-                                  struct audio_stream_in **stream_in)
+                                  struct audio_stream_in **stream_in,
+                                  audio_input_flags_t flags __unused)
 {
     ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
           config->sample_rate, config->channel_mask, config->format);
@@ -1499,6 +1693,9 @@
 
     in->dev = (struct audio_device *)dev;
 
+    in->profile = &(in->dev->in_profile);
+    in->profile->direction = PCM_IN;
+
     if (!input_hardware_config_is_cached) {
         // just return defaults until we can actually query the device.
         cached_input_hardware_config = default_alsa_in_config;
diff --git a/tests/hardware/struct-offset.cpp b/tests/hardware/struct-offset.cpp
index 8e5aa40..2354408 100644
--- a/tests/hardware/struct-offset.cpp
+++ b/tests/hardware/struct-offset.cpp
@@ -167,7 +167,9 @@
     CHECK_MEMBER_AT(hwc_composer_device_1_t, dump, 88, 168);
     CHECK_MEMBER_AT(hwc_composer_device_1_t, getDisplayConfigs, 92, 176);
     CHECK_MEMBER_AT(hwc_composer_device_1_t, getDisplayAttributes, 96, 184);
-    CHECK_MEMBER_AT(hwc_composer_device_1_t, reserved_proc, 100, 192);
+    CHECK_MEMBER_AT(hwc_composer_device_1_t, getActiveConfig, 100, 192);
+    CHECK_MEMBER_AT(hwc_composer_device_1_t, setActiveConfig, 104, 200);
+    CHECK_MEMBER_AT(hwc_composer_device_1_t, reserved_proc, 108, 208);
 
     //Types defined in gralloc.h
     CHECK_MEMBER_AT(gralloc_module_t, common, 0, 0);
diff --git a/tests/hwc/test-arrows.c b/tests/hwc/test-arrows.c
index a35faa7..12e7c8f 100644
--- a/tests/hwc/test-arrows.c
+++ b/tests/hwc/test-arrows.c
@@ -140,7 +140,7 @@
 int main(int argc, char **argv) {
 	EGLDisplay display;
 	EGLSurface surface;
-	int w, h, count;
+	int w, h, count = 0;
 
 	if (argc > 1)
 		count = atoi(argv[1]);