Teléfono SIP en STM32F7-Discovery

Hola a todos.

Hace un tiempo nosotros escribió sobre cómo logramos lanzar un teléfono SIP en STM32F4-Discovery con 1 MB de ROM y 192 KB de RAM) basado en Empaque. Aquí hay que decir que esa versión era mínima y conectaba dos teléfonos directamente sin servidor y con transmisión de voz en una sola dirección. Por lo tanto, decidimos lanzar un teléfono más completo con una llamada a través del servidor, transmisión de voz en ambas direcciones, pero al mismo tiempo mantener el tamaño de memoria más pequeño posible.


Para el teléfono, se decidió elegir una aplicación. simple_pjsua como parte de la biblioteca PJSIP. Esta es una aplicación mínima que puede registrarse en el servidor, recibir y contestar llamadas. A continuación, daré inmediatamente una descripción de cómo ejecutarlo en STM32F7-Discovery.

Cómo lanzar

  1. Configuración de Embox
    make confload-platform/pjsip/stm32f7cube
  2. Establezca la cuenta SIP requerida en el archivo conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    donde servidor es un servidor SIP (por ejemplo, sip.linphone.org), nombre de usuario и la contraseña - usuario y contraseña de la cuenta.

  3. Montaje de Embox en equipo para lograr. Sobre el firmware de la placa que tenemos en wiki y статье.
  4. Ejecute el comando "simple_pjsua_imported" en la consola de Embox
    
    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 insertar parlantes o auriculares en la salida de audio y hablar en dos pequeños micrófonos MEMS al lado de la pantalla. Llamamos desde Linux a través de la aplicación simple_pjsua, pjsua. Bueno, o puedes usar cualquier otro tipo de linphone.

Todo esto está descrito en nuestro wiki.

como llegamos alla

Entonces, inicialmente surgió la pregunta sobre elegir una plataforma de hardware. Dado que estaba claro que STM32F4-Discovery no encajaría en la memoria, se eligió STM32F7-Discovery. Tiene una unidad flash de 1 MB y 256 KB de RAM (+ 64 de memoria rápida especial, que también usaremos). Tampoco hay mucho para llamadas a través del servidor, pero decidimos intentar encajar.

Condicionalmente para ellos, la tarea se dividió en varias etapas:

  • Ejecutando PJSIP en QEMU. Era conveniente para la depuración, además ya teníamos soporte para el códec AC97 allí.
  • Grabación y reproducción de voz en QEMU y en STM32.
  • Portar una aplicación simple_pjsua del PJSIP. Le permite registrarse en el servidor SIP y realizar llamadas.
  • Implemente su propio servidor basado en Asterisk y pruébelo, luego pruebe con servidores externos como sip.linphone.org

El sonido en Embox funciona a través de Portaudio, que también se usa en PISIP. Los primeros problemas aparecieron en QEMU: WAV se reproducía bien a 44100 Hz, pero a 8000 algo claramente salió mal. Resultó que era una cuestión de configurar la frecuencia: por defecto, era 44100 en el equipo, y esto no cambió mediante programación.

Aquí, quizás, valga la pena explicar un poco cómo se reproduce el sonido en general. La tarjeta de sonido se puede configurar para que apunte a una parte de la memoria desde la que desea reproducir o grabar a una frecuencia predeterminada. Una vez que finaliza el búfer, se genera una interrupción y la ejecución continúa con el siguiente búfer. El hecho es que estos búferes deben llenarse con anticipación mientras se reproduce el anterior. Enfrentaremos este problema más adelante en STM32F7.

A continuación, alquilamos un servidor e implementamos Asterisk en él. Como era necesario depurar mucho, pero no quería hablar mucho por el micrófono, era necesario hacer una reproducción y grabación automáticas. Para hacer esto, parcheamos simple_pjsua para que pueda deslizar archivos en lugar de dispositivos de audio. En PJSIP, esto se hace de manera bastante simple, ya que tienen el concepto de puerto, que puede ser un dispositivo o un archivo. Y estos puertos se pueden conectar de manera flexible a otros puertos. Puedes ver el código en nuestro pjsip repositorios. Como resultado, el esquema fue el siguiente. En el servidor Asterisk, inicié dos cuentas: para Linux y para Embox. A continuación, el comando se ejecuta en Embox simple_pjsua_importado, Embox se registra en el servidor, después de lo cual llamamos a Embox desde Linux. Al momento de la conexión, verificamos en el servidor Asterisk que la conexión está establecida, y después de un tiempo deberíamos escuchar el sonido de Linux en Embox, y en Linux guardamos el archivo que se reproduce desde Embox.

Después de que funcionó en QEMU, pasamos a la migración a STM32F7-Discovery. El primer problema es que no cabían en 1 MB de ROM sin la optimización del compilador "-Os" habilitada para el tamaño de la imagen. Es por eso que incluimos "-Os". Además, el parche deshabilitó la compatibilidad con C ++, por lo que solo se necesita para pjsua, y usamos simple_pjsua.

Después de ser colocado simple_pjsua, decidió que ahora existe la posibilidad de lanzarlo. Pero primero era necesario ocuparse de la grabación y reproducción de la voz. La pregunta es ¿dónde escribir? Elegimos memoria externa - SDRAM (128 MB). Puedes probar esto tú mismo:

Crea un WAV estéreo con una frecuencia de 16000 Hz y una duración de 10 segundos:


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

Perdemos:


play -m C0000000

Hay dos problemas aquí. Se usa el primero con el códec: WM8994, y tiene una ranura, y hay 4 de estas ranuras. Entonces, de manera predeterminada, si esto no está configurado, cuando se reproduce audio, la reproducción ocurre en las cuatro ranuras. . Por lo tanto, a una frecuencia de 16000 Hz, recibimos 8000 Hz, pero para 8000 Hz, la reproducción simplemente no funcionó. Cuando solo se seleccionaron las ranuras 0 y 2, funcionó como debería. Otro problema fue la interfaz de audio en el STM32Cube, en el que la salida de audio funciona vía SAI (Serial Audio Interface) de forma sincrónica con la entrada de audio (no entendí los detalles, pero resulta que comparten un reloj común y cuando el la salida de audio se inicializa, el audio se adjunta de alguna manera a su entrada). Es decir, no puede ejecutarlos por separado, por lo que hicimos lo siguiente: la entrada de audio y la salida de audio siempre funcionan (incluidas las interrupciones que se generan). Pero cuando no se está reproduciendo nada en el sistema, simplemente insertamos un búfer vacío en la salida de audio y, cuando comienza la reproducción, honestamente comenzamos a llenarlo.

Además, nos encontramos con el hecho de que el sonido durante la grabación de voz era muy bajo. Esto se debe al hecho de que los micrófonos MEMS del STM32F7-Discovery no funcionan bien a frecuencias inferiores a 16000 Hz. Por lo tanto, configuramos 16000 Hz, incluso si vienen 8000 Hz. Sin embargo, para hacer esto, fue necesario agregar un software de conversión de una frecuencia a otra.

A continuación, tuve que aumentar el tamaño del montón, que se encuentra en la RAM. Según nuestros cálculos, pjsip requirió alrededor de 190 KB, y solo nos quedan alrededor de 100 KB. Aquí tuve que usar algo de memoria externa: SDRAM (alrededor de 128 KB).

Después de todas estas ediciones, vi los primeros paquetes entre Linux y Embox, ¡y escuché el sonido! Pero el sonido era terrible, para nada igual que en QEMU, era imposible distinguir nada. Entonces pensamos en lo que podría ser el problema. La depuración mostró que Embox simplemente no tiene tiempo para llenar/descargar búferes de audio. Mientras pjsip estaba procesando un cuadro, 2 interrupciones tuvieron tiempo de ocurrir sobre la finalización del procesamiento del búfer, lo cual es demasiado. El primer pensamiento para la velocidad fue la optimización del compilador, pero ya estaba incluido en PJSIP. El segundo es un punto flotante de hardware, hablamos de ello en статье. Pero como ha demostrado la práctica, FPU no dio un aumento significativo en la velocidad. El siguiente paso fue priorizar los hilos. Embox tiene diferentes estrategias de programación, y he incluido una que admite prioridades y establece transmisiones de audio en la prioridad más alta. Esto tampoco ayudó.

La siguiente idea fue que estamos trabajando con memoria externa y sería bueno mover allí estructuras a las que se accede con mucha frecuencia. Hice un análisis preliminar de cuándo y bajo qué simple_pjsua asigna memoria. Resultó que de 190 Kb, los primeros 90 Kb se asignan para necesidades internas de PJSIP y no se accede a ellos con mucha frecuencia. Además, durante una llamada entrante, se llama a la función pjsua_call_answer, en la que se asignan búferes para trabajar con marcos entrantes y salientes. Todavía era alrededor de 100 Kb. Y luego hicimos lo siguiente. Hasta el momento de la llamada, colocamos los datos en memoria externa. Tan pronto como la llamada, reemplazamos inmediatamente el montón con otro, en RAM. Por lo tanto, todos los datos "calientes" se transfirieron a una memoria más rápida y predecible.

Como resultado, todo esto en conjunto hizo posible el lanzamiento simple_pjsua y llame a través de su servidor. Y luego a través de otros servidores como sip.linphone.org.

Hallazgos

Como resultado, fue posible lanzar simple_pjsua con transmisión de voz en ambos sentidos a través del servidor. El problema con los 128 KB adicionales de SDRAM se puede resolver usando un Cortex-M7 un poco más potente (por ejemplo, STM32F769NI con 512 KB de RAM), pero al mismo tiempo, todavía no hemos perdido la esperanza de entrar en 256 KB 🙂 Estaremos encantados si alguien está interesado, o mejor aún, pruébalo. Todas las fuentes, como siempre, están en nuestro repositorios.

Fuente: habr.com

Añadir un comentario