2017-01-25 35 views
0

面對奇怪的PulseAudio監視器設備(即播放發送到揚聲器的聲音的音頻輸入設備)行爲。我將代碼從我的真實項目簡化爲基於PulseAudio文檔代碼的簡單示例https://freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html,我只添加了時間限制和讀取字節計數。它工作例如30秒並打印讀取字節數。問題是如果在程序運行過程中播放某些內容,則字節數會大大不同。我已經執行了這個程序並行執行bash for循環組成aplay與短tada.wav文件。差異是9%。爲了進一步測試,我嘗試了與PulseAudio例子並行運行4個這樣的循環,差異甚至更大--34%。但如果不是幾個aplay與短wav我運行mplayer長mp3文件 - 沒有這種差異,字節計數類似於沒有聲音播放時的情況。奇怪的PulseAudio監視器設備行爲

這樣的行爲會導致聲音處理代碼在我的真實項目中失敗,所以如果有人可以建議如何解決它 - 我將非常感激。

在基於Qt的Windows上使用類似的代碼,並且使用立體聲混音器設備作爲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 KER

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

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

試驗2擊for環「對i在SEQ 1 22;做aplay tada.wav;完成」在後臺短WAV文件。字節數增加5798912/5323776 = 1.089倍。

​​

測試3. 4猛砸for迴路短wav文件的背景。字節數增加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:我的系統的配置:

  • OS的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的回覆。不是一個完整的答案,但一點點的解釋和解決辦法:

你可能打一個已知的bug,我們有退在 監聽源處理(「已知」在這種情況下,意味着該症狀是 知道,但不是確切的原因)。當一個數據流開始播放到 受監控接收器時,接收器將重寫其播放緩衝區內容 (這稱爲「倒帶」),這會導致顯示器 源中出現毛刺(某些額外的音頻顯然會被推到錄音中 流,從您的實驗判斷)。我希望有一天能解決這個問題, ,但看起來我不會在不久的將來有時間。如果 你有時間和動力來調查和修復這個bug,那麼 會很棒。

作爲解決方法,您可以通過減少回放緩衝區大小來減少錯誤的大小。要做到這一點,請通過/etc/pulse/default.pa (將X替換爲緩衝區大小(以字節爲單位))將tsched_buffer_size = X傳遞到module-udev-detect。「