Telefone SIP no STM32F7-Discovery

Olá a todos.

Há algum tempo, nós reportou sobre como conseguimos rodar um telefone SIP no STM32F4-Discovery com 1 MB de ROM e 192 kB de RAM) baseado em Embox. É importante mencionar que aquela versão era mínima e conectava dois telefones diretamente sem servidor e com a transmissão de voz apenas em uma direção. Por isso, decidimos lançar um telefone mais completo, com chamadas através de um servidor, transmissão de voz em ambas as direções, mas mantendo o tamanho da memória o menor possível.

Por que no hosting comum a administração do PrestaShop é lenta, e no seu não é?

Para o telefone, decidimos escolher o aplicativo simple_pjsua parte da biblioteca PJSIP. Este é um aplicativo mínimo que pode se registrar no servidor, receber e realizar chamadas. Abaixo, já irei apresentar uma descrição de como executá-lo no STM32F7-Discovery.

Como executar

  1. Configurando o Embox
    make confload-platform/pjsip/stm32f7cube
  2. No arquivo conf/mods.config, definimos a conta SIP necessária.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    onde servidor — este é o servidor SIP (por exemplo, sip.linphone.org), nome de usuário e senha — o nome de usuário e a senha da conta.

  3. Compilamos o Embox com o comando make. Temos informações sobre a programação da placa em wiki e no artigo.
  4. Executamos no console do Embox o comando “simple_pjsua_imported”
    
    00:00:12.870    pjsua_acc.c  ....O status de saída SIP para acc 0 não está ativo
    00:00:12.884    pjsua_acc.c  ....sip:alexk2222@sip.linphone.org: registro bem-sucedido, status=200 (Registro bem-sucedido)
    00:00:12.911    pjsua_acc.c  ....Temporizador de keep-alive iniciado para acc 0, destino:91.121.209.194:5060, intervalo:15s
    

  5. Por fim, basta conectar alto-falantes ou fones de ouvido à saída de áudio e falar em dois pequenos microfones MEMS próximos ao display. Chamamos do Linux através do aplicativo simple_pjsua, pjsua. Ou você pode usar qualquer outro, como linphone.

Tudo isso está descrito em nosso wiki.

Como chegamos a isso

Então, inicialmente surgiu a questão da escolha da plataforma de hardware. Como ficou claro que o STM32F4-Discovery não seria suficiente em termos de memória, escolhemos o STM32F7-Discovery. Ele tem 1 MB de flash e 256 kB de RAM (+ 64 kB de memória rápida especial, que também iremos usar). Também não é muito para chamadas através de servidor, mas decidimos tentar.

Condicionalmente, dividimos a tarefa em várias etapas:

  • Execução do PJSIP no QEMU. Isso foi conveniente para depuração, além de já termos lá suporte para o codec AC97.
  • Gravação de voz e reprodução no QEMU e no STM32.
  • Portabilidade do aplicativo simple_pjsua da biblioteca PJSIP. Ele permite registrar-se no servidor SIP e fazer chamadas.
  • Implantar seu próprio servidor baseado em Asterisk e testá-lo, após o que tentaremos externos, como sip.linphone.org.

O som no Embox funciona através do Portaudio, que também é utilizado no PISIP. No QEMU, surgiram os primeiros problemas — os arquivos WAV de 44100 Hz eram reproduzidos corretamente, mas em 8000 algo definitivamente não estava certo. Descobriu-se que o problema estava na configuração da frequência — por padrão, no hardware, era 44100, e isso não alteramos programaticamente.

Aqui, talvez seja importante esclarecer como a reprodução de som ocorre. Um ponteiro de memória pode ser definido para a placa de som, a partir do qual deve ser reproduzido ou gravado em uma frequência previamente definida. Após o preenchimento do buffer, ocorre uma interrupção e a execução continua com o próximo buffer. O desafio é que esses buffers precisam ser preenchidos antecipadamente enquanto o anterior ainda está sendo reproduzido. Enfrentaremos esse problema mais adiante no STM32F7.

Em seguida, alugamos um servidor e instalamos o Asterisk nele. Como era necessário bastante depuração e não queríamos falar muito no microfone, precisávamos implementar a reprodução e gravação automáticas. Para isso, modificamos o simple_pjsua para permitir que arquivos fossem utilizados em vez de dispositivos de áudio. No PJSIP, isso é bastante simples, pois há o conceito de porta, que pode ser tanto um dispositivo quanto um arquivo. E essas portas podem ser conectadas de forma flexível a outras portas. O código pode ser consultado em nosso pjsip. repositórioAssim, o esquema era o seguinte. No servidor Asterisk, criei duas contas — uma para Linux e outra para Embox. Em seguida, no Embox, a seguinte comando é executado simple_pjsua_imported, o Embox se registra no servidor, após o qual fazemos uma chamada do Linux para o Embox. No momento da conexão, verificamos no servidor Asterisk se toda a conexão foi estabelecida, e após algum tempo devemos ouvir o som vindo do Linux no Embox, enquanto no Linux salvamos o arquivo que está sendo reproduzido a partir do Embox.

Após fazer isso funcionar no QEMU, passamos para a portabilidade no STM32F7-Discovery. O primeiro problema foi que não cabíamos em 1 MB de ROM sem habilitar a otimização do compilador '-Os' para o tamanho da imagem. Portanto, habilitamos '-Os'. Em seguida, desativamos o suporte a C++ através de patch, pois isso é necessário apenas para pjsua, e estamos usando o simple_pjsua.

Depois que conseguimos ajustar simple_pjsua, decidimos que agora havia chances de que isso funcionasse. Mas primeiro precisávamos resolver a gravação e reprodução da voz. A pergunta era — para onde gravar? Escolhemos a memória externa — SDRAM (128 MB). Você pode tentar isso você mesmo:

Criará um WAV estéreo a 16000 Hz e com duração de 10 segundos:


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

Reproduzindo:


play -m C0000000

Aqui surgiram dois problemas. O primeiro era com o codec — usa-se WM8994, que possui um conceito chamado slot, e existem 4 desses slots. Por padrão, se não for configurado, ao reproduzir áudio, a reprodução ocorre em todos os quatro slots. Portanto, à frequência de 16000 Hz, estávamos obtendo 8000 Hz, e para 8000 Hz a reprodução simplesmente não funcionava. Quando escolhemos apenas os slots 0 e 2, funcionou como deveria. Outro problema foi a interface de áudio no STM32Cube, onde a saída de áudio funciona através de SAI (Serial Audio Interface) de forma síncrona com a entrada de áudio (não me aprofundei nos detalhes, mas parece que eles compartilham um clock comum, e durante a inicialização da saída de áudio, de alguma forma está atrelada à entrada de áudio). Ou seja, não é possível iniciá-los separadamente, portanto fizemos o seguinte — a entrada e a saída de áudio sempre estão funcionando (incluindo a geração de interrupções). Mas quando nada está sendo reproduzido no sistema, simplesmente alimentamos a saída de áudio com um buffer vazio, e quando a reprodução é iniciada, começamos a preenchê-lo adequadamente.

Em seguida, encontramos o problema de que o som ao gravar a voz estava muito baixo. Isso ocorre porque os microfones MEMS no STM32F7-Discovery não funcionam bem em frequências abaixo de 16000 Hz. Portanto, configuramos para 16000 Hz, mesmo que a entrada seja 8000 Hz. Para isso, foi necessário adicionar uma conversão de frequência no software.

Depois, foi necessário aumentar o tamanho da pilha, que está localizada na RAM. Segundo nossas contas, o pjsip exigia cerca de 190 KB, enquanto nós tínhamos apenas cerca de 100 KB restantes. Então, foi preciso utilizar um pouco de memória externa — SDRAM (cerca de 128 KB).

Após todas essas alterações, vi os primeiros pacotes entre Linux e Embox e ouvi o som! Mas o som estava horrível, nada parecido com o do QEMU, nada podia ser compreendido. Então, questionamos qual poderia ser o problema. A depuração mostrou que o Embox simplesmente não estava conseguindo preencher/descarregar os buffers de áudio a tempo. Enquanto o pjsip processava um quadro, acabavam ocorrendo 2 interrupções ao finalizar o processamento dos buffers, o que era excessivo. O primeiro pensamento para acelerar foi a otimização do compilador, mas essa já estava ativada no PJSIP. O segundo — ponto flutuante de hardware, sobre o qual falamos em artigo. Mas como a prática mostrou, o FPU não proporcionou um ganho significativo de velocidade. O próximo passo foi a definição de prioridades de threads. No Embox, existem diferentes estratégias de escalonamento, e eu ativei a que suporta prioridades, dando ao fluxo de áudio a maior prioridade. Isso também não ajudou.

A próxima ideia foi que estávamos lidando com memória externa e seria bom mover para lá as estruturas que são acessadas com bastante frequência. Fiz uma análise preliminar de quando e para que simple_pjsua a memória é alocada. Verificou-se que dos 190 Kb, os primeiros 90 Kb são alocados para necessidades internas do PJSIP e são acessados com pouca frequência. Durante uma chamada recebida, a função pjsua_call_answer é chamada, na qual os buffers para trabalhar com os quadros de entrada e saída são alocados. Isso consumiu mais cerca de 100 Kb. E aqui fizemos o seguinte. Até o momento da chamada, as informações são armazenadas na memória externa. Assim que a chamada ocorre, mudamos imediatamente a heap para outra — na RAM. Dessa forma, todos os dados 'quentes' foram movidos para uma memória mais rápida e previsível.

Como resultado, tudo isso permitiu iniciar simple_pjsua e fazer chamadas através do nosso servidor. E depois, também através de outros servidores, como sip.linphone.org.

Como resultado, obtemos um serviço de "monitoramento como serviço", automatizado na linha de produção de integração contínua. O desenvolvedor ou testador precisa apenas definir a lista de métricas em um arquivo JSON, e tudo o mais acontece automaticamente. Obtemos um controle de qualidade transparente dos lançamentos: todas as notificações sobre desempenho, consumo de recursos ou regressões arquitetônicas.

No final, conseguimos iniciar simple_pjsua com a transmissão de voz em ambas as direções através do servidor. O problema com os 128 Kb SDRAM gastos a mais pode ser resolvido utilizando um Cortex-M7 um pouco mais potente (por exemplo, STM32F769NI com 512 Kb de RAM), mas ainda assim não desistimos da ideia de conseguir ajustar tudo dentro de 256 Kb 🙂 Ficaremos felizes se alguém se interessar, e ainda melhor — testar. Todos os fontes, como de costume, estão no nosso repositório.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster