alsa_api_test: Check device consumption rate

The sleep time in each period might not be accurate.
Check device consumption rate rather than checking buffer level.

BUG=chromium:617516
TEST=run alsa_api_test --move on samus.

Change-Id: I6d60c7839717a485fbe744dd6500041cbdcebfd6
Reviewed-on: https://chromium-review.googlesource.com/357691
Commit-Ready: Cheng-Yi Chiang <cychiang@chromium.org>
Tested-by: Cheng-Yi Chiang <cychiang@chromium.org>
Reviewed-by: Hsinyu Chao <hychao@chromium.org>
diff --git a/alsa_api_test.c b/alsa_api_test.c
index e42fa08..534176c 100644
--- a/alsa_api_test.c
+++ b/alsa_api_test.c
@@ -257,6 +257,9 @@
 {
     snd_pcm_sframes_t hw_level, avail_frames;
     int periods_after_move = 10;
+    struct timespec time_1, time_2;
+    snd_pcm_sframes_t level_1, level_2;
+    float time_diff, measure_rate;
 
     /* Checks the result after moving. The hw_level should be in the range
      * 0 - fuzz. */
@@ -269,21 +272,33 @@
 
     /* Fills some zeros after moving to make sure PCM still plays fine. */
     pcm_fill(handle, period_size * periods_after_move, 0);
-    hw_level = buffer_frames - snd_pcm_avail(handle);
-    printf("hw_level after filling %d period is %ld\n",
-           periods_after_move, hw_level);
+    clock_gettime(CLOCK_MONOTONIC_RAW, &time_1);
+    printf("time: %ld.%09ld", (long)time_1.tv_sec, (long)time_1.tv_nsec);
+    level_1 = buffer_frames - snd_pcm_avail(handle);
+    printf(" hw_level after filling %d period is %ld\n",
+           periods_after_move, level_1);
 
     wait_for_periods(handle, periods_after_move - 1);
-    hw_level = buffer_frames - snd_pcm_avail(handle);
-    printf("hw_level after playing %d period is %ld\n",
-           periods_after_move - 1, hw_level);
 
-    /* After playing for periods_after_move - 1 periods, the hw_level
-     * should be less than one period + fuzz. Set criteria to
-     * -periods + fuzz to two period + fuzz to tolerate some fluctuation.
-     */
-    check_hw_level_in_range(hw_level,
-                            -period_size + fuzz, period_size * 2 + fuzz);
+    clock_gettime(CLOCK_MONOTONIC_RAW, &time_2);
+    printf("time: %ld.%09ld", (long)time_2.tv_sec, (long)time_2.tv_nsec);
+    level_2 = buffer_frames - snd_pcm_avail(handle);
+    printf(" hw_level after playing %d period is %ld\n",
+           periods_after_move - 1, level_2);
+
+    /* Checks the device consumption rate in this duration is reasonable. */
+    time_diff = (time_2.tv_sec - time_1.tv_sec) +
+                (float)(time_2.tv_nsec - time_1.tv_nsec) * 1E-9;
+    measure_rate = (level_1 - level_2) / time_diff;
+
+    if (fabsf(measure_rate - rate) <= 1000) {
+        printf("rate %f is in the expected range near %u\n",
+               measure_rate, rate);
+    } else {
+        fprintf(stderr, "rate %f is not in the expected range near %u\n",
+                measure_rate, rate);
+        exit(1);
+    }
 }
 
 void move_and_check(snd_pcm_t *handle, snd_pcm_sframes_t fuzz)