audio: hal: support line out for transcode loopback

HW loopback extension and test app update
to support line out for transcode loopback.

CRs-Fixed: 2077703
Change-Id: I415830e3faefd7873c80075de8bf745780e7d0fb
diff --git a/hal/audio_extn/hw_loopback.c b/hal/audio_extn/hw_loopback.c
index 5b67284..6da9313 100644
--- a/hal/audio_extn/hw_loopback.c
+++ b/hal/audio_extn/hw_loopback.c
@@ -143,11 +143,21 @@
     return patch_init_rc;
 }
 
+bool is_supported_sink_device(audio_devices_t sink_device_mask)
+{
+    if((sink_device_mask & AUDIO_DEVICE_OUT_SPEAKER) ||
+       (sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+       (sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+           return true;
+       }
+    return false;
+}
+
 /* Get patch type based on source and sink ports configuration */
 /* Only ports of type 'DEVICE' are supported */
 patch_handle_type_t get_loopback_patch_type(loopback_patch_t*  loopback_patch)
 {
-    bool is_source_hdmi=false, is_sink_spkr=false;
+    bool is_source_hdmi=false, is_sink_supported=false;
     if (loopback_patch->patch_handle_id != PATCH_HANDLE_INVALID) {
         ALOGE("%s, Patch handle already exists", __func__);
         return loopback_patch->patch_handle_id;
@@ -178,30 +188,31 @@
     }
     if (loopback_patch->loopback_sink.role == AUDIO_PORT_ROLE_SINK) {
         switch (loopback_patch->loopback_sink.type) {
-            case AUDIO_PORT_TYPE_DEVICE :
-                if ((loopback_patch->loopback_sink.config_mask &
-                    AUDIO_PORT_CONFIG_FORMAT) &&
-                    (loopback_patch->loopback_sink.ext.device.type &
-                     AUDIO_DEVICE_OUT_SPEAKER)) {
-                       switch (loopback_patch->loopback_sink.format) {
-                           case AUDIO_FORMAT_PCM:
-                           case AUDIO_FORMAT_PCM_16_BIT:
-                           case AUDIO_FORMAT_PCM_32_BIT:
-                           case AUDIO_FORMAT_PCM_8_24_BIT:
-                           case AUDIO_FORMAT_PCM_24_BIT_PACKED:
-                              is_sink_spkr = true;
-			      break;
-                           default:
-                              break;
+        case AUDIO_PORT_TYPE_DEVICE :
+            if ((loopback_patch->loopback_sink.config_mask &
+                AUDIO_PORT_CONFIG_FORMAT) &&
+                (is_supported_sink_device(loopback_patch->loopback_sink.ext.device.type))) {
+                    switch (loopback_patch->loopback_sink.format) {
+                    case AUDIO_FORMAT_PCM:
+                    case AUDIO_FORMAT_PCM_16_BIT:
+                    case AUDIO_FORMAT_PCM_32_BIT:
+                    case AUDIO_FORMAT_PCM_8_24_BIT:
+                    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+                        is_sink_supported = true;
+                        break;
+                    default:
+                        break;
                     }
-                }
-                break;
-            default :
-                break;
-                //Unsupported as of now, need to extend for other sink types
+            } else {
+                ALOGE("%s, Unsupported sink port device %d", __func__,loopback_patch->loopback_sink.ext.device.type);
+            }
+            break;
+        default :
+            break;
+            //Unsupported as of now, need to extend for other sink types
         }
     }
-    if (is_source_hdmi && is_sink_spkr) {
+    if (is_source_hdmi && is_sink_supported) {
         return AUDIO_PATCH_HDMI_IN_SPKR_OUT;
     }
     ALOGE("%s, Unsupported source or sink port config", __func__);
@@ -403,6 +414,7 @@
         active_loopback_patch->source_stream)) {
         ALOGE("%s: %s", __func__, compress_get_error(active_loopback_patch->
         source_stream));
+        active_loopback_patch->source_stream = NULL;
         ret = -EIO;
         goto exit;
     } else if (active_loopback_patch->source_stream == NULL) {
@@ -429,6 +441,7 @@
         active_loopback_patch->sink_stream)) {
         ALOGE("%s: %s", __func__, compress_get_error(active_loopback_patch->
                 sink_stream));
+        active_loopback_patch->sink_stream = NULL;
         ret = -EIO;
         goto exit;
     } else if (active_loopback_patch->sink_stream == NULL) {
@@ -525,6 +538,8 @@
                                 audio_loopback_mod->patch_db.num_patches]);
     active_loopback_patch->patch_handle_id = PATCH_HANDLE_INVALID;
     active_loopback_patch->patch_state = PATCH_INACTIVE;
+    active_loopback_patch->patch_stream.ip_hdlr_handle = NULL;
+    active_loopback_patch->patch_stream.adsp_hdlr_stream_handle = NULL;
     memcpy(&active_loopback_patch->loopback_source, &sources[0], sizeof(struct
     audio_port_config));
     memcpy(&active_loopback_patch->loopback_sink, &sinks[0], sizeof(struct
diff --git a/qahw_api/test/trans_loopback_test.c b/qahw_api/test/trans_loopback_test.c
index 0fc2f08..a0673de 100644
--- a/qahw_api/test/trans_loopback_test.c
+++ b/qahw_api/test/trans_loopback_test.c
@@ -31,6 +31,7 @@
 /*#define LOG_NDEBUG 0*/
 #include <fcntl.h>
 #include <linux/netlink.h>
+#include <getopt.h>
 #include <pthread.h>
 #include <poll.h>
 #include <stdlib.h>
@@ -91,10 +92,16 @@
 #define TRANSCODE_LOOPBACK_SOURCE_PORT_ID 0x4C00
 #define TRANSCODE_LOOPBACK_SINK_PORT_ID 0x4D00
 
+#define DEVICE_SOURCE 0
+#define DEVICE_SINK 1
+
 #define MAX_MODULE_NAME_LENGTH  100
 
 #define DEV_NODE_CHECK(node_name,node_id) strncmp(node_name,node_id,strlen(node_name))
 
+/* Function declarations */
+void usage();
+
 typedef enum source_port_type {
     SOURCE_PORT_NONE,
     SOURCE_PORT_HDMI,
@@ -502,30 +509,86 @@
     pthread_exit(0);
 }
 
+bool is_device_supported(uint32_t device_id)
+{
+    switch(device_id)
+    {
+        case AUDIO_DEVICE_OUT_SPEAKER :
+        case AUDIO_DEVICE_OUT_WIRED_HEADSET :
+        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE :
+            return true;
+        default :
+            return false;
+    }
+}
+
+void set_device(uint32_t device_type, uint32_t device_id)
+{
+    transcode_loopback_config_t *transcode_loopback_config = &g_trnscode_loopback_config;
+    device_id = is_device_supported(device_id) ? device_id : AUDIO_DEVICE_OUT_SPEAKER;
+    switch( device_type )
+    {
+        case DEVICE_SINK:
+            transcode_loopback_config->sink_config.ext.device.type = device_id;
+        break;
+        case DEVICE_SOURCE:
+            transcode_loopback_config->source_config.ext.device.type = device_id;
+        break;
+    }
+}
+
 int main(int argc, char *argv[]) {
 
     int status = 0;
-    uint32_t play_duration_in_seconds = 30,play_duration_elapsed_msec = 0,play_duration_in_msec = 0;
+    uint32_t play_duration_in_seconds = 600,play_duration_elapsed_msec = 0,play_duration_in_msec = 0, sink_device = 2;
     source_port_type_t source_port_type = SOURCE_PORT_NONE;
     log_file = stdout;
-
-    fprintf(log_file,"\nUsage : trans_loopback_test <optional : duration_in_seconds>\n");
-    fprintf(log_file,"\nTranscode loopback test begin\n");
-    play_duration_in_seconds = 600;
-    if (argc == 2) {
-        play_duration_in_seconds = atoi(argv[1]);
-        if (play_duration_in_seconds < 0 | play_duration_in_seconds > 3600) {
-            fprintf(log_file,
-                    "\nPlayback duration %s invalid or unsupported(range : 1 to 3600, defaulting to 600 seconds )\n",
-                    argv[1]);
-            play_duration_in_seconds = 600;
-        }
-    }
-    play_duration_in_msec = play_duration_in_seconds * 1000;
-
     transcode_loopback_config_t    *transcode_loopback_config = NULL;
     transcode_loopback_config_t *temp = NULL;
 
+    struct option long_options[] = {
+        /* These options set a flag. */
+        {"sink-device", required_argument,    0, 'd'},
+        {"play-duration",  required_argument,    0, 'p'},
+        {"help",          no_argument,          0, 'h'},
+        {0, 0, 0, 0}
+    };
+
+    int opt = 0;
+    int option_index = 0;
+
+    while ((opt = getopt_long(argc,
+                              argv,
+                              "-d:p:h",
+                              long_options,
+                              &option_index)) != -1) {
+
+        fprintf(log_file, "for argument %c, value is %s\n", opt, optarg);
+
+        switch (opt) {
+        case 'd':
+            sink_device = atoi(optarg);
+            break;
+        case 'p':
+            play_duration_in_seconds = atoi(optarg);
+            break;
+        case 'h':
+        default :
+            usage();
+            return 0;
+            break;
+        }
+    }
+
+    fprintf(log_file,"\nTranscode loopback test begin\n");
+    if (play_duration_in_seconds < 0 | play_duration_in_seconds > 3600) {
+            fprintf(log_file,
+                    "\nPlayback duration %d invalid or unsupported(range : 1 to 3600, defaulting to 600 seconds )\n",
+                    play_duration_in_seconds);
+            play_duration_in_seconds = 600;
+    }
+    play_duration_in_msec = play_duration_in_seconds * 1000;
+
     /* Register the SIGINT to close the App properly */
     if (signal(SIGINT, break_signal_handler) == SIG_ERR) {
         fprintf(log_file, "Failed to register SIGINT:%d\n",errno);
@@ -536,6 +599,9 @@
     init_transcode_loopback_config(&temp);
     transcode_loopback_config = &g_trnscode_loopback_config;
 
+    /* Set devices */
+    set_device(DEVICE_SINK,sink_device);
+
     /* Load HAL */
     fprintf(log_file,"\nLoading HAL for loopback usecase begin\n");
     primary_hal_handle = load_hal(transcode_loopback_config->devices);
@@ -581,11 +647,12 @@
 
     fprintf(log_file,"\nTranscode loopback test end\n");
     return 0;
-usage:
-    fprintf(log_file,"\nInvald arguments\n");
-    fprintf(log_file,"\nUsage : trans_loopback_test <duration_in_seconds>\n");
-    fprintf(log_file,"\nExample to play for 1 minute : trans_loopback_test 60\n");
-    return 0;
 }
 
-
+void usage()
+{
+    fprintf(log_file,"\nUsage : trans_loopback_test -p <duration_in_seconds> -d <sink_device_id>\n");
+    fprintf(log_file,"\nExample to play for 1 minute on speaker device: trans_loopback_test -p 60 -d 2\n");
+    fprintf(log_file,"\nExample to play for 5 minutes on headphone device: trans_loopback_test -p 300 -d 8\n");
+    fprintf(log_file,"\nHelp : trans_loopback_test -h\n");
+ }