Compilando PJSIP (VOIP) para Linux embarcado

PJSIP-destaque

Os principais objetivos deste artigo são a compilação cruzada das bibliotecas PJSIP e da implementação de referência da API PJSUA2 e sua instalação no target, obtenção de uma visão geral sobre o protocolo SIP e exploração da implementação de referência, focando somente no áudio. Para este propósito, um CoM (computador em módulo) da Toradex foi escolhido na seguinte configuração: Colibri iMX6DL + Colibri Evaluation Board. A Evaluation Board e o CoM são apresentados nas figuras 1 e 2, respectivamente.

 

PJSIP-01
Figura 1: Colibri Evaluation Board
PJSIP-02
Figura 2: Colibri iMX6DL

 

VOIP é um termo utilizado para se referir a um conjunto de métodos e tecnologias focados na implementação de serviços de telefonia pela internet, logo o significado do termo: Voice over IP, ou Voz sobre IP. Sendo esta uma ampla área de aplicação, para os propósitos deste artigo o escopo será limitado ao uso de uma implementação de referência construída sobre o protocolo SIP de sinal para estabelecer chamadas sobre IP, por meio das bibliotecas PJSIP e da API PJSUA2. Se você desejar obter mais informações sobre VOIP em geral,  existe um website (em inglês) que se autodenomina "Um guia de referência para todas as coisas relacionadas a VOIP" e ele contém informações completas sobre o assunto.

 

SIP é o Protocolo de Iniciação de Sessão - um protocolo usado para sinalização e controle de sessões de comunicação. Este protocolo é muitas vezes considerado o padrão de facto para implementações de VOIP, sendo um padrão da IETF (Internet Engineering Task Force), embora existam outras opções como por exemplo o IAX2. SIP emprega o protocolo RTP para transmissão de dados e este, por sua vez, é encapsulado em TCP ou UDP e pode ser encriptado usando TLS.

 

PJSIP é um conjunto de bibliotecas que implementa em linguagem C o protocolo SIP e outros relacionados, como o RTP e STUN, dentre outros. Dentre suas vantagens está o fato de que PJSIP é open source, de alta portabilidade entre sistemas (Linux, Windows, iOS, dentre outros), começou em 2005 e continua sendo mantido e melhorado, além de possuir ampla documentação e a vantagem de oferecer uma API de alto nível de abstração chamada PJSUA2, para a construção fácil de aplicações customizadas. A PJSUA2 até possui um livro online como documentação oficial.

 

 

Compilação cruzada das bibliotecas PJSIP

 

O primeiro passo para realizar a compilação cruzada das bibliotecas PJSIP e aplicações de teste/referência é ter a toolchain pronta para uso. Para isto, nós podemos seguir os passos da seção toolchain for hard float calling convention deste artigo. Note que se você deseja utilizar sua própria toolchain para compilação cruzada, de acordo com esta documentação do PJSIP você precisa ter as seguintes ferramentas: GNU make, GNU binutils e GNU gcc para o target.

 

Como o sistema de arquivos básico que é provido pela toolchain Linaro não possui o ALSA instalado - que é necessário para compilar o PJSIP - nós vamos fazer o download e compilar estas bibliotecas, que podem ser obtidas no site do ALSA Project. Neste artigo, a versão da alsa-lib baixada foi a 1.1.1. Depois de baixar e compilar, nós temos que instalar os headers e a biblioteca no rootfs do Linaro.

 

Instalando a toolchain Linaro:

 

 

Exportando as variáveis de ambiente:

 

 

Fazendo download e descompactando a biblioteca ALSA:

 

 

Antes de compilar os códigos fonte da biblioteca, é preciso executar o script do autoconf com as variáveis CFLAGS, LDFLAGS e –prefix apontando para o rootfs da toolchain:

 

 

Depois disso é só compilar e instalar. Após o comando make a compilação vai quebrar em algum ponto, mas para nós isso não importa, já que a biblioteca que precisamos terá sido compilada:

 

 

Com a toolchain configurada, podemos fazer o download e extrair os códigos fonte do PJSIP no computador e então entrar no diretório em que está o conteúdo descompactado. Quando este artigo foi escrito, a versão do PJSIP era a 2.5.1:

 

 

Antes de compilar os códigos fonte do PJSIP, é preciso executar o script do autoconf apontando para o rootfs previamente modificado da toolchain. O procedimento é parecido com o que seguimos para compilar a ALSA, com a diferença de que o diretório para o qual queremos que as bibliotecas compiladas sejam instaladas é um diretório que iremos posteriormente compactar e transferir para o sistema embarcado (se você vai desenvolver suas próprias aplicações, talvez seja interessante instalar no rootfs do seu target ou até neste rootfs da toolchain que estamos usando).

 

 

Agora nós podemos compilar as bibliotecas e também copiar o executável da  implementação de referência para o diretório de instalação:

 

 

Os próximos passos são comprimir o diretório e copiá-lo para a Colibri iMX6. Para descobrir o IP do seu iMX6 você pode executar o comando ifconfig

 

Por fim, logado na Colibri iMX6:

 

 

Agora nós temos o PJSIP instalado no target - embora isto não seja necessário para os nossos próximos passos, pois executaremos um arquivo já compilado, talvez você ache útil ter tudo instalado enquanto desenvolve aplicações próprias. Nós também estamos prontos para começar a usar a implementação de referência, mas primeiro vamos verificar outras questões.

 

 

Verificação e configuração de áudio

 

A biblioteca PJSIP usa recursos do ALSA (Advanced Linux Sound Architecture), que é também o subsistema de áudio empregado pela Toradex em suas BSPs. Antes de começar, certifique-se de conectar um fone de ouvido/alto falante e um microfone na Evaluation Board, com o sistema desligado, conforme ilustrado na figura 3.

 

PJSIP-03
Figura 3: Conectando microfone/fones de ouvido/alto falante à Evaluation Board

 

Então você pode usar a aplicação alsamixer para ajustar as opções de audio de acordo com o seu sistema:

 

 

A configuração usada neste artigo é ilustrada na figura 4, e você pode perceber na prática que ajustar a amplificação do microfone muito alta pode causar distorção, portanto é bom experimentar as possibilidades - mesmo ajustando a opção mic para zero não irá desabilitar seu microfone - isto só significa que não haverá amplificação ou, em outras palavras, um ganho de 0dB. Outro ponto importante a ser notado é que se você desligar o sistema embarcado subitamente, as configurações podem ser perdidas, portanto faça um reboot ou desligue a partir da linha de comando sempre que você mudar as configurações:

 

 

PJSIP-04
Figura 4: Configuração do alsamixer

 

Para testar a entrada de áudio (microfone) e, subsequentemente a saída (fones/alto falante) nós vamos gravar um pequeno trecho de áudio usando o comando arecord e então vamos tocá-lo usando o comando aplay. Observe que para o arecord há algumas opções que precisamos passar: -V mostra um medidor de volume (VU meter) para que possamos ter feedback visual quanto às configurações do microfone; mono é passado já que o microfone é mono; -r é a taxa de amostragem; -f é o formato; e -d é a duração da gravação em segundos. Para mais informações sobre o arecord, você pode usar a opção --help, ou se quiser saber mais sobre audio no Colibri iMX6 você pode acessar a página relacionada no developer da Toradex.

 

 

Se você consegue ouvir bem a gravação, podemos seguir em frente. Caso contrário, verifique os conectores e as configurações de áudio.

 

Visão geral do protocolo SIP

 

SIP é o Protocolo de Iniciação de Sessão, padronizado pela IETF e usado para VOIP e outros tipos de sessão multimídia, como mensagem e vídeo, por exemplo. Este protocolo é baseado em texto e usa a codificação UTF-8, usualmente empregando UDP ou TCP como protocolo de transporte. O Agente do Utilizador ou terminal SIP é o software que implementa as funcionalidades SIP e este se comporta como cliente ao pedir o início de uma sessão e também como servidor ao responder a este pedido, o que possibilita a conexão ponto-a-ponto. As informações apresentadas nesta seção foram baseadas em informações deste site.  

 

O protocolo possui métodos definidos em sua RFC e métodos de extensão definidos em outras RFCs. Alguns deles são:

  • ACK: usado em algumas situações para handshake
  • BYE: desligar/desconectar da sessão
  • CANCEL: cancelar um convite
  • INVITE: adicionar outro terminal SIP a uma sessão
  • SUBSCRIBE: pede informações sobre o status de uma sessão
  • NOTIFY: enviado periodicamente pelo gateway, precisa ser respondido com 200 OK
  • MESSAGE: usado para transportar o conteúdo de mensagens instantâneas

 

Há também códigos de resposta, cada qual com um significado específico, que consistem de valores de 3 dígitos:

  • 1xx: provisional – requisições recebidas e que ainda estão sendo processadas e.g. 100 trying; 180 ringing
  • 2xx: success – ação recebida e aceita e.g. 200 ok
  • 3xx: redirection – ainda há ações necessárias para completar uma requisição e.g. 300 multiple choices; 305 use proxy
  • 4xx: client error – servidor não pode processar requisições ou o cliente enviou requisição inválida e.g. 400 bad request; 404 not found
  • 5xx: server error – servidor não conseguiu processar uma requisição válida e.g. 500 server internal error
  • 6xx: global failure – nenhum servidor conseguiu cumprir a requisição e.g. 600 busy everywhere; 603 decline

 

É importante notar que o protocolo SIP não carrega a informação de áudio. Ao invés disto, ele emprega o protocolo RTP encapsulado geralmente em UDP ou TCP. Para um melhor entendimento, o exemplo da figura 5 ilustra a transação entre dois terminais SIP para uma chamada simples.

 

PJSIP-05
Figura 5: Exemplo de uma chamada simples entre dois terminais SIP

 

Para realizar chamadas, uma URI SIP é necessária. Esta é uma maneira de identificar um recurso de comunicação, ou seja, um terminal. Uma URI completa tem o formato sip:usuário:[email protected]:port;uri-parameters?headers, mas ainda assim há sistemas que podem operar até mesmo com uma URI que informa somente o campo host.

 

 

Implementação de referência PJSUA

 

A implementação de referência da API PJSUA é uma aplicação baseada em linha de comando que usa as bibliotecas PJSIP, PJMEDIA e PJNATH para implementar um terminal SIP, também conhecido como Agente do Utilizador ou softphone. Seu código fonte pode ser encontrado aqui e este é um ótimo ponto de partida para desenvolver uma solução específica. A documentação completa que compreende o uso da aplicação PJSUA pode ser obtida aqui.

 

Antes de começar a testar, anote o endereço de IP do seu sistema embarcado e do seu PC/notebook. Você deve estar com ambos os dispositivos conectados na mesma LAN, uma vez que não estamos preocupados em usar um servidor proxy ou algo do tipo, portanto nossa conexão entre dispositivos será feita ponto-a-ponto.

 

 

Neste artigo, nós vamos assumir os endereços de IP 192.168.10.5 para o Colibri iMX6 e 192.168.10.1 para o PC. Você também precisa instalar um software de terminal SIP no seu PC – que pode ser até a mesma aplicação de referência usada no sistema embarcado, se você quiser compilar para a sua máquina - mas neste artigo vamos utilizar o softphone de código aberto Linphone, para Ubuntu 14.04 LTS. Para iniciar o PJSUA no sistema embarcado use o comando a seguir. A interface esperada está ilustrada na figura 6.

 

 

PJSIP-06
Figura 6: Interface do PJSUA por linha de comando

 

Para fazer uma nova chamada do sistema embarcado para o PC, tecle "m" e insira a URI SIP mais simples possível, que consiste em passar somente o IP do terminal ao qual deseja-se conectar, no formato sip:192.168.10.1. O processo de fazer a chamada está ilustrado na figura 7 e a chamada aceita no PC está ilustrada na figura 8. Para desligar, use o comando "h".

 

PJSIP-07
Figura 7: Fazendo uma chamada usando o PJSUA
PJSIP-08
Figura 8: Chamada aceita no Linphone – chamada em execução

 

Para mandar mensagens instantâneas, digite "i", a URI SIP do destino e a mensagem, de forma similar a quando foi realizada a chamada. No seu PC, você deverá ver a mensagem; após feito isso, tente mandar alguma mensagem para o iMX6 usando a GUI do Linphone. A figura 9 apresenta a interface de mensagens do Linphone com algumas mensagens trocadas entre os dispositivos, enquanto a figura 10 ilustra uma mensagem recebida pelo Colibri iMX6.

 

PJSIP-09
Figura 9: Troca de mensagens entre o Colibri iMX6 e o PC/notebook
PJSIP-10
Figura 10: Mensagem recebida pelo Colibri iMX6

 

Configuração adicional

 

Nesta subseção algumas das opções da aplicação PJSUA serão apresentadas, e elas podem ser consultadas em detalhes aqui, dentre outras diversas opções. Nosso primeiro passo é criar um arquivo nomeado .conf-pjsua no sistema embarcado, com o seguinte conteúdo:

 

 

A configuração stereo permite que a saída de áudio seja direcionada aos dois alto-falantes do fone de ouvido, enquanto ao omiti-la a saída só vai para um deles. A opção auto-answer permite a configuração de um código de resposta automaticamente para chamadas recebidas – no nosso caso vamos responder com 200, significando que a chamada é automaticamente aceita - e isto pode ser útil em situações nas quais o sistema embarcado não possui uma interface de usuário. Duração configura o tempo máximo de uma chamada, em segundos, e isto pode ser útil para depuração de uma aplicação em desenvolvimento, por exemplo. Color faz com que algumas mensagens de warning e de erro sejam impressas coloridas no terminal, ajudando na identificação de situações específicas. Por fim, a opção add-buddy permite a adição de URIs SIP para que não seja necessário adicioná-las manualmente toda vez que a aplicação é reiniciada ou digitar a URI sempre que for fazer uma chamada para um terminal específico - você pode usar essa opção mais de uma vez para múltiplas URIs.

 

Fornecendo o arquivo de configuração para a aplicação:

 

 

Dentre muitas outras opções, ainda há duas que são interessantes para propósito de testes: rx-drop-pct=PCT e tx-drop-pct=PCT. Ambas simulam a perda de pacotes ajustando a porcentagem de pacotes perdidos (PCT). Foram testados três casos com perdas para Rx e Tx iguais e nos valores de 10%, 20% e 30%, respectivamente, enquanto o monitoramento da qualidade média da chamada foi realizado no software Linphone , que a apresenta em uma escala de 0 a 5. A qualidade variou desde quase 5,0 sem perdas para 3,3 – 2,3 e 0,6, respectivamente para os casos previamente descritos. Você pode ver na figura 11 a captura de tela do Linphone para o pior caso (30% de perdas).

 

PJSIP-11
Figura 11: Qualidade da chamda para perda de pacotes de 30%

 

É isso aí! Agora você tem uma implementação de VOIP para o Colibri iMX6 funcionando e um ponto de partida para desenvolver a sua própria aplicação, de acordo com suas necessidades. Algumas informações complementares serão apresentadas no próximo capítulo: monitoramento de rede para podermos observar os pacotes e transações SIP em execução.

 

Monitoramento de rede para pacotes SIP

 

Para observar as transações SIP sendo realizadas entre os dispositivos, será usado o software Wireshark. Você perceberá que há um terceiro endereço de IP 192.168.0.20 em meio às transações, e isto se deve ao fato de que o notebook estava sendo usado como servidor DHCP para o iMX6 – portanto o notebook tem dois endereços de IP. Ainda assim, não foi feita uma investigação sobre como ou porquê a aplicação SIP está usando o segundo endereço de IP.

 

A sequência de operações feita enquanto era realizada a captura da rede está descrita abaixo:

  1. Chamada do Colibri iMX6 e rejeição pelo notebook
  2. Chamada do Colibri iMX6 atendida pelo notebook
  3. Colibri iMX6 desliga a chamada
  4. Chamada do notebook atendida pelo Colibri iMX6
  5. Colibri iMX6 coloca em espera
  6. Colibri iMX6 retorna a chamada
  7. Colibri iMX6 envia UPDATE
  8. Colibri iMX6 envia mensagem instantânea
  9. Notebook envia mensagem  
  10. SUBSCRIBE/NOTIFY

 

A figura 12 apresenta somente os pacotes do protocolo SIP trocados durante a captura, com as linhas destacadas correspondentes ao começo das situações descritas acima, logo 10 linhas estão destacadas. Perceba que há um handshake SUBSCRIBE/NOTIFY um momento antes da terceira operação listada.

 

PJSIP-12
Figura 12: Monitoramento de rede somente para pacotes SIP

 

Na figura 13, é apresentada a captura de pacotes SIP e RTP de uma chamada brevíssima (~4s). Perceba que enquanto o notebook usa o endereço de IP 192.168.10.1 para enviar dados para o sistema embarcado, este responde para o endereço 192.168.0.20 do notebook.

 

PJSIP-13
Figura 13: Monitoramento de rede para pacotes SIP e RTP, em uma chamada breve

 

Com a informação obtida, esta é uma maneira de confirmar na prática um pouco das informações apresentadas previamente no capítulo Visão geral do protocolo SIP.

 

Com isto chegamos ao fim do artigo que apresenta a implementação de uma aplicação PJSUA para linha de comando, em um sistema embarcado Toradex Colibri iMX6 + Evaluation Board, rodando Linux embarcado. Obrigado pela leitura e espero que este artigo lhe tenha sido útil!

 

Referências

 

Artigo publicado originalmente em: http://www.cnx-software.com/2016/07/19/setting-a-voip-sip-user-agent-with-embedded-linux/

 

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

6
Deixe um comentário

avatar
 
3 Comment threads
3 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
Manoel Renato GomesLeonardo VeigaGlauber SaldanhaVinicius Maciel Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Manoel Renato Gomes
Visitante
Manoel Renato Gomes

Posso usar essa instalação para o uso no raspberry pi 3 ?

Leonardo Veiga
Visitante
Leonardo Graboski Veiga

Olá Manoel,

Com certeza você pode tentar, o caminho das pedras é parecido. O que eu faria é pesquisar se o repositório da Rasp já tem algo de PJSIP (apt-get) e caso não tenha, partir pra essa abordagem.

Não conheço muito da Rasp, mas acho que ela tem os headers no target, se isso for verdade você pode tentar compilar direto nela, o que vai demorar mais mas é mais simples. Nesse caso não precisa se preocupar com sysroot, LDFLAGS e prefix.

Abraço

Glauber Saldanha
Visitante
Glauber Saldanha

Excelente artigo!
Obrigado!

Leonardo Veiga
Visitante
Leonardo Graboski Veiga

Eu é que agradeço, Glauber!
Abraço.

Vinicius Maciel
Visitante
vinifr

Ótimo artigo, muito bom mesmo! Se me permite, gostaria de incluir seu artigo num grupo que tenho no Linkedin: https://www.linkedin.com/groups/7411745

Leonardo Veiga
Visitante
Leonardo Graboski Veiga

Olá Vinicius, fique à vontade pra compartilhar. Estou à disposição.
Abraço.