Added logic to switch zones at right speaker

Added aae.playZoneId to allow different zones to play at right speaker
when using the car emulator.

Bug: 134524865
Test: Ran kitchen sink emulator
Change-Id: Ie05718feff62e84d7bd3e40f250e5de0a7bf585c
diff --git a/emulator/audio/audio_policy_configuration.xml b/emulator/audio/audio_policy_configuration.xml
index 9b81599..0499a8a 100644
--- a/emulator/audio/audio_policy_configuration.xml
+++ b/emulator/audio/audio_policy_configuration.xml
@@ -59,7 +59,10 @@
                 <item>bus5_alarm_out</item>
                 <item>bus6_notification_out</item>
                 <item>bus7_system_sound_out</item>
-                <item>bus100_rear_seat</item>
+                <!-- names with _rear_seat_# are used for defined an emulator rear seat audio zone
+                    where each number # is the zone id number -->
+                <item>bus100_left_rear_seat_1</item>
+                <item>bus200_right_rear_seat_2</item>
                 <item>Built-In Mic</item>
                 <item>Built-In Back Mic</item>
                 <item>Echo-Reference Mic</item>
@@ -115,12 +118,18 @@
                              samplingRates="48000"
                              channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                 </mixPort>
-                <mixPort name="mixport_bus100_rear_seat" role="source"
+                <mixPort name="mixport_bus100_left_rear_seat_1" role="source"
                         flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="48000"
                              channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                 </mixPort>
+                <mixPort name="mixport_bus200_right_rear_seat_2" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
                 <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
@@ -205,8 +214,8 @@
                                 minValueMB="-3200" maxValueMB="600" defaultValueMB="0" stepValueMB="100"/>
                     </gains>
                 </devicePort>
-                <devicePort tagName="bus100_rear_seat" role="sink" type="AUDIO_DEVICE_OUT_BUS"
-                        address="bus100_rear_seat">
+                <devicePort tagName="bus100_left_rear_seat_1" role="sink" type="AUDIO_DEVICE_OUT_BUS"
+                        address="bus100_left_rear_seat_1">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                     <gains>
@@ -214,6 +223,15 @@
                                 minValueMB="-3200" maxValueMB="600" defaultValueMB="0" stepValueMB="100"/>
                     </gains>
                 </devicePort>
+                <devicePort tagName="bus200_right_rear_seat_2" role="sink" type="AUDIO_DEVICE_OUT_BUS"
+                            address="bus200_right_rear_seat_2">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                    <gains>
+                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
+                              minValueMB="-3200" maxValueMB="600" defaultValueMB="0" stepValueMB="100"/>
+                    </gains>
+                </devicePort>
                 <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
@@ -249,7 +267,8 @@
                 <route type="mix" sink="bus5_alarm_out" sources="mixport_bus5_alarm_out"/>
                 <route type="mix" sink="bus6_notification_out" sources="mixport_bus6_notification_out"/>
                 <route type="mix" sink="bus7_system_sound_out" sources="mixport_bus7_system_sound_out"/>
-                <route type="mix" sink="bus100_rear_seat" sources="mixport_bus100_rear_seat"/>
+                <route type="mix" sink="bus100_left_rear_seat_1" sources="mixport_bus100_left_rear_seat_1"/>
+                <route type="mix" sink="bus200_right_rear_seat_2" sources="mixport_bus200_right_rear_seat_2"/>
                 <route type="mix" sink="primary input" sources="Built-In Mic,Built-In Back Mic,Echo-Reference Mic"/>
                 <route type="mix" sink="mixport_tuner0" sources="FM Tuner"/>
             </routes>
diff --git a/emulator/audio/car_audio_configuration.xml b/emulator/audio/car_audio_configuration.xml
index 7d3cf01..a819e06 100644
--- a/emulator/audio/car_audio_configuration.xml
+++ b/emulator/audio/car_audio_configuration.xml
@@ -70,10 +70,10 @@
                 where port is the physical port of the display (See DisplayAddress.Phyisical)
             -->
         </zone>
-        <zone name="rear seat zone">
+        <zone name="rear seat zone 1">
             <volumeGroups>
                 <group>
-                    <device address="bus100_rear_seat">
+                    <device address="bus100_left_rear_seat_1">
                         <context context="music"/>
                         <context context="navigation"/>
                         <context context="voice_command"/>
@@ -89,5 +89,24 @@
                 <display port="1"/>
             </displays>
         </zone>
+        <zone name="rear seat zone 2">
+            <volumeGroups>
+                <group>
+                    <device address="bus200_right_rear_seat_2">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <displays>
+                <display port="2"/>
+            </displays>
+        </zone>
     </zones>
 </carAudioConfiguration>
diff --git a/emulator/audio/driver/audio_hw.c b/emulator/audio/driver/audio_hw.c
index 13cb72b..40ce21e 100644
--- a/emulator/audio/driver/audio_hw.c
+++ b/emulator/audio/driver/audio_hw.c
@@ -53,7 +53,20 @@
 
 #define _bool_str(x) ((x)?"true":"false")
 
-#define PROP_KEY_SIMULATE_MULTI_ZONE_AUDIO "ro.aae.simulateMultiZoneAudio"
+static const char * const PROP_KEY_SIMULATE_MULTI_ZONE_AUDIO = "ro.aae.simulateMultiZoneAudio";
+static const char * const AAE_PARAMETER_KEY_FOR_SELECTED_ZONE = "com.android.car.emulator.selected_zone";
+// Lapse time between checking audio id changes
+#define DEFAULT_PLAYZONE_ID_ELAPSE_TIME_MS 300.0f
+#define MILLISECONDS_TO_MICROSECONDS 1000.0f
+#define SECONDS_TO_MILLISECONDS 1000.0f
+#define PRIMARY_ZONE_ID 0
+#define INVALID_ZONE_ID -1
+// Note the primary zone goes to left speaker so route other zone to right speaker
+#define DEFAULT_ZONE_TO_LEFT_SPEAKER (PRIMARY_ZONE_ID + 1)
+
+static const char * const REAR_SEAT_KEYWORD = "_rear_seat_";
+
+#define SIZE_OF_PARSE_BUFFER 32
 
 static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state);
 
@@ -66,6 +79,22 @@
     .start_threshold = 0,
 };
 
+static int get_int_value(const struct str_parms *str_parms, const char *key, int *return_value) {
+    char value[SIZE_OF_PARSE_BUFFER];
+    int results = str_parms_get_str(str_parms, key, value, SIZE_OF_PARSE_BUFFER);
+    if (results >= 0) {
+        char *end = NULL;
+        errno = 0;
+        long val = strtol(value, &end, 10);
+        if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int) val == val)) {
+            *return_value = val;
+        } else {
+            results = -EINVAL;
+        }
+    }
+    return results;
+}
+
 static struct pcm_config pcm_config_in = {
     .channels = 2,
     .rate = 0,
@@ -76,9 +105,26 @@
     .stop_threshold = INT_MAX,
 };
 
+float time_difference_msec(struct timeval t0, struct timeval t1) {
+    return (t1.tv_sec - t0.tv_sec) * SECONDS_TO_MILLISECONDS +
+        (t1.tv_usec - t0.tv_usec) / MILLISECONDS_TO_MICROSECONDS;
+}
+
 static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
 static unsigned int audio_device_ref_count = 0;
 
+static bool is_zone_selected_to_play(struct audio_hw_device *dev, int zone_id) {
+    // play if current zone is enable or zone equal to primary zone
+    bool is_selected_zone = true;
+    if (zone_id != PRIMARY_ZONE_ID) {
+        struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+        pthread_mutex_lock(&adev->lock);
+        is_selected_zone = adev->last_zone_selected_to_play == zone_id;
+        pthread_mutex_unlock(&adev->lock);
+    }
+    return is_selected_zone;
+}
+
 static uint32_t out_get_sample_rate(const struct audio_stream *stream) {
     struct generic_stream_out *out = (struct generic_stream_out *)stream;
     return out->req_config.sample_rate;
@@ -139,10 +185,7 @@
 static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) {
     struct generic_stream_out *out = (struct generic_stream_out *)stream;
     struct str_parms *parms;
-    char value[32];
-    int ret;
-    long val;
-    char *end;
+    int ret = 0;
 
     pthread_mutex_lock(&out->lock);
     if (!out->standby) {
@@ -150,17 +193,11 @@
         ret = -ENOSYS;
     } else {
         parms = str_parms_create_str(kvpairs);
-        ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
-                                value, sizeof(value));
+        int val = 0;
+        ret = get_int_value(parms, AUDIO_PARAMETER_STREAM_ROUTING, &val);
         if (ret >= 0) {
-            errno = 0;
-            val = strtol(value, &end, 10);
-            if (errno == 0 && (end != NULL) && (*end == '\0') && ((int)val == val)) {
-                out->device = (int)val;
-                ret = 0;
-            } else {
-                ret = -EINVAL;
-            }
+            out->device = (int)val;
+            ret = 0;
         }
         str_parms_destroy(parms);
     }
@@ -201,6 +238,19 @@
     return -ENOSYS;
 }
 
+static int get_rear_zone_id_from_name(const char *name) {
+    int zone_id = INVALID_ZONE_ID;
+    char *rear_start = strstr(name, REAR_SEAT_KEYWORD);
+    if (rear_start) {
+        char *end = NULL;
+        zone_id = strtol(rear_start + strlen(REAR_SEAT_KEYWORD), &end, 10);
+        if (end == NULL || zone_id < 0) {
+            return INVALID_ZONE_ID;
+        }
+    }
+    return zone_id;
+}
+
 static void *out_write_worker(void *args) {
     struct generic_stream_out *out = (struct generic_stream_out *)args;
     struct ext_pcm *ext_pcm = NULL;
@@ -209,6 +259,18 @@
     int buffer_size;
     bool restart = false;
     bool shutdown = false;
+    int zone_id = PRIMARY_ZONE_ID;
+    // If it is a rear seat bus address then get zone id
+    if (strstr(out->bus_address, REAR_SEAT_KEYWORD)) {
+        zone_id = get_rear_zone_id_from_name(out->bus_address);
+        if (zone_id == INVALID_ZONE_ID) {
+            ALOGE("%s Found invalid zone id, defaulting device %s to zone %d", __func__,
+                out->bus_address, DEFAULT_ZONE_TO_LEFT_SPEAKER);
+            zone_id = DEFAULT_ZONE_TO_LEFT_SPEAKER;
+        }
+    }
+    ALOGD("Out worker:%s zone id %d", out->bus_address, zone_id);
+
     while (true) {
         pthread_mutex_lock(&out->lock);
         while (out->worker_standby || restart) {
@@ -265,13 +327,17 @@
         }
         int frames = audio_vbuffer_read(&out->buffer, buffer, buffer_frames);
         pthread_mutex_unlock(&out->lock);
-        int write_error = ext_pcm_write(ext_pcm, out->bus_address,
+
+        if (is_zone_selected_to_play(out->dev, zone_id)) {
+            int write_error = ext_pcm_write(ext_pcm, out->bus_address,
                 buffer, ext_pcm_frames_to_bytes(ext_pcm, frames));
-        if (write_error) {
-            ALOGE("pcm_write failed %s address %s", ext_pcm_get_error(ext_pcm), out->bus_address);
-            restart = true;
-        } else {
-            ALOGV("pcm_write succeed address %s", out->bus_address);
+            if (write_error) {
+                ALOGE("pcm_write failed %s address %s",
+                    ext_pcm_get_error(ext_pcm), out->bus_address);
+                restart = true;
+            } else {
+                ALOGV("pcm_write succeed address %s", out->bus_address);
+            }
         }
     }
     if (buffer) {
@@ -402,8 +468,8 @@
     }
 
     if (frames_written < frames) {
-        ALOGW("Hardware backing HAL too slow, could only write %zu of %zu frames",
-                frames_written, frames);
+        ALOGW("%s Hardware backing HAL too slow, could only write %zu of %zu frames",
+            __func__, frames_written, frames);
     }
 
     /* Always consume all bytes */
@@ -641,28 +707,18 @@
 static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) {
     struct generic_stream_in *in = (struct generic_stream_in *)stream;
     struct str_parms *parms;
-    char value[32];
-    int ret;
-    long val;
-    char *end;
+    int ret = 0;
 
     pthread_mutex_lock(&in->lock);
     if (!in->standby) {
         ret = -ENOSYS;
     } else {
         parms = str_parms_create_str(kvpairs);
-
-        ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
-                                value, sizeof(value));
+        int val = 0;
+        ret = get_int_value(parms, AUDIO_PARAMETER_STREAM_ROUTING, &val);
         if (ret >= 0) {
-            errno = 0;
-            val = strtol(value, &end, 10);
-            if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) {
-                in->device = (int)val;
-                ret = 0;
-            } else {
-                ret = -EINVAL;
-            }
+            in->device = (int)val;
+            ret = 0;
         }
 
         str_parms_destroy(parms);
@@ -1034,10 +1090,12 @@
         if (property_get_bool(PROP_KEY_SIMULATE_MULTI_ZONE_AUDIO, false)) {
             out->enabled_channels = strstr(out->bus_address, "rear")
                 ? RIGHT_CHANNEL: LEFT_CHANNEL;
+            ALOGD("%s Routing %s to %s channel", __func__,
+             out->bus_address, out->enabled_channels == RIGHT_CHANNEL ? "Right" : "Left");
         }
     }
     *stream_out = &out->stream;
-    ALOGD("%s bus:%s", __func__, out->bus_address);
+    ALOGD("%s bus: %s", __func__, out->bus_address);
 
 error:
     return ret;
@@ -1067,7 +1125,19 @@
 }
 
 static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) {
-    return 0;
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+    pthread_mutex_lock(&adev->lock);
+    struct str_parms *parms = str_parms_create_str(kvpairs);
+    int value = 0;
+    int results = get_int_value(parms, AAE_PARAMETER_KEY_FOR_SELECTED_ZONE, &value);
+    if (results >= 0) {
+        adev->last_zone_selected_to_play = value;
+        results = 0;
+        ALOGD("%s Changed play zone id to %d", __func__, adev->last_zone_selected_to_play);
+    }
+    str_parms_destroy(parms);
+    pthread_mutex_unlock(&adev->lock);
+    return results;
 }
 
 static char *adev_get_parameters(const struct audio_hw_device *dev, const char *keys) {
@@ -1404,6 +1474,8 @@
     *device = &adev->device.common;
 
     adev->mixer = mixer_open(PCM_CARD);
+
+    ALOGD("%s Mixer name %s", __func__, mixer_get_name(adev->mixer));
     struct mixer_ctl *ctl;
 
     // Set default mixer ctls
@@ -1432,6 +1504,8 @@
     // Initialize the bus address to output stream map
     adev->out_bus_stream_map = hashmapCreate(5, str_hash_fn, str_eq);
 
+    adev->last_zone_selected_to_play = DEFAULT_ZONE_TO_LEFT_SPEAKER;
+
     audio_device_ref_count++;
 
 unlock:
diff --git a/emulator/audio/driver/audio_hw.h b/emulator/audio/driver/audio_hw.h
index 903a9b8..6b6148a 100644
--- a/emulator/audio/driver/audio_hw.h
+++ b/emulator/audio/driver/audio_hw.h
@@ -33,6 +33,8 @@
   bool mic_mute;                // Protected by this->lock
   struct mixer *mixer;          // Protected by this->lock
   Hashmap *out_bus_stream_map;  // Extended field. Constant after init
+  // Play on Speaker zone selection
+  int last_zone_selected_to_play; // Protected by this->lock
 };
 
 enum output_channel_enable {
diff --git a/emulator/audio/overlay/packages/services/Car/tests/EmbeddedKitchenSinkApp/res/values/display_to_audio_device_configs.xml b/emulator/audio/overlay/packages/services/Car/tests/EmbeddedKitchenSinkApp/res/values/display_to_audio_device_configs.xml
new file mode 100644
index 0000000..7f2496d
--- /dev/null
+++ b/emulator/audio/overlay/packages/services/Car/tests/EmbeddedKitchenSinkApp/res/values/display_to_audio_device_configs.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds.  Do not translate. -->
+<resources>
+    <string-array name="config_displayToAudioDeviceConfig">
+        <!-- Add display to audio device pair as such
+            <item>"0,bus0_media_out"</item>
+        -->
+        <item>"0,bus0_media_out"</item>
+        <item>"1,bus100_left_rear_seat_1"</item>
+        <item>"2,bus200_right_rear_seat_2"</item>
+    </string-array>
+</resources>
\ No newline at end of file