您好!
前一段时间我们
对于手机,决定选择一个应用程序 简单_pjsua 作为 PJSIP 库的一部分。 这是一个最小的应用程序,可以在服务器上注册、接听和应答呼叫。 下面我将立即介绍如何在STM32F7-Discovery上运行它。
如何跑
- 配置 Embox
make confload-platform/pjsip/stm32f7cube
- 在conf/mods.config 文件中设置所需的SIP 帐户。
include platform.pjsip.cmd.simple_pjsua_imported( sip_domain="server", sip_user="username", sip_passwd="password")
哪里 服务器 是 SIP 服务器(例如 sip.linphone.org), 用户名 и 密码 - 帐户用户名和密码。
- 将 Embox 组建为一个团队 使。 关于我们拥有的主板固件
维基 和文章 . - 在 Embox 控制台中运行“simple_pjsua_imported”命令
00:00:12.870 pjsua_acc.c ....SIP outbound status for acc 0 is not active 00:00:12.884 pjsua_acc.c ....sip:[email protected]: registration success, status=200 (Registration succes 00:00:12.911 pjsua_acc.c ....Keep-alive timer started for acc 0, destination:91.121.209.194:5060, interval:15s
- 最后,还需要将扬声器或耳机插入音频输出,并对显示屏旁边的两个小型 MEMS 麦克风讲话。 我们通过应用程序 simple_pjsua、pjsua 从 Linux 进行调用。 好吧,或者您可以使用任何其他类型的 linphone。
所有这些都在我们的
我们是如何到达那里的
因此,最初出现了选择硬件平台的问题。 由于内存显然不适合 STM32F4-Discovery,因此选择了 STM32F7-Discovery。 她有一个 1 MB 闪存驱动器和 256 KB RAM(+ 64 个特殊快速内存,我们也将使用它)。 通过服务器进行的呼叫也不是很多,但我们决定尝试适应。
有条件为自己,任务分为几个阶段:
- 在 QEMU 上运行 PJSIP。 它方便调试,而且我们已经支持 AC97 编解码器。
- 在 QEMU 和 STM32 上进行语音录制和播放。
- 移植应用程序 简单_pjsua 来自 PJSIP。 它允许您在 SIP 服务器上注册并拨打电话。
- 部署您自己的基于 Asterisk 的服务器并对其进行测试,然后尝试外部服务器,例如 sip.linphone.org
Embox 中的声音通过 Portaudio 工作,PISIP 中也使用了 Portaudio。 第一个问题出现在 QEMU 上 - WAV 在 44100 Hz 时播放良好,但在 8000 Hz 时明显出现问题。 事实证明,这是设置频率的问题 - 默认情况下,设备中的频率为 44100,并且这不会以编程方式更改。
在这里,也许值得解释一下声音的一般播放方式。 声卡可以设置为指向您想要以预定频率播放或录制的内存的某个指针。 缓冲区结束后,会生成中断并继续执行下一个缓冲区。 事实上,这些缓冲区需要在播放前一个缓冲区时提前填充。 我们将在STM32F7上进一步面对这个问题。
接下来,我们租了一台服务器并在其上部署了Asterisk。 由于需要调试很多,但又不想对着麦克风说话太多,所以需要进行自动播放和录音。 为此,我们修补了 simple_pjsua,以便您可以滑动文件而不是音频设备。 在 PJSIP 中,这很简单,因为它们有端口的概念,端口可以是设备也可以是文件。 并且这些端口可以灵活地与其他端口连接。 你可以在我们的pjsip中看到代码
在 QEMU 上运行后,我们开始移植到 STM32F7-Discovery。 第一个问题是,如果没有针对映像大小启用编译器优化“-Os”,它们就无法装入 1 MB 的 ROM。 这就是我们添加“-Os”的原因。 此外,该补丁禁用了对C++的支持,因此仅pjsua需要它,我们使用simple_pjsua。
放置后 简单_pjsua,决定现在有机会推出它。 但首先需要处理语音的录制和播放。 问题是写到哪里呢? 我们选择外部存储器 - SDRAM (128 MB)。 你可以自己尝试一下:
创建频率为 16000 Hz、持续时间为 10 秒的立体声 WAV:
record -r 16000 -c 2 -d 10000 -m C0000000
我们输了:
play -m C0000000
这里有两个问题。 第一个使用编解码器 - WM8994,它有一个插槽这样的东西,并且有 4 个插槽。因此,默认情况下,如果未配置此选项,则在播放音频时,会在所有四个插槽中进行播放。 因此,在 16000 Hz 的频率下,我们收到了 8000 Hz,但对于 8000 Hz,播放根本不起作用。 当仅选择插槽 0 和 2 时,它可以正常工作。 另一个问题是STM32Cube中的音频接口,其中音频输出通过SAI(串行音频接口)与音频输入同步工作(我不明白细节,但事实证明它们共享一个公共时钟,当音频输出已初始化,音频以某种方式附加到其入口)。 也就是说,你不能单独运行它们,所以我们做了以下操作——音频输入和音频输出始终工作(包括生成中断)。 但是,当系统中没有播放任何内容时,我们只需将一个空缓冲区滑入音频输出,当播放开始时,我们就开始填充它。
此外,我们还发现录音时的声音非常小。 这是因为 STM32F7-Discovery 上的 MEMS 麦克风在低于 16000 Hz 的频率下无法正常工作。 因此,即使16000 Hz到来,我们也设置8000 Hz。 然而,要做到这一点,有必要添加一种频率到另一种频率的软件转换。
接下来,我必须增加位于 RAM 中的堆的大小。 根据我们的计算,pjsip 需要大约 190 KB,而我们只剩下大约 100 KB。 这里我不得不使用一些外部存储器——SDRAM(大约128 KB)。
经过所有这些编辑后,我看到了 Linux 和 Embox 之间的第一个软件包,并且我听到了声音! 但声音很糟糕,和QEMU上的完全不一样,根本听不清任何东西。 然后我们思考可能出了什么问题。 调试表明 Embox 根本没有时间填充/卸载音频缓冲区。 当pjsip处理一帧的时候,有2次中断来得及完成缓冲区处理,这太多了。 对于速度的第一个想法是编译器优化,但它已经包含在 PJSIP 中。 第二个是硬件浮点,我们在
下一个想法是,我们正在使用外部存储器,最好将经常访问的结构移动到那里。 我初步分析了何时何地 简单_pjsua 分配内存。 结果发现,在 190 Kb 中,前 90 Kb 分配用于 PJSIP 的内部需求,并且访问频率不高。 此外,在传入呼叫期间,将调用 pjsua_call_answer 函数,然后在其中分配缓冲区以处理传入和传出帧。 仍然是 100 Kb 左右。 然后我们做了以下事情。 直到调用的那一刻,我们将数据放置在外部存储器中。 一旦调用,我们立即用 RAM 中的另一个堆替换该堆。 因此,所有“热”数据都被转移到更快、更可预测的内存中。
结果,所有这些共同使得启动成为可能 简单_pjsua 并通过您的服务器调用。 然后通过其他服务器,例如 sip.linphone.org。
发现
结果,可以启动 简单_pjsua 通过服务器进行双向语音传输。 额外花费128 KB SDRAM的问题可以通过使用稍微强大的Cortex-M7(例如具有32 KB RAM的STM769F512NI)来解决,但同时我们仍然没有放弃进入256的希望KB 🙂 如果有人感兴趣,我们会很高兴,或者更好的是,尝试一下。 像往常一样,所有来源都在我们的
来源: habr.com