SIP-telefon på STM32F7-Discovery

Hej alla.

För ett tag sedan vi писали om hur vi lyckades lansera en SIP-telefon på STM32F4-Discovery med 1 MB ROM och 192 KB RAM) baserat på embox. Här ska sägas att den versionen var minimal och kopplade ihop två telefoner direkt utan server och med röstöverföring i endast en riktning. Därför bestämde vi oss för att lansera en mer komplett telefon med ett samtal via servern, röstöverföring i båda riktningarna, men samtidigt hålla sig inom minsta möjliga minnesstorlek.


För telefonen beslutades att välja en applikation simple_pjsua som en del av PJSIP-biblioteket. Detta är en minimal applikation som kan registrera sig på servern, ta emot och svara på samtal. Nedan kommer jag omedelbart att ge en beskrivning av hur man kör det på STM32F7-Discovery.

Hur man springer

  1. Konfigurera Embox
    make confload-platform/pjsip/stm32f7cube
  2. Ställ in önskat SIP-konto i filen conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    där server är en SIP-server (till exempel sip.linphone.org), Användarnamn и Lösenord - användarnamn och lösenord för kontot.

  3. Att montera Embox som ett team göra. Om kortets firmware vi har på wiki och artikeln.
  4. Kör kommandot "simple_pjsua_imported" i Embox-konsolen
    
    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. Slutligen återstår det att sätta in högtalare eller hörlurar i ljudutgången och tala i två små MEMS-mikrofoner bredvid skärmen. Vi ringer från Linux genom applikationen simple_pjsua, pjsua. Tja, eller så kan du använda vilken annan typ av linphone som helst.

Allt detta beskrivs på vår wiki.

Hur kom vi dit

Så till en början uppstod frågan om att välja en hårdvaruplattform. Eftersom det stod klart att STM32F4-Discovery inte skulle passa från minnet valdes STM32F7-Discovery. Hon har en 1 MB flash-enhet och 256 KB RAM (+ 64 speciellt snabbt minne, som vi också kommer att använda). Inte mycket för samtal via servern, men vi bestämde oss för att försöka passa in.

Villkorligt för sig själva var uppgiften uppdelad i flera steg:

  • Kör PJSIP på QEMU. Det var bekvämt för felsökning, plus att vi redan hade stöd för AC97-codec där.
  • Röstinspelning och uppspelning på QEMU och på STM32.
  • Portera en applikation simple_pjsua från PJSIP. Det låter dig registrera dig på SIP-servern och ringa samtal.
  • Distribuera din egen Asterisk-baserade server och testa på den, prova sedan externa som sip.linphone.org

Ljud i Embox fungerar via Portaudio, som även används i PISIP. De första problemen dök upp på QEMU - WAV spelade bra vid 44100 Hz, men vid 8000 gick något helt klart fel. Det visade sig att det handlade om att ställa in frekvensen - som standard var den 44100 i utrustningen, och detta ändrades inte programmässigt.

Här är det kanske värt att förklara lite hur ljudet spelas i allmänhet. Ljudkortet kan ställas in på någon pekare till en minnesbit som du vill spela eller spela in med en förutbestämd frekvens. Efter att bufferten slutar genereras ett avbrott och exekveringen fortsätter med nästa buffert. Faktum är att dessa buffertar måste fyllas i förväg medan den föregående spelas. Vi kommer att möta detta problem ytterligare på STM32F7.

Därefter hyrde vi en server och installerade Asterisk på den. Eftersom det var nödvändigt att felsöka mycket, men jag inte ville prata mycket i mikrofonen, var det nödvändigt att göra automatisk uppspelning och inspelning. För att göra detta patchade vi simple_pjsua så att du kan skjuta filer istället för ljudenheter. I PJSIP görs detta helt enkelt, eftersom de har konceptet med en port, som kan vara antingen en enhet eller en fil. Och dessa portar kan flexibelt kopplas till andra portar. Du kan se koden i vår pjsip förråd. Som ett resultat var schemat följande. På Asterisk-servern startade jag två konton - för Linux och för Embox. Därefter körs kommandot på Embox simple_pjsua_imported, registrerar Embox på servern, varefter vi anropar Embox från Linux. I anslutningsögonblicket kontrollerar vi på Asterisk-servern att anslutningen är upprättad, och efter ett tag bör vi höra ljud från Linux i Embox, och i Linux sparar vi filen som spelas från Embox.

Efter att det fungerade på QEMU gick vi vidare till portering till STM32F7-Discovery. Det första problemet är att de inte passade in i 1 MB ROM utan den aktiverade kompilatoroptimeringen "-Os" för storleken på bilden. Det var därför vi tog med "-Os". Vidare inaktiverade patchen stödet för C++, så det behövs bara för pjsua, och vi använder simple_pjsua.

Efter att ha placerats simple_pjsua, bestämde att nu finns det en chans att lansera den. Men först var det nödvändigt att ta itu med inspelningen och uppspelningen av rösten. Frågan är var man ska skriva? Vi valde externt minne - SDRAM (128 MB). Du kan prova detta själv:

Skapar en stereo WAV med en frekvens på 16000 Hz och en varaktighet på 10 sekunder:


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

Vi förlorar:


play -m C0000000

Det finns två problem här. Den första med codec - WM8994 används, och den har en sådan sak som en slot, och det finns 4 av dessa slots. Så, som standard, om detta inte är konfigurerat, då när du spelar ljud, sker uppspelning i alla fyra slots . Därför, vid en frekvens på 16000 Hz, fick vi 8000 Hz, men för 8000 Hz fungerade uppspelningen helt enkelt inte. När endast plats 0 och 2 valdes fungerade det som det skulle. Ett annat problem var ljudgränssnittet i STM32Cube, där ljudutgången fungerar via SAI (Serial Audio Interface) synkront med ljudingången (jag förstod inte detaljerna, men det visar sig att de delar en gemensam klocka och när ljudutgången initieras, ljudet är på något sätt kopplat till ingången). Det vill säga, du kan inte köra dem separat, så vi gjorde följande - ljudingången och ljudutgången fungerar alltid (inklusive avbrott genereras). Men när ingenting spelas i systemet, skjuter vi helt enkelt in en tom buffert i ljudutgången, och när uppspelningen startar börjar vi ärligt talat fylla den.

Vidare stötte vi på det faktum att ljudet under röstinspelning var väldigt tyst. Detta beror på att MEMS-mikrofoner på STM32F7-Discovery på något sätt inte fungerar bra vid frekvenser under 16000 Hz. Därför ställer vi in ​​16000 Hz, även om 8000 Hz kommer. För att göra detta var det dock nödvändigt att lägga till en mjukvarukonvertering av en frekvens till en annan.

Därefter var jag tvungen att öka storleken på högen, som ligger i RAM. Enligt våra beräkningar krävde pjsip cirka 190 KB, och vi har bara cirka 100 KB kvar. Här fick jag använda lite externt minne - SDRAM (ca 128 KB).

Efter alla dessa redigeringar såg jag de första paketen mellan Linux och Embox, och jag hörde ljudet! Men ljudet var hemskt, inte alls detsamma som på QEMU, det var omöjligt att urskilja någonting. Sedan funderade vi på vad som kunde vara grejen. Felsökning visade att Embox helt enkelt inte har tid att fylla/avlasta ljudbuffertar. Medan pjsip bearbetade en bildruta, hann 2 avbrott inträffa om slutförandet av buffertbearbetning, vilket är för mycket. Den första tanken på hastighet var kompilatoroptimering, men den ingick redan i PJSIP. Den andra är en flytande punkt för hårdvara, vi pratade om det i artikeln. Men som praxis har visat, gav FPU ingen signifikant ökning av hastigheten. Nästa steg var att prioritera trådar. Embox har olika schemaläggningsstrategier, och jag har inkluderat en som stöder prioriteringar och ställer in ljudströmmar till högsta prioritet. Detta hjälpte inte heller.

Nästa idé var att vi jobbar med externt minne och det skulle vara trevligt att flytta dit strukturer som nås extremt ofta. Jag gjorde en preliminär analys av när och under vad simple_pjsua allokerar minne. Det visade sig att av 190 Kb är de första 90 Kb tilldelade för PJSIPs interna behov och de nås inte särskilt ofta. Vidare, under ett inkommande samtal, anropas pjsua_call_answer-funktionen, i vilken buffertar sedan allokeras för att arbeta med inkommande och utgående ramar. Det var fortfarande cirka 100 Kb. Och sedan gjorde vi följande. Fram till ögonblicket för samtalet placerar vi data i externt minne. Så snart samtalet ersätter vi omedelbart högen med en annan - i RAM. Således överfördes all "het" data till ett snabbare och mer förutsägbart minne.

Som ett resultat gjorde allt detta tillsammans det möjligt att lansera simple_pjsua och ring via din server. Och sedan via andra servrar som sip.linphone.org.

Resultat

Som ett resultat var det möjligt att lansera simple_pjsua med röstöverföring i båda riktningarna genom servern. Problemet med att ytterligare spendera 128 KB SDRAM kan lösas genom att använda en något kraftfullare Cortex-M7 (till exempel STM32F769NI med 512 KB RAM), men samtidigt har vi fortfarande inte gett upp hoppet om att komma in i 256 KB 🙂 Vi blir glada om någon är intresserad, eller ännu bättre, prova. Alla källor finns som vanligt i vår förråd.

Källa: will.com

Lägg en kommentar