将Elevenlabs音频流集成到采用G.711 PCMA编码的PyVoip通话中
解决Elevenlabs音频流转G.711 PCMA适配PyVoIP的流程
核心前提:G.711 PCMA要求8kHz采样率、单声道、8bit u-law编码,而Elevenlabs默认输出为16bit PCM(多为44.1kHz/16kHz立体声),必须严格按顺序完成格式转换,任何一步偏差都会导致噪音、爆音问题。
正确转换与接入步骤
1. 获取Elevenlabs原始PCM流
调用API时指定输出为无容器的原始PCM(优先选pcm_16000,减少后续采样率转换压力),避免获取带WAV/MP3头的流:
import requests ELEVENLABS_API_KEY = "your_api_key" VOICE_ID = "target_voice_id" text = "需要转换的语音内容" # 流式获取16kHz 16bit单声道PCM response = requests.post( f"https://api.elevenlabs.io/v1/text-to-speech/{VOICE_ID}/stream", headers={"xi-api-key": ELEVENLABS_API_KEY}, json={ "text": text, "model_id": "eleven_monolingual_v1", "output_format": "pcm_16000" }, stream=True ) # 读取纯PCM字节数据 raw_pcm = b"" for chunk in response.iter_content(chunk_size=1024): if chunk: raw_pcm += chunk
2. 格式转换(采样率/声道/编码)
使用pydub(依赖ffmpeg)完成标准化转换,关键是降低增益避免削波爆音:
from pydub import AudioSegment # 加载原始16kHz 16bit单声道PCM audio = AudioSegment( data=raw_pcm, sample_width=2, # 16bit对应2字节采样宽度 frame_rate=16000, channels=1 ) # 转换为G.711 PCMA要求的8kHz单声道 audio_8k_mono = audio.set_frame_rate(8000).set_channels(1) # 降低增益避免爆音,转成8bit u-law编码 audio_pcma = audio_8k_mono.set_sample_width(1).apply_gain(-4) # 获取最终PCMA字节流 pcma_data = audio_pcma.raw_data
3. 注入PyVoIP通话流
按RTP包标准切割PCMA数据(20ms对应160字节),直接发送:
from pyvoip import VoIPPhone, CallState def stream_pcma_to_call(phone, pcma_data): chunk_size = 160 # 8kHz采样率下,20ms对应160个采样点 for i in range(0, len(pcma_data), chunk_size): chunk = pcma_data[i:i+chunk_size] # 补全不足的字节避免RTP包异常 if len(chunk) < chunk_size: chunk += b"\x00" * (chunk_size - len(chunk)) phone.send_audio(chunk) # 通话建立后发送音频 if phone.call_state == CallState.CONNECTED: stream_pcma_to_call(phone, pcma_data)
常见问题排查
- 爆音:多为音频增益过高导致削波,调整
apply_gain的参数(-3到-6之间测试) - 噪音:检查是否混入WAV头/其他容器数据;确认采样率转换用高质量算法(pydub依赖ffmpeg默认算法即可,勿用简单降采样)
- 协商异常:确保PyVoIP通话时明确指定
PCMA编码,避免自动协商到不兼容格式
内容的提问来源于stack exchange,提问作者gear1900
相关产品推荐
相关产品推荐

