今年公司开始转型AI产品,涉及到人工智能大模型,产品目前分别接入字节跳动的豆包大模型及科大讯飞的星火大模型,由于产品都涉及语音交互,这半年以来对音频略有熟悉,熟悉了PCM音频后又接触到了opus音频,其中星火大模型opus音频有一些特殊,它是opus音频流,没有ogg封装,而目前PC的播放器似乎没有支持播放纯opus音频流的,在未找到合适的播放器之后准备自己实现了。

判断opus音频有没有ogg封装很简单,将音频文件以十六进制显示即可,前4字节为0x4F、0x67、0x67、0x53,对应ASCII为Oggs,如果想深入了解opus编码可以查看Opus音频编码格式

目前常用的opus播放方案都是基于libopus+python3,所以我基于此方案开始搭建环境。

首先安装python库:

1
2
pip install pyaudio
pip install opuslib

其中opuslib还需要单独安装依赖库libopus,官方库提供了Linux/Mac的编译方法但没有Windows版的,但好在有开发者提供了Windows的编译方案及库,直接去Github 下载即可,虽然版本落后于官方版本,但不妨碍我们使用,这里我以Windows 11为例,下载编译好的库libopus_v1.4_msvc17.zip,解压后将bin\x64\opus.dll文件添加到环境变量即可。

这里我再简单介绍一下讯飞opus的编码,方便理解代码。

讯飞支持opus、opus-wb两种编码,这两种格式每一帧均为2字节长度+压缩音频数据,其中opus采样率为8000kpbs,每帧长度为2+20;opus-wb采用率为16000kpbs,每帧长度为2+40。

这里以opus-wb举例,帧长度为40(十六进制为0x28),后续为压缩的音频数据。以下为一帧示例:

00 28 4B 41 11 0B E4 4A 30 B1 5A 56 CA C5 70 CB 18 C3 05 8A 81 84 2E D2 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

好了,到这里我们就可以写代码了,我们每次读取一帧(42字节),将长度去掉后再解码,解码结果为PCM数据,所以我们最终播放的是PCM数据,完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import opuslib
import pyaudio

with open('test.opus-wb', 'rb') as opus_file:
decoder = opuslib.Decoder(16000, 1)

pa = pyaudio.PyAudio()

pcm_stream = pa.open(
format=pyaudio.paInt16,
channels=1,
rate=16000,
output=True
)

while True:
encoded_data = opus_file.read(42)
if not encoded_data:
break

pcm_data = decoder.decode(encoded_data[2:], 10000)
pcm_stream.write(pcm_data)