/* Test playback/capture position of alsa playback/capture device Playback - Try to use 2 seconds buffer , or maximum buffer size/maximum period size when sound card does not has a 2 second buffer fill the buffer collect the value from snd_pcm_avail() every 1 ms call snd_pcm_drain when avail < buffer_size Record - Try to use 2 seconds buffer , or maximum buffer size/maximum period size when sound card does not has a 2 second buffer start capturing collect the value from snd_pcm_avail() every 1 ms alsa_test device dir rate periods stop_at_underrun you can compare the test result of different devices 1) hw:0,0 2) plug:dmix 3) pulse 4) plug:jack 5) plughw:0 */ #include #include //#define DISABLE_RESAMPLE 1 int main(int argc, char *argv[]) { const char *dev; int cap, err; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; snd_pcm_t *pcm; snd_output_t *output = NULL; snd_pcm_format_t fmt = SND_PCM_FORMAT_S16_LE; snd_pcm_uframes_t boundary, buffer_size, period_size, this_period; snd_pcm_sframes_t avail; int chn = 2; unsigned rate; unsigned periods;; unsigned int this_time, buffer_time; int sleep_time = 1000; int buffer[65536]; int stat[65536]; int dir = 1; int stop_at_underrun; int i, counter; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); dev = argc > 1 ? argv[1] : "hw:0,0"; cap = argc > 2 ? atoi(argv[2]) : 0; rate = argc > 3 ? atoi(argv[3]) : 44100; periods = argc > 4 ? atoi(argv[4]) : 2; stop_at_underrun = argc > 5 ? atoi(argv[5]) : 1; err = snd_pcm_open(&pcm, dev, cap == 0 ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, 0); if (err < 0) { printf("snd_pcm_open fail %s err %s\n",dev, snd_strerror(err)); exit(0); } err = snd_pcm_hw_params_any(pcm, hwparams); #ifdef DISABLE_RESAMPLE err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 0); if (err < 0) { printf("set rate resample err %s\n", snd_strerror(err)); exit(0); }; #endif err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { printf("set access err %s\n", snd_strerror(err)); exit(0); }; err = snd_pcm_hw_params_set_format(pcm, hwparams, fmt); if (err < 0) { printf("set format %s err %s\n",snd_pcm_format_name(fmt), snd_strerror(err)); exit(0); }; err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, NULL); if (err < 0) { printf("set rate to %dHz err %s\n",rate, snd_strerror(err)); exit(0); }; err = snd_pcm_hw_params_set_channels(pcm, hwparams, chn); if (err < 0) { printf("set channel to %d err %s\n",chn, snd_strerror(err)); exit(0); }; /* snd_pcm_hw_params_set_periods_integer(pcm, hwparams); */ dir = 0; err = snd_pcm_hw_params_set_periods_near(pcm, hwparams, &periods, &dir); if (err < 0) { printf("set perods err %s\n", snd_strerror(err)); exit(0); }; buffer_size = rate * 2; err = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &buffer_size); if (err < 0) { printf("set buffer size near err %s\n", snd_strerror(err)); exit(0); }; err = snd_pcm_hw_params(pcm, hwparams); if (err < 0) { printf("hw_params err %s\n", snd_strerror(err)); exit(0); }; err = snd_pcm_sw_params_current(pcm, swparams); if (err < 0) { printf("sw_params current %s\n", snd_strerror(err)); exit(0); }; err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if (err < 0) { printf("get buffer size err %s\n", snd_strerror(err)); exit(0); }; /* err = snd_pcm_hw_params_get_buffer_time(hwparams, &buffer_time, 0); if (err < 0) { printf("get buffer time err %s\n", snd_strerror(err)); exit(0); }; */ err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0); if (err < 0) { printf("get period size err %s\n", snd_strerror(err)); exit(0); }; err = snd_pcm_sw_params_get_boundary(swparams, &boundary); if (err < 0) { printf("get boundary err %s\n", snd_strerror(err)); exit(0); }; /* err = snd_pcm_sw_params_set_avail_min(pcm, swparams, period_size); if (err < 0) { printf("set avail min err %s\n", snd_strerror(err)); exit(0); }; */ /* err = snd_pcm_sw_params_set_period_event(pcm, swparams, 0); assert(err == 0); */ if (cap == 0) { err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, buffer_size); if (err < 0) { printf("set start threshold err %s\n", snd_strerror(err)); exit(0); }; }; if (!stop_at_underrun) { err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary); if (err < 0) { printf("set stop threshold err %s\n", snd_strerror(err)); exit(0); }; }; err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE); if (err < 0) { printf("set tstamp mode err %s\n", snd_strerror(err)); exit(0); }; err = snd_pcm_sw_params(pcm, swparams); if (err < 0) { printf("sw_params err %s\n", snd_strerror(err)); exit(0); }; err = snd_pcm_sw_params_current(pcm, swparams); if (err < 0) { printf("sw_params current %s\n", snd_strerror(err)); exit(0); }; err = snd_output_stdio_attach(&output, stdout, 0); if (err < 0) { printf("Output failed: %s\n", snd_strerror(err)); exit(0); }; snd_pcm_dump(pcm, output); /* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */ if (cap) { err = snd_pcm_start(pcm); assert(err == 0); } else { /* FIXME: Write whole buffer instead of periods */ this_period = 0; while (this_period < buffer_size) { err = snd_pcm_writei(pcm, buffer, period_size); if (err < 0) printf("pcm write err %d %s\n",err,snd_strerror(err)); else this_period += period_size; }; }; avail = 0; this_time = 0; counter = 0; while (counter <= 3000 && avail >= 0) { avail = snd_pcm_avail(pcm); stat[counter] = avail; usleep(sleep_time); counter++; this_time += sleep_time; }; printf("Time %s available\n", cap == 0 ? "Playback" : "Capture" ); for (i=0; i 0) && (avail < buffer_size)) { err = snd_pcm_drain(pcm); if (err < 0) { printf("pcm drain err %d %s\n",err,snd_strerror(err)); exit(0); }; printf("pcm drain : avail %d\n",snd_pcm_avail(pcm)); }; }; snd_pcm_dump(pcm, output); snd_pcm_close(pcm); snd_output_close(output); return 0; }