alsa/0028-test-add-audio_time.patch
Takashi Iwai 8a90d87ca6 Accepting request 138456 from home:tiwai:branches:multimedia:libs
- backport from upstream tree:
  * lots of patches to support the new chmap API
  * fix segfault in rate plugin error path
  * add a couple of test programs
  * fix inifinte loop in htimestamp of dmix & co

OBS-URL: https://build.opensuse.org/request/show/138456
OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=113
2012-10-17 08:17:46 +00:00

288 lines
8.5 KiB
Diff

From 6429a450a315e00d9e00af46eb42784a4cc5dce1 Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Date: Fri, 21 Sep 2012 20:05:18 -0500
Subject: [PATCH 28/30] test: add audio_time
Simple test to create playback and capture streams, and
check elapsed time vs. sample counts reported by driver.
This should be helpful for driver developers and anyone
interested in system/audio time drift.
tested only on HDAudio
[added Makefile.am change by tiwai]
TODO:
- make period configurable
- better output messages
- support for wall clock when it's in the mainline
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
test/Makefile.am | 4
test/audio_time.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 240 insertions(+), 1 deletion(-)
create mode 100644 test/audio_time.c
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,7 +2,8 @@ SUBDIRS=. lsb
check_PROGRAMS=control pcm pcm_min latency seq \
playmidi1 timer rawmidi midiloop \
- oldapi queue_timer namehint client_event_filter chmap
+ oldapi queue_timer namehint client_event_filter \
+ chmap audio_time
control_LDADD=../src/libasound.la
pcm_LDADD=../src/libasound.la
@@ -19,6 +20,7 @@ namehint_LDADD=../src/libasound.la
client_event_filter_LDADD=../src/libasound.la
code_CFLAGS=-Wall -pipe -g -O2
chmap_LDADD=../src/libasound.la
+audio_time_LDADD=../src/libasound.la
INCLUDES=-I$(top_srcdir)/include
AM_CFLAGS=-Wall -pipe -g
--- /dev/null
+++ b/test/audio_time.c
@@ -0,0 +1,237 @@
+/*
+ * This program only tracks the difference between system time
+ * and audio time, as reported in snd_pcm_status(). It should be
+ * helpful to verify the information reported by drivers.
+ */
+
+#include "../include/asoundlib.h"
+#include <math.h>
+
+static char *device = "hw:0,0";
+
+snd_output_t *output = NULL;
+
+long long timestamp2ns(snd_htimestamp_t t)
+{
+ long long nsec;
+
+ nsec = t.tv_sec * 1000000000;
+ nsec += t.tv_nsec;
+
+ return nsec;
+}
+
+long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
+{
+ long long nsec1, nsec2;
+
+ nsec1 = timestamp2ns(t1);
+ nsec2 = timestamp2ns(t2);
+
+ return nsec1 - nsec2;
+}
+
+void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
+ snd_htimestamp_t *trigger_timestamp,
+ snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
+{
+ int err;
+ snd_pcm_status_t *status;
+
+ snd_pcm_status_alloca(&status);
+ if ((err = snd_pcm_status(handle, status)) < 0) {
+ printf("Stream status error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+ snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
+ snd_pcm_status_get_htstamp(status, timestamp);
+ *avail = snd_pcm_status_get_avail(status);
+ *delay = snd_pcm_status_get_delay(status);
+}
+
+#define PERIOD 6000
+#define PCM_LINK /* sync start for playback and capture */
+#define TRACK_CAPTURE /* dump capture timing info */
+#define TRACK_PLAYBACK /* dump playback timing info */
+#define PLAYBACK_BUFFERS 4
+
+
+int main(void)
+{
+ int err;
+ unsigned int i;
+ snd_pcm_t *handle_p = NULL;
+ snd_pcm_t *handle_c = NULL;
+ snd_pcm_sframes_t frames;
+ snd_htimestamp_t tstamp_c, tstamp_p;
+ snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
+ unsigned char buffer_p[PERIOD*4*4];
+ unsigned char buffer_c[PERIOD*4*4];
+
+ snd_pcm_sw_params_t *swparams_p;
+ snd_pcm_sw_params_t *swparams_c;
+
+ snd_pcm_uframes_t curr_count_c;
+ snd_pcm_uframes_t frame_count_c = 0;
+ snd_pcm_uframes_t curr_count_p;
+ snd_pcm_uframes_t frame_count_p = 0;
+
+ snd_pcm_sframes_t delay_p, delay_c;
+ snd_pcm_uframes_t avail_p, avail_c;
+
+ if ((err = snd_pcm_open(&handle_p, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ printf("Playback open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+ if ((err = snd_pcm_set_params(handle_p,
+ SND_PCM_FORMAT_S16,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 2,
+ 48000,
+ 0,
+ 500000)) < 0) { /* 0.5sec */
+ printf("Playback open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ snd_pcm_sw_params_alloca(&swparams_p);
+ /* get the current swparams */
+ err = snd_pcm_sw_params_current(handle_p, swparams_p);
+ if (err < 0) {
+ printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* enable tstamp */
+ err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
+ if (err < 0) {
+ printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* write the sw parameters */
+ err = snd_pcm_sw_params(handle_p, swparams_p);
+ if (err < 0) {
+ printf("Unable to set swparams_p : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ if ((err = snd_pcm_open(&handle_c, device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
+ printf("Capture open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+ if ((err = snd_pcm_set_params(handle_c,
+ SND_PCM_FORMAT_S16,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 2,
+ 48000,
+ 0,
+ 500000)) < 0) { /* 0.5sec */
+ printf("Capture open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ snd_pcm_sw_params_alloca(&swparams_c);
+ /* get the current swparams */
+ err = snd_pcm_sw_params_current(handle_c, swparams_c);
+ if (err < 0) {
+ printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* enable tstamp */
+ err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
+ if (err < 0) {
+ printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* write the sw parameters */
+ err = snd_pcm_sw_params(handle_c, swparams_c);
+ if (err < 0) {
+ printf("Unable to set swparams_c : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+#ifdef PCM_LINK
+ if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
+ printf("Streams link error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+#endif
+
+ i = PLAYBACK_BUFFERS;
+ while (i--) {
+ frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+ if (frames < 0) {
+ printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+ frame_count_p += frames;
+ }
+
+ if (PLAYBACK_BUFFERS != 4)
+ snd_pcm_start(handle_p);
+
+#ifndef PCM_LINK
+ /* need to start capture explicitly */
+ snd_pcm_start(handle_c);
+#endif
+
+ while (1) {
+
+ frames = snd_pcm_wait(handle_c, -1);
+ if (frames < 0) {
+ printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+
+ frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
+ if (frames < 0) {
+ printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+ frame_count_c += frames;
+
+ frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+ if (frames < 0) {
+ printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+
+ frame_count_p += frames;
+
+#if defined(TRACK_PLAYBACK)
+ gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &avail_p, &delay_p);
+
+ curr_count_p = frame_count_p - delay_p; /* written minus queued */
+
+ printf("playback: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
+ timediff(tstamp_p,trigger_tstamp_p),
+ (long long)round(((float)curr_count_p * 1000000000.0 / 48000.0)),
+ timediff(tstamp_p, trigger_tstamp_p) - (long long)round((double)curr_count_p * 1000000000.0 / 48000.0)
+ );
+#endif
+
+#if defined(TRACK_CAPTURE)
+ gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &avail_c, &delay_c);
+
+ curr_count_c = frame_count_c + delay_c; /* read plus queued */
+
+ printf("\t capture: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
+ timediff(tstamp_c,trigger_tstamp_c),
+ (long long)round(((float)curr_count_c * 1000000000.0 / 48000.0)),
+ timediff(tstamp_c, trigger_tstamp_c) - (long long)round((double)curr_count_c * 1000000000.0 / 48000.0)
+ );
+#endif
+
+ }
+
+_exit:
+ if (handle_p)
+ snd_pcm_close(handle_p);
+ if (handle_c)
+ snd_pcm_close(handle_c);
+
+ return 0;
+}