简体   繁体   English

奇怪的 PulseAudio 监控设备行为

[英]Strange PulseAudio monitor device behaviour

Faced strange PulseAudio monitor device (ie audio input device which plays sound sent to speaker) behaviour.面临奇怪的 PulseAudio 监控设备(即播放发送到扬声器的声音的音频输入设备)行为。 I've reduced code from my real project to simple example based on code from PulseAudio docs https://freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html , I've only added time limit and read bytes counting.我已根据 PulseAudio 文档https://freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html 的代码将实际项目中的代码简化为简单示例,我只添加了时间限制和读取字节数数。 It works for example 30 seconds and prints read bytes count.它工作例如 30 秒并打印读取的字节数。 Problem is that bytes count vastly differs if something is played during program run.问题是如果在程序运行期间播放某些内容,则字节数会大不相同。 I've executed this program and in parallel executed bash for loop consisting aplay with short tada.wav file.我已经执行了这个程序,并并行执行了 bash for循环,其中包含带有短tada.wav文件的aplay Difference is 9%.差异为 9%。 To test it more, I tried to run 4 such loops in parallel with PulseAudio example and difference is even more - 34%.为了进行更多测试,我尝试与 PulseAudio 示例并行运行 4 个这样的循环,差异甚至更多 - 34%。 But if instead of several aplay with short wav I run mplayer with long mp3 file - there is no such difference, bytes count is similar to case when no sound is played.但是,如果我运行带有长 mp3 文件的mplayer而不是使用短 wav 的几个aplay - 没有这种区别,字节数类似于没有播放声音的情况。

Such behaviour causes failure of sound processing code in my real project, so if somebody could suggest how to solve it - I'll be very grateful.这种行为会导致我的真实项目中的声音处理代码失败,所以如果有人能建议如何解决它 - 我将不胜感激。

Similar code on Windows, Qt based and using Stereo Mixer device as analog of PulseAudio monitor works without such problems. Windows 上的类似代码,基于 Qt 并使用立体声混音器设备作为 PulseAudio 监视器的模拟,没有此类问题。

Here is my code based on example from PulseAudio docs:这是我基于 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;
}

It could be built with following command:它可以使用以下命令构建:

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

Example wav file i've taken from http://d0.waper.ru/f/462151/23/HgDwimvX37CwxWqW38eywg%2C1485353628/7d74/9/462151.wav/tada.wav我从http://d0.waper.ru/f/462151/23/HgDwimvX37CwxWqW38eywg%2C1485353628/7d74/9/462151.wav/tada.wav 获取的示例 wav 文件

And here are test results:以下是测试结果:

Test 1. No sound in speaker测试 1. 扬声器没有声音

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

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

Test 2. Bash for loop "for i in seq 1 22; do aplay tada.wav; done" with short wav files in background.测试 2. Bash for循环“for i in seq 1 22; do aplay tada.wav; done”在后台使用短 wav 文件。 Bytes count increase is 5798912 / 5323776 = 1.089 times.字节数增加是5798912 / 5323776 = 1.089倍。

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

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

Test 3. 4 Bash for loops with short wav files in background.测试 3。4 Bash for循环在后台使用短 wav 文件。 Bytes count increase is 7129088 / 5323776 = 1.339 times.字节数增加是7129088 / 5323776 = 1.339倍。

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

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

Test 4. mplayer with long mp3 in background.测试 4. 背景为长 mp3 的mplayer 5288960 / 5323776 = 0.993 , ie no significant bytes count difference. 5288960 / 5323776 = 0.993 ,即没有重要的字节数差异。

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

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

Tried to execute a set of each test, averaged bytes count - similar difference.尝试执行一组每个测试,平均字节数 - 类似的差异。

PS: Configuration of my system: PS:我的系统配置:

  • OS Ubuntu 16.04.1 amd64操作系统 Ubuntu 16.04.1 amd64
  • pulseaudio 1:8.0-0ubuntu3.2脉冲音频 1:8.0-0ubuntu3.2
  • alsa-base 1.0.25+dfsg-0ubuntu5 alsa-base 1.0.25+dfsg-0ubuntu5

Here is reply from Tanu Kaskinen from PulseAudio mailing list https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-January/027412.html .这是来自 PulseAudio 邮件列表https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-January/027412.html 的Tanu Kaskinen 的回复。 Not a full answer, but a little explanation and workaround:不是完整的答案,而是一些解释和解决方法:

You're probably hitting a known bug we have with rewind handling in monitor sources ("known" means in this case that the symptoms are known, but not the exact cause).您可能遇到了我们在监视器源中进行倒带处理时遇到的已知错误(“已知”在这种情况下表示已知症状,但不知道确切原因)。 When a stream starts to play to the monitored sink, the sink will rewrite its playback buffer contents (this is called "rewinding"), and this causes a glitch in the monitor source (some extra audio apparently gets pushed to the recording stream, judging from your experiments).当流开始播放到受监控的接收器时,接收器将重写其播放缓冲区内容(这称为“倒带”),这会导致监控源出现故障(一些额外的音频显然被推送到记录流,判断从你的实验)。 I hope to fix this some day, but it doesn't look like I'll have time for it in the near future.我希望有一天能解决这个问题,但在不久的将来我似乎没有时间解决这个问题。 If you have the time and motivation to investigate and fix the bug, that would be awesome.如果您有时间和动力来调查和修复错误,那就太棒了。

As a workaround, you can probably reduce the magnitude of the error by reducing the playback buffer size.作为一种解决方法,您可能可以通过减少播放缓冲区大小来减少错误的幅度。 To do that, pass tsched_buffer_size=X to module-udev-detect in /etc/pulse/default.pa (replace X with the buffer size in bytes)."为此,请将 tsched_buffer_size=X 传递给 /etc/pulse/default.pa 中的 module-udev-detect(将 X 替换为以字节为单位的缓冲区大小)。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM