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

如何确保pjsua2音频回环录制保持原始音质?

解决pjsua2音频回环录制音质劣化问题

核心问题根源

你当前的方案依赖物理音频设备做回环(监听端采集本地播放的音频再回传),这会引入多次D/A/A/D转换损耗、硬件回声、虚拟化层干扰,再加上pjsua2默认音频处理模块的误触发,最终导致音质崩溃。要实现无损回环,必须绕过物理声卡,直接在数字媒体流层面完成路由。


具体修复步骤

1. 监听端:替换物理设备回环为媒体流端到端路由

删除监听端将capture_media路由到playback_media的逻辑,改为直接将呼叫的接收媒体流转发到发送媒体流,完全跳过物理声卡:

class MyCall(pj.Call):
    def onCallMediaState(self, prm):
        # 获取呼叫的音频媒体实例
        call_info = self.getInfo()
        for mi in call_info.media:
            if mi.type == pj.PJMEDIA_TYPE_AUDIO and mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE:
                # 获取接收(rx)和发送(tx)媒体
                rx_media = pj.AudioMedia.typecastFromMedia(self.getMedia(mi.index))
                tx_media = pj.AudioMedia.typecastFromMedia(self.getMedia(mi.index))
                # 直接将收到的音频原路回传
                rx_media.startTransmit(tx_media)
                break

2. 主叫端:绕过本地声卡,直接向呼叫流播放音频

不要将AudioMediaPlayer路由到系统playback_media,改为直接传输到呼叫的发送媒体流:

# 主叫端呼叫建立后,获取呼叫音频媒体
call_media = pj.AudioMedia.typecastFromMedia(my_call.getMedia(0))
# 初始化播放器(确保WAV参数与媒体配置一致)
player = pj.AudioMediaPlayer()
player.createPlayer("test_audio.wav")
# 直接向呼叫流播放音频
player.startTransmit(call_media)

3. 主叫端:直接录制呼叫接收流,跳过本地声卡采集

不要从capture_media录制,改为直接录制呼叫的接收媒体流:

# 获取呼叫的接收音频媒体
call_rx_media = pj.AudioMedia.typecastFromMedia(my_call.getMedia(0))
# 初始化录制器
recorder = pj.AudioMediaRecorder()
recorder.createRecorder("recorded_loop.wav")
# 直接录制回传的音频流
call_rx_media.startTransmit(recorder)

4. 彻底禁用pjsua2所有音频处理模块

在初始化Endpoint时,关闭所有可能修改音频的功能,确保音频流无额外处理:

ep = pj.Endpoint()
ep_cfg = pj.EpConfig()

# 媒体核心配置
ep_cfg.mediaConfig.ecOptions.enabled = False  # 关闭回声消除
ep_cfg.mediaConfig.vadOption = pj.PJMEDIA_VAD_DISABLED  # 关闭语音活动检测
ep_cfg.mediaConfig.agcConfig.enabled = False  # 关闭自动增益控制
ep_cfg.mediaConfig.noiseSuppressConfig.enabled = False  # 关闭降噪
ep_cfg.mediaConfig.clockRate = 16000  # 与测试WAV采样率一致(如8kHz则设8000)
ep_cfg.mediaConfig.channelCount = 1  # 与测试WAV声道数一致(单声道设1,立体声设2)
ep_cfg.mediaConfig.sndClockRate = ep_cfg.mediaConfig.clockRate  # 同步音频设备采样率

# 音频设备配置
ep_cfg.audDevConfig.ecEnabled = False
ep_cfg.audDevConfig.agcEnabled = False
ep_cfg.audDevConfig.vadEnabled = False

ep.libCreate()
ep.libInit(ep_cfg)

5. 确保音频文件与媒体配置完全匹配

测试用WAV文件的参数必须和pjsua2配置一致:

  • 采样率:16kHz/8kHz(与clockRate对应)
  • 声道数:单声道/立体声(与channelCount对应)
  • 位深:16位(pjsua2默认支持,避免使用8位或24位)

6. 虚拟机环境优化

  • 将虚拟机音频设备设置为直通模式,禁用虚拟声卡的内置回声消除、增益调整功能
  • 确保虚拟机之间的网络延迟稳定,避免丢包导致的音频失真

为什么之前的尝试无效?

你之前调整的VAD、线程模式、quality参数都是针对媒体流的边缘设置,但核心问题是多次物理音频转换引入的不可逆损耗,以及默认音频处理模块在设备回环场景下的误触发(比如回声消除会把正常回传音频判定为回声进行压制,导致音量忽强忽弱)。只有跳过物理声卡,直接在数字流层面路由,才能彻底解决音质问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:53:17