c - Pulseaudio 的 pa_simple_read() 输出 0-5 或 248-255
问题描述
我正在尝试学习使用 pulseaudio 的 Simple API for C。当我意识到我收到的值没有意义时,我开始有所收获。起初他们在 ~64-66 和 0 之间交换。即像这样的“65 0 64 0 65 0 66 0 64 0”。然后,过了一会儿(也许我做了一些事情来促使这种变化?)我开始得到非常低或非常高的值,没有介于两者之间。更奇怪的是,这些值是 4 的系列。即 n 个小数后面跟着 m 个大数,其中 n 和 m 是 4 的倍数。
偶尔会有一些数字不是那么极端,但非常罕见。
这是代码:
#include <pulse/simple.h>
#include <pulse/sample.h>
#include <pulse/error.h>
#include <stdio.h>
int main() {
pa_simple *s;
pa_sample_spec ss;
ss.format = PA_SAMPLE_S16NE;
ss.channels = 2;
ss.rate = 44100;
int error;
s = pa_simple_new(
NULL,
"PulseAudioTest",
PA_STREAM_RECORD,
NULL,
"My test",
&ss,
NULL,
NULL,
&error
);
if(!s)
printf("error: %s", pa_strerror(error));
uint8_t buf[1024];
while(1) {
pa_simple_read(s, buf, sizeof(buf), NULL);
for(int i = 0; i < sizeof(buf); i++)
printf("%d,", buf[i]);
printf("\n-----------\n"); // just here for me separating the data, im not playing this back
}
if(s)
pa_simple_free(s);
else
printf("error\n");
return 0;
}
和一些示例输出:https ://pastebin.com/FgFekmf0 。
我也尝试过http://0pointer.de/lennart/projects/pulseaudio/doxygen/parec-simple_8c-example.html中的 parec.c 和 pacat.c ,但是当我播放录音时,它只是静态的。我还尝试切换默认接收器并通过默认和非默认接收器播放音乐。
此外,如果有人对在哪里学习使用它(以及音频的一般工作方式)有任何建议,我会喜欢建议(即使只是我对谷歌的一个术语 - 我花了一段时间才知道输出是“pcm”,甚至是什么)。
解决方案
为什么代码打印值以零分隔,即“65 0 64 0 65 0 66 0 64 0 ...”?
通常,默认的录制音频规范是编写在您的代码中的规范:
/* Each sample is Signed 16-bit integer recorded in little-endian (the Native
* Endian in intel x86 and x86-64).
*/
ss.format = PA_SAMPLE_S16NE;
/* There are 2 channels. */
ss.channels = 2;
/* Sample rate is 44100 Hz. */
ss.rate = 44100;
/* This is how audio samples are arranged. Given a stream of samples
*
* ADDR 0x0 0x2 0x4 0x6 0x8 0xA
* SAMPLE 12345, 13579, -185, -3, -9876, -9999, ...
* |-----||-----||-----||-----||-----||-----|
* CH1 CH2 CH1 CH2 CH1 CH2
* |------------||------------||------------|
* FRAME FRAME FRAME
*/
给定一个值为 65 的样本,其十六进制为 0x0041,使用little-endian,它将存储41 00
在内存中。buf
请注意,您的代码逐字节打印,这就是您得到65 0
. 因此,对于样本流 65、64、65,...,您将打印65 0 64 0 65 0 ...
.
试过parec
and pacat
,但只有静态噪音。如何让它发挥作用?
确保音频输入(麦克风)未静音且音量合适。运行pavucontrol
,进入“输入设备”选项卡,取消麦克风静音,并调整音量。发出一些噪音,您应该会看到信号条(在音量条下方)跳跃。
PulseAudio 附带了几个录音和播放实用程序(libpulse
arch 中的软件包pulseaudio-utils
,debian 中的软件包):parec
, parecord
, pacat
, paplay
. 试试看。他们应该工作。
播放parec
用录制的声音pacat
。
$ parec sample1.wav
^C
$ pacat sample1.wav
播放parecord
用录制的声音paplay
。
$ parecord sample2.wav
^C
$ paplay sample2.wav
它们之间的主要区别在于,parec
和pacat
不写和读声音文件中的头文件,而parecord
和paplay
做。
成功运行这些命令后,您可以尝试从官方存储库中编译pacat-simple.c和parec-simple.c,位于.src/tests/
$ gcc pacat-simple.c -o pacat-simple -lpulse-simple -lpulse
$ gcc parec-simple.c -o parec-simple -lpulse-simple -lpulse
之后,尝试运行它们。
$ ./parec-simple > sample3.wav
^C
$ ./pacat-simple < sample3.wav
它应该工作。现在您可以开始检查和玩parec-simple.c
and了pacat-simple.c
。请注意,parec-simple
也pacat-simple
不要在声音文件中写入和读取标题,就像parec
and一样pacat
。
通过对 while 循环进行一些修改,您的代码将像parec-simple
. 修改版(文件my-parec.c
):
while(1) {
pa_simple_read(s, buf, sizeof(buf), NULL);
//for(int i = 0; i < sizeof(buf); i++)
// printf("%d,", buf[i]);
//printf("\n-----------\n"); // just here for me separating the data, im not playing this back
fwrite(buf, 1, sizeof(buf), stdout);
}
编译并运行它:
$ gcc my-parec.c -o my-parec -lpulse-simple -lpulse
$ my-parec > sample4.wav
^C
有没有使用 PulseAudio C API 的例子?
此外parec-simple.c
,pacat-simple.c
如果您已经阅读了 PulseAudio异步 API 文档,您可以查看下面的pacat.csrc/utils/
作为示例。实际上parec
,parecord
和paplay
只是pacat
源代码的符号链接pacat.c
。
声音文件的标题是什么?上面提到过。
如果声音文件仅包含数据,则播放器无法知道该文件的音频规范,例如通道数、每个样本的位数(位深度)、字节序等。在这种情况下,它只能假设默认规范是使用过,可能不是这样。因此,为了将这些属性保存到声音文件中,我们在该文件中创建了一个标题部分来存储它们。有关标头格式,请参阅WAV PCM 声音文件格式和音频文件格式规范。
要管理声音文件的标头部分,可以使用C 库libsndfile 。pacat.c
确实使用该库来读取和写入带有标题的声音文件。libsndfile
还提供了一些实用程序,例如sndfile-info
帮助我们检查声音文件。这些实用程序包含libsndfile
在 arch中的包和sndfile-programs
debian 中的包中。
$ sndfile-info sample2.wav
========================================
File : sample2.wav
Length : 698668
RIFF : 698660
WAVE
fmt : 16
Format : 0x1 => WAVE_FORMAT_PCM
Channels : 2
Sample Rate : 44100
Block Align : 4
Bit Width : 16
Bytes/sec : 176400
data : 698624
End
----------------------------------------
Sample Rate : 44100
Frames : 174656
Channels : 2
Format : 0x00010002
Sections : 1
Seekable : TRUE
Duration : 00:00:03.960
Signal Max : 17226 (-5.59 dB)
要将标题添加到没有标题的声音文件中,我能想到的最简单的方法是,从另一个有标题的声音文件中复制标题,将其添加到没有标题的声音文件中,然后使用十六进制编辑器更改一些值(我使用ghex)。编辑标题中的数字字段时请注意字节顺序。
# In my system, sample2.wav has the simplest header which is 44 bytes long.
head -c 44 sample2.wav > header.wav
# Prepend header to sound file without header.
cat header.wav sample3.wav > sample3-with-header.wav
# Edit the chunk size field and data chunk size field.
ghex sample3-with-header.wav
其他参考
PulseAudio 在后台很好地解释了 PulseAudio 服务器。它关于缓冲和延迟的主题有助于理解 API 的使用,例如pa_stream_begin_write()
和pa_stream_write()
.
推荐阅读
- python - 在不添加权重属性的情况下查找图中两个节点之间的所有最短路径
- angular - 嵌套的 cdkDrag 属性
- jenkins - 相当于 Job DSL 插件的构建步骤?
- flutter - 在颤动中识别屏幕切口位置
- python-3.x - 使用 pytest 对包含某些类的实例的某些函数进行单元测试
- android - Cordova [Android 平台] 从 API 29 迁移到 API 30
- python - 如何将管道分隔字符串转换为熊猫数据框中列的python列表
- javascript - D3 工具提示不跟随鼠标
- mysql - 试图在mysql中连接三个不同的行
- rest - REST API Payload 中的 thorntail 和多态性部署问题