This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/xawtv3.git tree:
Subject: alsa_stream: add an extra algorithm to help configuring latency Author: Mauro Carvalho Chehab <[email protected]> Date: Fri Aug 12 12:03:04 2011 -0300 At least on my Dell Vostro 1310, the Realtek hda chip supports a very limited playback period time range. It is between 21333 and 21334. However, to avoid underrun/overrun, delay needs to be bigger than 30ms. With the new algorithm, instead of changing the period (that won't work here anway, due to the very limited range), it will now change the number of periods: alsa: playback periods range between 1 and 17. Want: 6 alsa: playback period time range between 21333 and 21334. Want: 21334 alsa: capture period set to 3 periods of 21343 time alsa: playback period set to 6 periods of 21333 time ... alsa: stream started from hw:1,0 to default (32000 Hz, buffer delay = 64,03 ms) Of course, the algorithm won't give the exact desired delay, but this avoids overrun/underrun. Signed-off-by: Mauro Carvalho Chehab <[email protected]> common/alsa_stream.c | 76 ++++++++++++++++++++++++++++++++++++------------- 1 files changed, 56 insertions(+), 20 deletions(-) --- http://git.linuxtv.org/xawtv3.git?a=commitdiff;h=94e533ca28e3f1a9f434697dff0acb1baa40bac8 diff --git a/common/alsa_stream.c b/common/alsa_stream.c index cc26596..20a45ef 100644 --- a/common/alsa_stream.c +++ b/common/alsa_stream.c @@ -98,20 +98,20 @@ static int setparams_stream(snd_pcm_t *handle, return 0; } -static int setparams_periods(snd_pcm_t *handle, +static void getparams_periods(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int *usecs, unsigned int *count, const char *id) { - int err; unsigned min = 0, max = 0; snd_pcm_hw_params_get_periods_min(params, &min, 0); snd_pcm_hw_params_get_periods_max(params, &max, 0); if (min && max) { if (verbose) - fprintf(error_fp, "alsa: %s periods range between %d and %d\n", id, min, max); + fprintf(error_fp, "alsa: %s periods range between %u and %u. Want: %u\n", + id, min, max, *count); if (*count < min) *count = min; if (*count > max) @@ -123,12 +123,22 @@ static int setparams_periods(snd_pcm_t *handle, snd_pcm_hw_params_get_period_time_max(params, &max, 0); if (min && max) { if (verbose) - fprintf(error_fp, "alsa: %s period time range between %d and %d\n", id, min, max); + fprintf(error_fp, "alsa: %s period time range between %u and %u. Want: %u\n", + id, min, max, *usecs); if (*usecs < min) *usecs = min; if (*usecs > max) *usecs = max; } +} + +static int setparams_periods(snd_pcm_t *handle, + snd_pcm_hw_params_t *params, + unsigned int *usecs, + unsigned int *count, + const char *id) +{ + int err; err = snd_pcm_hw_params_set_period_time_near(handle, params, usecs, 0); if (err < 0) { @@ -144,6 +154,10 @@ static int setparams_periods(snd_pcm_t *handle, return err; } + if (verbose) + fprintf(error_fp, "alsa: %s period set to %u periods of %u time\n", + id, *count, *usecs); + return 0; } @@ -204,7 +218,7 @@ static int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, snd_pcm_uframes_t c_size, p_psize, c_psize; /* Our latency is 2 periods (in usecs) */ unsigned int c_periods = 2, p_periods; - unsigned int periodtime = latency * 1000; + unsigned int c_periodtime, p_periodtime; snd_pcm_hw_params_alloca(&p_hwparams); snd_pcm_hw_params_alloca(&c_hwparams); @@ -284,10 +298,32 @@ static int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, if (verbose) fprintf(error_fp, "alsa: Using Rate %d\n", ratec); - if (setparams_periods(chandle, c_hwparams, &periodtime, &c_periods, "capture")) - return 1; + /* Negociate period parameters */ + c_periodtime = latency * 1000 / c_periods; + getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, "capture"); p_periods = c_periods * 2; + p_periodtime = c_periodtime; + getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, "playback"); + c_periods = p_periods / 2; + + /* + * Some playback devices support a very limited periodtime range. If the user needs to + * use a higher latency to avoid overrun/underrun, use an alternate algorithm of incresing + * the number of periods, to archive the needed latency + */ + if (p_periodtime < c_periodtime) { + c_periodtime = p_periodtime; + c_periods = round (latency * 1000.0 / c_periodtime + 0.5); + getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, "capture"); + p_periods = c_periods * 2; + p_periodtime = c_periodtime; + getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, "playback"); + c_periods = p_periods / 2; + } + + if (setparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, "capture")) + return 1; /* Note we use twice as much periods for the playback buffer, since we will get a period size near the requested time and we don't want it to @@ -295,7 +331,7 @@ static int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, on writing to it. Note we will configure the playback dev to start playing as soon as it has 2 capture periods worth of data, so this won't influence latency */ - if (setparams_periods(phandle, p_hwparams, &periodtime, &p_periods, "playback")) + if (setparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, "playback")) return 1; snd_pcm_hw_params_get_period_size(p_hwparams, &p_psize, NULL); @@ -404,24 +440,24 @@ static int alsa_stream(const char *pdevice, const char *cdevice, int latency) /* Try to use plughw instead, as it allows emulating speed */ if (err == 2 && strncmp(pdevice, "hw", 2) == 0) { - snd_pcm_close(phandle); + snd_pcm_close(phandle); - sprintf(pdevice_new, "plug%s", pdevice); - pdevice = pdevice_new; - if (verbose) - fprintf(error_fp, "alsa: Trying %s for playback\n", pdevice); - if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, - 0)) < 0) { - fprintf(error_fp, "alsa: Cannot open playback device %s: %s\n", - pdevice, snd_strerror(err)); - } + sprintf(pdevice_new, "plug%s", pdevice); + pdevice = pdevice_new; + if (verbose) + fprintf(error_fp, "alsa: Trying %s for playback\n", pdevice); + if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, + 0)) < 0) { + fprintf(error_fp, "alsa: Cannot open playback device %s: %s\n", + pdevice, snd_strerror(err)); + } err = setparams(phandle, chandle, format, latency, 1, &negotiated); } if (err != 0) { - fprintf(error_fp, "alsa: setparams failed\n"); - return 1; + fprintf(error_fp, "alsa: setparams failed\n"); + return 1; } buffer = malloc((negotiated.bufsize * snd_pcm_format_width(format) / 8) _______________________________________________ linuxtv-commits mailing list [email protected] http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits
