2017-01-25 25 views
0

Столкнувшись с необычным устройством мониторинга PulseAudio (то есть устройством ввода звука, которое воспроизводит звук, отправленный динамику). Я уменьшил код от моего реального проекта до простого примера на основе кода из PulseAudio docs https://freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html, я добавил только ограничение по времени и чтение байтов. Он работает, например, 30 секунд и печатает количество считанных байтов. Проблема в том, что количество байтов значительно отличается, если во время прогона программы происходит что-то. Я выполнил эту программу и параллельно выполнил bash for цикл, состоящий из aplay с коротким tada.wav файлом. Разница составляет 9%. Чтобы проверить его больше, я попытался запустить 4 таких цикла параллельно с примером PulseAudio, а разница еще больше - 34%. Но если вместо нескольких aplay с коротким wav я запускаю mplayer с длинным mp3-файлом - такой разницы нет, количество байт похоже на случай, когда звук не воспроизводится.Поведение монитора монитора Strange PulseAudio

Такое поведение вызывает отказ в обработке кода обработки звука в моем реальном проекте, поэтому, если кто-то может предложить, как его решить, я буду очень благодарен.

Аналогичный код на Windows, основанном на Qt и использующем устройство Stereo Mixer в качестве аналога монитора PulseAudio, без таких проблем работает.

Вот мой код, основанный на примере из PulseAudio документации:

#ifdef HAVE_CONFIG_H 
#include <config.h> 
#endif 

#include <iostream> 
#include <chrono> 

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

#include <pulse/simple.h> 
#include <pulse/error.h> 

#define BUFSIZE 1024 

using namespace std; 
using namespace std::chrono; 

int main(int argc, char *argv[]) 
{ 
    int duration = 30000; 
    int64_t readBytesCounter = 0; 
    milliseconds msStart = duration_cast<milliseconds>(system_clock::now().time_since_epoch()); 

    /* The sample type to use */ 
    static const pa_sample_spec ss = { 
     .format = PA_SAMPLE_S16LE, 
     .rate = 44100, 
     .channels = 2 
    }; 
    pa_simple *s = NULL; 
    int ret = 1; 
    int error; 
    /* Create the recording stream */ 
    if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor", "record", &ss, NULL, NULL, &error))) { 
     fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); 
     goto finish; 
    } 
    for (;;) { 
     uint8_t buf[BUFSIZE]; 
     /* Record some data ... */ 
     if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { 
      fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); 
      goto finish; 
     } 
     readBytesCounter += BUFSIZE; 

     milliseconds msCurrent = duration_cast<milliseconds>(system_clock::now().time_since_epoch()); 
     int elapsed = msCurrent.count() - msStart.count(); 
     if (elapsed > duration) 
     { 
      cerr << int(elapsed/1000) << " seconds elapsed, terminating" << endl; 
      cerr << readBytesCounter << " bytes read" << endl; 
      goto finish; 
     } 
    } 
    ret = 0; 
finish: 
    if (s) 
     pa_simple_free(s); 
    return ret; 
} 

Он может быть построен с помощью следующей команды:

g++ -o main main.cpp -lpulse -lpulse-simple -std=c++11 

Пример Wav файл я взял из http://d0.waper.ru/f/462151/23/HgDwimvX37CwxWqW38eywg%2C1485353628/7d74/9/462151.wav/tada.wav

И вот результаты испытаний:

Тест 1. Нет звука в spea кег

$ time ./main 
30 seconds elapsed, terminating 
5323776 bytes read 

real 0m30.028s 
user 0m0.168s 
sys  0m0.388s 

Тест 2. Баш for петля «для г в последовательности 1 22; сделать aplay tada.wav; сделано»с короткими Wav файлов в фоновом режиме. Bytes подсчитывать увеличение 5798912/5323776 = 1.089 раз.

$ time ./main 
30 seconds elapsed, terminating 
5798912 bytes read 

real 0m30.023s 
user 0m0.120s 
sys  0m0.184s 

Тест 3. 4 Bash for петли с короткими файлами WAV в фоновом режиме. Bytes рассчитывать увеличение 7129088/5323776 = 1.339 раз.

$ time ./main 
30 seconds elapsed, terminating 
7129088 bytes read 

real 0m30.019s 
user 0m0.164s 
sys  0m0.196s 

Тест 4. mplayer с длинным mp3 в фоновом режиме. 5288960/5323776 = 0.993, т.е. никаких существенных байт не считать разницу.

$ time ./main 
30 seconds elapsed, terminating 
5288960 bytes read 

real 0m30.024s 
user 0m0.096s 
sys  0m0.204s 

Пытался выполнить набор каждого теста, усредненное количество байтов - аналогичную разницу.

PS: Конфигурация моей системы:

  • ОС Ubuntu 16.04.1 amd64
  • PulseAudio 1: 8.0-0ubuntu3.2
  • ALSA база 1.0.25 + DFSG-0ubuntu5

ответ

1

Это ответ от Tanu Kaskinen из списка рассылки PulseAudio https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-January/027412.html.Не полный ответ, но немного объяснения и обходной путь:

Вы, вероятно, ударяя известную ошибку, мы с обработкой в ​​ источниках монитора перемотки («известной» в данном случае означают, что симптомы известно, но не точная причина). Когда поток начнет воспроизводиться на приемнике , приемник перепишет его содержимое буфера воспроизведения (это называется перемоткой), и это вызывает сбой на мониторе источник (некоторые дополнительные аудио, по-видимому, попадают на запись поток, судя по вашим экспериментам). Надеюсь исправить это однажды, , но это не похоже, что у меня будет время для этого в ближайшем будущем. Если у вас есть время и мотивация для расследования и исправления ошибки, то будет потрясающе.

В качестве обходного пути вы, вероятно, можете уменьшить величину ошибки, уменьшив размер буфера воспроизведения. Чтобы сделать это, передать tsched_buffer_size = X в модуль-Udev обнаружение в /etc/pulse/default.pa (замените X с размером буфера в байтах).»