ALSA во встроенной системе — readi — ошибка ввода / вывода и зависание

Я все еще сталкиваюсь с проблемами при использовании захвата ALSA во встроенной системе.

Теперь я могу открыть устройство из библиотеки после использования snddevices скрипт. Но приложение возвращает сообщения об ошибках Input/output error (EIO) на readi звонки через время около 10 секунд для каждого звонка.
После попытки остановить устройство вся система зависает и требует полной перезагрузки.

Я не могу сказать, правильно ли установлен ALSA в системе. При запуске упоминается драйвер ALSA. Это version 1.0.18.rc3, Как я могу проверить, правильно ли установлены ALSA и / или устройства?

Вот мой тестовый код, пожалуйста, скажите, есть ли ошибка внутри. Я не уверен, что frame размеры и period Правильно ли настроен (я не очень разбираюсь в обработке звука) и нужно ли мне interleaved или же non-interleaved захватывать или не имеет значения.

#include <alsa/asoundlib.h>const char* print_pcm_state(snd_pcm_state_t state)
{
switch(state)
{
case SND_PCM_STATE_OPEN: return("SND_PCM_STATE_OPEN");
case SND_PCM_STATE_SETUP: return("SND_PCM_STATE_SETUP");
case SND_PCM_STATE_PREPARED: return("SND_PCM_STATE_PREPARED");
case SND_PCM_STATE_RUNNING: return("SND_PCM_STATE_RUNNING");
case SND_PCM_STATE_XRUN: return("SND_PCM_STATE_XRUN");
case SND_PCM_STATE_DRAINING: return("SND_PCM_STATE_DRAINING");
case SND_PCM_STATE_PAUSED: return("SND_PCM_STATE_PAUSED");
case SND_PCM_STATE_SUSPENDED: return("SND_PCM_STATE_SUSPENDED");
case SND_PCM_STATE_DISCONNECTED: return("SND_PCM_STATE_DISCONNECTED");
}
return "UNKNOWN STATE";
}int main(int argc, char* argv[])
{
int rc; int err;

// pcm state
snd_pcm_state_t pcm_state;
// handle
snd_pcm_t *handle;

// hardware to open
char *pcm_name;
pcm_name =  strdup("hw:0,0");

// parameters
snd_pcm_hw_params_t *params;

/* Open PCM device for playback. */
rc = snd_pcm_open(&handle, pcm_name, SND_PCM_STREAM_CAPTURE, 0);

if (rc < 0)
{

printf("unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}

// Allocate a hardware parameters object.
//  rc = snd_pcm_hw_params_alloca(&params); // original from a sample code, didn't compile?!?
rc = snd_pcm_hw_params_malloc(&params);
if(rc<0)
{
printf("cannot allocate hardware parameter structure (%s) ...\n", snd_strerror(rc));
}

/* Fill it in with default values. */
rc = snd_pcm_hw_params_any(handle, params);
if(rc<0)
{
printf("Error: (%s) ...\n", snd_strerror(rc));
}

bool interleaved = true;
// Set the desired hardware parameters.
if (interleaved)
{
// Interleaved mode
if ((rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
printf("cannot set access type (%s) ...\n", snd_strerror(rc));
return rc;
}
printf("access type = SND_PCM_ACCESS_RW_INTERLEAVED\n");
}
else
{
if ((rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_NONINTERLEAVED)) < 0)
{
printf("cannot set access type (%s) ...\n", snd_strerror(rc));
return rc;
}
printf("access type = SND_PCM_ACCESS_RW_NONINTERLEAVED\n");
}

// Signed 16-bit little-endian format
if ((rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE)) < 0) {
printf("cannot set sample format (%s) ...\n", snd_strerror(rc));
return 1;
}

// TODO: channel number important - will a bad channel number crash the whole capturing?
int nChannels = 2;
if ((rc = snd_pcm_hw_params_set_channels(handle, params, nChannels)) < 0) {
printf("cannot set channel count (%s) ...\n", snd_strerror(rc));
return 1;
}

// TODO: right?
unsigned int wanted_rate = 22000;
unsigned int exact_rate = wanted_rate;
if ((rc = snd_pcm_hw_params_set_rate_near(handle, params, &exact_rate, 0)) < 0) {
printf("cannot set sample rate (%s) ...\n", snd_strerror(rc));
return 1;
}

if (wanted_rate != exact_rate)
{
printf("The rate %i Hz is not supported by your hardware.\n""==> Using %i Hz instead.\n", wanted_rate, exact_rate);
}

// TODO: what about these parts? What are those "frames" and what are the "periods"?
// must this be set according to the hardware?!?
snd_pcm_uframes_t frames = 640;
int periods = 8;

// Set number of periods. Periods used to be called fragments.
if (snd_pcm_hw_params_set_periods(handle, params, periods, 0) < 0) {
printf("Error setting periods.\n");
return 1;
}

if ((err = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, 0)) < 0) {
fprintf(stderr, "Init: cannot set period_size (%s) ...\n", snd_strerror(err));
return err;
}

// TODO: is this the size needed for a single read-call?
snd_pcm_uframes_t buff_size = 0;
err = snd_pcm_hw_params_get_buffer_size(params, &buff_size);
if (err < 0) {
printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
return err;
}
printf("needed buffersize: %i \n", (int)buff_size);

pcm_state = snd_pcm_state(handle);
printf("0.m State: %s\n", print_pcm_state(pcm_state));

// what's this?
snd_pcm_sw_params_t*  swparams_c;

// snd_pcm_hw_params will call PREPARE internally!
if ((err = snd_pcm_hw_params(handle, params)) < 0) {
fprintf(stderr, "Init: cannot set parameters (%s) ...\n", snd_strerror(err));
return err;
}

pcm_state = snd_pcm_state(handle);
printf("0.n State: %s\n", print_pcm_state(pcm_state));

printf("capture\n");

// test: start device:
/*
err = snd_pcm_start(handle);
if(err < 0)
{
fprintf (stderr, "cannot start device (%s)\n",
snd_strerror (err));
exit (1);
}
*///state
pcm_state = snd_pcm_state(handle);
printf("1. State: %s\n", print_pcm_state(pcm_state));

// Is this ok?!?
//short buf[100*2048];
//short buf[5120*1024]; // seg-fault?!?
short buf[5120];

// only try to read a single time
int i=0;
for (i = 0; i < 1; ++i) {
if(interleaved)
{
if ((err = snd_pcm_readi (handle, buf, frames)) < 0)
//      if ((err = snd_pcm_writei (handle, buf, 1)) < 0)  // ioctl error
{
printf("EBADFD %i -> EPIPE %i -> ESTRPIPE %i\n",EBADFD,EPIPE,ESTRPIPE);
if(err == -EBADFD)
printf("-EBADFD: PCM is not in the right state (SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING) \n");
if(err == -EPIPE) printf("-EPIPE:   an overrun occurred \n");
if(err == -ESTRPIPE) printf("-ESTRPIPE: a suspend event occurred (stream is suspended and waiting for an application recovery)\n");

fprintf (stderr, "error %i : interleaved read from audio interface failed (%s)\n",
err, snd_strerror (err));

pcm_state = snd_pcm_state(handle);
printf("1.1 State: %s\n", print_pcm_state(pcm_state));
exit (1);
}
}
else
{
// TODO: is it hardware dependent whether I can exlusively use readi or readn?
// how does a readn call have to look like? needs multiple buffers?!?
printf("non-interleaved capture not implemented\n");//if ((err = snd_pcm_readn (handle, buf, frames)) != frames) {
//  fprintf (stderr, "non-interleaved read from audio interface failed (%s)\n",
//       snd_strerror (err));
//  exit (1);
//}
}
}

pcm_state = snd_pcm_state(handle);
printf("2. State: %s\n", print_pcm_state(pcm_state));

printf("close\n");

snd_pcm_close (handle);

pcm_state = snd_pcm_state(handle);
printf("3. State: %s\n", print_pcm_state(pcm_state));

printf("finish\n");
return 0;
}

производя этот вывод:

~ # ./audioTest
access type = SND_PCM_ACCESS_RW_INTERLEAVED
The rate 22000 Hz is not supported by your hardware.
==> Using 16000 Hz instead.
needed buffersize: 5120
0.m State: SND_PCM_STATE_OPEN
hello, alsa~.
0.n State: SND_PCM_STATE_PREPARED
capture
1. State: SND_PCM_STATE_PREPARED
EBADFD 77 -> EPIPE 32 -> ESTRPIPE 86
error -5 : interleaved read from audio interface failed (Input/output error)
1.1 State: SND_PCM_STATE_RUNNING

потом замерзает …

если я добавлю еще один блок параметризации перед capture печать (взято из эталонной реализации):

{
snd_pcm_uframes_t boundary = 0;
snd_pcm_sw_params_alloca(&swparams_c);
/* get the current swparams */
err = snd_pcm_sw_params_current(handle, swparams_c);
if (err < 0) {
printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
return err;
}

// what's this? necessary?
/*
//err = snd_pcm_sw_params_set_tstamp_mode(handle, swparams_c, SND_PCM_TSTAMP_ENABLE);
err = snd_pcm_sw_params_set_tstamp_mode(handle, swparams_c, SND_PCM_TSTAMP_MMAP);
if (err < 0) {
printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
return err;
}
*/

err = snd_pcm_sw_params_set_avail_min(handle, swparams_c, frames);
if (err < 0) {
printf("Unable to call snd_pcm_sw_params_set_avail_min(): %s\n", snd_strerror(err));
return err;
}

err = snd_pcm_sw_params_set_start_threshold(handle, swparams_c, (buff_size / frames) * frames);
if (err < 0) {
printf("Unable to call snd_pcm_sw_params_set_start_threshold(): %s\n", snd_strerror(err));
return err;
}

err =  snd_pcm_sw_params_get_boundary(swparams_c, &boundary);
if (err < 0) {
printf("Unable to call snd_pcm_sw_params_get_boundary(): %s\n", snd_strerror(err));
return err;
}err = snd_pcm_sw_params_set_stop_threshold(handle, swparams_c, boundary);
if (err < 0) {
printf("Unable to call snd_pcm_sw_params_set_stop_threshold(): %s\n", snd_strerror(err));
return err;
}

/* align all transfers to 1 sample */
err = snd_pcm_sw_params_set_xfer_align(handle, swparams_c, 1);
if (err < 0) {
printf("Unable to set transfer align for playback: %s\n", snd_strerror(err));
return err;
}

/* write the sw parameters */
err = snd_pcm_sw_params(handle, swparams_c);
if (err < 0) {
printf("Unable to set swparams_c : %s\n", snd_strerror(err));
return err;
}
}

Я получаю сообщения:

error -5 : interleaved read from audio interface failed (Input/output error)
2.1 State: SND_PCM_STATE_PREPARED

но не замерзать.
Так почему он может зависнуть, если устройство «работает»?

Любые предложения, что сделать, чтобы это устройство / код работал?

Извините за весь этот код, я не уверен, нужны ли все параметры. Если читать слишком сложно, скажите мне, может быть, лучше инкапсулировать всю часть инициализации для удобства чтения?

0

Решение

Второй случай (установка параметров программного обеспечения) приводит к неопределенному поведению, когда состояние ПОДГОТОВЛЕНО и вы читать меньше, чем start_threshold кадры. На самом деле происходит тайм-аут в процедуре ожидания, что приводит к ошибке EIO. Это более или менее ошибка. Я отправил пластырь исправить это.

В первом случае не должно было быть проблем. Когда параметры оборудования установлены, ALSA устанавливает значения по умолчанию для параметров программного обеспечения. start_threshold установлен в 1, Устройство запускается при первом чтении. Однако, кажется, есть другой тайм-аут, приводящий к EIO. Я исследую это и выложу здесь обновление, если обнаружу проблему в ядре ALSA. В любом случае это, вероятно, драйвер устройства, который не выдавал прерываний и не приводил к зависанию системы.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]