Telefon SIP pe STM32F7-Discovery

Buna ziua.

Cu ceva timp în urmă noi писали despre cum am reușit să lansăm un telefon SIP pe STM32F4-Discovery cu 1 MB ROM și 192 KB RAM) pe baza Embox. Aici trebuie spus că acea versiune a fost minimă și a conectat două telefoane direct fără server și cu transmisie vocală doar într-o singură direcție. Prin urmare, am decis să lansăm un telefon mai complet cu un apel printr-un server, transmisie vocală în ambele sensuri, dar în același timp să se încadreze în cea mai mică dimensiune de memorie posibilă.


S-a decis alegerea unei aplicații pentru telefon simple_pjsua ca parte a bibliotecii PJSIP. Aceasta este o aplicație minimă care se poate înregistra pe server, poate primi și răspunde la apeluri. Mai jos voi oferi imediat o descriere a modului de rulare pe STM32F7-Discovery.

Cum se lansează

  1. Configurarea Embbox
    make confload-platform/pjsip/stm32f7cube
  2. În fișierul conf/mods.config setăm contul SIP necesar.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    unde serverul este un server SIP (de exemplu, sip.linphone.org), nume de utilizator и parola — numele de utilizator și parola pentru cont.

  3. Asamblam Embox cu o echipă face. Avem informații despre firmware-ul plăcii la вики și articol.
  4. Rulați comanda „simple_pjsua_imported” în consola 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. În cele din urmă, tot ce rămâne este să introduceți difuzoare sau căști în ieșirea audio și să vorbiți în două microfoane MEMS mici de lângă afișaj. Apelăm din Linux folosind aplicația simple_pjsua, pjsua. Ei bine, sau poți folosi orice alt tip de linphone.

Toate acestea sunt descrise pe site-ul nostru вики.

Cum am ajuns aici

Deci, inițial a apărut întrebarea despre alegerea unei platforme hardware. Deoarece era clar că STM32F4-Discovery nu ar fi potrivit pentru memorie, a fost ales STM32F7-Discovery. Are o unitate flash de 1 MB și 256 KB de RAM (+ 64 de memorie specială rapidă, pe care o vom folosi și noi). De asemenea, nu este prea mult pentru apeluri prin server, dar am decis să încercăm să intrăm.

În mod convențional, sarcina a fost împărțită în mai multe etape:

  • Rulează PJSIP pe QEMU. Era convenabil pentru depanare, plus că aveam deja suport pentru codecul AC97 acolo.
  • Înregistrare și redare voce pe QEMU și STM32.
  • Portarea aplicației simple_pjsua de la PJSIP. Vă permite să vă înregistrați pe un server SIP și să efectuați apeluri.
  • Implementați-vă propriul server bazat pe Asterisk și testați-l, apoi încercați unul extern, cum ar fi sip.linphone.org

Sunetul din Embbox funcționează prin Portaudio, care este folosit și în PISIP. Primele probleme au apărut pe QEMU - WAV-urile au fost redate bine la 44100 Hz, dar la 8000 ceva nu mergea clar. S-a dovedit că problema a fost în setarea frecvenței - implicit în echipament a fost 44100 și nu am schimbat acest lucru în software.

Aici, probabil că merită să explicăm puțin despre modul în care este redat sunetul în general. Placa de sunet poate seta un indicator către o bucată de memorie din care trebuie redată sau înregistrată la o frecvență predeterminată. După ce bufferul se epuizează, este generată o întrerupere și execuția continuă din următorul buffer. Ideea este că aceste buffere trebuie umplute în avans în timp ce se redă cel precedent. Vom întâlni această problemă în continuare pe STM32F7.

Apoi, am închiriat un server și am instalat Asterisk pe el. Deoarece erau multe depanare de făcut și nu voiam să vorbesc prea mult în microfon, a fost necesar să fac redare și înregistrare automată. Pentru a face acest lucru, am corectat simple_pjsua, astfel încât să putem insera fișiere în loc de dispozitive audio. În PJSIP acest lucru se face destul de simplu, deoarece au conceptul de port, care poate fi fie un dispozitiv, fie un fișier. Și aceste porturi pot fi conectate în mod flexibil la alte porturi. Puteți vizualiza codul în pjsip-ul nostru depozite. Ca urmare, schema a fost următoarea. Am creat două conturi pe serverul Asterisk - pentru Linux și pentru Embbox. Apoi, comanda este executată pe Embbox simple_pjsua_imported, Embbox se înregistrează pe server, după care numim Embox din Linux. În momentul conexiunii, verificăm pe serverul Asterisk că întreaga conexiune este stabilită, iar după un timp ar trebui să auzim sunet de la Linux în Embbox, iar în Linux salvăm fișierul care este redat de pe Embbox.

Odată ce a funcționat pe QEMU, am trecut la portarea lui la STM32F7-Discovery. Prima problemă a fost că nu am putea încadra în 1 MB de ROM fără optimizarea compilatorului „-Os” pentru dimensiunea imaginii activată. Prin urmare, am inclus „-Os”. Apoi, patch-ul a dezactivat suportul pentru C++, deci este necesar doar pentru pjsua și folosim simple_pjsua.

După plasare simple_pjsua, a decis că acum există șansa de a-l lansa. Dar mai întâi a trebuit să ne dăm seama cum să înregistrăm și să redăm vocile. Întrebare - unde să scriu? Am ales memoria externă - SDRAM (128 MB). Puteți încerca asta singur:

Va crea un WAV stereo cu o frecvență de 16000 Hz și o durată de 10 secunde:


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

Noi pierdem:


play -m C0000000

Au fost două probleme aici. Primul este cu codecul - se folosește WM8994 și are un astfel de slot și există 4 dintre aceste sloturi.Deci, în mod implicit, dacă acesta nu este configurat, atunci când redați audio, redarea are loc în toate patru sloturi. Prin urmare, la o frecvență de 16000 Hz am primit 8000 Hz, dar pentru redarea la 8000 Hz pur și simplu nu a funcționat. Când am selectat doar sloturile 0 și 2, a funcționat conform așteptărilor. O altă problemă a fost interfața audio din STM32Cube, în care ieșirea audio funcționează prin SAI (Serial Audio Interface) sincron cu intrarea audio (nu am înțeles detaliile, dar se dovedește că au un ceas comun și la inițializare). ieșirea audio, sunetul este cumva legat de intrarea acestuia). Adică, este imposibil să le rulăm separat, așa că am făcut următoarele - intrarea audio și ieșirea audio funcționează întotdeauna (inclusiv întreruperile sunt generate). Dar când nu se redă nimic în sistem, pur și simplu introducem un buffer gol în ieșirea audio, iar când începe redarea, începem sincer să-l umplem.

Apoi am întâlnit faptul că sunetul la înregistrarea vocii era foarte liniștit. Acest lucru se datorează faptului că microfoanele MEMS de pe STM32F7-Discovery nu funcționează cumva bine la frecvențe sub 16000 Hz. Prin urmare, îl setăm la 16000 Hz, chiar dacă sosesc 8000 Hz. Pentru a face acest lucru, a fost însă necesar să adăugați conversia software a unei frecvențe la alta.

Apoi, a trebuit să creștem dimensiunea heap-ului, care se află în RAM. Conform calculelor noastre, pjsip necesita aproximativ 190 KB și mai aveam doar aproximativ 100 KB. Aici a trebuit să folosim puțină memorie externă - SDRAM (aproximativ 128 KB).

După toate aceste editări, am văzut primele pachete între Linux și Embbox și am auzit sunetul! Dar sunetul era groaznic, deloc ca pe QEMU, nu se auzea nimic. Apoi ne-am întrebat care ar putea fi problema. Depanarea a arătat că Embbox pur și simplu nu are timp să umple/descărce bufferele audio. În timp ce pjsip procesează un cadru, au avut loc 2 întreruperi despre finalizarea procesării bufferului, ceea ce este prea mult. Primul meu gând pentru accelerare a fost optimizarea compilatorului, dar aceasta era deja inclusă în PJSIP. Al doilea este virgulă mobilă hardware, am vorbit despre asta în articol. Dar, după cum a arătat practica, FPU nu a oferit o creștere semnificativă a vitezei. Următorul pas a fost stabilirea priorităților firelor. Embox are strategii de programare diferite, iar eu am activat-o pe cea care acceptă priorități și a dat fluxurilor audio cea mai mare prioritate. Nici asta nu a ajutat.

Următoarea idee a fost că lucrăm cu memorie externă și ar fi bine să mutăm acolo structuri care sunt accesate extrem de des. Am efectuat o analiză preliminară a când și sub ce simple_pjsua alocă memorie. S-a dovedit că din 190 KB, primii 90 KB sunt alocați pentru nevoile interne ale PJSIP și nu sunt accesați foarte des. Apoi, în timpul unui apel de intrare, este apelată funcția pjsua_call_answer, în care sunt apoi alocate buffer-uri pentru lucrul cu cadrele de intrare și de ieșire. Era încă aproximativ 100 KB. Și apoi am făcut următoarele. Până la efectuarea apelului, datele sunt stocate în memoria externă. De îndată ce apelul sună, înlocuim imediat heap-ul cu altul în RAM. Astfel, toate datele „fierbinte” au fost transferate într-o memorie mai rapidă și mai previzibilă.

Drept urmare, toate acestea împreună ne-au permis să lansăm simple_pjsua și sunați prin serverul dvs. Și apoi prin alte servere precum sip.linphone.org.

Constatări

Până la urmă a fost posibilă lansarea simple_pjsua cu transmisie vocală în ambele direcții prin server. Problema cu 128 KB suplimentar de SDRAM poate fi rezolvată folosind un Cortex-M7 ceva mai puternic (de exemplu, STM32F769NI cu 512 KB de RAM), dar încă nu am renunțat la speranța de a încadra 256 KB :) Vom bucură-te dacă cineva este interesat, sau mai bine, încearcă. Toate sursele, ca de obicei, sunt în nostru depozite.

Sursa: www.habr.com

Adauga un comentariu