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

基于pjsua2的Python SIP客户端能否内存实时处理音频帧?

在Python的pjsua2中直接内存处理音频帧的方案

好问题!直接跳过磁盘IO、在内存中处理通话音频帧确实是更高效的方案,结合你已经基于Call类实现的通话逻辑,我来给你分享最直接且官方推荐的实现方式:

方法:继承pj.Port实现自定义音频端口

虽然你提到SWIG封装没有直接暴露MediaPort的回调typedef,但pjsua2的Python绑定提供了pj.Port基类,我们可以通过继承它来创建自己的音频端口,从而直接捕获和处理内存中的PCM音频帧。

步骤1:实现自定义音频处理器类

创建一个继承自pj.Port的类,核心是覆盖onPutFrame方法(用于接收通话传入的音频帧)和onGetFrame方法(用于向通话发送处理后的音频帧):

import pj
import numpy as np  # 可选:用于数值化处理音频数据

class CustomAudioProcessor(pj.Port):
    def __init__(self, audio_media):
        super().__init__()
        # 同步通话音频的核心参数,必须和源音频一致
        self.clock_rate = audio_media.getClockRate()
        self.channels = audio_media.getChannelCount()
        self.samples_per_frame = audio_media.getSamplesPerFrame()
        self.bits_per_sample = 16  # pjsua默认采用16位PCM格式
        
        # 配置自定义端口的参数
        self.setName("CustomAudioProcessor")
        self.setClockRate(self.clock_rate)
        self.setChannelCount(self.channels)
        self.setSamplesPerFrame(self.samples_per_frame)
        self.setBitsPerSample(self.bits_per_sample)

    def onPutFrame(self, frame):
        """收到通话传入的音频帧时触发,在这里处理内存中的PCM数据"""
        # frame.buf是原始的16位PCM字节数据
        pcm_raw = frame.buf
        
        # 可选:转换为numpy数组方便后续处理(比如降噪、语音特征提取)
        pcm_array = np.frombuffer(pcm_raw, dtype=np.int16)
        
        # 加入你的自定义处理逻辑:
        # 示例:打印帧信息、实时滤波、语音识别预处理等
        print(f"Received audio frame: {len(pcm_raw)} bytes | {len(pcm_array)} samples")
        
        return pj.PJ_SUCCESS

    def onGetFrame(self, frame):
        """当需要向通话发送音频帧时触发(比如回传处理后的音频)"""
        # 如果不需要回传音频,保持默认返回成功即可
        # 若要回传处理后的音频,可以在这里填充PCM数据到frame.buf
        return pj.PJ_SUCCESS

步骤2:在通话回调中绑定自定义端口

修改你的onCallMediaState方法,将通话的AudioMedia流转发到自定义端口,触发帧处理回调:

def onCallMediaState(self, prm):
    ci = self.getInfo()
    logger.info("onCallMediaState", media_size=ci.media.size())
    self._print_call_info("onCallMediaState")
    for media_index, media in enumerate(ci.media):
        if media.type == pj.PJMEDIA_TYPE_AUDIO:
            if ci.stateText == "CONFIRMED":
                logger.info("Call CONFIRMED")
                # 获取通话的AudioMedia实例
                audio_media = pj.AudioMedia.typecastFromMedia(self.getMedia(media_index))
                # 初始化自定义音频处理器
                self.audio_processor = CustomAudioProcessor(audio_media)
                # 将通话音频流转发到自定义端口,触发onPutFrame回调
                audio_media.startTransmit(self.audio_processor)
                
                # 可选:如果需要把处理后的音频回传给对方,添加下面一行
                # self.audio_processor.startTransmit(audio_media)

关键细节说明

  1. PCM数据格式:pjsua默认使用16位有符号小端PCM,采样率通常为8kHz或16kHz,声道数默认单声道,你可以通过audio_media的方法获取准确参数。
  2. 性能注意事项:onPutFrame会被高频调用(比如8kHz采样率下每10ms触发一次),所以这里的处理逻辑要尽量轻量化,避免阻塞音频流。
  3. 彻底摆脱磁盘依赖:整个过程完全在内存中完成,不需要生成WAV文件,彻底避开磁盘IO的额外开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:57:46