You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python提升Twilio媒体流音频的保存质量,解决播放失真问题?

解决Twilio Streams音频流式传输失真问题

从你提供的音频参数对比和代码来看,问题的核心很明确:Twilio Streams推送的媒体 payload 是 μ-law(PCMU)压缩的8位音频样本,而你直接将这些原始压缩字节保存为 μ-law 格式的WAV文件,部分播放器对这种编码的解析支持不佳,导致出现"慢动作"和压缩伪像;而Twilio控制台的录音已经自动解码为无压缩的PCM 16位音频,所以音质更清晰。

要解决这个问题,你需要把μ-law编码的音频数据解码为和控制台录音一致的PCM 16位无压缩格式,再保存成WAV文件。下面是具体的实现方案:

方案1:使用Python内置audioop模块解码(无需额外依赖)

audioop是Python标准库中的音频处理模块,可以直接完成μ-law到PCM的转换,步骤如下:

  1. 导入audioop模块
  2. 对每个解码后的μ-law音频chunk,转换为16位PCM格式
  3. 最后将所有PCM数据拼接,保存为PCM 16位的WAV文件

修改后的代码如下:

import base64
import audioop
import pywav

# 初始化存储PCM数据的列表
recorded_pcm = []
has_seen_media = False
message_count = 0

# (这里是你的WebSocket消息循环逻辑,省略连接部分)
while True:
    message = # 你的WebSocket接收消息逻辑
    data = # 解析消息为字典
    message_count += 1
    
    if data['event'] == "media":
        payload = data['media']['payload']
        app.logger.info("Payload is: {}".format(payload))
        # 解码base64得到μ-law字节
        ulaw_chunk = base64.b64decode(payload)
        # 将μ-law(8位)转换为16位PCM单声道音频
        pcm_chunk = audioop.ulaw2lin(ulaw_chunk, 2)  # 2代表16位样本宽度
        recorded_pcm.append(pcm_chunk)
        app.logger.info("Converted chunk to {} bytes of PCM".format(len(pcm_chunk)))
        has_seen_media = True
    elif data['event'] == "closed":
        app.logger.info("Closed Message received: {}".format(message))
        break

app.logger.info("Connection closed. Received a total of {} messages".format(message_count))

# 拼接所有PCM数据
data_bytes = b''.join(recorded_pcm)

# 保存为PCM 16位单声道、8000采样率的WAV文件
# 参数说明:文件名,声道数,采样率,位深(16),音频格式(1代表PCM无压缩)
wave_write = pywav.WavWrite("Recording.wav", 1, 8000, 16, 1)
wave_write.write(data_bytes)
wave_write.close()

方案2:使用pydub简化处理(需要额外安装)

如果你更倾向于使用更直观的音频处理库,可以用pydub,它封装了ffmpeg,处理起来更灵活:

  1. 安装依赖:pip install pydub(需要提前安装ffmpeg并配置到环境变量)
  2. 将μ-law字节转换为AudioSegment,再导出为PCM 16位WAV

示例代码片段:

from pydub import AudioSegment

# 拼接所有μ-law字节
ulaw_data = b''.join(recorded)
# 创建μ-law音频段:单声道,8000采样率,8位深度
ulaw_audio = AudioSegment(
    data=ulaw_data,
    sample_width=1,  # 8位对应sample_width=1
    frame_rate=8000,
    channels=1
).set_sample_width(2)  # 转换为16位PCM

# 导出为WAV文件
ulaw_audio.export("Recording.wav", format="wav")

关键注意事项

  • 你之前修改WavWrite的位参数从8到16但没效果,是因为原始数据还是μ-law压缩的8位,没有做解码转换,只是强制标记位深,播放器自然无法正确解析。
  • 转换后的音频参数会和Twilio控制台的录音完全一致:numchannels:1, samplerate:8000, bitspersample:16, audioformat:PCM,这样就能保证音质匹配,也能直接输入你的机器学习模型。

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 17:44:06