[alsa-devel] snd_pcm_avail_update returns bogus values with the OSS PCM plugin

Sindre Aamås aamas at stud.ntnu.no
Fri Jul 10 10:29:55 CEST 2009


Hi.

For the attached test case snd_pcm_avail_update returns values higher  
than the buffer size when run with the OSS PCM plugin. Output of  
alsa-info.sh is at
http://www.alsa-project.org/db/?f=77a873e55d5d6ca50d67a035a9d6b7e10cca179d .

--- alsa_oss_pcm_avail_bug.c ---
/*
  * Public domain test case to illustrate a bug in the ALSA OSS PCM plugin
  * where snd_pcm_avail_update returns bogus values.
  */

#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static short buf[803 * 2];
static snd_pcm_t *pcm_handle = NULL;

void close_pcm(void)
{
	if (pcm_handle)
		snd_pcm_close(pcm_handle);

	pcm_handle = NULL;
}

static int set_pcm_parameters(void) {
	snd_pcm_hw_params_t *hwparams;
	snd_pcm_hw_params_alloca(&hwparams);

	if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
		fprintf(stderr, "snd_pcm_hw_params_any failed.\n");
		return -1;
	}

	if (snd_pcm_hw_params_set_access(pcm_handle, hwparams,
				SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
		fprintf(stderr, "snd_pcm_hw_params_set_access failed.\n");
		return -1;
	}

	if (snd_pcm_hw_params_set_format(pcm_handle, hwparams,
				SND_PCM_FORMAT_S16) < 0) {
		fprintf(stderr, "snd_pcm_hw_params_set_format failed.\n");
		return -1;
	}

	{
		unsigned rate = 48000;

		if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
					&rate, 0) < 0) {
			fprintf(stderr, "snd_pcm_hw_params_set_rate_near failed.\n");
			return -1;
		}
	}

	if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) {
		fprintf(stderr, "snd_pcm_hw_params_set_channels failed.\n");
		return -1;
	}

	{
		unsigned ulatency = 100000;

		if (snd_pcm_hw_params_set_buffer_time_near(pcm_handle,
					hwparams, &ulatency, 0) < 0) {
			fprintf(stderr, "snd_pcm_hw_params_set_buffer_time_near failed.\n");
			return -1;
		}
	}

	if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
		fprintf(stderr, "snd_pcm_hw_params failed.\n");
		return -1;
	}

	{
		snd_pcm_uframes_t bSize = 0;

		if (snd_pcm_hw_params_get_buffer_size(hwparams, &bSize) < 0) {
			fprintf(stderr, "snd_pcm_hw_params_get_buffer_size failed\n");
			return -1;
		}

		printf("buffer_size: %u\n", (unsigned int) bSize);
	}

	return 0;
}

static void test_loop(int n) {
	while (n--) {
		snd_pcm_sframes_t sframes = snd_pcm_avail_update(pcm_handle);
		printf("snd_pcm_avail: %d\n", (int) sframes);
		printf("writing %d frames\n", (int) sizeof(buf) / 4);
		sframes = snd_pcm_writei(pcm_handle, buf, sizeof(buf) / 4);

		if (sframes != sizeof(buf) / 4) {
			if (sframes < 0)
				snd_pcm_prepare(pcm_handle);

			printf("snd_pcm_writei returned %d\n", (int) sframes);
		}
	}
}

int main(int argc, char **argv)
{
	atexit(close_pcm);

	if (argc < 2) {
		printf("usage: %s <ALSA pcm device>\n", argv[0]);
		return 0;
	}

	if (snd_pcm_open(&pcm_handle, argv[1],
				SND_PCM_STREAM_PLAYBACK, 0) < 0) {
		fprintf(stderr, "Error opening PCM device %s\n", argv[1]);
		pcm_handle = NULL;
		return -1;
	}

	if (set_pcm_parameters() < 0)
		return -1;

	memset(buf, 0, sizeof(buf));

	test_loop(500);

	return 0;
}

--
Sindre Aamås



More information about the Alsa-devel mailing list