4

我正在基于pjsua2使用 python 开发一个 SIP 客户端。我有一个基于python 包装器调用的自定义 Call 类,并且我的代码能够获得活动连接。在我的 customonCallMediaState上,我可以访问音频会议桥:

    def onCallMediaState(self, prm):
        """
        Manage call media state callbacks.

        - Autoconnect audio
        """
        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":
                    """
                    It seems a bug with callbacks. CONFIRMED
                    is send at start and disconnect. So stop
                    record is manual, cannot use DISCONNECTD
                    """
                    logger.info("Call CONFIRMED")

此时我可以media_index用来录制或播放来自通话的音频。例如,对于录制:

    def record_call(self, media_index):
        """
        Record the audio incoming from call using default playback device
        """
        record_media = pj.Endpoint_instance().audDevManager().getCaptureDevMedia()
        audio_media = pj.AudioMedia.typecastFromMedia(self.getMedia(media_index))
        port_id = audio_media.getPortId()
        rx_level = audio_media.getRxLevel()
        tx_level = audio_media.getTxLevel()
        filename = "file.wav"
        logger.info("Recording audio media", port_id=port_id, rx_level=rx_level, tx_level=tx_level)
        self._recorder = pj.AudioMediaRecorder()
        self._recorder.createRecorder(filename);
        self._is_recording = True
        record_media.startTransmit(self._recorder)

并创建了一个 file.wav。或使用默认音频设备:

    def play_call(self, media_index):
        """
        Play the audio incoming from call using default playback device
        """
        playback_media = pj.Endpoint_instance().audDevManager().getPlaybackDevMedia()
        audio_media = pj.AudioMedia.typecastFromMedia(self.getMedia(media_index))
        port_id = audio_media.getPortId()
        rx_level = audio_media.getRxLevel()
        tx_level = audio_media.getTxLevel()
        logger.info("Playing audio media", port_id=port_id, rx_level=rx_level, tx_level=tx_level)
        audio_media.startTransmit(playback_media)

这两个示例都有效,根据PjSUA2 媒体文档音频媒体文档,可以传输和接收音频、播放和录制 WAV。但根据pjsip 媒体端口文档,其他媒体也是可能的。似乎SWIG 包装器不支持它。

最后,我的问题是,是否可以在不记录 wav 文件的情况下管理内存中的音频帧?

我不想将音频写入硬盘,只是在内存中使用它,为此我需要直接原始数据。一种解决方法是编写一个块 wav 文件,并一个一个地读取它,但这是一个开销很大的肮脏解决方案。根据媒体流文档,可以获得回调,但我找不到如何在 Python 中执行此操作。在 python 包装器中不存在typedef void *MediaPort试图绕过回调。

4

1 回答 1

1

我一直在研究同样的问题,但对于 pjsua 而不是 pjsua2。最初 pjsip 不支持 pjsua(不确定 pjsua2),但我在 GitHub 上找到了一个项目,该项目对 pjproject 2.2 进行了自定义,带有缓冲流,称为“UFAL-DSG/alex”。

我将自定义移植到“nicolaipre/python3-pjsip-memory-buffer”中的 python3 和 pjproject 2.9。

我知道 pjsua2 可能对您没有用,但也许它可以帮助其他人寻找类似的东西。

于 2020-01-08T21:12:44.733 回答