我正在尝试将音频字节流式传输到共享缓冲区中,并通过转录模型传递它。音频来自以 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)
这个答案建议仅使用出站,但我在这里需要两条轨道!
问题在于您正在连接音频块。你的意图是加入那些。让我举例说明。
让我们将输入流中的块标记为
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 编码转换为“原始”数字,组合每个样本的值并转换回您可用的任何格式。