SIP-telefoon op STM32F7-Discovery

Hallo allemaal

Een tijdje geleden hebben we писали over hoe we erin geslaagd zijn om een ​​SIP-telefoon te lanceren op STM32F4-Discovery met 1 MB ROM en 192 KB RAM) gebaseerd op embox. Hier moet gezegd worden dat die versie minimaal was en twee telefoons rechtstreeks met elkaar verbond zonder server en met spraakoverdracht in slechts één richting. Daarom hebben we besloten om een ​​completere telefoon te lanceren met een oproep via de server, spraakoverdracht in beide richtingen, maar tegelijkertijd binnen de kleinst mogelijke geheugenruimte.


Voor de telefoon is gekozen voor een applicatie eenvoudige_pjsua als onderdeel van de PJSIP-bibliotheek. Dit is een minimale applicatie die zich op de server kan registreren, oproepen kan ontvangen en beantwoorden. Hieronder zal ik meteen een beschrijving geven van hoe het op STM32F7-Discovery moet worden uitgevoerd.

Hoe te lanceren

  1. Embox configureren
    make confload-platform/pjsip/stm32f7cube
  2. Stel het vereiste SIP-account in in het bestand conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    waar server is een SIP-server (bijvoorbeeld sip.linphone.org), gebruikersnaam и wachtwoord - account gebruikersnaam en wachtwoord.

  3. Embox als team in elkaar zetten maken. Over de bordfirmware die we hebben wiki en статье.
  4. Voer de opdracht "simple_pjsua_imported" uit in de Embox-console
    
    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. Ten slotte blijft het over om luidsprekers of een koptelefoon in de audio-uitgang te steken en in twee kleine MEMS-microfoons naast het scherm te spreken. We bellen vanuit Linux via de applicatie simple_pjsua, pjsua. Nou ja, of je kunt elk ander type linphone gebruiken.

Dit alles staat beschreven op onze wiki.

Hoe zijn we daar gekomen

Dus in eerste instantie rees de vraag over het kiezen van een hardwareplatform. Omdat het duidelijk was dat STM32F4-Discovery niet uit het geheugen zou passen, werd gekozen voor STM32F7-Discovery. Ze heeft een flashdrive van 1 MB en 256 KB RAM (+ 64 speciaal snel geheugen, dat we ook zullen gebruiken). Ook niet veel voor oproepen via de server, maar we besloten om te proberen erbij te horen.

Voorwaardelijk voor zichzelf was de taak verdeeld in verschillende fasen:

  • PJSIP uitvoeren op QEMU. Het was handig om te debuggen, en we hadden daar al ondersteuning voor de AC97-codec.
  • Spraakopname en -weergave op QEMU en op STM32.
  • Een applicatie porteren eenvoudige_pjsua van PJSIP. Hiermee kunt u zich registreren op de SIP-server en bellen.
  • Implementeer uw eigen op Asterisk gebaseerde server en test erop, en probeer vervolgens externe servers zoals sip.linphone.org

Geluid in Embox werkt via Portaudio, dat ook in PISIP wordt gebruikt. De eerste problemen deden zich voor op QEMU - WAV speelde goed op 44100 Hz, maar bij 8000 ging er duidelijk iets mis. Het bleek een kwestie van het instellen van de frequentie - standaard was het 44100 in de apparatuur, en dit veranderde niet programmatisch.

Hier is het misschien de moeite waard om een ​​beetje uit te leggen hoe het geluid in het algemeen wordt gespeeld. De geluidskaart kan worden ingesteld op een bepaalde pointer naar een stuk geheugen waarvan u met een vooraf bepaalde frequentie wilt afspelen of opnemen. Nadat de buffer is beëindigd, wordt een interrupt gegenereerd en gaat de uitvoering verder met de volgende buffer. Feit is dat deze buffers vooraf gevuld moeten worden terwijl de vorige wordt gespeeld. We zullen dit probleem verder onder ogen zien op STM32F7.

Vervolgens hebben we een server gehuurd en daar Asterisk op ingezet. Omdat het nodig was om veel te debuggen, maar ik niet veel in de microfoon wilde spreken, was het nodig om automatisch afspelen en opnemen te maken. Om dit te doen, hebben we simple_pjsua gepatcht, zodat je bestanden kunt slippen in plaats van audioapparaten. In PJSIP wordt dit heel eenvoudig gedaan, omdat ze het concept van een poort hebben, wat een apparaat of een bestand kan zijn. En deze poorten kunnen flexibel worden aangesloten op andere poorten. Je kunt de code zien in onze pjsip opslagplaatsen. Als gevolg hiervan was de regeling als volgt. Op de Asterisk-server startte ik twee accounts - voor Linux en voor Embox. Vervolgens wordt de opdracht uitgevoerd op Embox simple_pjsua_geïmporteerd, registreert Embox zich op de server, waarna we vanuit Linux Embox aanroepen. Op het moment van verbinding controleren we op de Asterisk-server of de verbinding tot stand is gebracht, en na een tijdje horen we geluid van Linux in Embox, en in Linux slaan we het bestand op dat wordt afgespeeld vanuit Embox.

Nadat het op QEMU werkte, gingen we verder met porten naar STM32F7-Discovery. Het eerste probleem is dat ze niet in 1 MB ROM pasten zonder de ingeschakelde compileroptimalisatie "-Os" voor de grootte van de afbeelding. Daarom hebben we "-Os" opgenomen. Verder heeft de patch ondersteuning voor C ++ uitgeschakeld, dus het is alleen nodig voor pjsua, en we gebruiken simple_pjsua.

Na geplaatst te zijn eenvoudige_pjsua, besloten dat er nu een kans is om het te lanceren. Maar eerst was het nodig om te gaan met het opnemen en afspelen van de stem. De vraag is waar te schrijven? We kozen voor extern geheugen - SDRAM (128 MB). Dit kun je zelf proberen:

Creëert een stereo WAV met een frequentie van 16000 Hz en een duur van 10 seconden:


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

We verliezen:


play -m C0000000

Er zijn hier twee problemen. De eerste met de codec - WM8994 wordt gebruikt, en het heeft zoiets als een slot, en er zijn 4 van deze slots.Dus standaard, als dit niet is geconfigureerd, wordt bij het afspelen van audio in alle vier de slots afgespeeld . Daarom ontvingen we bij een frequentie van 16000 Hz 8000 Hz, maar voor 8000 Hz werkte het afspelen gewoon niet. Toen alleen slots 0 en 2 waren geselecteerd, werkte het zoals het hoort. Een ander probleem was de audio-interface in de STM32Cube, waarbij de audio-uitvoer via SAI (Serial Audio Interface) synchroon werkt met de audio-invoer (ik begreep de details niet, maar het blijkt dat ze een gemeenschappelijke klok delen en wanneer de audio-uitvoer wordt geïnitialiseerd, audio is op de een of andere manier aan de ingang gekoppeld). Dat wil zeggen, je kunt ze niet afzonderlijk uitvoeren, dus hebben we het volgende gedaan: de audio-invoer en audio-uitvoer werken altijd (inclusief interrupts die worden gegenereerd). Maar als er niets wordt afgespeeld in het systeem, stoppen we gewoon een lege buffer in de audio-uitvoer, en als het afspelen begint, beginnen we die echt te vullen.

Verder stuitten we op het feit dat het geluid tijdens stemopname erg zacht was. Dit komt door het feit dat MEMS-microfoons op de STM32F7-Discovery op de een of andere manier niet goed werken bij frequenties onder de 16000 Hz. Daarom stellen we 16000 Hz in, zelfs als er 8000 Hz komt. Om dit te doen was het echter nodig om een ​​softwareconversie van de ene frequentie naar de andere toe te voegen.

Vervolgens moest ik de grootte van de heap, die zich in RAM bevindt, vergroten. Volgens onze berekeningen had pjsip ongeveer 190 KB nodig en hebben we nog maar ongeveer 100 KB over. Hier moest ik wat extern geheugen gebruiken - SDRAM (ongeveer 128 KB).

Na al deze bewerkingen zag ik de eerste pakketten tussen Linux en Embox, en ik hoorde het geluid! Maar het geluid was verschrikkelijk, helemaal niet hetzelfde als op QEMU, het was onmogelijk om iets te onderscheiden. Toen hebben we nagedacht over wat er aan de hand zou kunnen zijn. Debugging toonde aan dat Embox simpelweg geen tijd heeft om audiobuffers te vullen/ontladen. Terwijl pjsip één frame aan het verwerken was, hadden 2 interrupts tijd om op te treden over de voltooiing van de bufferverwerking, wat te veel is. De eerste gedachte voor snelheid was compileroptimalisatie, maar deze was al opgenomen in PJSIP. De tweede is een drijvende komma voor hardware, we hebben er over gesproken статье. Maar zoals de praktijk heeft aangetoond, gaf FPU geen significante toename in snelheid. De volgende stap was het prioriteren van threads. Embox heeft verschillende planningsstrategieën en ik heb er een toegevoegd die prioriteiten ondersteunt en audiostreams op de hoogste prioriteit zet. Dit hielp ook niet.

Het volgende idee was dat we met extern geheugen werken en dat het leuk zou zijn om structuren daarheen te verplaatsen die extreem vaak worden gebruikt. Ik heb een voorlopige analyse gemaakt van wanneer en onder wat eenvoudige_pjsua wijst geheugen toe. Het bleek dat van de 190 Kb de eerste 90 Kb zijn toegewezen voor interne behoeften van PJSIP en dat ze niet vaak worden gebruikt. Verder wordt tijdens een inkomende oproep de functie pjsua_call_answer aangeroepen, waarin buffers worden toegewezen voor het werken met inkomende en uitgaande frames. Het was nog steeds ongeveer 100 Kb. En toen deden we het volgende. Tot het moment van de oproep plaatsen we de gegevens in het externe geheugen. Zodra we bellen, vervangen we de hoop onmiddellijk door een andere - in RAM. Zo werden alle "hete" gegevens overgebracht naar een sneller en voorspelbaarder geheugen.

Als gevolg hiervan maakte dit alles samen de lancering mogelijk eenvoudige_pjsua en bel via uw server. En dan via andere servers zoals sip.linphone.org.

Bevindingen

Als gevolg hiervan was het mogelijk om te lanceren eenvoudige_pjsua met spraakoverdracht in beide richtingen via de server. Het probleem met extra uitgegeven 128 KB SDRAM kan worden opgelost door een iets krachtigere Cortex-M7 te gebruiken (bijvoorbeeld STM32F769NI met 512 KB RAM), maar tegelijkertijd hebben we de hoop nog steeds niet opgegeven om in 256 te komen KB 🙂 We zullen blij zijn als iemand geïnteresseerd is, of beter nog, probeer het. Alle bronnen staan, zoals gebruikelijk, in onze opslagplaatsen.

Bron: www.habr.com

Voeg een reactie