Teléfono SIP en STM32F7-Discovery

Ola a todos.

Hai un tempo nós писали sobre como conseguimos lanzar un teléfono SIP en STM32F4-Discovery con 1 MB de ROM e 192 KB de RAM) baseado en Embox. Aquí hai que dicir que esa versión era mínima e conectaba dous teléfonos directamente sen servidor e con transmisión de voz nun só sentido. Por iso, decidimos lanzar un teléfono máis completo cunha chamada a través do servidor, transmisión de voz en ambas direccións, pero ao mesmo tempo manter o menor tamaño de memoria posible.


Para o teléfono, decidiuse escoller unha aplicación simple_pjsua como parte da biblioteca PJSIP. Esta é unha aplicación mínima que pode rexistrarse no servidor, recibir e responder chamadas. A continuación, darei inmediatamente unha descrición de como executalo en STM32F7-Discovery.

Como correr

  1. Configurando embox
    make confload-platform/pjsip/stm32f7cube
  2. Establece a conta SIP necesaria no ficheiro conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    onde servidor é un servidor SIP (por exemplo, sip.linphone.org), nome de usuario и contrasinal - nome de usuario e contrasinal da conta.

  3. Montando Embox como un equipo facer. Sobre o firmware da placa que temos wiki e Artigo.
  4. Executa o comando "simple_pjsua_imported" na consola de Embbox
    
    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
    

  5. Finalmente, queda inserir altofalantes ou auriculares na saída de audio e falar en dous pequenos micrófonos MEMS xunto á pantalla. Chamamos dende Linux a través da aplicación simple_pjsua, pjsua. Ben, ou podes usar calquera outro tipo de teléfono.

Todo isto está descrito no noso wiki.

Como chegamos alí

Entón, inicialmente xurdiu a pregunta sobre a elección dunha plataforma de hardware. Dado que estaba claro que STM32F4-Discovery non cabería da memoria, escolleuse STM32F7-Discovery. Ten unha unidade flash de 1 MB e 256 KB de RAM (+ 64 de memoria rápida especial, que tamén utilizaremos). Tampouco hai moitas chamadas a través do servidor, pero decidimos tentar encaixar.

Condicionalmente, a tarefa dividiuse en varias etapas:

  • Execución de PJSIP en QEMU. Era conveniente para a depuración, ademais de que xa tiñamos soporte para o códec AC97 alí.
  • Gravación e reprodución de voz en QEMU e en STM32.
  • Portar unha aplicación simple_pjsua de PJSIP. Permítelle rexistrarse no servidor SIP e facer chamadas.
  • Implementa o teu propio servidor baseado en Asterisk e proba nel, despois proba con outros externos como sip.linphone.org

O son en Embox funciona a través de Portaudio, que tamén se usa en PISIP. Os primeiros problemas apareceron en QEMU - WAV tocou ben a 44100 Hz, pero a 8000 algo saíu mal. Resultou que se trataba de establecer a frecuencia: por defecto era 44100 no equipo, e isto non cambiou programáticamente.

Aquí, quizais, paga a pena explicar un pouco como se reproduce o son en xeral. A tarxeta de son pódese definir como un punteiro a unha peza de memoria desde a que quere reproducir ou gravar a unha frecuencia predeterminada. Despois de que remate o búfer, xérase unha interrupción e a execución continúa co seguinte búfer. O caso é que estes buffers deben encherse con antelación mentres se xoga o anterior. Afrontaremos este problema máis en STM32F7.

A continuación, alugamos un servidor e implantamos Asterisk nel. Como era necesario depurar moito, pero non quería falar moito polo micrófono, foi necesario facer a reprodución e gravación automáticas. Para iso, parcheamos simple_pjsua para que poidas deslizar ficheiros en lugar de dispositivos de audio. En PJSIP, isto faise de forma sinxela, xa que teñen o concepto de porto, que pode ser un dispositivo ou un ficheiro. E estes portos pódense conectar de forma flexible a outros portos. Podes ver o código no noso pjsip repositorios. Como resultado, o esquema foi o seguinte. No servidor Asterisk, iniciei dúas contas: para Linux e para Embox. A continuación, o comando execútase en Embox simple_pjsua_imported, Embox está rexistrado no servidor, despois de que chamamos Embox desde Linux. No momento da conexión, comprobamos no servidor Asterisk que a conexión está establecida, e despois dun tempo deberiamos escoitar o son de Linux en Embox, e en Linux gardamos o ficheiro que se reproduce desde Embox.

Despois de que funcionase en QEMU, pasamos á portabilidade a STM32F7-Discovery. O primeiro problema é que non encaixaban en 1 MB de ROM sen a optimización do compilador activada "-Os" para o tamaño da imaxe. Por iso incluímos "-Os". Ademais, o parche desactivou o soporte para C++, polo que só se necesita para pjsua, e usamos simple_pjsua.

Despois de ser colocado simple_pjsua, decidiu que agora hai unha oportunidade de lanzalo. Pero antes había que ocuparse da gravación e reprodución da voz. A pregunta é onde escribir? Escollemos memoria externa - SDRAM (128 MB). Podes probar isto ti mesmo:

Crea un WAV estéreo cunha frecuencia de 16000 Hz e unha duración de 10 segundos:


record -r 16000 -c 2 -d 10000 -m C0000000

Perdemos:


play -m C0000000

Aquí hai dous problemas. O primeiro co códec utilízase - WM8994, e ten un slot, e hai 4 destes slots. Polo tanto, de forma predeterminada, se isto non está configurado, ao reproducir audio, a reprodución ocorre nas catro ranuras. . Polo tanto, a unha frecuencia de 16000 Hz, recibimos 8000 Hz, pero para 8000 Hz, a reprodución simplemente non funcionou. Cando só se seleccionaron os slots 0 e 2, funcionou como debería. Outro problema foi a interface de audio no STM32Cube, na que a saída de audio funciona a través de SAI (Serial Audio Interface) de forma sincronizada coa entrada de audio (non entendín os detalles, pero resulta que comparten un reloxo común e cando o a saída de audio está inicializada, o audio está conectado dalgún xeito á súa entrada). É dicir, non pode executalos por separado, polo que fixemos o seguinte: a entrada de audio e a saída de audio sempre funcionan (incluídas as interrupcións que se xeran). Pero cando non se reproduce nada no sistema, simplemente introducimos un búfer baleiro na saída de audio e, cando comeza a reprodución, comezamos a enchelo sinceramente.

Ademais, atopamos o feito de que o son durante a gravación de voz era moi silencioso. Isto débese ao feito de que os micrófonos MEMS do STM32F7-Discovery dalgún xeito non funcionan ben a frecuencias inferiores a 16000 Hz. Polo tanto, establecemos 16000 Hz, aínda que veña 8000 Hz. Para iso, porén, foi necesario engadir unha conversión de software dunha frecuencia a outra.

A continuación, tiven que aumentar o tamaño do montón, que está situado na memoria RAM. Segundo os nosos cálculos, pjsip requiriu uns 190 KB e só nos quedan uns 100 KB. Aquí tiven que usar algunha memoria externa: SDRAM (uns 128 KB).

Despois de todas estas edicións, vin os primeiros paquetes entre Linux e Embox, e escoitei o son! Pero o son era terrible, non era para nada o mesmo que en QEMU, era imposible distinguir nada. Despois pensamos cal podería ser o problema. A depuración mostrou que Embox simplemente non ten tempo para encher/descargar búfers de audio. Mentres pjsip procesaba un fotograma, tivo tempo para producirse 2 interrupcións sobre a finalización do procesamento do búfer, que é demasiado. O primeiro pensamento para a velocidade foi a optimización do compilador, pero xa estaba incluído en PJSIP. O segundo é un punto flotante de hardware, falamos del Artigo. Pero como demostrou a práctica, FPU non deu un aumento significativo da velocidade. O seguinte paso foi priorizar os fíos. Embox ten diferentes estratexias de programación e incluín unha que admite prioridades e establece as emisións de audio coa máxima prioridade. Isto tampouco axudou.

A seguinte idea foi que estamos a traballar con memoria externa e sería bo mover alí estruturas ás que se accede con moita frecuencia. Fixen unha análise preliminar de cando e baixo que simple_pjsua asigna memoria. Resultou que dos 190 Kb, os primeiros 90 Kb destínanse para necesidades internas de PJSIP e non se accede a eles con moita frecuencia. Ademais, durante unha chamada entrante, chámase á función pjsua_call_answer, na que despois se asignan búfers para traballar con fotogramas entrantes e saíntes. Aínda eran uns 100 Kb. E despois fixemos o seguinte. Ata o momento da chamada, colocamos os datos na memoria externa. Tan pronto como a chamada, substituímos inmediatamente o montón por outro - en RAM. Así, todos os datos "quentes" foron transferidos a unha memoria máis rápida e previsible.

Como resultado, todo isto en conxunto fixo posible o seu lanzamento simple_pjsua e chama a través do teu servidor. E despois a través doutros servidores como sip.linphone.org.

Descubrimentos

Como resultado, foi posible lanzar simple_pjsua con transmisión de voz en ambas direccións a través do servidor. O problema con 128 KB de SDRAM gastados adicionalmente pódese resolver usando un Cortex-M7 un pouco máis potente (por exemplo, STM32F769NI con 512 KB de RAM), pero ao mesmo tempo, aínda non perdemos a esperanza de entrar en 256. KB 🙂 Estaremos encantados se alguén está interesado, Ou mellor aínda, proba. Todas as fontes, como é habitual, están na nosa repositorios.

Fonte: www.habr.com

Engadir un comentario