/* * This extra small demo sends silence to your speakers and tests the precision of the reported position. */ #include #include #include const char* device; const int channels = 2; const snd_pcm_sframes_t period_size = 960; const int periods = 4; const int rate = 48000; int main(int argc, char* argv[]) { int err; int failed = 0; unsigned int j, j_old; short *silence; snd_pcm_sframes_t avail = -1, delay = -1; snd_pcm_uframes_t min_period_size; snd_pcm_uframes_t boundary; int dir; struct timeval tv_old; if (argc != 2) { fprintf(stderr, "Usage: %s pcm_name\n", argv[0]); exit(EXIT_FAILURE); } device = argv[1]; printf("======= testing %s =======\n", device); snd_pcm_t *handle; snd_output_t *out = NULL; snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); snd_output_stdio_attach(&out, stdout, 0); silence = calloc(period_size * periods, sizeof(short) * channels); if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf(stderr, "Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } failed = (err = snd_pcm_hw_params_any(handle, params)) < 0; failed = failed || (err = snd_pcm_hw_params_set_rate_resample(handle, params, 1)) < 0; failed = failed || (err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0; failed = failed || (err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16)) < 0; failed = failed || (err = snd_pcm_hw_params_set_channels(handle, params, channels)) < 0; failed = failed || (err = snd_pcm_hw_params_set_rate(handle, params, rate, 0)) < 0; if (failed) { fprintf(stderr, "Playback hwparams (access & format) error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_get_period_size_min(params, &min_period_size, &dir); if (err < 0) { fprintf(stderr, "Cannot get minimum period size: %s\n", snd_strerror(err)); } printf("min_period_size: %d frames, dir: %d\n", (int)min_period_size, dir); failed = (err = snd_pcm_hw_params_set_period_size(handle, params, period_size, 0)) < 0; failed = failed || (err = snd_pcm_hw_params_set_periods(handle, params, periods, 0)) < 0; failed = failed || (err = snd_pcm_hw_params(handle, params)) < 0; if (failed) { fprintf(stderr, "Playback hwparams (period size & periods) error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_get_fifo_size(params); if (err < 0) { fprintf(stderr, "Playback hwparams: can't get FIFO size, error: %s\n", snd_strerror(err)); } else { printf("FIFO size is %d\n", err); } failed = (err = snd_pcm_sw_params_current(handle, swparams)) < 0; failed = failed || (err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period_size)) < 0; failed = failed || (err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size)) < 0; failed = failed || (err = snd_pcm_sw_params(handle, swparams)) < 0; if (failed) { fprintf(stderr, "Playback swparams error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } snd_pcm_dump(handle, out); printf("Playing silence\n"); fflush(stdout); memset(silence, 0, period_size * periods * sizeof(short) * channels); err = snd_pcm_writei(handle, silence, period_size * periods); if (err < 0) { fprintf(stderr, "Playback error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } j = 0; j_old = 0; gettimeofday(&tv_old, NULL); while (1) { snd_pcm_sframes_t avail1; snd_pcm_sframes_t delay1; err = snd_pcm_avail_delay(handle, &avail1, &delay1); if (err < 0 || avail1 < 0) break; if (avail != avail1 || delay != delay1) { struct timeval tv; gettimeofday(&tv, NULL); printf("Available: %d, delay: %d, loop iteration: %d, diff: %d, timestamp diff: %d usec\n", (int)avail1, (int)delay1, j, j - j_old, (int)((tv.tv_sec - tv_old.tv_sec) * 1000000 + (tv.tv_usec - tv_old.tv_usec))); tv_old = tv; j_old = j; } avail = avail1; delay = delay1; j++; } snd_pcm_drop(handle); snd_pcm_close(handle); free(silence); return 0; }