On Sat, Feb 06, 2016 at 04:12:39PM +0000, Fons Adriaensen wrote:

> > That, helped thanks.
> > Unfortunately I’m still getting the same huge latency as before..
> 
> Looks like a driver problem then... 

Not impossible, but I fail to see how. Here is the relevant driver side:

        .channels_min = 1,
        .channels_max = 196,
        .buffer_bytes_max = OUTPUT_DMA_BUFFER_SIZE,
        .period_bytes_min = (32 * 4),
        .period_bytes_max = OUTPUT_DMA_BUFFER_SIZE,
        .periods_min = 2,
        .periods_max = 1024,


and according to some doc on the internet:


--- cut ---
buffer_bytes_max defines the maximum buffer size in bytes. There is no
buffer_bytes_min field, since it can be calculated from the minimum
period size and the minimum number of periods. Meanwhile,
period_bytes_min and define the minimum and maximum size of the period
in bytes. periods_max and periods_min define the maximum and minimum
number of periods in the buffer.

The “period” is a term that corresponds to a fragment in the OSS world.
The period defines the size at which a PCM interrupt is generated. This
size strongly depends on the hardware. Generally, the smaller period
size will give you more interrupts, that is, more controls. In the case
of capture, this size defines the input latency. On the other hand, the
whole buffer size defines the output latency for the playback direction.
--- cut ---

>From my understanding, this allows userspace to request a buffer of
1ch*2periods*32samples.

Fokke, do you mind running the attached program?


Cheers

-- 
mail: a...@thur.de      http://adi.thur.de      PGP/GPG: key via keyserver

/*
 * hw_params.c - print hardware capabilities
 *
 * compile with: gcc -o hw_params hw_params.c -lasound
 */

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

#define ARRAY_SIZE(a) (sizeof(a) / sizeof *(a))

static const snd_pcm_access_t accesses[] = {
	SND_PCM_ACCESS_MMAP_INTERLEAVED,
	SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
	SND_PCM_ACCESS_MMAP_COMPLEX,
	SND_PCM_ACCESS_RW_INTERLEAVED,
	SND_PCM_ACCESS_RW_NONINTERLEAVED,
};

static const snd_pcm_format_t formats[] = {
	SND_PCM_FORMAT_S8,
	SND_PCM_FORMAT_U8,
	SND_PCM_FORMAT_S16_LE,
	SND_PCM_FORMAT_S16_BE,
	SND_PCM_FORMAT_U16_LE,
	SND_PCM_FORMAT_U16_BE,
	SND_PCM_FORMAT_S24_LE,
	SND_PCM_FORMAT_S24_BE,
	SND_PCM_FORMAT_U24_LE,
	SND_PCM_FORMAT_U24_BE,
	SND_PCM_FORMAT_S32_LE,
	SND_PCM_FORMAT_S32_BE,
	SND_PCM_FORMAT_U32_LE,
	SND_PCM_FORMAT_U32_BE,
	SND_PCM_FORMAT_FLOAT_LE,
	SND_PCM_FORMAT_FLOAT_BE,
	SND_PCM_FORMAT_FLOAT64_LE,
	SND_PCM_FORMAT_FLOAT64_BE,
	SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
	SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
	SND_PCM_FORMAT_MU_LAW,
	SND_PCM_FORMAT_A_LAW,
	SND_PCM_FORMAT_IMA_ADPCM,
	SND_PCM_FORMAT_MPEG,
	SND_PCM_FORMAT_GSM,
	SND_PCM_FORMAT_SPECIAL,
	SND_PCM_FORMAT_S24_3LE,
	SND_PCM_FORMAT_S24_3BE,
	SND_PCM_FORMAT_U24_3LE,
	SND_PCM_FORMAT_U24_3BE,
	SND_PCM_FORMAT_S20_3LE,
	SND_PCM_FORMAT_S20_3BE,
	SND_PCM_FORMAT_U20_3LE,
	SND_PCM_FORMAT_U20_3BE,
	SND_PCM_FORMAT_S18_3LE,
	SND_PCM_FORMAT_S18_3BE,
	SND_PCM_FORMAT_U18_3LE,
	SND_PCM_FORMAT_U18_3BE,
};

static const unsigned int rates[] = {
	5512,
	8000,
	11025,
	16000,
	22050,
	32000,
	44100,
	48000,
	64000,
	88200,
	96000,
	176400,
	192000,
};

int main(int argc, char *argv[])
{
	const char *device_name = "hw";
	snd_pcm_t *pcm;
	snd_pcm_hw_params_t *hw_params;
	unsigned int i;
	unsigned int min, max;
	int any_rate;
	int err;

	if (argc > 1)
		device_name = argv[1];

	err = snd_pcm_open(&pcm, device_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
	if (err < 0) {
		fprintf(stderr, "cannot open device '%s': %s\n", device_name, snd_strerror(err));
		return 1;
	}

	snd_pcm_hw_params_alloca(&hw_params);
	err = snd_pcm_hw_params_any(pcm, hw_params);
	if (err < 0) {
		fprintf(stderr, "cannot get hardware parameters: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}

	printf("Device: %s (type: %s)\n", device_name, snd_pcm_type_name(snd_pcm_type(pcm)));

	printf("Access types:");
	for (i = 0; i < ARRAY_SIZE(accesses); ++i) {
		if (!snd_pcm_hw_params_test_access(pcm, hw_params, accesses[i]))
			printf(" %s", snd_pcm_access_name(accesses[i]));
	}
	putchar('\n');

	printf("Formats:");
	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
		if (!snd_pcm_hw_params_test_format(pcm, hw_params, formats[i]))
			printf(" %s", snd_pcm_format_name(formats[i]));
	}
	putchar('\n');

	err = snd_pcm_hw_params_get_channels_min(hw_params, &min);
	if (err < 0) {
		fprintf(stderr, "cannot get minimum channels count: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	err = snd_pcm_hw_params_get_channels_max(hw_params, &max);
	if (err < 0) {
		fprintf(stderr, "cannot get maximum channels count: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	printf("Channels:");
	for (i = min; i <= max; ++i) {
		if (!snd_pcm_hw_params_test_channels(pcm, hw_params, i))
			printf(" %u", i);
	}
	putchar('\n');

	err = snd_pcm_hw_params_get_rate_min(hw_params, &min, NULL);
	if (err < 0) {
		fprintf(stderr, "cannot get minimum rate: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	err = snd_pcm_hw_params_get_rate_max(hw_params, &max, NULL);
	if (err < 0) {
		fprintf(stderr, "cannot get maximum rate: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	printf("Sample rates:");
	if (min == max)
		printf(" %u", min);
	else if (!snd_pcm_hw_params_test_rate(pcm, hw_params, min + 1, 0))
		printf(" %u-%u", min, max);
	else {
		any_rate = 0;
		for (i = 0; i < ARRAY_SIZE(rates); ++i) {
			if (!snd_pcm_hw_params_test_rate(pcm, hw_params, rates[i], 0)) {
				any_rate = 1;
				printf(" %u", rates[i]);
			}
		}
		if (!any_rate)
			printf(" %u-%u", min, max);
	}
	putchar('\n');

	err = snd_pcm_hw_params_get_period_time_min(hw_params, &min, NULL);
	if (err < 0) {
		fprintf(stderr, "cannot get minimum period time: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	err = snd_pcm_hw_params_get_period_time_max(hw_params, &max, NULL);
	if (err < 0) {
		fprintf(stderr, "cannot get maximum period time: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	printf("Interrupt interval: %u-%u us\n", min, max);

	err = snd_pcm_hw_params_get_buffer_time_min(hw_params, &min, NULL);
	if (err < 0) {
		fprintf(stderr, "cannot get minimum buffer time: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &max, NULL);
	if (err < 0) {
		fprintf(stderr, "cannot get maximum buffer time: %s\n", snd_strerror(err));
		snd_pcm_close(pcm);
		return 1;
	}
	printf("Buffer size: %u-%u us\n", min, max);

	snd_pcm_close(pcm);
	return 0;
}

_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@lists.linuxaudio.org
http://lists.linuxaudio.org/listinfo/linux-audio-dev

Reply via email to