SIP telefón na STM32F7-Discovery

Ahojte všetci.

Pred nejakým časom sme písali hovorili o tom, ako sa nám podarilo spustiť SIP telefón na STM32F4-Discovery s 1 MB ROM a 192 KB RAM) na základe Embox. Je potrebné povedať, že tá verzia bola minimálna a spojila dva telefóny priamo bez servera a s prenosom hlasu len jedným smerom. Preto sme sa rozhodli spustiť plnohodnotnejší telefón so volaním cez server, prenosom hlasu v oboch smeroch, ale pritom sa zmestiť do čo najmenšej pamäti.

Prehrajte video

Pre telefón bolo rozhodnuté vybrať aplikáciu simple_pjsua ausch PJSIP. Ide o minimálnu aplikáciu, ktorá vie registrovať na serveri, prijímať a odpovedať na hovory. Nižšie okamžite uvediem popis toho, ako to spustiť na STM32F7-Discovery.

Ako spustiť

  1. Konfigurujeme Embox
    make confload-platform/pjsip/stm32f7cube
  2. V súbore conf/mods.config nastavíme potrebný SIP účet.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    kde server — to je SIP server (napríklad sip.linphone.org), username a password — používateľské meno a heslo účtu.

  3. Skladáme Embox príkazom make. O firmvéri dosky máme informácie na wiki a v článku.
  4. Spúšťame v konzole Embox príkaz “simple_pjsua_imported”
    
    00:00:12.870    pjsua_acc.c  ....SIP outbound status pre acc 0 nie je aktívny
    00:00:12.884    pjsua_acc.c  ....sip:alexk2222@sip.linphone.org: registrácia úspešná, stav=200 (Registrácia úspešná
    00:00:12.911    pjsua_acc.c  ....Keep-alive časovač spustený pre acc 0, cieľ: 91.121.209.194:5060, interval: 15s
    

  5. Nakoniec zostáva zasunúť reproduktory alebo slúchadlá do audio výstupu a hovoriť do dvoch malých MEMS mikrofónov vedľa displeja. Voláme z Linuxu cez aplikáciu simple_pjsua, pjsua. Alebo môžeme použiť aj akúkoľvek inú, ako je linphone.

Všetko toto je popísané na našej wiki.

Ako sme k tomu dospeli

Teda, pôvodne sa objavila otázka voľby hardvérovej platformy. Keďže bolo jasné, že STM32F4-Discovery nebude vyhovovať z hľadiska pamäte, bola vybraná STM32F7-Discovery. Má 1 MB Flash a 256 KB RAM (+ 64 špeciálnej rýchlej pamäte, ktorú tiež použijeme). Tiež to nie je veľa na telefonovanie cez server, ale rozhodli sme sa to skúsiť.

Úlohu sme si podmienečne rozdelili na niekoľko etáp:

  • Spustenie PJSIP na QEMU. To bolo pohodlné na ladenie, plus sme tam už mali podporu kodeku AC97.
  • Záznam hlasu a jeho prehrávanie na QEMU a na STM32.
  • Portovanie aplikácie simple_pjsua z PJSIP. Umožňuje registrovať sa na SIP serveri a volať.
  • Rozbehnúť svoj vlastný server na báze Asterisk a testovať na ňom, potom vyskúšať vonkajšie, ako sip.linphone.org

Zvuk v Emboxe pracuje cez Portaudio, ktorý sa používa aj v PISIP. Na QEMU sa objavili prvé problémy – WAV súbory na 44100 Hz sa prehrávali dobre, ale na 8000 Hz niečo očividne nefungovalo. Zistilo sa, že problém bol v nastavení frekvencie – v hardvéri bola predvolená hodnota 44100 a túto sme programovo nezmenili.

Tu asi stojí za to trochu objasniť, ako sa vlastne prehrávanie zvuku deje. Zvukovej karte môžete nastaviť určitý ukazovateľ na úsek pamäte, z ktorého sa má prehrávať alebo zapisovať pri vopred nastavenej frekvencii. Po ukončení jedného buffera sa vytvorí prerušenie a vykonávanie pokračuje s ďalším bufferom. Problém je v tom, že tieto buffery musíte stihnúť naplniť vopred, kým sa prehráva predchádzajúci. S týmto problémom sa ešte stretneme na STM32F7.

Následne sme si prenajali server a nasadili na ňom Asterisk. Pretože bolo potrebné veľa ladit, a nechcelo sa nám neustále hovoriť do mikrofónu, potrebovali sme automatické prehrávanie a nahrávanie. Na to sme upravili simple_pjsua tak, aby sme mohli nahradiť audio zariadenia súbormi. V PJSIP sa to robí celkom jednoducho, pretože tam majú pojem port, ktorý môže byť zariadením aj súborom. A tieto porty je možné flexibilne pripojiť k iným portom. Kód si môžete pozrieť v našom pjsipe. repozitári. Výsledná schéma bola nasledujúca. Na serveri Asterisk som vytvoril dva účty – pre Linux a pre Embox. Potom sa na Emboxe vykoná príkaz simple_pjsua_imported, Embox sa zaregistruje na serveri, po čom voláme z Linuxu na Embox. V okamihu spojenia kontrolujeme na serveri Asterisk, že je všetko pripojené, a po chvíli by sme mali počuť v Emboxe zvuk z Linuxu, pričom v Linuxe si ukladáme súbor, ktorý sa prehráva z Emboxu.

Potom, čo to začalo fungovať na QEMU, sme prešli k portovaniu na STM32F7-Discovery. Prvý problém – nezmestili sme sa do 1 MB ROM bez zapnutej optimalizácie kompilátora „-Os“ kvôli veľkosti obrazu. Preto sme zapli „-Os“. Následne sme patchom vypnuli podporu C++, pretože tá je potrebná len pre pjsua, a my používame simple_pjsua.

Potom, čo sme to zmestili simple_pjsua, sme usúdili, že máme teraz šance to spustiť. Ale najskôr sme sa museli vysporiadať s nahrávaním a prehrávaním hlasu. Otázka — kam nahrávať? Vybrali sme vonkajšiu pamäť — SDRAM (128 MB). Môžete to vyskúšať sami:

Vytvorí stereo WAV s frekvenciou 16000 Hz a dĺžkou 10 sekúnd:


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

Prehrávame:


play -m C0000000

Tu sa objavili dve problémy. Prvý sa týka kodeku – používa sa WM8994, ktorý má štyri sloty. Takže ak to nenastavíte, počas prehrávania sa zvuk prehráva vo všetkých štyroch slotoch. Preto pri frekvencii 16000 Hz sme dostali 8000 Hz a prehrávanie pri 8000 Hz jednoducho nefungovalo. Keď sme vybrali len sloty 0 a 2, fungovalo to správne. Ďalším problémom bol audio rozhranie v STM32Cube, kde audio výstup funguje cez SAI (Serial Audio Interface) synchronne s audio vstupom (neponorili sme sa do podrobností, ale zrejme zdieľajú spoločný clock a pri inicializácii audio výstupu sa nejako viaže audio vstup). Teda ich nie je možné spustiť samostatne, takže sme urobili nasledovné – vždy funguje (vrátane generovania prerušenia) audio vstup a audio výstup. Ale keď v systéme nič neprehráva, jednoducho posúvame audio výstupu prázdny buffer a keď sa spustí prehrávanie, začíname ho poctivo plniť.

Následne sme sa stretli s tým, že zvuk pri nahrávaní hlasu bol veľmi tichý. To sa deje preto, že MEMS mikrofóny na STM32F7-Discovery zle fungujú na frekvenciách pod 16000 Hz. Preto nastavujeme 16000 Hz, aj keď sa dostane 8000 Hz. Na to bolo treba pridať programovú konverziu jednej frekvencie na druhú.

Následne sme museli zvýšiť veľkosť hromady, ktorá sa nachádza v RAM. Podľa našich výpočtov, pjsip vyžadoval približne 190 kB, a u nás zostalo len okolo 100 kB. Tu sme museli zapojiť trochu vonkajšej pamäte – SDRAM (približne 128 kB).

Po všetkých týchto úpravách som videl prvé pakety medzi Linuxom a Emboxom a počul zvuk! Ale zvuk bol hrozný, rozhodne nie taký ako na QEMU, nič nebolo možné rozlíšiť. Potom sme sa zamysleli, v čom môže byť problém. Debugging ukázal, že Embox jednoducho nestíha plniť/vyprázdňovať audio buffery. Kým pjsip spracováva jeden rámec, došlo k dvom prerušením o dokončení spracovania bufferov, čo je príliš veľa. Prvou myšlienkou na urýchlenie bola optimalizácia kompilátora, no bola už zapnutá v PJSIP. Druhým - hardvérová plávajúca desatinná čiarka, o ktorej sme rozprávali v článku. No ako ukázala prax, FPU neprinieslo podstatné zvýšenie rýchlosti. Ďalším krokom bolo nastavenie priorít pre prúdy. V Embox sú rôzne stratégie plánovania, a ja som zapol tú, ktorá podporuje priority, a nastavila som audiosprávy na najvyššiu prioritu. To tiež nepomohlo.

Ďalšia myšlienka bola, že pracujeme s externou pamäťou, a bolo by dobré tam presunúť štruktúry, k ktorým sa pristupuje veľmi často. Urobil som predbežnú analýzu toho, kedy a pod čo simple_pjsua sa prideľuje pamäť. Ukázalo sa, že z 190 Kb prvých 90 Kb je vyhradených pre vnútorné potreby PJSIP a k nim sa pristupuje nie veľmi často. Potom počas príchozího hovoru sa vyvolá funkcia pjsua_call_answer, v ktorej sa následne vyhradzujú buffery na prácu s príchozími a odchozími rámcami. To bolo ďalších približne 100 Kb. A tu sme postupovali nasledovne. Pred momentom hovoru sú dáta umiestnené v externej pamäti. Hneď ako je hovor - okamžite nahradíme haldu za inú - v RAM. Týmto spôsobom sa všetky „horúce“ dáta presunuli do rýchlejšej a predvídateľnejšej pamäti.

Nakoniec to všetko spolu umožnilo spustiť simple_pjsua a zavolať cez svoj server. A potom aj cez iné servery ako sip.linphone.org.

Zhrnutie

Nakoniec sa podarilo spustiť simple_pjsua s prenosom hlasu oboma smermi cez server. Problém s dodatočnými 128 Kb SDRAM sa dá vyriešiť použitím o niečo výkonnejšieho Cortex-M7 (napríklad STM32F769NI s 512 Kb RAM), ale zároveň sme ešte nestratili nádej zmestiť sa aj do 256 Kb 🙂 Budeme radi, ak sa niekto zaujíma, a ešte lepšie — vyskúša to. Všetky zdrojové kódy, ako obvykle, sú v našom repozitári.

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster