奇怪的PulseAudio监视设备行为 [英] Strange PulseAudio monitor device behaviour

查看:206
本文介绍了奇怪的PulseAudio监视设备行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

异常的PulseAudio监视设备(即播放输入到扬声器的声音的音频输入设备)行为。我已将我的真实项目中的代码简化为基于PulseAudio docs https://freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html ,我只添加了时间限制并读取了字节计数。例如,它可以工作30秒,并打印读取的字节数。问题是,如果在程序运行期间播放某些内容,字节数会大大不同。我已经执行了此程序,并并行执行了bash for 循环,其中包括 aplay 和短的 tada .wav 文件。相差9%。为了进一步测试,我尝试与PulseAudio示例并行运行4个这样的循环,差异甚至更大-34%。但是,如果不是用短波来代替几个 aplay ,而是用长mp3文件运行 mplayer -没有这种区别,字节计数类似于没有声音播放的情况。

Faced strange PulseAudio monitor device (i.e. audio input device which plays sound sent to speaker) behaviour. 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. It works for example 30 seconds and prints read bytes count. 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. Difference is 9%. To test it more, I tried to run 4 such loops in parallel with PulseAudio example and difference is even more - 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.

这种行为会导致我的真实项目中的声音处理代码失败,所以如果有人可以提出解决方法-我会非常感激的。

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.

在Windows上基于Qt的类似代码,并使用Stereo Mixer设备作为PulseAudio监视器的类似物,都可以正常工作。

Similar code on Windows, Qt based and using Stereo Mixer device as analog of PulseAudio monitor works without such problems.

这是我的基于PulseAudio文档示例的代码:

Here is my code based on example from PulseAudio docs:

#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

我从 http://d0.waper.ru/f/462151/23/HgDwimvX37CwxWqW38eywg%2C1485353628/7d74/9/462151.wav/tada.wav

这是测试结果:

测试1.扬声器无声音

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

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

测试2。 Bash for 循环在序列1 22中为i进行;播放tada.wav;完成,背景中包含简短的wav文件。字节计数增加了 5798912/5323776 = 1.089 次。

Test 2. Bash for loop "for i in seq 1 22; do aplay tada.wav; done" with short wav files in background. Bytes count increase is 5798912 / 5323776 = 1.089 times.

$ 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 次。

Test 3. 4 Bash for loops with short wav files in background. Bytes count increase is 7129088 / 5323776 = 1.339 times.

$ 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 ,即没有明显的字节数差异。

Test 4. mplayer with long mp3 in background. 5288960 / 5323776 = 0.993, i.e. no significant bytes count difference.

$ 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:我的系统配置:

P.S.: Configuration of my system:


  • OS Ubuntu 16.04.1 amd64

  • pulseaudio 1:8.0-0ubuntu3.2

  • alsa-base 1.0.25 + dfsg-0ubuntu5

推荐答案

以下是PulseAudio邮件列表 https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-January/027412.html 。不是一个完整的答案,而是一些解释和解决方法:

Here is reply from Tanu Kaskinen from PulseAudio mailing list https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-January/027412.html . Not a full answer, but a little explanation and workaround:


您可能遇到了一个已知的错误,该错误与$ b中的倒带处理有关$ b监视源(在这种情况下,已知表示症状为
,但不是确切原因)。当流开始播放受监视的
接收器时,接收器将重写其回放缓冲区内容
(这称为倒带),这会导致监视器
源中的故障(根据您的实验判断,一些额外的音频显然会推送到录制的
流中)。我希望有一天能解决这个问题,
,但看起来在不久的将来我不会有时间。如果
您有时间和动力去调查和修复错误,那么
真是棒极了。

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.

作为一种解决方法,您可以减少通过减小播放缓冲区的大小来确定错误的大小。为此,请将
tsched_buffer_size = X传递到/etc/pulse/default.pa
中的module-udev-detect(将X替换为字节大小的缓冲区)。

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)."

这篇关于奇怪的PulseAudio监视设备行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆