Hallo zusammen.
Vor einiger Zeit haben wir darüber gesprochen, wie es uns gelungen ist, ein SIP-Telefon auf der STM32F4-Discovery mit 1 MB ROM und 192 KB RAM zu starten, basierend auf . Hier muss gesagt werden, dass diese Version minimal war und zwei Telefone direkt ohne Server verband und die Sprachübertragung nur in eine Richtung erfolgte. Daher haben wir beschlossen, ein vollständigeres Telefon mit Anrufen über einen Server und Sprachübertragung in beide Richtungen zu starten, dabei jedoch den Speicherplatz so gering wie möglich zu halten.

Für das Telefon wurde entschieden, die Anwendung simple_pjsua aus der PJSIP-Bibliothek zu wählen. Dies ist eine minimale Anwendung, die sich auf dem Server registrieren, Anrufe empfangen und beantworten kann. Im Folgenden werde ich gleich beschreiben, wie man das auf der STM32F7-Discovery startet.
So starten Sie
- Konfigurieren Sie Embox
make confload-platform/pjsip/stm32f7cube - Im Datei conf/mods.config geben wir das benötigte SIP-Konto an.
include platform.pjsip.cmd.simple_pjsua_imported( sip_domain="server", sip_user="username", sip_passwd="password")wo server — das ist der SIP-Server (zum Beispiel sip.linphone.org), username und passwort — der Benutzername und das Passwort des Kontos.
- Wir kompilieren Embox mit dem Befehl make. Über das Flashen des Boards haben wir Informationen auf unserem und in .
- Wir starten im Embox-Konsolenbefehl „simple_pjsua_imported“
00:00:12.870 pjsua_acc.c ....SIP-Outbound-Status für acc 0 ist nicht aktiv 00:00:12.884 pjsua_acc.c ....sip:alexk2222@sip.linphone.org: Registrierung erfolgreich, status=200 (Registrierung erfolgreich) 00:00:12.911 pjsua_acc.c ....Keep-alive-Timer für acc 0 gestartet, Ziel:91.121.209.194:5060, Intervall:15s - Schließlich bleibt es nur noch, Lautsprecher oder Kopfhörer an den Audioausgang anzuschließen und in zwei kleine MEMS-Mikrofone neben dem Display zu sprechen. Wir rufen von Linux über die Anwendung simple_pjsua an, pjsua. oder jede andere wie linphone.
All dies ist auf unserem .
Wie wir dazu gekommen sind
Ursprünglich stellte sich die Frage nach der Wahl der Hardware-Plattform. Da klar war, dass die STM32F4-Discovery aufgrund des Speichers nicht geeignet war, wurde die STM32F7-Discovery gewählt. Sie hat 1 MB Flash-Speicher und 256 KB RAM (+ 64 KB speziellen schnellen Speicher, den wir ebenfalls nutzen werden). Auch dies ist nicht viel für Anrufe über den Server, aber wir wollten es versuchen.
Wir haben uns die Aufgabe grob in mehrere Phasen unterteilt:
- Starten von PJSIP auf QEMU. Das war praktisch für das Debugging, außerdem hatten wir dort bereits Unterstützung für den AC97-Codec.
- Aufnahme und Wiedergabe von Stimmen auf QEMU und auf STM32.
- Portierung der Anwendung simple_pjsua aus PJSIP. Diese ermöglicht die Registrierung auf einem SIP-Server und das Tätigen von Anrufen.
- Erstellen Sie Ihren eigenen Server auf Basis von Asterisk und testen Sie darauf, danach versuchen Sie externe wie sip.linphone.org.
Der Sound in Embox funktioniert über Portaudio, das auch in PISIP verwendet wird. Auf QEMU traten die ersten Probleme auf – WAV-Dateien wurden bei 44100 Hz gut abgespielt, aber bei 8000 Hz lief etwas offensichtlich nicht richtig. Es stellte sich heraus, dass es an der Frequenzeinstellung lag – standardmäßig war sie in der Hardware auf 44100 eingestellt, was wir programmatisch nicht geändert hatten.
Hier sollte vielleicht etwas erklärt werden, wie das Abspielen von Sound überhaupt funktioniert. Der Soundkarte kann ein Zeiger auf einen Speicherbereich zugewiesen werden, aus dem bei einer zuvor festgelegten Frequenz abgespielt oder aufgezeichnet werden soll. Nachdem der Puffer aufgebraucht ist, wird eine Unterbrechung ausgelöst, und die Ausführung geht mit dem nächsten Puffer weiter. Das Problem ist, dass diese Puffer im Voraus gefüllt werden müssen, während der vorherige abgespielt wird. Mit diesem Problem werden wir später noch auf dem STM32F7 konfrontiert werden.
Dann haben wir einen Server gemietet und Asterisk darauf installiert. Da viel debuggt werden musste und ich nicht gerne ins Mikrofon sprach, musste ein automatisches Abspielen und Aufzeichnen implementiert werden. Dafür haben wir simple_pjsua gepatcht, damit wir Dateien anstelle von Audiogeräten verwenden können. In PJSIP ist das ziemlich einfach, da es dort das Konzept eines Ports gibt, der sowohl ein Gerät als auch eine Datei sein kann. Diese Ports können flexibel mit anderen Ports verbunden werden. Den Code kann man in unserem pjsip anschauen. Das Ergebnis war folgendes Schema. Auf dem Asterisk-Server habe ich zwei Konten angelegt – eines für Linux und eines für Embox. Dann wird auf Embox der Befehl simple_pjsua_imported, Embox registriert sich am Server, danach rufen wir von Linux aus auf Embox an. Zum Zeitpunkt der Verbindung überprüfen wir am Asterisk-Server, dass die gesamte Verbindung hergestellt wurde, und nach einiger Zeit sollten wir in Embox den Sound von Linux hören, während wir in Linux die Datei speichern, die aus Embox abgespielt wird.
Nachdem das auf QEMU funktioniert hatte, gingen wir zur Portierung auf das STM32F7-Discovery über. Das erste Problem war – wir passten nicht in 1 MB ROM ohne aktivierte Compiler-Optimierung „-Os“ bezüglich der Bildgröße. Daher aktivierten wir „-Os“. Außerdem deaktivierten wir mit einem Patch die Unterstützung für C++, da sie nur für pjsua benötigt wird, und wir verwenden simple_pjsua.
Nachdem wir Platz schaffen konnten simple_pjsua, waren wir der Meinung, dass die Chancen, das jetzt zu starten, bestehen. Aber zuerst mussten wir uns mit der Aufnahme und Wiedergabe von Sprache befassen. Die Frage – wo aufzeichnen? Wir wählten externen Speicher – SDRAM (128 MB). Sie können es selbst ausprobieren:
Erstellt Stereo-WAV mit einer Frequenz von 16000 Hz und einer Dauer von 10 Sekunden:
record -r 16000 -c 2 -d 10000 -m C0000000
Wiedergabe:
play -m C0000000
Hier gab es zwei Probleme. Das erste betraf den Codec – es wird WM8994 verwendet, und in diesem gibt es einen Begriff namens Slot, von denen es vier gibt. Wenn dies nicht eingestellt wird, spielt AUDIO standardmäßig in allen vier Slots ab. Bei einer Frequenz von 16000 Hz erhielten wir also 8000 Hz, und bei 8000 Hz funktionierte die Wiedergabe einfach nicht. Als wir nur die Slots 0 und 2 auswählten, funktionierte es wie gewünscht. Ein weiteres Problem war die Audio-Schnittstelle in STM32Cube, bei der der Audioausgang synchron mit dem Audioeingang über SAI (Serial Audio Interface) funktioniert (ich habe mich nicht im Detail damit beschäftigt, aber es scheint, dass sie eine gemeinsame Uhr teilen, und bei der Initialisierung des Audioausgangs wird der Audioeingang irgendwie eingebunden). Das heißt, wir können sie nicht getrennt starten, also haben wir Folgendes gemacht – sowohl der Audioeingang als auch der Audioausgang arbeiten immer (einschließlich der erzeugten Unterbrechungen). Wenn im System nichts wiedergegeben wird, geben wir einfach einen leeren Puffer an den Audioausgang weiter, und wenn die Wiedergabe gestartet wird, fangen wir an, ihn richtig zu füllen.
Später stießen wir auf das Problem, dass der Ton bei der Sprachaufnahme sehr leise war. Dies liegt daran, dass die MEMS-Mikrofone auf STM32F7-Discovery bei Frequenzen unter 16000 Hz schlecht arbeiten. Daher stellen wir 16000 Hz ein, selbst wenn 8000 Hz ankommen. Dafür war es nötig, eine Softwareumwandlung von einer Frequenz zur anderen hinzuzufügen.
Außerdem mussten wir die Größe des Heaps, der im RAM liegt, erhöhen. Nach unseren Berechnungen benötigte pjsip etwa 190 KB, und uns blieben nur noch etwa 100 KB. Dabei mussten wir ein wenig externen Speicher – SDRAM (ca. 128 KB) – verwenden.
Nach all diesen Änderungen sah ich die ersten Pakete zwischen Linux und Embox und hörte den Ton! Aber der Ton war schrecklich, ganz anders als in QEMU, nichts war zu erkennen. Dann überlegten wir, wo das Problem liegen könnte. Das Debugging zeigte, dass Embox einfach nicht rechtzeitig die Audio-Puffer füllen/entladen konnte. Während pjsip einen Frame verarbeitet, traten bereits 2 Unterbrechungen über die Beendigung der Pufferverarbeitung auf, was zu viel ist. Der erste Gedanke zur Beschleunigung war die Compiler-Optimierung, aber die war bereits in PJSIP aktiviert. Das zweite – Hardware-Gleitkomma, über die wir gesprochen haben. . Aber wie sich gezeigt hat, hat die FPU keinen wesentlichen Geschwindigkeitszuwachs gebracht. Der nächste Schritt war das Setzen von Prioritäten für die Streams. In Embox gibt es verschiedene Planungsstrategien, und ich habe die aktiviert, die Prioritäten unterstützt, und den Audiostreams die höchste Priorität zugewiesen. Das hat auch nicht geholfen.
Die nächste Idee war, dass wir mit externer Speicher arbeiten und es gut wäre, die Strukturen dorthin zu verschieben, auf die sehr häufig zugegriffen wird. Ich habe eine vorläufige Analyse durchgeführt, wann und wofür simple_pjsua Speicher reserviert wird. Es stellte sich heraus, dass von 190 Kb die ersten 90 Kb für interne Bedürfnisse von PJSIP reserviert werden und der Zugriff darauf nicht sehr häufig erfolgt. Darüber hinaus wird während eines eingehenden Anrufs die Funktion pjsua_call_answer aufgerufen, bei der dann Puffer für die Verarbeitung von eingehenden und ausgehenden Frames reserviert werden. Das waren noch etwa 100 Kb. Und hier sind wir wie folgt vorgegangen. Vor dem Anruf platzieren wir die Daten im externen Speicher. Sobald der Anruf kommt, tauschen wir sofort den Heap gegen einen anderen aus – im RAM. So wurden alle „heißen“ Daten in einen schnelleren und vorhersehbareren Speicher verschoben.
Letztendlich hat all das zusammen ermöglicht, simple_pjsua und über unseren Server zu telefonieren. Und dann auch über andere Server wie sip.linphone.org.
Das DBMS Tarantool ist ein attraktives, zukunftsträchtiges Produkt zur Erstellung von hochbelasteten Anwendungen.
Letztendlich gelang es, simple_pjsua mit der Sprachübertragung in beide Richtungen über den Server. Das Problem mit den zusätzlich benötigten 128 Kb SDRAM kann durch den Einsatz eines etwas leistungsstärkeren Cortex-M7 (zum Beispiel STM32F769NI mit 512 Kb RAM) gelöst werden, aber wir haben auch die Hoffnung nicht aufgegeben, es in 256 Kb zu schaffen 🙂 Wir würden uns freuen, wenn sich jemand dafür interessiert, noch besser – es ausprobiert. Alle Quellcodes sind wie gewohnt in unserem .
Quelle: habr.com
