SIP-telefon på STM32F7-Discovery

Hei alle sammen.

For en stund siden vi skrev om hvordan vi klarte å lansere en SIP-telefon på STM32F4-Discovery med 1 MB ROM og 192 KB RAM) basert på embox. Her skal det sies at den versjonen var minimal og koblet sammen to telefoner direkte uten server og med taleoverføring i kun én retning. Derfor bestemte vi oss for å lansere en mer komplett telefon med en samtale gjennom serveren, stemmeoverføring i begge retninger, men samtidig holde innenfor minst mulig minnestørrelse.


For telefonen ble det besluttet å velge en applikasjon simple_pjsua som en del av PJSIP-biblioteket. Dette er en minimal applikasjon som kan registrere seg på serveren, motta og svare på anrop. Nedenfor vil jeg umiddelbart gi en beskrivelse av hvordan du kjører den på STM32F7-Discovery.

Hvordan løpe

  1. Konfigurerer Embox
    make confload-platform/pjsip/stm32f7cube
  2. Sett den nødvendige SIP-kontoen i conf/mods.config-filen.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    der server er en SIP-server (for eksempel sip.linphone.org), brukernavn и passord - brukernavn og passord for kontoen.

  3. Sette sammen Embox som et team gjøre. Om brettfastvaren vi har på wiki og artikkel.
  4. Kjør kommandoen "simple_pjsua_imported" i Embox-konsollen
    
    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. Til slutt gjenstår det å sette inn høyttalere eller hodetelefoner i lydutgangen, og snakke inn i to små MEMS-mikrofoner ved siden av skjermen. Vi ringer fra Linux gjennom applikasjonen simple_pjsua, pjsua. Vel, eller du kan bruke hvilken som helst annen type linphone.

Alt dette er beskrevet på vår wiki.

Hvordan kom vi dit

Så i utgangspunktet oppsto spørsmålet om valg av maskinvareplattform. Siden det var klart at STM32F4-Discovery ikke ville passe fra minnet, ble STM32F7-Discovery valgt. Hun har en 1 MB flash-stasjon og 256 KB RAM (+ 64 spesielt hurtigminne, som vi også skal bruke). Heller ikke mye for samtaler gjennom serveren, men vi bestemte oss for å prøve å passe inn.

Betinget for seg selv ble oppgaven delt inn i flere stadier:

  • Kjører PJSIP på QEMU. Det var praktisk for feilsøking, pluss at vi allerede hadde støtte for AC97-kodeken der.
  • Stemmeopptak og avspilling på QEMU og på STM32.
  • Portere en applikasjon simple_pjsua fra PJSIP. Den lar deg registrere deg på SIP-serveren og ringe.
  • Distribuer din egen Asterisk-baserte server og test på den, og prøv deretter eksterne som sip.linphone.org

Lyd i Embox fungerer gjennom Portaudio, som også brukes i PISIP. De første problemene dukket opp på QEMU - WAV spilte bra ved 44100 Hz, men ved 8000 gikk noe tydelig galt. Det viste seg at det var snakk om å stille inn frekvensen – som standard var den 44100 i utstyret, og dette endret seg ikke programmessig.

Her er det kanskje verdt å forklare litt hvordan lyden spilles generelt. Lydkortet kan settes til en peker til et stykke minne som du vil spille av eller ta opp med en forhåndsbestemt frekvens. Etter at bufferen er slutt, genereres et avbrudd og utførelsen fortsetter med neste buffer. Faktum er at disse bufferne må fylles på forhånd mens den forrige spilles. Vi vil møte dette problemet videre på STM32F7.

Deretter leide vi en server og distribuerte Asterisk på den. Siden det var nødvendig å feilsøke mye, men jeg ikke ville snakke mye inn i mikrofonen, var det nødvendig å gjøre automatisk avspilling og opptak. For å gjøre dette, lappet vi simple_pjsua slik at du kan slippe filer i stedet for lydenheter. I PJSIP gjøres dette ganske enkelt, siden de har konseptet med en port, som enten kan være en enhet eller en fil. Og disse portene kan fleksibelt kobles til andre porter. Du kan se koden i vår pjsip depoter. Som et resultat ble ordningen som følger. På Asterisk-serveren startet jeg to kontoer - for Linux og for Embox. Deretter utføres kommandoen på Embox simple_pjsua_imported, Embox er registrert på serveren, deretter kaller vi Embox fra Linux. I tilkoblingsøyeblikket sjekker vi på Asterisk-serveren at tilkoblingen er etablert, og etter en stund skal vi høre lyd fra Linux i Embox, og i Linux lagrer vi filen som spilles av fra Embox.

Etter at det fungerte på QEMU, gikk vi videre til portering til STM32F7-Discovery. Det første problemet er at de ikke passet inn i 1 MB ROM uten den aktiverte kompilatoroptimaliseringen "-Os" for størrelsen på bildet. Derfor tok vi med «-Os». Videre deaktiverte oppdateringen støtte for C ++, så det er bare nødvendig for pjsua, og vi bruker simple_pjsua.

Etter å ha blitt plassert simple_pjsua, bestemte at nå er det en sjanse til å lansere den. Men først var det nødvendig å forholde seg til opptak og avspilling av stemmen. Spørsmålet er hvor du skal skrive? Vi valgte eksternt minne - SDRAM (128 MB). Du kan prøve dette selv:

Skaper en stereo WAV med en frekvens på 16000 Hz og en varighet på 10 sekunder:


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

Vi taper:


play -m C0000000

Det er to problemer her. Den første med kodeken - WM8994 brukes, og den har noe som en spilleautomat, og det er 4 av disse sporene. Så, som standard, hvis dette ikke er konfigurert, vil avspilling skje i alle fire sporene når du spiller av lyd. . Derfor, ved en frekvens på 16000 Hz, mottok vi 8000 Hz, men for 8000 Hz fungerte rett og slett ikke avspilling. Når kun spor 0 og 2 ble valgt, fungerte det som det skulle. Et annet problem var lydgrensesnittet i STM32Cube, der lydutgangen fungerer via SAI (Serial Audio Interface) synkront med lydinngangen (jeg forsto ikke detaljene, men det viser seg at de deler en felles klokke og når lydutgang er initialisert, lyd er på en eller annen måte knyttet til inngangen). Det vil si at du ikke kan kjøre dem separat, så vi gjorde følgende - lydinngangen og lydutgangen fungerer alltid (inkludert avbrudd genereres). Men når det ikke spilles av noe i systemet, slipper vi ganske enkelt en tom buffer inn i lydutgangen, og når avspillingen starter, begynner vi ærlig talt å fylle den.

Videre møtte vi det faktum at lyden under taleopptak var veldig stille. Dette skyldes det faktum at MEMS-mikrofoner på STM32F7-Discovery på en eller annen måte ikke fungerer godt på frekvenser under 16000 Hz. Derfor setter vi 16000 Hz, selv om 8000 Hz kommer. For å gjøre dette var det imidlertid nødvendig å legge til en programvarekonvertering av en frekvens til en annen.

Deretter måtte jeg øke størrelsen på haugen, som ligger i RAM. I følge våre beregninger krevde pjsip ca. 190 KB, og vi har bare ca. 100 KB igjen. Her måtte jeg bruke litt eksternt minne - SDRAM (ca. 128 KB).

Etter alle disse redigeringene så jeg de første pakkene mellom Linux og Embox, og jeg hørte lyden! Men lyden var forferdelig, slett ikke den samme som på QEMU, det var umulig å skjønne noe. Så tenkte vi på hva som kunne være i veien. Feilsøking viste at Embox rett og slett ikke har tid til å fylle / losse lydbuffere. Mens pjsip behandlet én ramme, hadde 2 avbrudd tid til å oppstå om fullføringen av bufferbehandling, noe som er for mye. Den første tanken for hastighet var kompilatoroptimalisering, men den var allerede inkludert i PJSIP. Det andre er et flytende punkt for maskinvare, vi snakket om det i artikkel. Men som praksis har vist, ga ikke FPU en betydelig hastighetsøkning. Neste steg var å prioritere tråder. Embox har forskjellige planleggingsstrategier, og jeg har inkludert en som støtter prioriteringer og setter lydstrømmer til høyeste prioritet. Dette hjalp heller ikke.

Den neste ideen var at vi jobber med eksternt minne, og det ville være fint å flytte strukturer dit som man får tilgang til ekstremt ofte. Jeg gjorde en foreløpig analyse av når og under hva simple_pjsua tildeler minne. Det viste seg at av 190 Kb er de første 90 Kb tildelt for interne behov i PJSIP, og de blir ikke aksessert så ofte. Videre, under et innkommende anrop, kalles pjsua_call_answer-funksjonen, der buffere deretter tildeles for arbeid med innkommende og utgående rammer. Det var fortsatt rundt 100 Kb. Og så gjorde vi følgende. Inntil samtaleøyeblikket legger vi dataene i eksternt minne. Så snart vi ringer, erstatter vi umiddelbart haugen med en annen - i RAM. Dermed ble alle "varme" data overført til raskere og mer forutsigbart minne.

Som et resultat gjorde alt dette til sammen det mulig å lansere simple_pjsua og ring gjennom serveren din. Og så gjennom andre servere som sip.linphone.org.

Funn

Som et resultat var det mulig å lansere simple_pjsua med taleoverføring i begge retninger gjennom serveren. Problemet med ekstra brukt 128 KB SDRAM kan løses ved å bruke en litt kraftigere Cortex-M7 (for eksempel STM32F769NI med 512 KB RAM), men samtidig har vi fortsatt ikke gitt opp håpet om å komme inn i 256 KB 🙂 Vi blir glade hvis noen er interessert, eller enda bedre, prøv det. Alle kilder er som vanlig i vår depoter.

Kilde: www.habr.com

Legg til en kommentar