[alsa-devel] [PATCH] test: add audio_time

Takashi Iwai tiwai at suse.de
Sat Sep 22 09:39:55 CEST 2012


At Fri, 21 Sep 2012 20:05:18 -0500,
Pierre-Louis Bossart wrote:
> 
> 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
> 
> 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 at linux.intel.com>

Applied now.  Thanks.


Takashi

> ---
>  test/audio_time.c |  237 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 237 insertions(+)
>  create mode 100644 test/audio_time.c
> 
> diff --git a/test/audio_time.c b/test/audio_time.c
> new file mode 100644
> index 0000000..a910783
> --- /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;
> +}
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 


More information about the Alsa-devel mailing list