Я пытаюсь написать программу C (на Linux), которая воспроизводит синусоидальную волну от динамиков, используя интерфейс ядра ALSA (минимальный воспроизводимый пример). < /p>
Я открываю FD, как это: < /p>
int controlfd = open("/dev/snd/controlC0",O_RDWR);
int subdev = 0;
ioctl(controlfd,SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE,&subdev)
close(controlfd);
int fd = open("/dev/snd/pcmC0D0p", O_RDWR | __O_CLOEXEC);
< /code>
Моя конфигурация выглядит следующим образом: < /p>
set_param(params,SNDRV_PCM_HW_PARAM_ACCESS,SNDRV_PCM_ACCESS_RW_INTERLEAVED);
set_param(params,SNDRV_PCM_HW_PARAM_FORMAT,SNDRV_PCM_FORMAT_S16_LE);
set_param(params,SNDRV_PCM_HW_PARAM_CHANNELS,2);
set_param(params,SNDRV_PCM_HW_PARAM_RATE,48000);
...
get_param_int(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,&period_size)
sparams->tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
sparams->period_step = 1;
sparams->avail_min = period_size;
sparams->start_threshold = ALSA_BUFFER_SIZE - period_size;
sparams->stop_threshold = ALSA_BUFFER_SIZE;
sparams->xfer_align = period_size / 2;
< /code>
И я пытаюсь воспроизводить звук здесь: < /p>
unsigned int numframes=48000;
short* samples = calloc(numframes,sizeof(short));
// generate frames
for (int i = 0; i < numframes; i++) {
samples[i] = 30000 * sinf(2 * M_PI * 200 *((float)i / (numframes)));
}
unsigned char *data = (unsigned char*)samples;
numframes*=4; // (sizeof(int16_t)/sizeof(byte))
struct snd_xferi xfer = { 0 };
int ret, avail;
if (ioctl(fd,SNDRV_PCM_IOCTL_PREPARE) < 0) pexit("ioctl SNDRV_PCM_IOCTL_PREPARE");
// play the frames
int correct_count = 0;
do {
xfer.buf = data;
xfer.frames = numframes > period_size ? period_size : numframes;
xfer.result = 0;
if(!(ret = ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xfer))) {
avail = mmap_status->hw_ptr + ALSA_BUFFER_SIZE - mmap_control->appl_ptr;
if(avail < 0) avail += boundary; else
if((unsigned int)avail >= boundary) avail -= boundary;
numframes -= xfer.result;
data += xfer.result * 4; // 4==channels*(int16_t/byte)
++correct_count;
} else if (errno == EPIPE) {
if (ioctl(fd,SNDRV_PCM_IOCTL_PREPARE) < 0) pexit("ioctl SNDRV_PCM_IOCTL_PREPARE");
} else {
ioctl(fd, SNDRV_PCM_IOCTL_DRAIN);
close(fd);
fprintf(stderr,"ioctl SNDRV_PCM_IOCTL_WRITEI_FRAMES failed after successfully sending %li bytes in %d portions: ", ((size_t)data-(size_t)samples),correct_count);
pexit("");
}
} while(numframes > 0);
< /code>
и после нескольких итераций цикла while и lecmiting ~ 0,1 секунды (всегда одного и того же) звука на моем ноутбуке, но не в виртуальной машине Qemu, программа всегда выходит с: < /p>
ioctl SNDRV_PCM_IOCTL_WRITEI_FRAMES failed after successfully sending 4096 bytes in 32 portions: Input/output error
... вместо того, чтобы записывать целые 48000 байтов в буфере
(и по какой -то причине 4096 - это то же число, что и Alsa_buffer_size macro)
x11 и федора quemu vm без pulseaudio или jack или даже asoundlib, и я проверил, этот звук работает в виртуальной машине.
Я пытаюсь написать программу C (на Linux), которая воспроизводит синусоидальную волну от динамиков, используя интерфейс ядра ALSA (минимальный воспроизводимый пример). < /p> Я открываю FD, как это: < /p> [code] int controlfd = open("/dev/snd/controlC0",O_RDWR); int subdev = 0; ioctl(controlfd,SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE,&subdev) close(controlfd); int fd = open("/dev/snd/pcmC0D0p", O_RDWR | __O_CLOEXEC); < /code> Моя конфигурация выглядит следующим образом: < /p> set_param(params,SNDRV_PCM_HW_PARAM_ACCESS,SNDRV_PCM_ACCESS_RW_INTERLEAVED); set_param(params,SNDRV_PCM_HW_PARAM_FORMAT,SNDRV_PCM_FORMAT_S16_LE); set_param(params,SNDRV_PCM_HW_PARAM_CHANNELS,2); set_param(params,SNDRV_PCM_HW_PARAM_RATE,48000); ... get_param_int(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,&period_size)
sparams->tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; sparams->period_step = 1; sparams->avail_min = period_size; sparams->start_threshold = ALSA_BUFFER_SIZE - period_size; sparams->stop_threshold = ALSA_BUFFER_SIZE; sparams->xfer_align = period_size / 2; < /code> И я пытаюсь воспроизводить звук здесь: < /p> unsigned int numframes=48000; short* samples = calloc(numframes,sizeof(short));
// generate frames for (int i = 0; i < numframes; i++) { samples[i] = 30000 * sinf(2 * M_PI * 200 *((float)i / (numframes))); }
if (ioctl(fd,SNDRV_PCM_IOCTL_PREPARE) < 0) pexit("ioctl SNDRV_PCM_IOCTL_PREPARE");
// play the frames int correct_count = 0; do { xfer.buf = data; xfer.frames = numframes > period_size ? period_size : numframes; xfer.result = 0; if(!(ret = ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xfer))) { avail = mmap_status->hw_ptr + ALSA_BUFFER_SIZE - mmap_control->appl_ptr; if(avail < 0) avail += boundary; else if((unsigned int)avail >= boundary) avail -= boundary; numframes -= xfer.result; data += xfer.result * 4; // 4==channels*(int16_t/byte) ++correct_count; } else if (errno == EPIPE) { if (ioctl(fd,SNDRV_PCM_IOCTL_PREPARE) < 0) pexit("ioctl SNDRV_PCM_IOCTL_PREPARE"); } else { ioctl(fd, SNDRV_PCM_IOCTL_DRAIN); close(fd); fprintf(stderr,"ioctl SNDRV_PCM_IOCTL_WRITEI_FRAMES failed after successfully sending %li bytes in %d portions: ", ((size_t)data-(size_t)samples),correct_count); pexit(""); } } while(numframes > 0); < /code> и после нескольких итераций цикла while и lecmiting ~ 0,1 секунды (всегда одного и того же) звука на моем ноутбуке, но не в виртуальной машине Qemu, программа всегда выходит с: < /p> ioctl SNDRV_PCM_IOCTL_WRITEI_FRAMES failed after successfully sending 4096 bytes in 32 portions: Input/output error [/code] ... вместо того, чтобы записывать целые 48000 байтов в буфере (и по какой -то причине 4096 - это то же число, что и Alsa_buffer_size macro) x11 и федора quemu vm без pulseaudio или jack или даже asoundlib, и я проверил, этот звук работает в виртуальной машине.