[英]Strange PulseAudio monitor device behaviour
面临奇怪的 PulseAudio 监控设备(即播放发送到扬声器的声音的音频输入设备)行为。 我已根据 PulseAudio 文档https://freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html 的代码将实际项目中的代码简化为简单示例,我只添加了时间限制和读取字节数数。 它工作例如 30 秒并打印读取的字节数。 问题是如果在程序运行期间播放某些内容,则字节数会大不相同。 我已经执行了这个程序,并并行执行了 bash for
循环,其中包含带有短tada.wav
文件的aplay
。 差异为 9%。 为了进行更多测试,我尝试与 PulseAudio 示例并行运行 4 个这样的循环,差异甚至更多 - 34%。 但是,如果我运行带有长 mp3 文件的mplayer
而不是使用短 wav 的几个aplay
- 没有这种区别,字节数类似于没有播放声音的情况。
这种行为会导致我的真实项目中的声音处理代码失败,所以如果有人能建议如何解决它 - 我将不胜感激。
Windows 上的类似代码,基于 Qt 并使用立体声混音器设备作为 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
我从http://d0.waper.ru/f/462151/23/HgDwimvX37CwxWqW38eywg%2C1485353628/7d74/9/462151.wav/tada.wav 获取的示例 wav 文件
以下是测试结果:
测试 1. 扬声器没有声音
$ time ./main
30 seconds elapsed, terminating
5323776 bytes read
real 0m30.028s
user 0m0.168s
sys 0m0.388s
测试 2. Bash for
循环“for i in seq 1 22; do aplay tada.wav; done”在后台使用短 wav 文件。 字节数增加是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 文件。 字节数增加是7129088 / 5323776 = 1.339
倍。
$ time ./main
30 seconds elapsed, terminating
7129088 bytes read
real 0m30.019s
user 0m0.164s
sys 0m0.196s
测试 4. 背景为长 mp3 的mplayer
。 5288960 / 5323776 = 0.993
,即没有重要的字节数差异。
$ time ./main
30 seconds elapsed, terminating
5288960 bytes read
real 0m30.024s
user 0m0.096s
sys 0m0.204s
尝试执行一组每个测试,平均字节数 - 类似的差异。
PS:我的系统配置:
这是来自 PulseAudio 邮件列表https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-January/027412.html 的Tanu Kaskinen 的回复。 不是完整的答案,而是一些解释和解决方法:
您可能遇到了我们在监视器源中进行倒带处理时遇到的已知错误(“已知”在这种情况下表示已知症状,但不知道确切原因)。 当流开始播放到受监控的接收器时,接收器将重写其播放缓冲区内容(这称为“倒带”),这会导致监控源出现故障(一些额外的音频显然被推送到记录流,判断从你的实验)。 我希望有一天能解决这个问题,但在不久的将来我似乎没有时间解决这个问题。 如果您有时间和动力来调查和修复错误,那就太棒了。
作为一种解决方法,您可能可以通过减少播放缓冲区大小来减少错误的幅度。 为此,请将 tsched_buffer_size=X 传递给 /etc/pulse/default.pa 中的 module-udev-detect(将 X 替换为以字节为单位的缓冲区大小)。”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.