alsa_conformance_test: Add strict and dev_info_only mode.

Strict mode: If it can not set params to the value user set, it
will fail.

Dev_info_only mode: Show device information only without run and set
params.

BUG=chromium:685077
TEST=Tested on several boards including samus, peppy.

Change-Id: Ibb5d897006bb0c39922c94091acc05d9e9561393
Reviewed-on: https://chromium-review.googlesource.com/1149668
Commit-Ready: Yu-Hsuan Hsu <yuhsuan@chromium.org>
Tested-by: Yu-Hsuan Hsu <yuhsuan@chromium.org>
Reviewed-by: Cheng-Yi Chiang <cychiang@chromium.org>
diff --git a/include/alsa_conformance_args.h b/include/alsa_conformance_args.h
index 1d82945..260cbe5 100644
--- a/include/alsa_conformance_args.h
+++ b/include/alsa_conformance_args.h
@@ -45,6 +45,9 @@
 /* Return device file of argument. */
 const char* args_get_device_file(const struct alsa_conformance_args *args);
 
+/* Return whether it is in device info only mode. */
+int args_get_dev_info_only(const struct alsa_conformance_args *args);
+
 /* Set playback device name. */
 void args_set_playback_dev_name(struct alsa_conformance_args *args,
                                 const char *name);
@@ -78,4 +81,8 @@
 void args_set_device_file(struct alsa_conformance_args *args,
                           const char *name);
 
+/* Set info only flag of argument. */
+void args_set_dev_info_only(struct alsa_conformance_args *args,
+                            int flag);
+
 #endif /* INCLUDE_ALSA_CONFORMANCE_ARGS_H_ */
diff --git a/src/alsa_conformance_args.c b/src/alsa_conformance_args.c
index fd0d1f7..9dc1586 100644
--- a/src/alsa_conformance_args.c
+++ b/src/alsa_conformance_args.c
@@ -5,6 +5,7 @@
  */
 
 #include <alsa/asoundlib.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -22,6 +23,7 @@
     unsigned int block_size;
     double duration;
     char *device_file;
+    int dev_info_only;
 };
 
 struct alsa_conformance_args *args_create()
@@ -44,6 +46,7 @@
     args->block_size = 240;
     args->duration = 1.0;
     args->device_file = NULL;
+    args->dev_info_only = false;
 
     return args;
 }
@@ -101,6 +104,11 @@
     return args->device_file;
 }
 
+int args_get_dev_info_only(const struct alsa_conformance_args *args)
+{
+    return args->dev_info_only;
+}
+
 void args_set_playback_dev_name(struct alsa_conformance_args *args,
                                 const char *name)
 {
@@ -159,3 +167,9 @@
     free(args->device_file);
     args->device_file = strdup(name);
 }
+
+void args_set_dev_info_only(struct alsa_conformance_args *args,
+                            int flag)
+{
+    args->dev_info_only = flag;
+}
diff --git a/src/alsa_conformance_test.c b/src/alsa_conformance_test.c
index f1aa81a..78f8c88 100644
--- a/src/alsa_conformance_test.c
+++ b/src/alsa_conformance_test.c
@@ -21,6 +21,7 @@
 
 int DEBUG_MODE = false;
 int SINGLE_THREAD;
+int STRICT_MODE = false;
 
 void show_usage(const char *name)
 {
@@ -42,6 +43,11 @@
            "Enable debug mode. (Not support multi-streams in this version)\n");
     printf("\t--device_file: "
            "Device file path. It will load devices from the file.\n");
+    printf("\t--strict: "
+           "Enable strict mode. It will set params to the fixed value.\n");
+    printf("\t--dev_info_only: "
+           "Show device information only without setting params and running "
+           "I/O.\n");
 
     printf("\n");
     printf("Device file format:\n"
@@ -195,14 +201,21 @@
         SINGLE_THREAD = true;
     }
 
-    for (i = 0; i < thread_count; i++) {
+    for (i = 0; i < thread_count; i++)
         dev_thread_device_open(thread_list[i]);
-        if (SINGLE_THREAD)
+
+    if (args_get_dev_info_only(args)) {
+        for (i = 0; i < thread_count; i++) {
             dev_thread_print_device_information(thread_list[i]);
-        dev_thread_set_params(thread_list[i]);
+            dev_thread_destroy(thread_list[i]);
+        }
+        return;
     }
 
     for (i = 0; i < thread_count; i++)
+        dev_thread_set_params(thread_list[i]);
+
+    for (i = 0; i < thread_count; i++)
         pthread_create(&thread_id[i],
                        NULL,
                        alsa_conformance_run_thread,
@@ -227,7 +240,9 @@
 {
     enum OPTION {
         OPT_DEBUG = 300,
-        OPT_DEVICE_FILE
+        OPT_DEVICE_FILE,
+        OPT_STRICT,
+        OPT_DEV_INFO_ONLY
     };
     int c;
     const char *short_opt = "hP:C:c:f:r:p:B:d:D";
@@ -244,6 +259,8 @@
         {"durations",    required_argument, NULL, 'd'},
         {"debug",        no_argument,       NULL, OPT_DEBUG},
         {"device_file",  required_argument, NULL, OPT_DEVICE_FILE},
+        {"strict",       no_argument,       NULL, OPT_STRICT},
+        {"dev_info_only",no_argument,       NULL, OPT_DEV_INFO_ONLY},
         {0, 0, 0, 0}
     };
     while (1) {
@@ -297,6 +314,15 @@
             args_set_device_file(test_args, optarg);
             break;
 
+        case OPT_STRICT:
+            STRICT_MODE = true;
+            puts("Enable strict mode!");
+            break;
+
+        case OPT_DEV_INFO_ONLY:
+            args_set_dev_info_only(test_args, true);
+            break;
+
         case ':':
         case '?':
             fprintf(stderr, "Try `%s --help' for more information.\n",
diff --git a/src/alsa_conformance_thread.c b/src/alsa_conformance_thread.c
index e928b88..7ef5fa9 100644
--- a/src/alsa_conformance_thread.c
+++ b/src/alsa_conformance_thread.c
@@ -13,6 +13,7 @@
 #include "include/alsa_conformance_timer.h"
 
 extern int DEBUG_MODE;
+extern int STRICT_MODE;
 
 struct dev_thread {
     snd_pcm_t *handle;
@@ -134,8 +135,13 @@
 
 void dev_thread_set_params(struct dev_thread *thread)
 {
+    unsigned int rate;
+    snd_pcm_uframes_t period_size;
     int rc;
+
     assert(thread->handle);
+    rate = thread->rate;
+    period_size = thread->period_size;
     rc = alsa_helper_set_hw_params(thread->timer,
                                    thread->handle,
                                    thread->params,
@@ -146,6 +152,19 @@
     if (rc < 0)
         exit(EXIT_FAILURE);
 
+    if (STRICT_MODE) {
+        if (rate != thread->rate) {
+            fprintf(stderr, "%s want to set rate %u but get %u.\n",
+                    thread->dev_name, rate, thread->rate);
+            exit(EXIT_FAILURE);
+        }
+        if (period_size != thread->period_size) {
+            fprintf(stderr, "%s want to set period_size %lu but get %lu.\n",
+                    thread->dev_name, period_size, thread->period_size);
+            exit(EXIT_FAILURE);
+        }
+    }
+
     rc = alsa_helper_set_sw_param(thread->timer,
                                   thread->handle);
     if (rc < 0)