ALSA - чтение без блокировки (с чередованием) - PullRequest
1 голос
/ 04 июля 2019

Я унаследовал некоторый код ALSA, который работает на встроенной платформе Linux.Существующая реализация блокирует чтения и записи с использованием snd_pcm_readi() и snd_pcm_writei().

Мне поручено выполнить этот запуск на процессоре ARM, но я обнаружил, что заблокированное чередованное чтение читает pushЦП на 99%, поэтому я изучаю неблокирующие операции чтения и записи.

Я открываю устройство, как и следовало ожидать:

snd_pcm_handle *handle;
const char* hwname = "plughw:0"; // example name

snd_pcm_open(&handle, hwname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);

Затем происходят другие вещи ALSA, которые я могу предоставитьпо запросу.Следует отметить, что:

  • мы устанавливаем частоту дискретизации 48 000 [Гц]
  • , тип выборки имеет 32-разрядное целое число со знаком
  • устройство всегдапереопределяет запрошенный размер периода на 1024 кадра

Считывание потока следующим образом:

int32* buffer; // buffer set up to hold #period_size samples
int actual = snd_pcm_readi(handle, buffer, period_size);

Этот вызов занимает около 15 [мс] для завершения в режиме блокировки.Очевидно, переменная actual будет возвращать 1024 по возвращении.

Проблема в том, что;в режиме неблокирующем эта функция также требует 15 мсек для завершения и actual также всегда читает 1024 при возврате.

Я ожидаю, что функция вернется немедленно, с actual быть <= 1024 и вполне возможно читать «EAGAIN» (-11). </p>

Между попытками чтения я планирую перевести поток в спящий режим на определенное время, уступая процессорное время другим процессам.

Я неправильно понимаю API ALSA?Или может быть, в моем коде отсутствует жизненно важный шаг?

Ответы [ 2 ]

0 голосов
/ 12 июля 2019

Я решил свою проблему, обернув snd_pcm_readi() следующим образом:

/*
** Read interleaved stream in non-blocking mode
*/
template <typename SampleType>
snd_pcm_sframes_t snd_pcm_readi_nb(snd_pcm_t* pcm, SampleType* buffer, snd_pcm_uframes_t size, unsigned samplerate)
{
    const snd_pcm_sframes_t avail = ::snd_pcm_avail(pcm);
    if (avail < 0) {
        return avail;
    }

    if (avail < size) {

        snd_pcm_uframes_t remain = size - avail;
        unsigned long msec = (remain * 1000) / samplerate;

        static const unsigned long SLEEP_THRESHOLD_MS = 1;

        if (msec > SLEEP_THRESHOLD_MS) {
            msec -= SLEEP_THRESHOLD_MS;
            // exercise for the reader: sleep for msec
        }
    }

    return ::snd_pcm_readi(pcm, buffer, size);
}

Это работает довольно хорошо для меня.Мой аудио процесс теперь «только» занимает 19% процессорного времени.И это не имеет значения, если интерфейс PCM был открыт с помощью SND_PCM_NONBLOCK или 0.

Выполнение анализа callgrind, чтобы посмотреть, можно ли сохранить больше циклов ЦП в другом месте кода.

0 голосов
/ 04 июля 2019

Если функция возвращает значение 1024, то на момент вызова было доступно как минимум 1024 кадра.(Возможно, что 15 мс - это время, необходимое драйверу для фактического запуска устройства.)

В любом случае, режим блокировки или неблокирования не влияет на загрузку процессора.Чтобы уменьшить нагрузку на процессор, замените устройство default на plughw или hw, но тогда вы потеряете такие функции, как совместное использование устройства или преобразование частоты дискретизации / формата.

...