Telefon SIP na STM32F7-Discovery

Cześć wszystkim

Jakiś czas temu my napisał o tym, jak udało nam się uruchomić telefon SIP na STM32F4-Discovery z 1 MB ROM i 192 KB RAM) na podstawie Skrzynka odbiorcza. Tutaj trzeba powiedzieć, że ta wersja była minimalna i łączyła dwa telefony bezpośrednio bez serwera iz transmisją głosu tylko w jednym kierunku. Dlatego zdecydowaliśmy się na uruchomienie pełniejszego telefonu z połączeniem przez serwer, transmisją głosu w obie strony, ale jednocześnie zachowującym jak najmniejszy rozmiar pamięci.


W przypadku telefonu postanowiono wybrać aplikację proste_pjsua jako część biblioteki PJSIP. Jest to minimalna aplikacja, która może rejestrować się na serwerze, odbierać i odbierać połączenia. Poniżej od razu podam opis jak go uruchomić na STM32F7-Discovery.

Jak biegać

  1. Konfigurowanie Emboksa
    make confload-platform/pjsip/stm32f7cube
  2. Ustaw wymagane konto SIP w pliku conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    gdzie serwer jest serwerem SIP (na przykład sip.linphone.org), nazwa użytkownika и password - nazwa użytkownika i hasło do konta.

  3. Montaż Embox jako zespół robić. O oprogramowaniu płyty, które mamy włączone вики i Artykuł.
  4. Uruchom polecenie „simple_pjsua_imported” w konsoli Embox
    
    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. Na koniec pozostaje włożyć głośniki lub słuchawki do wyjścia audio i mówić do dwóch małych mikrofonów MEMS obok wyświetlacza. Dzwonimy z Linuksa za pośrednictwem aplikacji simple_pjsua, pjsua. Cóż, albo możesz użyć dowolnego innego rodzaju linphone.

Wszystko to jest opisane na naszym вики.

Jak się tam dostaliśmy

Tak więc początkowo pojawiło się pytanie o wybór platformy sprzętowej. Ponieważ było jasne, że STM32F4-Discovery nie zmieści się z pamięci, wybrano STM32F7-Discovery. Ma 1 MB pamięci flash i 256 KB pamięci RAM (+ 64 specjalna szybka pamięć, z której również będziemy korzystać). Również nie za dużo połączeń przez serwer, ale postanowiliśmy spróbować się dopasować.

Warunkowo dla siebie zadanie podzielono na kilka etapów:

  • Uruchamianie PJSIP na QEMU. Było to wygodne do debugowania, a ponadto mieliśmy już tam obsługę kodeka AC97.
  • Nagrywanie i odtwarzanie głosu na QEMU i na STM32.
  • Portowanie aplikacji proste_pjsua z PJSIP. Pozwala zarejestrować się na serwerze SIP i wykonywać połączenia.
  • Wdróż własny serwer oparty na Asterisk i przetestuj na nim, a następnie wypróbuj zewnętrzne, takie jak sip.linphone.org

Dźwięk w Embox działa przez Portaudio, które jest również używane w PISIP. Pierwsze problemy pojawiły się na QEMU - WAV grał dobrze przy 44100 Hz, ale przy 8000 coś wyraźnie poszło nie tak. Okazało się, że to kwestia ustawienia częstotliwości – domyślnie w sprzęcie było to 44100, a tego programowo nie zmieniano.

Być może tutaj warto trochę wyjaśnić, jak ogólnie odtwarzany jest dźwięk. W karcie dźwiękowej można ustawić jakiś wskaźnik na fragment pamięci, z którego chcesz odtwarzać lub nagrywać z określoną częstotliwością. Po zakończeniu bufora generowane jest przerwanie i wykonywanie jest kontynuowane z następnym buforem. Faktem jest, że te bufory muszą być wypełnione z wyprzedzeniem, podczas gdy poprzedni jest odtwarzany. Z tym problemem zmierzymy się dalej w STM32F7.

Następnie wynajęliśmy serwer i wdrożyliśmy na nim Asterisk. Ponieważ trzeba było dużo debugować, ale nie chciałem dużo mówić do mikrofonu, konieczne było automatyczne odtwarzanie i nagrywanie. Aby to zrobić, załataliśmy simple_pjsua, aby można było przesyłać pliki zamiast urządzeń audio. W PJSIP odbywa się to po prostu, ponieważ mają koncepcję portu, którym może być urządzenie lub plik. Porty te można elastycznie łączyć z innymi portami. Możesz zobaczyć kod w naszym pjsip repozytoria. W rezultacie schemat był następujący. Na serwerze Asterisk założyłem dwa konta - dla Linuksa i dla Emboxa. Następnie polecenie jest wykonywane na Embox simple_pjsua_imported, Embox rejestruje się na serwerze, po czym wywołujemy Embox z Linuksa. W momencie połączenia sprawdzamy na serwerze Asterisk czy połączenie jest nawiązane i po chwili powinniśmy usłyszeć dźwięk z Linuksa w Emboxie, aw Linuksie zapisujemy plik odtwarzany z Emboxa.

Po tym, jak zadziałało na QEMU, przeszliśmy do przenoszenia do STM32F7-Discovery. Pierwszy problem polega na tym, że nie mieściły się one w 1 MB pamięci ROM bez włączonej optymalizacji kompilatora „-Os” dla rozmiaru obrazu. Dlatego uwzględniliśmy „-Os”. Co więcej, łatka wyłączyła obsługę C++, więc jest potrzebna tylko dla pjsua, a my używamy simple_pjsua.

Po umieszczeniu proste_pjsua, zdecydował, że teraz jest szansa na jego uruchomienie. Ale najpierw trzeba było zająć się nagrywaniem i odtwarzaniem głosu. Pytanie gdzie pisać? Wybraliśmy pamięć zewnętrzną - SDRAM (128 MB). Możesz spróbować tego sam:

Tworzy stereofoniczny plik WAV o częstotliwości 16000 Hz i czasie trwania 10 sekund:


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

Przegrywamy:


play -m C0000000

Są tutaj dwa problemy. Używany jest pierwszy z kodekiem - WM8994, który ma coś takiego jak gniazdo, a tych gniazd jest 4. Tak więc domyślnie, jeśli nie jest to skonfigurowane, to podczas odtwarzania dźwięku odtwarzanie odbywa się we wszystkich czterech gniazdach . Dlatego przy częstotliwości 16000 Hz otrzymaliśmy 8000 Hz, ale dla 8000 Hz odtwarzanie po prostu nie działało. Gdy wybrano tylko gniazda 0 i 2, działało tak, jak powinno. Kolejnym problemem był interfejs audio w STM32Cube, w którym wyjście audio działa poprzez SAI (Serial Audio Interface) synchronicznie z wejściem audio (nie zrozumiałem szczegółów, ale okazuje się, że mają wspólny zegar i kiedy wyjście audio jest inicjowane, dźwięk jest w jakiś sposób do niego dołączony). Oznacza to, że nie można ich uruchomić osobno, więc zrobiliśmy co następuje - wejście audio i wyjście audio zawsze działają (w tym generowane są przerwania). Ale kiedy nic nie jest odtwarzane w systemie, po prostu wsuwamy pusty bufor do wyjścia audio, a kiedy rozpocznie się odtwarzanie, uczciwie zaczynamy go wypełniać.

Ponadto napotkaliśmy fakt, że dźwięk podczas nagrywania głosu był bardzo cichy. Wynika to z faktu, że mikrofony MEMS w STM32F7-Discovery jakoś nie działają dobrze przy częstotliwościach poniżej 16000 Hz. Dlatego ustawiamy 16000 Hz, nawet jeśli przyjdzie 8000 Hz. Aby to zrobić, konieczne było jednak dodanie oprogramowania do konwersji jednej częstotliwości na drugą.

Następnie musiałem zwiększyć rozmiar sterty, która znajduje się w pamięci RAM. Według naszych obliczeń pjsip wymagał około 190 KB, a zostało nam tylko około 100 KB. Tutaj musiałem użyć trochę pamięci zewnętrznej - SDRAM (około 128 KB).

Po tych wszystkich edycjach zobaczyłem pierwsze pakiety między Linuksem a Emboxem i usłyszałem dźwięk! Ale dźwięk był okropny, wcale nie taki sam jak na QEMU, nie można było niczego rozróżnić. Potem zastanawialiśmy się, o co może chodzić. Debugowanie wykazało, że Embox po prostu nie ma czasu na zapełnienie/rozładowanie buforów audio. Podczas gdy pjsip przetwarzał jedną ramkę, zdążyły wystąpić 2 przerwania dotyczące zakończenia przetwarzania bufora, czyli za dużo. Pierwszą myślą dotyczącą szybkości była optymalizacja kompilatora, ale była ona już uwzględniona w PJSIP. Drugi to sprzętowy zmiennoprzecinkowy, rozmawialiśmy o tym w Artykuł. Ale jak pokazała praktyka, FPU nie dał znaczącego wzrostu prędkości. Kolejnym krokiem było ustalenie priorytetów wątków. Embox ma różne strategie planowania, a ja uwzględniłem jedną, która obsługuje priorytety i ustawia strumienie audio na najwyższy priorytet. To też nie pomogło.

Następnym pomysłem było to, że pracujemy z pamięcią zewnętrzną i fajnie byłoby przenieść tam struktury, do których dostęp jest niezwykle często. Dokonałem wstępnej analizy, kiedy i pod czym proste_pjsua przydziela pamięć. Okazało się, że ze 190 Kb pierwsze 90 Kb przeznaczone jest na potrzeby wewnętrzne PJSiP i nie są one często udostępniane. Ponadto podczas połączenia przychodzącego wywoływana jest funkcja pjsua_call_answer, w której następnie przydzielane są bufory do pracy z ramkami przychodzącymi i wychodzącymi. Nadal było to około 100 Kb. A potem wykonaliśmy następujące czynności. Do momentu wywołania dane umieszczamy w pamięci zewnętrznej. Zaraz po wezwaniu natychmiast zamieniamy stertę na inną - w RAM. W ten sposób wszystkie „gorące” dane zostały przeniesione do szybszej i bardziej przewidywalnej pamięci.

W rezultacie wszystko to razem umożliwiło uruchomienie proste_pjsua i zadzwoń przez swój serwer. A następnie przez inne serwery, takie jak sip.linphone.org.

odkrycia

Dzięki temu można było wystartować proste_pjsua z transmisją głosu w obu kierunkach przez serwer. Problem z wydatkowanymi dodatkowo 128 KB SDRAM-u można rozwiązać stosując nieco mocniejszy Cortex-M7 (np. STM32F769NI z 512 KB RAM), ale jednocześnie nie tracimy nadziei na dostanie się do 256 KB KB 🙂 Będzie nam miło, jeśli ktoś będzie zainteresowany, albo jeszcze lepiej spróbuje. Wszystkie źródła, jak zwykle, są w naszym repozytoria.

Źródło: www.habr.com

Dodaj komentarz