奇怪的 PulseAudio 监控设备行为

Posted

技术标签:

【中文标题】奇怪的 PulseAudio 监控设备行为【英文标题】:Strange PulseAudio monitor device behaviour 【发布时间】:2017-06-10 08:45:07 【问题描述】:

面对奇怪的 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 文件 - 没有这样的区别,字节数类似于没有声音播放的情况。

这种行为会导致我的实际项目中的声音处理代码失败,所以如果有人可以建议如何解决它 - 我将非常感激。

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

我从 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 loop "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.mplayer,背景为长 mp3。 5288960 / 5323776 = 0.993,即没有明显的字节数差异。

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

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

尝试执行一组每个测试,平均字节数 - 相似的差异。

P.S.:我的系统配置:

操作系统 Ubuntu 16.04.1 amd64 pulseaudio 1:8.0-0ubuntu3.2 alsa-base 1.0.25+dfsg-0ubuntu5

【问题讨论】:

【参考方案1】:

这是来自 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 替换为以字节为单位的缓冲区大小)。”

【讨论】:

以上是关于奇怪的 PulseAudio 监控设备行为的主要内容,如果未能解决你的问题,请参考以下文章

奇怪的缩放和尺寸行为与设备工具栏和 chrome 和边缘的响应式布局

“NSString stringWithFormat:”在 32 位设备中具有“%zd”奇怪行为

带有 Xcode 4.3.1 的 iOS 5.1:[UIColor colorWithPatternImage:] 奇怪的行为仅在设备上

AudioServicesPlaySystemSound 奇怪的行为

ubuntu18.04 PulseAudio蓝牙耳机开启mic的解决办法

不同 API 上的奇怪自定义 SeekBar 可绘制行为