SIP телефон на STM32F7-Discovery

Здравейте на всички.

Преди малко ние писали за това как успяхме да стартираме SIP телефон на STM32F4-Discovery с 1 MB ROM и 192 KB RAM) въз основа на Embox. Тук трябва да се каже, че тази версия беше минимална и свързваше два телефона директно без сървър и с предаване на глас само в една посока. Затова решихме да пуснем по-пълен телефон с обаждане през сървъра, предаване на глас в двете посоки, но в същото време да запазим възможно най-малкия размер на паметта.


За телефона беше решено да се избере приложение simple_pjsua като част от библиотеката на PJSIP. Това е минимално приложение, което може да се регистрира на сървъра, да получава и отговаря на обаждания. По-долу веднага ще дам описание как да го стартирам на STM32F7-Discovery.

Как да тичам

  1. Конфигуриране на Embox
    make confload-platform/pjsip/stm32f7cube
  2. Задайте необходимия SIP акаунт във файла conf/mods.config.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    където сървър е SIP сървър (например sip.linphone.org), потребителско име и парола - потребителско име и парола за акаунт.

  3. Сглобяване на Embox като екип правя. Относно фърмуера на платката, който имаме уики и Статия.
  4. Изпълнете командата “simple_pjsua_imported” в конзолата на 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. Накрая остава да поставите високоговорители или слушалки в аудио изхода и да говорите в два малки MEMS микрофона до дисплея. Обаждаме се от Linux чрез приложението simple_pjsua, pjsua. Е, или можете да използвате всеки друг тип линфон.

Всичко това е описано на нашия уики.

Как стигнахме до там

И така, първоначално възникна въпросът за избора на хардуерна платформа. Тъй като беше ясно, че STM32F4-Discovery няма да се побере от паметта, беше избран STM32F7-Discovery. Тя има 1 MB флашка и 256 KB RAM (+ 64 специална бърза памет, която също ще използваме). Също така не е много за обаждания през сървъра, но решихме да опитаме да се вместим.

Условно за себе си задачата беше разделена на няколко етапа:

  • Изпълнение на PJSIP на QEMU. Беше удобно за отстраняване на грешки, освен това вече имахме поддръжка за AC97 кодека там.
  • Записване и възпроизвеждане на глас на QEMU и на STM32.
  • Пренасяне на приложение simple_pjsua от PJSIP. Позволява ви да се регистрирате на SIP сървъра и да провеждате разговори.
  • Разположете свой собствен сървър, базиран на Asterisk, и го тествайте, след което опитайте външни, като sip.linphone.org

Звукът в Embox работи чрез Portaudio, който се използва и в PISIP. Първите проблеми се появиха на QEMU - WAV свиреше добре на 44100 Hz, но на 8000 явно нещо се обърка. Оказа се, че е въпрос на настройка на честотата - по подразбиране е 44100 в оборудването и това не се променя програмно.

Тук може би си струва да обясним малко как се възпроизвежда звукът като цяло. Звуковата карта може да бъде настроена на някакъв указател към част от паметта, от която искате да възпроизвеждате или записвате на предварително определена честота. След края на буфера се генерира прекъсване и изпълнението продължава със следващия буфер. Факт е, че тези буфери трябва да бъдат запълнени предварително, докато се играе предишният. Ще се сблъскаме с този проблем по-нататък на STM32F7.

След това наехме сървър и разположихме Asterisk на него. Тъй като беше необходимо да се отстраняват много грешки, но не исках да говоря много в микрофона, беше необходимо да се направи автоматично възпроизвеждане и запис. За да направим това, направихме корекция на simple_pjsua, така че да можете да приплъзвате файлове вместо аудио устройства. В PJSIP това се прави доста просто, тъй като те имат концепцията за порт, който може да бъде или устройство, или файл. И тези портове могат да бъдат гъвкаво свързани с други портове. Можете да видите кода в нашия pjsip хранилища. В резултат на това схемата беше следната. На сървъра на Asterisk стартирах два акаунта - за Linux и за Embox. След това командата се изпълнява в Embox simple_pjsua_imported, Embox се регистрира на сървъра, след което извикваме Embox от Linux. В момента на свързване проверяваме на сървъра на Asterisk дали връзката е установена и след известно време трябва да чуем звука от Linux в Embox, а в Linux запазваме файла, който се възпроизвежда от Embox.

След като проработи на QEMU, преминахме към пренасяне към STM32F7-Discovery. Първият проблем е, че те не се побират в 1 MB ROM без активираната оптимизация на компилатора „-Os“ за размера на изображението. Ето защо включихме "-Os". Освен това корекцията деактивира поддръжката за C ++, така че е необходима само за pjsua, а ние използваме simple_pjsua.

След поставяне simple_pjsua, реши, че сега има шанс да го стартира. Но първо беше необходимо да се справим със записа и възпроизвеждането на гласа. Въпросът е къде да пиша? Избрахме външна памет - SDRAM (128 MB). Можете да опитате това сами:

Създава стерео WAV с честота 16000 Hz и продължителност 10 секунди:


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

Ние губим:


play -m C0000000

Тук има два проблема. Използва се първият с кодека - WM8994 и има такова нещо като слот и има 4 от тези слота.Така че по подразбиране, ако това не е конфигурирано, тогава при възпроизвеждане на аудио възпроизвеждането се извършва и в четирите слота . Следователно при честота от 16000 Hz получихме 8000 Hz, но за 8000 Hz възпроизвеждането просто не работи. Когато бяха избрани само слотове 0 и 2, той работи както трябва. Друг проблем беше аудио интерфейсът в STM32Cube, в който аудио изходът работи чрез SAI (сериен аудио интерфейс) синхронно с аудио входа (не разбрах подробностите, но се оказа, че те споделят общ часовник и когато аудио изходът се инициализира, аудиото по някакъв начин е прикрепено към входа му). Тоест не можете да ги стартирате отделно, затова направихме следното - аудио входът и аудио изходът винаги работят (включително се генерират прекъсвания). Но когато нищо не се възпроизвежда в системата, ние просто поставяме празен буфер в аудио изхода и когато възпроизвеждането започне, ние честно започваме да го запълваме.

Освен това се натъкнахме на факта, че звукът по време на запис на глас беше много тих. Това се дължи на факта, че MEMS микрофоните на STM32F7-Discovery по някакъв начин не работят добре при честоти под 16000 Hz. Затова задаваме 16000 Hz, дори и да дойде 8000 Hz. За да направите това обаче, беше необходимо да добавите софтуерно преобразуване на една честота в друга.

След това трябваше да увелича размера на купчината, която се намира в RAM. Според нашите изчисления, pjsip изисква около 190 KB, а ние имаме само около 100 KB. Тук трябваше да използвам малко външна памет - SDRAM (около 128 KB).

След всички тези редакции видях първите пакети между Linux и Embox и чух звука! Но звукът беше ужасен, изобщо не беше същият като на QEMU, беше невъзможно да се различи нещо. Тогава се замислихме какво може да е. Отстраняването на грешки показа, че Embox просто няма време да запълни / разтовари аудио буфери. Докато pjsip обработваше един кадър, имаше време да възникнат 2 прекъсвания за завършване на обработката на буфера, което е твърде много. Първата мисъл за скоростта беше оптимизацията на компилатора, но тя вече беше включена в PJSIP. Второто е хардуерна плаваща запетая, говорихме за него в Статия. Но както показа практиката, FPU не даде значително увеличение на скоростта. Следващата стъпка беше да се даде приоритет на нишките. Embox има различни стратегии за планиране и аз съм включил една, която поддържа приоритети и задава аудио потоци с най-висок приоритет. Това също не помогна.

Следващата идея беше, че работим с външна памет и би било хубаво да преместим там структури, които са достъпни изключително често. Направих предварителен анализ кога и под какво simple_pjsua разпределя памет. Оказа се, че от 190 Kb, първите 90 Kb са заделени за вътрешни нужди на PJSIP и те не се посещават много често. Освен това, по време на входящо повикване се извиква функцията pjsua_call_answer, в която след това се разпределят буфери за работа с входящи и изходящи рамки. Все още беше около 100 Kb. И тогава направихме следното. До момента на обаждането съхраняваме данните във външна памет. Веднага след обаждането веднага заменяме купчината с друга - в RAM. По този начин всички „горещи“ данни бяха прехвърлени към по-бърза и по-предсказуема памет.

В резултат на това всичко това заедно направи възможно стартирането simple_pjsua и се обадете през вашия сървър. И след това през други сървъри като sip.linphone.org.

Данни

В резултат на това беше възможно да се стартира simple_pjsua с предаване на глас в двете посоки през сървъра. Проблемът с допълнително изразходваните 128 KB SDRAM може да бъде решен с помощта на малко по-мощен Cortex-M7 (например STM32F769NI с 512 KB RAM), но в същото време все още не сме се отказали от надеждата да влезем в 256 KB 🙂 Ще се радваме, ако някой се интересува, или още по-добре, опитайте. Всички източници, както обикновено, са в нашия хранилища.

Източник: www.habr.com

Добавяне на нов коментар