Telefono SIP su STM32F7-Discovery

Ciao.

Qualche tempo fa noi ha scritto su come siamo riusciti a lanciare un telefono SIP su STM32F4-Discovery con 1 MB di ROM e 192 KB di RAM) basato su Embox. Qui va detto che quella versione era minimale e collegava due telefoni direttamente senza server e con trasmissione della voce in una sola direzione. Pertanto, abbiamo deciso di lanciare un telefono più completo con una chiamata attraverso il server, trasmissione vocale in entrambe le direzioni, ma allo stesso tempo mantenendo la dimensione di memoria più piccola possibile.


Per il telefono si è deciso di scegliere un'applicazione simple_pjsua come parte della libreria PJSIP. Questa è un'applicazione minima che può registrarsi sul server, ricevere e rispondere alle chiamate. Di seguito fornirò immediatamente una descrizione di come eseguirlo su STM32F7-Discovery.

Come avviare

  1. Configurazione di EmBox
    make confload-platform/pjsip/stm32f7cube
  2. Imposta l'account SIP richiesto nel file conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    dove server è un server SIP (ad esempio, sip.linphone.org), nome utente и parola d'ordine - nome utente e password dell'account.

  3. Assemblare Embox come una squadra make. Informazioni sul firmware della scheda che abbiamo вики e Articolo.
  4. Esegui il comando "simple_pjsua_imported" nella console di 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. Infine, resta da inserire altoparlanti o cuffie nell'uscita audio e parlare in due piccoli microfoni MEMS accanto al display. Chiamiamo da Linux tramite l'applicazione simple_pjsua, pjsua. Bene, oppure puoi usare qualsiasi altro tipo di linphone.

Tutto questo è descritto sul nostro вики.

Come ci siamo arrivati

Quindi, inizialmente è sorta la domanda sulla scelta di una piattaforma hardware. Poiché era chiaro che STM32F4-Discovery non si adattava alla memoria, è stato scelto STM32F7-Discovery. Ha un'unità flash da 1 MB e 256 KB di RAM (+ 64 memoria veloce speciale, che useremo anche noi). Inoltre non molto per le chiamate tramite il server, ma abbiamo deciso di provare ad adattarci.

Condizionalmente per se stessi, il compito è stato suddiviso in più fasi:

  • Esecuzione di PJSIP su QEMU. Era comodo per il debug, inoltre avevamo già il supporto per il codec AC97 lì.
  • Registrazione e riproduzione vocale su QEMU e su STM32.
  • Portare un'applicazione simple_pjsua da PJSIP. Ti consente di registrarti sul server SIP ed effettuare chiamate.
  • Distribuisci il tuo server basato su Asterisk e testalo, quindi prova quelli esterni come sip.linphone.org

Il suono in Embox funziona tramite Portaudio, utilizzato anche in PISIP. I primi problemi sono apparsi su QEMU: WAV ha funzionato bene a 44100 Hz, ma a 8000 qualcosa è chiaramente andato storto. Si è scoperto che si trattava di impostare la frequenza: per impostazione predefinita era 44100 nell'apparecchiatura e questo non è cambiato a livello di codice.

Qui, forse, vale la pena spiegare un po 'come viene riprodotto il suono in generale. La scheda audio può essere impostata su un puntatore a un pezzo di memoria da cui si desidera riprodurre o registrare a una frequenza predeterminata. Al termine del buffer, viene generato un interrupt e l'esecuzione continua con il buffer successivo. Il fatto è che questi buffer devono essere riempiti in anticipo durante la riproduzione del precedente. Affronteremo ulteriormente questo problema su STM32F7.

Successivamente, abbiamo noleggiato un server e vi abbiamo distribuito Asterisk. Poiché era necessario eseguire molto il debug, ma non volevo parlare molto nel microfono, era necessario eseguire la riproduzione e la registrazione automatiche. Per fare ciò, abbiamo applicato una patch a simple_pjsua in modo da poter eseguire lo slip dei file invece dei dispositivi audio. In PJSIP, questo viene fatto in modo abbastanza semplice, poiché hanno il concetto di porta, che può essere un dispositivo o un file. E queste porte possono essere collegate in modo flessibile ad altre porte. Puoi vedere il codice nel nostro pjsip repository. Di conseguenza, lo schema era il seguente. Sul server Asterisk, ho avviato due account: per Linux e per Embox. Successivamente, il comando viene eseguito su Embox simple_pjsua_imported, Embox si registra sul server, dopodiché chiamiamo Embox da Linux. Al momento della connessione, controlliamo sul server Asterisk che la connessione sia stabilita, e dopo un po' dovremmo sentire il suono da Linux in Embox, e in Linux salviamo il file che viene riprodotto da Embox.

Dopo aver funzionato su QEMU, siamo passati al porting su STM32F7-Discovery. Il primo problema è che non si adattavano a 1 MB di ROM senza l'ottimizzazione del compilatore abilitata "-Os" per la dimensione dell'immagine. Ecco perché abbiamo incluso "-Os". Inoltre, la patch ha disabilitato il supporto per C ++, quindi è necessario solo per pjsua e usiamo simple_pjsua.

Dopo essere stato posizionato simple_pjsua, ha deciso che ora c'è la possibilità di lanciarlo. Ma prima bisognava occuparsi della registrazione e della riproduzione della voce. La domanda è dove scrivere? Abbiamo scelto la memoria esterna - SDRAM (128 MB). Puoi provare tu stesso:

Crea un WAV stereo con una frequenza di 16000 Hz e una durata di 10 secondi:


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

Noi perdiamo:


play -m C0000000

Ci sono due problemi qui. Viene utilizzato il primo con il codec - WM8994 e ha qualcosa come uno slot e ce ne sono 4. Quindi, per impostazione predefinita, se questo non è configurato, durante la riproduzione dell'audio, la riproduzione avviene in tutti e quattro gli slot . Pertanto, a una frequenza di 16000 Hz, abbiamo ricevuto 8000 Hz, ma per 8000 Hz la riproduzione semplicemente non ha funzionato. Quando sono stati selezionati solo gli slot 0 e 2, ha funzionato come dovrebbe. Un altro problema era l'interfaccia audio nell'STM32Cube, in cui l'uscita audio funziona tramite SAI (Serial Audio Interface) in sincronia con l'ingresso audio (non ho capito i dettagli, ma si scopre che condividono un clock comune e quando il l'uscita audio è inizializzata, l'audio è in qualche modo collegato all'ingresso). Cioè, non puoi eseguirli separatamente, quindi abbiamo fatto quanto segue: l'ingresso audio e l'uscita audio funzionano sempre (compresi gli interrupt vengono generati). Ma quando non viene riprodotto nulla nel sistema, inseriamo semplicemente un buffer vuoto nell'uscita audio e, quando inizia la riproduzione, iniziamo onestamente a riempirlo.

Inoltre, abbiamo riscontrato che il suono durante la registrazione vocale era molto basso. Ciò è dovuto al fatto che i microfoni MEMS sull'STM32F7-Discovery in qualche modo non funzionano bene a frequenze inferiori a 16000 Hz. Pertanto, impostiamo 16000 Hz, anche se arrivano 8000 Hz. Per fare questo, però, è stato necessario aggiungere una conversione software di una frequenza all'altra.

Successivamente, ho dovuto aumentare la dimensione dell'heap, che si trova nella RAM. Secondo i nostri calcoli, pjsip ha richiesto circa 190 KB e ci rimangono solo circa 100 KB. Qui ho dovuto usare della memoria esterna - SDRAM (circa 128 KB).

Dopo tutte queste modifiche, ho visto i primi pacchetti tra Linux ed Embox e ne ho sentito il suono! Ma il suono era terribile, per niente uguale a QEMU, era impossibile distinguere qualcosa. Quindi abbiamo pensato a quale potrebbe essere il problema. Il debug ha mostrato che Embox semplicemente non ha il tempo di riempire / scaricare i buffer audio. Mentre pjsip stava elaborando un frame, 2 interruzioni hanno avuto il tempo di verificarsi per il completamento dell'elaborazione del buffer, che è troppo. Il primo pensiero per la velocità è stata l'ottimizzazione del compilatore, ma era già inclusa in PJSIP. Il secondo è un punto mobile hardware, ne abbiamo parlato in Articolo. Ma come ha dimostrato la pratica, FPU non ha dato un aumento significativo della velocità. Il passaggio successivo è stato quello di dare la priorità ai thread. Embox ha diverse strategie di pianificazione e ne ho inclusa una che supporta le priorità e imposta i flussi audio sulla massima priorità. Anche questo non ha aiutato.

L'idea successiva era che stiamo lavorando con una memoria esterna e sarebbe bello spostare lì le strutture a cui si accede molto spesso. Ho fatto un'analisi preliminare di quando e sotto cosa simple_pjsua alloca memoria. Si è scoperto che su 190 Kb, i primi 90 Kb sono allocati per esigenze interne di PJSIP e non vi si accede molto spesso. Inoltre, durante una chiamata in arrivo, viene chiamata la funzione pjsua_call_answer, in cui vengono quindi allocati i buffer per lavorare con i frame in entrata e in uscita. Era ancora circa 100 Kb. E poi abbiamo fatto quanto segue. Fino al momento della chiamata, posizioniamo i dati nella memoria esterna. Non appena la chiamata, sostituiamo immediatamente l'heap con un altro - nella RAM. Pertanto, tutti i dati "caldi" sono stati trasferiti in una memoria più veloce e prevedibile.

Di conseguenza, tutto questo insieme ha permesso il lancio simple_pjsua e chiama attraverso il tuo server. E poi attraverso altri server come sip.linphone.org.

risultati

Di conseguenza, è stato possibile lanciare simple_pjsua con trasmissione vocale in entrambe le direzioni attraverso il server. Il problema con 128 KB di SDRAM spesi in più può essere risolto utilizzando un Cortex-M7 leggermente più potente (ad esempio, STM32F769NI con 512 KB di RAM), ma allo stesso tempo non abbiamo ancora perso la speranza di entrare in 256 KB 🙂 Saremo lieti se qualcuno è interessato, o meglio ancora, provalo. Tutte le fonti, come al solito, sono nel nostro repository.

Fonte: habr.com

Aggiungi un commento