PulseAudio 使用心得记录

pulseaudio 是一个声音服务器。

文档参考:PulseAudio
模块文档:PA Module

名词解释:

  • sink 是声音输出的目的地;
  • source 是声音的输入来源;
  • 可以用 pacmd list-sinks/list-sources 查看本地的 sinks/sources;
  • pacmd/pactl 是命令行工具,可以查看信息或者在 PA 启动后在命令行更新配置,具体可用 man pacmd 查看用法;
  • pacat 是 PA 提供的一些工具,可以录音、播放声音等,可通过 man pacat 查看,像 parec 等是 pacat 的软链接;

parec 是 pacat 的软链接,但为什么 parec 等效于 pacat -r 呢?
我怀疑是因为 pacat 命令内判断了执行脚本的名称,根据名称自动加了参数。

Pulseaudio 的配置与运行

pa 在启动时,会首先查询 ~/.config/pulse 找到配置文件,如果没找到会从 /etc/pulse 中查询系统级配置。

default.pa 是启动脚本,用于配置模块,在守护进程初始化完成后被解析。自己变更配置应该在 ~/.config/pulse 中创建 default.pa,并且应该首行执行 .include /etc/pulse/default.pa 导入系统级配置,并在下方使用配置行覆盖原配置,切忌直接变更系统级配置。

如我本地的配置文件 ~/.config/pulse/default.pa

.include /etc/pulse/default.pa

load-module module-null-sink sink_name=null_sink
load-module module-null-sink sink_name=null_sink2

load-module module-pipe-source channels=2  file=/tmp/fifo.in source_name=fifo_source

set-default-source fifo_source
set-default-sink null_sink

如上配置,我加载了三个模块:

  • null_sink 是个 module-null-sink,向这里播放声音会直接消失,它有自己的速率控制;
  • null_sink2 也是个 module-null-sink,pa 可以加载多次相同的模块,但设置不同的命名;
  • fifo_source 是个 module-pipe-source 模块,它创建了一个 pipe 文件(可通过参数 file=/tmp/fifo.in 指定),作为声音

配置中设置了默认的 source/sink。

注:

  • pipe 文件是个管道文件,可以通过 linux 的管道命令操作写入和读出,如上若 cat audio_file > /tmp/fifo.in 就可以向模拟的麦克风中输入声音,也可通过 cat /tmp/fifo.in > audio_file 重定向声音到文件,但同时 pipe 文件写入和读出都是有 buffer 的,如果写满了但此时没读的操作就不会再写了,读的时候为空了也就读不到了。

重定向喇叭输出的声音到文件

如配置信息中 set-default-sink null_sink 默认的 sink 是 null_sink,每启动一个 sink,会有对应的 *.monitor 出现,作为 source。因此可以使用 parec -d null_sink2.monitor audio_file.pcm 命令将声音录制到本地文件中。

播放声音到麦克风做声音输入

由于每一个 sink 会自动有一个 *.monitor 的 source,是用于 parec 录音用的。

使用命令 pacmd set-default-source null_sink2.monitornull_sink2.monitor 指定为默认 source,然后使用 paplay -d null_sink2 ./home.wav 播放声音到 null_sink2 中,此时声音会自动从 null_sink2.monitor 中出来作为输入(到浏览器的麦克风)。

使用中发现命令 pacmd set-default-source null_sink2.monitor 必须要现在浏览器开启后才能设置,并且不能写在配置文件中。

弃用但保留的信息

读流的方法

最初我在配置文件中用 module-pipe-sink 做 sink:

load-module module-pipe-sink channels=2 rate=44100 format=s16le file=/tmp/fifo.out sink_name=fifo_sink

在读声音的时候使用 cat /tmp/fifo.out > audio_file 读到的 audio_file 很大。原因是要读 fifo.out 需要进行速率控制,即每 20ms 读取一次,一次读取 X bytes。

这是我写的一个比较好的读流的脚本:

import os
import time

stream_out_file = '/tmp/fifo.out'
output_file = 'py_t.wav'

if not output_file.endswith('.wav'):
    output_file = output_file + '.wav'

# 经计算 16bit 2ch 44.1kHz 下,每秒读取数据 176400B(精确计算)
# 所以,200ms 有数据 35280B,20ms 有 3528B
# 系统 buf 大小 64k,为 65536B,约 18.57ms
stream = os.open(stream_out_file, os.O_RDONLY)
with open(output_file, 'wb') as wav_fd:
    start = time.time_ns()                   # start time
    _next = time.time_ns() + 20 * 1000*1000  # next time is after 20ms
    while True:
        if time.time_ns() > _next:   # 每 20ms 读取一次
            _next += 20 * 1000*1000  # next time
            s = os.read(stream, 3528)
            print("read length", len(s))
            wav_fd.write(s)
        else: # 睡 2ms
            time.sleep(0.002)

写流的方法

向 fifo.in 中写流也一样,如下我之前写的一个比较流畅的脚本:

import time

stream_in_file = '/tmp/fifo.in'

def play_file(sound_file):
    with open(stream_in_file, 'wb') as w_fd, \
        open(sound_file, 'rb') as r_fd:

        while True:
            data = r_fd.read(441*8) # 数值可能与码率有关
            w_fd.write(data)
            w_fd.flush()
            time.sleep(0.02)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,667评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,361评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,700评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,027评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,988评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,230评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,705评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,366评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,496评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,405评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,453评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,725评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,803评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,015评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,514评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,111评论 2 341

推荐阅读更多精彩内容