Telefon SIP na STM32F7-Discovery

Ahoj všichni

Před chvílí my писали o tom, jak se nám podařilo spustit SIP telefon na STM32F4-Discovery s 1 MB ROM a 192 KB RAM) na základě Embox. Zde je třeba říci, že tato verze byla minimální a spojovala dva telefony přímo bez serveru a s přenosem hlasu pouze jedním směrem. Proto jsme se rozhodli uvést na trh kompletnější telefon s voláním přes server, přenosem hlasu oběma směry, ale zároveň s co nejmenší velikostí paměti.


Pro telefon bylo rozhodnuto zvolit aplikaci simple_pjsua jako součást knihovny PJSIP. Jedná se o minimální aplikaci, která se může registrovat na serveru, přijímat a přijímat hovory. Níže hned uvedu popis, jak jej spustit na STM32F7-Discovery.

Jak běhat

  1. Konfigurace Emboxu
    make confload-platform/pjsip/stm32f7cube
  2. Nastavte požadovaný SIP účet v souboru conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    kde Server je server SIP (například sip.linphone.org), uživatelské jméno и heslo - uživatelské jméno a heslo účtu.

  3. Sestavení Emboxu jako týmu činit. O firmwaru desky, který máme wiki a článek.
  4. Spusťte příkaz „simple_pjsua_imported“ v konzole 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. Nakonec zbývá vložit reproduktory nebo sluchátka do audio výstupu a mluvit do dvou malých MEMS mikrofonů vedle displeje. Z Linuxu voláme přes aplikaci simple_pjsua, pjsua. No, nebo můžete použít jakýkoli jiný typ linphone.

To vše je popsáno na našem wiki.

Jak jsme se tam dostali

Zpočátku tedy vyvstala otázka výběru hardwarové platformy. Protože bylo jasné, že STM32F4-Discovery se z paměti nevejde, byl vybrán STM32F7-Discovery. Ta má 1 MB flash disk a 256 KB RAM (+ 64 speciální rychlá paměť, kterou také využijeme). Také to není moc na volání přes server, ale rozhodli jsme se zkusit zapadnout.

Podmíněně pro ně byl úkol rozdělen do několika fází:

  • Spuštění PJSIP na QEMU. Bylo to pohodlné pro ladění, navíc jsme tam už měli podporu pro kodek AC97.
  • Záznam a přehrávání hlasu na QEMU a na STM32.
  • Portování aplikace simple_pjsua z PJSIP. Umožňuje vám zaregistrovat se na SIP serveru a volat.
  • Nasaďte svůj vlastní server založený na Asterisk a otestujte jej, poté vyzkoušejte externí server, jako je sip.linphone.org

Zvuk v Emboxu funguje přes Portaudio, které se používá i v PISIP. Na QEMU se objevily první problémy - WAV hrál dobře na 44100 Hz, ale na 8000 se zjevně něco pokazilo. Ukázalo se, že šlo o nastavení frekvence - ve výbavě byla standardně 44100 a to se programově neměnilo.

Zde snad stojí za to trochu vysvětlit, jak se zvuk obecně hraje. Zvukovou kartu lze nastavit na nějaký ukazatel na část paměti, ze které chcete přehrávat nebo nahrávat na předem určené frekvenci. Po ukončení vyrovnávací paměti se vygeneruje přerušení a provádění pokračuje s další vyrovnávací pamětí. Faktem je, že tyto vyrovnávací paměti je třeba naplnit předem, zatímco se hraje předchozí. S tímto problémem se budeme dále potýkat na STM32F7.

Dále jsme si pronajali server a nasadili na něj Asterisk. Jelikož bylo potřeba hodně ladit, ale do mikrofonu se mi moc mluvit nechtělo, bylo potřeba udělat automatické přehrávání a nahrávání. Abychom toho dosáhli, opravili jsme simple_pjsua, abyste mohli podsouvat soubory místo zvukových zařízení. V PJSIP se to dělá docela jednoduše, protože mají koncept portu, kterým může být zařízení nebo soubor. A tyto porty lze flexibilně propojit s dalšími porty. Kód můžete vidět v našem pjsip úložišť. V důsledku toho bylo schéma následující. Na serveru Asterisk jsem založil dva účty - pro Linux a pro Embox. Dále se příkaz provede na Emboxu simple_pjsua_imported, Embox je registrován na serveru, poté zavoláme Embox z Linuxu. V okamžiku připojení zkontrolujeme na serveru Asterisk, že je spojení navázáno a po chvíli bychom měli slyšet zvuk z Linuxu v Emboxu a v Linuxu uložíme soubor, který se přehrává z Emboxu.

Poté, co to fungovalo na QEMU, jsme přešli k portování na STM32F7-Discovery. Prvním problémem je, že se nevešly do 1 MB ROM bez povolené optimalizace kompilátoru „-Os“ pro velikost obrázku. Proto jsme zařadili „-Os“. Dále patch deaktivoval podporu pro C++, takže je potřeba pouze pro pjsua a my používáme simple_pjsua.

Po umístění simple_pjsua, rozhodl, že nyní je šance jej spustit. Nejprve ale bylo nutné se vypořádat s nahráváním a přehráváním hlasu. Otázka je, kam psát? Zvolili jsme externí paměť – SDRAM (128 MB). Můžete to zkusit sami:

Vytvoří stereo WAV s frekvencí 16000 Hz a trváním 10 sekund:


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

Prohráváme:


play -m C0000000

Jsou zde dva problémy. Použije se první s kodekem - WM8994 a má něco jako slot a tyto sloty jsou 4. Takže ve výchozím nastavení, pokud toto není nakonfigurováno, tak se při přehrávání zvuku přehrává ve všech čtyřech slotech . Při frekvenci 16000 Hz jsme tedy obdrželi 8000 Hz, ale pro 8000 Hz přehrávání prostě nefungovalo. Když byly vybrány pouze sloty 0 a 2, fungovalo to, jak mělo. Dalším problémem bylo audio rozhraní v STM32Cube, ve kterém audio výstup funguje přes SAI (Serial Audio Interface) synchronně s audio vstupem (nepochopil jsem detaily, ale ukázalo se, že sdílejí společné hodiny a když se zvukový výstup je inicializován, zvuk je nějak připojen k jeho vstupu). To znamená, že je nemůžete spustit samostatně, takže jsme udělali následující - zvukový vstup a zvukový výstup vždy fungují (včetně generování přerušení). Když se ale v systému nic nepřehrává, pak do audio výstupu jednoduše šoupneme prázdnou vyrovnávací paměť, a když se spustí přehrávání, začneme ji poctivě plnit.

Dále jsme se setkali s tím, že zvuk při nahrávání hlasu byl velmi tichý. To je způsobeno tím, že MEMS mikrofony na STM32F7-Discovery nějak nefungují dobře na frekvencích pod 16000 Hz. Proto nastavíme 16000 Hz, i když přijde 8000 Hz. K tomu však bylo nutné přidat softwarovou konverzi jedné frekvence na druhou.

Dále jsem musel zvětšit velikost haldy, která se nachází v RAM. Podle našich výpočtů pjsip vyžadoval asi 190 KB a zbývá nám jen asi 100 KB. Zde jsem musel použít nějakou externí paměť – SDRAM (asi 128 KB).

Po všech těchto úpravách jsem viděl první balíčky mezi Linuxem a Emboxem a slyšel jsem zvuk! Zvuk byl ale hrozný, vůbec ne stejný jako na QEMU, nedalo se nic rozeznat. Pak jsme přemýšleli, co by se mohlo stát. Ladění ukázalo, že Embox prostě nemá čas naplnit / uvolnit zvukové buffery. Zatímco pjsip zpracovával jeden snímek, došlo ke 2 přerušením o dokončení zpracování vyrovnávací paměti, což je příliš mnoho. První myšlenka na rychlost byla optimalizace kompilátoru, ale ta již byla zahrnuta v PJSIP. Druhá je hardwarová s pohyblivou řádovou čárkou, mluvili jsme o ní článek. Ale jak ukázala praxe, FPU neposkytlo výrazné zvýšení rychlosti. Dalším krokem bylo upřednostnění vláken. Embox má různé strategie plánování a já zahrnul jednu, která podporuje priority a nastavuje audio streamy na nejvyšší prioritu. Ani tohle nepomohlo.

Další myšlenka byla, že pracujeme s externí pamětí a bylo by hezké tam přesunout struktury, ke kterým se přistupuje extrémně často. Udělal jsem předběžný rozbor, kdy a za co simple_pjsua alokuje paměť. Ukázalo se, že ze 190 Kb je prvních 90 Kb alokováno pro interní potřeby PJSIP a není k nim příliš často přistupováno. Dále je během příchozího hovoru volána funkce pjsua_call_answer, ve které jsou pak alokovány buffery pro práci s příchozími a odchozími rámci. Stále to bylo asi 100 Kb. A pak jsme udělali následující. Do okamžiku hovoru ukládáme data do externí paměti. Jakmile zavoláme, okamžitě vyměníme haldu za jinou - v RAM. Všechna „horká“ data tak byla přenesena do rychlejší a předvídatelnější paměti.

Ve výsledku to vše dohromady umožnilo start simple_pjsua a zavolejte přes váš server. A pak prostřednictvím dalších serverů, jako je sip.linphone.org.

Závěry

V důsledku toho bylo možné spustit simple_pjsua s přenosem hlasu v obou směrech přes server. Problém s dodatečně utracenými 128 KB SDRAM lze vyřešit použitím o něco výkonnějšího Cortex-M7 (například STM32F769NI s 512 KB RAM), ale zároveň jsme se stále nevzdali naděje dostat se do 256 KB 🙂 Budeme rádi, když to někoho zaujme, nebo ještě lépe, zkuste to. Všechny zdroje jsou jako obvykle v našem úložišť.

Zdroj: www.habr.com

Přidat komentář