STM32F7上的SIP电话-发现

大家好

前一段时间,我们写了关于如何在Em32的STM32F4-Discovery上启动SIP电话(具有1 MB ROM和192 KB RAM)的信息 。 这里必须说该版本是最小的,可以直接连接两部电话而无需服务器,并且只能在一个方向上进行语音传输。 因此,我们决定推出一款功能更完整的电话,通过服务器进行通话,双向语音传输,但同时将内存保持在最小范围内。


对于电话,决定选择simple_pjsua应用程序作为PJSIP库的一部分。 这是一个最小的应用程序,可以在服务器上注册,接听和接听电话。 下面,我将立即描述如何在STM32F7-Discovery上运行它。

怎么跑


  1. 配置Embox
    make confload-platform/pjsip/stm32f7cube 
  2. 在conf / mods.config文件中,设置所需的SIP帐户。

     include platform.pjsip.cmd.simple_pjsua_imported( sip_domain="server", sip_user="username", sip_passwd="password") 

    其中server是SIP服务器(例如sip.linphone.org), usernamepassword是帐户的用户名和密码。
  3. 使用make命令构建Embox。 关于我们在Wiki文章中拥有的主板的固件。
  4. 在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:alexk2222@sip.linphone.org: 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 

  5. 最后,仍然需要将扬声器或耳机插入音频输出,并与显示器附近的两个小型MEMS麦克风通话。 我们通过pjsua应用程序simple_pjsua从Linux调用。 好吧,或者您可以使用任何其他类型的线性电话。

所有这些都在我们的Wiki中进行了描述。

我们怎么来的?


因此,最初出现了有关选择硬件平台的问题。 由于很明显STM32F4-Discovery无法容纳在内存中,因此选择了STM32F7-Discovery。 她有一个1 MB的闪存驱动器和256 KB的RAM(+ 64个特殊的快速内存,我们还将使用)。 通过服务器拨打电话也不是很多,但决定尝试加入。

按照惯例,任务分为几个阶段:

  • 在QEMU上运行PJSIP。 调试起来很方便,而且我们在那里已经有了AC97编解码器支持。
  • 在QEMU和STM32上进行语音记录和回放。
  • 从PJSIP内移植simple_pjsua应用程序。 它允许您在SIP服务器上注册并拨打电话。
  • 部署您自己的基于Asterisk的服务器并对其进行测试,然后尝试使用外部服务器,例如sip.linphone.org

Embox中的声音通过Portaudio进行工作,Portaudio也用于PISIP。 QEMU上出现了第一个问题-WAV在44100 Hz时表现良好,但在8000时显然出了问题。 事实证明,这是设置频率的问题-默认情况下,设备中的频率为44100,而这并没有通过编程方式更改。

在这里,大概值得解释一下声音的总体播放方式。 声卡可以将一些指针设置为您要以预定频率从中播放或记录的一块内存。 缓冲区结束后,将产生中断,并从下一个缓冲区继续执行。 事实是,在播放前一个缓冲区之前,需要提前填充这些缓冲区。 我们将在STM32F7上进一步遇到这个问题。

接下来,我们租用了服务器并在其上部署了Asterisk。 由于有必要进行大量调试,但又不想对麦克风说太多声,因此有必要进行自动播放和录音。 为此,我们修补了simple_pjsua,以便可以滑动文件代替音频设备。 在PJSIP中,这非常简单,因为它们具有端口的概念,该端口可以是设备或文件。 这些端口可以灵活地连接到其他端口。 您可以在我们的pjsip 存储库中查看代码。 结果,方案如下。 我在Asterisk服务器上创建了两个帐户-Linux和Embox。 接下来,在Embox上执行simple_pjsua_imported命令,在服务器上注册Embox,然后从Linux调用Embox。 在连接时,我们在Asterisk服务器上检查是否已建立整个连接,过一会儿他们应该在Embox中听到来自Linux的声音,在Linux中,我们保存从Embox播放的文件。

在QEMU上运行后,我们切换到了STM32F7-Discovery的移植。 第一个问题-如果没有在图像大小方面对“ -Os”编译器进行优化,它们就不会进入1 MB ROM。 因此包括“ -Os”。 此外,该补丁禁用了C ++支持,因此仅pjsua才需要此补丁,我们使用simple_pjsua。

安装simple_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以下的频率下无法正常工作。 因此,即使出现8000 Hz,我们也将设置为16000 Hz。 为此,事实是要添加一个频率到另一个频率的软件转换。

接下来,我必须增加堆的大小,该堆位于RAM中。 根据我们的估计,pjsip大约需要190 Kb,而我们只有大约100 Kb。 在这里,我不得不使用一些外部存储器-SDRAM(大约128 Kb)。

完成所有这些编辑之后,我看到了Linux和Embox之间的第一个软件包,并且听到了声音! 但是声音太糟糕了,根本不像QEMU上的声音,什么也听不见。 然后我们考虑可能是怎么回事。 调试表明Embox根本没有时间填充/卸载音频缓冲区。 当pjsip处理一帧时,在完成缓冲区处理之前发生了2次中断,这太多了。 加速的第一个想法是优化编译器,但是它已经包含在PJSIP中。 第二个是硬件浮点,我们在本文中已经讨论过 。 但是,正如实践表明的那样,FPU的速度并未显着提高。 下一步是确定线程的优先级。 Embox具有不同的调度策略,我提供了一种支持优先级并将音频流设置为最高优先级的策略。 也没有帮助。

接下来是我们正在使用外部存储器的想法,最好将结构移动到外部存储器,这种结构非常经常被访问。 我对simple_pjsua何时以及在什么情况下分配内存进行了初步分析。 事实证明,在190 Kb中,前90 Kb是为PJSIP的内部需求分配的,并且很少被访问。 然后,在传入呼叫期间,将调用pjsua_call_answer函数,然后在其中分配用于传入和传出帧的缓冲区。 大约是100 kb。 在这里,我们的行为如下。 通话之前,数据将放置在外部存储器中。 一旦调用-立即在另一个RAM中替换堆。 因此,所有“热”数据都被传输到更快,更可预测的存储器中。

结果,所有这些都允许启动simple_pjsua并通过其服务器进行调用。 然后通过其他服务器,例如sip.linphone.org。

结论


结果,结果是运行了simple_pjsua并通过服务器双向传输语音。 可以通过使用功能更强大的Cortex-M7(例如具有512 Kb RAM的STM32F769NI)来解决额外花费128 Kb SDRAM的问题,但与此同时,我们仍然不希望将其容纳到256 Kb :)如果有人感兴趣,我们将非常高兴。 ,甚至更好-试试。 所有资源,通常都在我们的资源库中

Source: https://habr.com/ru/post/zh-CN431134/


All Articles