On Thu, Dec 14, 2023 at 11:41:55PM +0100, Sebastien Alaiwan wrote: > Hi, > > I've been running some experiments on the Behringer UMC1820, which is a USB audio interface, supposedly class-compliant. > I wrote a tiny program "alsa-sine" that simply plays silence on a given ALSA device ( please find the source for it at the bottom of this message ). > This tiny program allows to specify the buffer size, and the period size ( Here, I'll always be using a buffer size of 256 ). > > Here, i'm testing 5 values for the period size (the last command line argument). All period sizes work, except ... 127. Hi Sebastien, See https://www.alsa-project.org/wiki/FramesPeriods Common period sizes are 2 or 3 since this is the number of times the hardware will interrupt per buffer. It's curious behavior you have found but I don't think it's a bug. Regards, Geraldo Nascimento > See below: > > $ ./alsa_sine 'hw:CARD=UMC1820,DEV=0' 256 125 > buffer_size=256 (asked 256), period_size=125 (asked 125), channels=12, format=S24_3LE (24 bpp) > OK > > $ ./alsa_sine 'hw:CARD=UMC1820,DEV=0' 256 126 > buffer_size=256 (asked 256), period_size=126 (asked 126), channels=12, format=S24_3LE (24 bpp) > OK > > $ ./alsa_sine 'hw:CARD=UMC1820,DEV=0' 256 127 > buffer_size=256 (asked 256), period_size=127 (asked 127), channels=12, format=S24_3LE (24 bpp) > [alsa_sine.c:66] error: snd_pcm_drain(pcm) : Input/output error > Aborting. > > $ ./alsa_sine 'hw:CARD=UMC1820,DEV=0' 256 128 > buffer_size=256 (asked 256), period_size=128 (asked 128), channels=12, format=S24_3LE (24 bpp) > OK > > $ ./alsa_sine 'hw:CARD=UMC1820,DEV=0' 256 129 > buffer_size=256 (asked 256), period_size=128 (asked 129), channels=12, format=S24_3LE (24 bpp) > OK > > I also own a Virus TI, which also implements an USB audio interface, also supposedly class-compliant. > So I ran the same test on it, and interestingly, there's no error: > > $ ./alsa_sine 'hw:CARD=TI,DEV=0' 256 125 > buffer_size=256 (asked 256), period_size=125 (asked 125), channels=2, format=S16_LE (16 bpp) > OK > > $ ./alsa_sine 'hw:CARD=TI,DEV=0' 256 126 > buffer_size=256 (asked 256), period_size=126 (asked 126), channels=2, format=S16_LE (16 bpp) > OK > > $ ./alsa_sine 'hw:CARD=TI,DEV=0' 256 127 > buffer_size=256 (asked 256), period_size=127 (asked 127), channels=2, format=S16_LE (16 bpp) > OK > > $ ./alsa_sine 'hw:CARD=TI,DEV=0' 256 128 > buffer_size=256 (asked 256), period_size=128 (asked 128), channels=2, format=S16_LE (16 bpp) > OK > > $ ./alsa_sine 'hw:CARD=TI,DEV=0' 256 129 > buffer_size=256 (asked 256), period_size=128 (asked 129), channels=2, format=S16_LE (16 bpp) > OK > > So at this point, I'm wondering if I might be doing something wrong. I'm not trying to achieve anything here other than trying to understand what's going on. > Maybe the UMC1820 doesn't support a period size of 127 ? ( does it even make sense to say this? ) If so, how is it possible for an application to know about this limitation? > Maybe my test program is simply incorrect, and it's behavior is undefined? But then, how can we explain the difference in behavior between the UMC1820 and the Virus TI ? > > My kernel version is: Linux ANTEC 6.5.0-5-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.5.13-1 (2023-11-29) x86_64 GNU/Linux > Also, Debian tells me I'm using the package: libasound 1.2.10-1 > > BTW, please let me know if this is not the proper mailing list to talk about such things! > > Thanks, > Sebastien Alaiwan > > > > > > > //--------------------------------------------------------------- > // gcc alsa_sine.c -lasound > #include <alsa/asoundlib.h> > #include <stdio.h> > > const int SampleRate = 48000; > > void checkCall(int ret, const char* expr, const char* file, int line) > { > if(ret < 0) > { > fprintf(stderr, "[%s:%d] error: %s : %s\nAborting.\n", file, line, expr, snd_strerror(ret)); > exit(1); > } > } > > #define CHECK_CALL(a) checkCall(a, # a, __FILE__, __LINE__) > > int main(int argc, char* argv[]) > { > if(argc != 4) > { > fprintf(stderr, "Usage: %s <device> <buffer_size> <period_size>\n", argv[0]); > return 1; > } > > const char* devName = argv[1]; > const snd_pcm_uframes_t asked_buffer_size = atoi(argv[2]); > const snd_pcm_uframes_t asked_period_size = atoi(argv[3]); > > snd_pcm_t* pcm = NULL; > CHECK_CALL(snd_pcm_open(&pcm, devName, SND_PCM_STREAM_PLAYBACK, 0)); > > snd_pcm_hw_params_t* hw_params = NULL; > CHECK_CALL(snd_pcm_hw_params_malloc(&hw_params)); > CHECK_CALL(snd_pcm_hw_params_any(pcm, hw_params)); > > snd_pcm_format_t fmt; > unsigned int channels = 0; > CHECK_CALL(snd_pcm_hw_params_get_format(hw_params, &fmt)); > CHECK_CALL(snd_pcm_hw_params_get_channels_min(hw_params, &channels)); > > snd_pcm_uframes_t buffer_size = asked_buffer_size; > snd_pcm_uframes_t period_size = asked_period_size; > CHECK_CALL(snd_pcm_hw_params_set_rate(pcm, hw_params, SampleRate, 0)); > CHECK_CALL(snd_pcm_hw_params_set_access(pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)); > CHECK_CALL(snd_pcm_hw_params_set_buffer_size_near(pcm, hw_params, &buffer_size)); > CHECK_CALL(snd_pcm_hw_params_set_period_size_near(pcm, hw_params, &period_size, NULL)); > CHECK_CALL(snd_pcm_hw_params(pcm, hw_params)); > snd_pcm_hw_params_free(hw_params); > > printf("buffer_size=%d (asked %d), ", (int)buffer_size, (int)asked_buffer_size); > printf("period_size=%d (asked %d), ", (int)period_size, (int)asked_period_size); > printf("channels=%d, ", channels); > printf("format=%s (%d bpp)\n", snd_pcm_format_name(fmt), snd_pcm_format_width(fmt)); > > const int totalSamples = SampleRate * 1.0; > > int bitsPerSample = snd_pcm_format_width(fmt); > assert(bitsPerSample % 8 == 0); > int size = totalSamples * channels * bitsPerSample / 8; > uint8_t* buffer = (uint8_t*)malloc(size); > memset(buffer, 0, size); > CHECK_CALL(snd_pcm_writei(pcm, buffer, totalSamples)); > free(buffer); > > CHECK_CALL(snd_pcm_drain(pcm)); > snd_pcm_close(pcm); > > printf("OK\n"); > return 0; > } > //--------------------------------------------------------------- > >