SIP-Telefon auf STM32F7-Discovery

Hallo.

Vor einiger Zeit haben wir schrieb darüber, wie wir es geschafft haben, ein SIP-Telefon auf STM32F4-Discovery mit 1 MB ROM und 192 KB RAM zu starten Embox. Hier muss gesagt werden, dass diese Version minimal war und zwei Telefone direkt ohne Server und mit Sprachübertragung in nur eine Richtung verband. Aus diesem Grund haben wir uns entschieden, ein umfassenderes Telefon mit einem Anruf über den Server und Sprachübertragung in beide Richtungen auf den Markt zu bringen, aber gleichzeitig die kleinstmögliche Speichergröße beizubehalten.


Für das Telefon wurde beschlossen, eine Anwendung auszuwählen simple_pjsua als Teil der PJSIP-Bibliothek. Dabei handelt es sich um eine Minimalanwendung, die sich auf dem Server registrieren, Anrufe entgegennehmen und beantworten kann. Im Folgenden werde ich sofort beschreiben, wie es auf STM32F7-Discovery ausgeführt wird.

Wie man läuft

  1. Embox konfigurieren
    make confload-platform/pjsip/stm32f7cube
  2. Legen Sie das erforderliche SIP-Konto in der Datei conf/mods.config fest.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    wo Server ist ein SIP-Server (zum Beispiel sip.linphone.org), Benutzername и Passwort - Benutzername und Passwort des Kontos.

  3. Embox als Team zusammenstellen um. Über die Board-Firmware, die wir haben Wiki und Artikel.
  4. Führen Sie den Befehl „simple_pjsua_imported“ in der Embox-Konsole aus
    
    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. Schließlich müssen noch Lautsprecher oder Kopfhörer an den Audioausgang angeschlossen und in zwei kleine MEMS-Mikrofone neben dem Display gesprochen werden. Wir rufen von Linux aus über die Anwendung simple_pjsua, pjsua auf. Nun, Sie können auch jede andere Art von Linphone verwenden.

All dies ist auf unserer Seite beschrieben Wiki.

Wie sind wir dorthin gekommen?

Daher stellte sich zunächst die Frage nach der Wahl einer Hardwareplattform. Da klar war, dass STM32F4-Discovery nicht aus dem Speicher passen würde, wurde STM32F7-Discovery ausgewählt. Sie verfügt über ein 1-MB-Flash-Laufwerk und 256 KB RAM (+ 64 besonders schnelle Speicher, die wir auch verwenden werden). Auch für Anrufe über den Server gibt es nicht viel, aber wir haben beschlossen, zu versuchen, uns anzupassen.

Bedingt für sich selbst wurde die Aufgabe in mehrere Phasen unterteilt:

  • Ausführen von PJSIP auf QEMU. Es war praktisch zum Debuggen, außerdem hatten wir dort bereits Unterstützung für den AC97-Codec.
  • Sprachaufzeichnung und -wiedergabe auf QEMU und auf STM32.
  • Portierung einer Anwendung simple_pjsua von PJSIP. Es ermöglicht Ihnen, sich am SIP-Server zu registrieren und Anrufe zu tätigen.
  • Stellen Sie Ihren eigenen Asterisk-basierten Server bereit und testen Sie ihn. Probieren Sie dann externe Server wie sip.linphone.org aus

Der Ton in Embox funktioniert über Portaudio, das auch in PISIP verwendet wird. Die ersten Probleme traten bei QEMU auf – WAV spielte bei 44100 Hz gut, aber bei 8000 ging eindeutig etwas schief. Es stellte sich heraus, dass es sich um die Einstellung der Frequenz handelte – standardmäßig war sie im Gerät 44100, und dies änderte sich nicht programmgesteuert.

Hier lohnt es sich vielleicht, ein wenig zu erklären, wie der Ton im Allgemeinen abgespielt wird. Die Soundkarte kann auf einen Zeiger auf einen Speicherbereich eingestellt werden, von dem aus Sie mit einer vorgegebenen Frequenz abspielen oder aufnehmen möchten. Nachdem der Puffer beendet ist, wird ein Interrupt generiert und die Ausführung wird mit dem nächsten Puffer fortgesetzt. Tatsache ist, dass diese Puffer im Voraus gefüllt werden müssen, während der vorherige abgespielt wird. Wir werden diesem Problem bei STM32F7 weiter begegnen.

Als nächstes haben wir einen Server gemietet und Asterisk darauf bereitgestellt. Da viel debuggt werden musste, ich aber nicht viel ins Mikrofon sprechen wollte, war eine automatische Wiedergabe und Aufnahme notwendig. Zu diesem Zweck haben wir simple_pjsua gepatcht, sodass Sie Dateien anstelle von Audiogeräten einfügen können. In PJSIP geschieht dies ganz einfach, da sie das Konzept eines Ports haben, der entweder ein Gerät oder eine Datei sein kann. Und diese Ports können flexibel mit anderen Ports verbunden werden. Sie können den Code in unserem pjsip sehen Lagerstätten. Infolgedessen war das Schema wie folgt. Auf dem Asterisk-Server habe ich zwei Konten angelegt – für Linux und für Embox. Als nächstes wird der Befehl auf Embox ausgeführt simple_pjsua_imported, Embox registriert sich auf dem Server, woraufhin wir Embox unter Linux aufrufen. Im Moment der Verbindung überprüfen wir auf dem Asterisk-Server, ob die Verbindung hergestellt wurde, und nach einer Weile sollten wir in Embox einen Ton von Linux hören, und in Linux speichern wir die Datei, die von Embox abgespielt wird.

Nachdem es auf QEMU funktionierte, gingen wir zur Portierung auf STM32F7-Discovery über. Das erste Problem besteht darin, dass sie nicht in 1 MB ROM passten, ohne dass die Compiler-Optimierung „-Os“ für die Größe des Bildes aktiviert war. Deshalb haben wir „-Os“ eingefügt. Darüber hinaus wurde durch den Patch die C++-Unterstützung deaktiviert, sodass sie nur für pjsua benötigt wird und wir simple_pjsua verwenden.

Nach dem Platzieren simple_pjsua, entschied, dass es jetzt eine Chance gibt, es zu starten. Doch zunächst galt es, sich mit der Aufnahme und Wiedergabe der Stimme zu befassen. Die Frage ist, wo schreiben? Wir haben uns für einen externen Speicher entschieden – SDRAM (128 MB). Das können Sie selbst ausprobieren:

Erstellt ein Stereo-WAV mit einer Frequenz von 16000 Hz und einer Dauer von 10 Sekunden:


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

Wir verlieren:


play -m C0000000

Hier gibt es zwei Probleme. Der erste mit dem Codec WM8994 wird verwendet und hat so etwas wie einen Steckplatz, und es gibt 4 dieser Steckplätze. Wenn dies also nicht konfiguriert ist, erfolgt die Wiedergabe bei der Audiowiedergabe standardmäßig in allen vier Steckplätzen . Daher haben wir bei einer Frequenz von 16000 Hz 8000 Hz empfangen, aber bei 8000 Hz funktionierte die Wiedergabe einfach nicht. Wenn nur die Slots 0 und 2 ausgewählt waren, funktionierte es wie es sollte. Ein weiteres Problem war die Audioschnittstelle im STM32Cube, bei der der Audioausgang über SAI (Serial Audio Interface) synchron mit dem Audioeingang funktioniert (ich habe die Details nicht verstanden, aber es stellt sich heraus, dass sie einen gemeinsamen Takt haben und wann die Die Audioausgabe wird initialisiert, Audio ist irgendwie mit dem Eingang verbunden. Das heißt, Sie können sie nicht separat ausführen, daher haben wir Folgendes getan: Der Audioeingang und der Audioausgang funktionieren immer (einschließlich der Generierung von Interrupts). Aber wenn im System nichts abgespielt wird, schieben wir einfach einen leeren Puffer in den Audioausgang, und wenn die Wiedergabe beginnt, beginnen wir ehrlich gesagt, ihn zu füllen.

Außerdem ist uns aufgefallen, dass der Ton bei der Sprachaufnahme sehr leise war. Dies liegt daran, dass die MEMS-Mikrofone des STM32F7-Discovery bei Frequenzen unter 16000 Hz irgendwie nicht gut funktionieren. Deshalb stellen wir 16000 Hz ein, auch wenn 8000 Hz kommen. Dazu war jedoch eine Software-Konvertierung einer Frequenz in eine andere erforderlich.

Als nächstes musste ich die Größe des Heaps erhöhen, der sich im RAM befindet. Nach unseren Berechnungen benötigte pjsip etwa 190 KB und wir haben nur noch etwa 100 KB übrig. Hier musste ich externen Speicher verwenden – SDRAM (ca. 128 KB).

Nach all diesen Änderungen sah ich die ersten Pakete zwischen Linux und Embox und hörte den Ton! Aber der Ton war schrecklich, überhaupt nicht derselbe wie bei QEMU, es war unmöglich, etwas zu erkennen. Dann haben wir darüber nachgedacht, was los sein könnte. Beim Debuggen zeigte sich, dass Embox einfach keine Zeit hat, Audiopuffer zu füllen/entladen. Während pjsip einen Frame verarbeitete, kam es zu zwei Interrupts über den Abschluss der Pufferverarbeitung, was zu viel ist. Der erste Gedanke für Geschwindigkeit war die Compileroptimierung, aber sie war bereits in PJSIP enthalten. Das zweite ist ein Hardware-Gleitkomma, darüber haben wir bereits gesprochen Artikel. Aber wie die Praxis gezeigt hat, brachte die FPU keine nennenswerte Geschwindigkeitssteigerung. Der nächste Schritt bestand darin, Threads zu priorisieren. Embox verfügt über verschiedene Planungsstrategien, und ich habe eine hinzugefügt, die Prioritäten unterstützt und Audiostreams auf die höchste Priorität setzt. Auch das hat nicht geholfen.

Die nächste Idee war, dass wir mit externem Speicher arbeiten und es schön wäre, Strukturen dorthin zu verschieben, auf die extrem oft zugegriffen wird. Ich habe eine vorläufige Analyse durchgeführt, wann und unter was simple_pjsua reserviert Speicher. Es stellte sich heraus, dass von den 190 KB die ersten 90 KB für den internen Bedarf von PJSIP reserviert sind und nicht sehr oft darauf zugegriffen wird. Darüber hinaus wird bei einem eingehenden Anruf die Funktion pjsua_call_answer aufgerufen, in der dann Puffer für die Arbeit mit eingehenden und ausgehenden Frames zugewiesen werden. Es waren immer noch etwa 100 KB. Und dann haben wir Folgendes gemacht. Bis zum Zeitpunkt des Anrufs legen wir die Daten im externen Speicher ab. Sobald der Anruf erfolgt, ersetzen wir den Heap sofort durch einen anderen – im RAM. Somit wurden alle „heißen“ Daten in einen schnelleren und vorhersehbareren Speicher übertragen.

All dies zusammen ermöglichte den Start simple_pjsua und rufen Sie über Ihren Server an. Und dann über andere Server wie sip.linphone.org.

Befund

Dadurch war der Start möglich simple_pjsua mit Sprachübertragung in beide Richtungen über den Server. Das Problem mit zusätzlich verbrauchten 128 KB SDRAM lässt sich durch den Einsatz eines etwas leistungsstärkeren Cortex-M7 (z. B. STM32F769NI mit 512 KB RAM) lösen, gleichzeitig haben wir aber die Hoffnung auf 256 noch nicht aufgegeben KB 🙂 Wir freuen uns, wenn jemand Interesse hat, oder noch besser, probiert es aus. Alle Quellen befinden sich wie üblich in unserem Lagerstätten.

Source: habr.com

Kommentar hinzufügen