为什么收集入站和出站音频会产生音频失真?

问题描述 投票:0回答:1

我正在尝试将音频字节流式传输到共享缓冲区中,并通过转录模型传递它。音频来自以 8kHz 采样并经过 mu-law 编码的 Websocket。如果我将入站和出站音频流到单独的音频缓冲区(

ibuffer
obuffer
)中,我已经成功地为自己播放了几秒钟的音频,但是如果我收集到
shared
缓冲区中,则音频是真的很慢而且延迟。这是我的测试代码的摘录:

obuffer = b""
ibuffer = b""
shared = b""

while True:
    data = await queue.get()
    if data["event"] == "media":
        websocket_payload = data["media"]["payload"]
        chunk = audioop.ulaw2lin(base64.b64decode(websocket_payload), 2)
        if data["media"]["track"] == INBOUND:
            obuffer += chunk
        if data["media"]["track"] == OUTBOUND:
            ibuffer += chunk
        shared += chunk

我一直在测试,收集

obuffer
ibuffer
shared
,腌制缓冲区,然后保存为
.wav
文件并在我的机器上播放它们。单独的缓冲区播放得很好,甚至可以通过简单地平均它们来合并,这也播放得很好 - 但为什么不能将它们收集到共享缓冲区中产生相同质量的音频?产生的声音与原始声音相去甚远,我尝试过高达 16 kHz 的不同采样率等。有人知道在这里要做什么吗?

这很奇怪,因为 Twilio 的自己的文档说你可以毫无问题地做到这一点。

import pickle
import wave

with open("all_bytes.pkl", "rb") as f:
    loaded_audio_bytes = pickle.load(f)

nchannels = 1
sampwidth = 2
framerate = 8000
nframes = len(loaded_audio_bytes) // (nchannels * sampwidth)

with wave.open("wav.wav", 'wb') as wf:
    wf.setnchannels(nchannels)
    wf.setsampwidth(sampwidth)
    wf.setframerate(framerate)
    wf.setnframes(nframes)
    wf.writeframes(loaded_audio_bytes)

这个答案建议仅使用出站,但我在这里需要两条轨道!

python audio twilio
1个回答
0
投票

问题在于您正在连接音频块。你的意图是加入那些。让我举例说明。

让我们将输入流中的块标记为

I0, I1, ...
,将输出流中的块标记为
O0, O1, O2, ...
,并将生成的音频标记为
S0, S1, ...

您的应用程序中现在发生的情况是来自流的块以“随机”顺序出现,因此您会得到类似的内容

S = [I0, I1, O0, I2, I3, O1, O2, O3, I4, O4 ... ] 

由于您的块很短,您会感知到输入和输出音频流随着音频减慢而交错(并且在来自不同源的块的边界处失真)。如果您将块持续时间设置为几秒,您会清楚地听到。

您的共享音频应该已加入:

S0 = (I0 + O0)/2  << for each audio sample in the chunk
S1 = (I1 + O1)/2 
...

假设两个流的块持续时间相同。您需要将二进制块从 mu-law 编码转换为“原始”数字,组合每个样本的值并转换回您可用的任何格式。

© www.soinside.com 2019 - 2024. All rights reserved.