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

Усім прывітанне.

Некаторы час таму мы распавядаў аб тым як нам удалося запусціць SIP тэлефон на STM32F4-Discovery c 1 Мб ROM і 192 Кб RAM) на базе Embox. Тут трэба сказаць, што тая версія была мінімальнай і злучала два тэлефоны напрамую без сервера і з перадачай голасу толькі ў адзін бок. Таму мы вырашылі запусціць больш паўнавартасны тэлефон са званком праз сервер, перадачай голасу ў абодва бакі, але пры гэтым укласціся ў як мага меншы памер памяці.


Для тэлефона было вырашана выбраць дадатак simple_pjsua у складзе бібліятэкі PJSIP. Гэта мінімальнае дадатак, якое ўмее рэгістравацца на серверы, прымаць і адказваць на званкі. Ніжэй я адразу прывяду апісанне таго, як гэта запусціць на STM32F7-Discovery.

Як запускаць

  1. Канфігуруем Embox
    make confload-platform/pjsip/stm32f7cube
  2. У файле conf/mods.config задаём патрэбны SIP акаўнт.
    
    include platform.pjsip.cmd.simple_pjsua_imported(
        sip_domain="server", 
        sip_user="username",
        sip_passwd="password")
    

    дзе сервер - гэта SIP server (напрыклад, sip.linphone.org), імя карыстальніка и пароль - імя карыстальніка і пароль ад акаўнта.

  3. Збіраны Embox камандай рабіць. Пра прашыўку платы ў нас ёсць на вікі і ў артыкуле.
  4. Запускаем у кансолі Embox каманду "simple_pjsua_imported"
    
    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 мікрафона побач з дысплеем. Тэлефануем з лінукса праз прыкладанне simple_pjsua, pjsua. Ну ці можна любое іншае тыпу linphone.

Усё гэта апісана на нашым вікі.

Як мы да гэтага прыйшлі

Такім чынам, першапачаткова паўстала пытанне аб выбары апаратнай платформы. Бо было ясна, што STM32F4-Discovery не падыдзе па памяці, была абраная STM32F7-Discovery. У яе 1 Мб флэшка і 256 Кб АЗП (+ 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. У момант злучэння правяраем на серверы Asterisk, што ўсё злучэнне ўсталявана, і праз некаторы час павінны пачуць у Embox гук з Лінукса, а ў Лінуксе захоўваем той файл, які прайграваецца з Embox.

Пасля таго як гэта зарабіла на QEMU, мы перайшлі да партавання на STM32F7-Discovery. Першая праблема – не ўлазілі ў 1 Мб ROM без уключанай аптымізацыі кампілятара "-Os" па памеры выявы. Таму ўключылі "-Os". Далей, патчам адключылі падтрымку C++, так яна патрэбна толькі для pjsua, а мы выкарыстоўваем simple_pjsua.

Пасля таго як змясцілі simple_pjsua, вырашылі, што шанцы гэта запусціць зараз ёсць. Але спачатку трэба было разабрацца з запісам і ўзнаўленнем голасу. Пытанне - куды запісваць? Выбралі знешнюю памяць – SDRAM (128 Мб). Вы можаце паспрабаваць гэта самі:

Створыць стэрэа 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 (Serial Audio Interface) сінхронна з аўдыё ўваходам (не разбіраўся ў дэталях, але атрымліваецца што яны дзеляць агульны clock і пры ініцыялізацыі аўдыё выйсця да яго неяк прывязваецца аўдыё уваход). Гэта значыць запусціць іх па асобнасці нельга, таму зрабілі наступнае - заўсёды працуюць (у тым ліку генеруюцца перапыненні) аўдыё ўваход і аўдыё выхад. Але калі ў сістэме нічога не прайграваецца, то мы проста падсоўваем аўдыё выхаду пусты буфер, а калі запускаецца прайграванне, то па-чэснаму пачынаем яго запаўняць.

Далей сутыкнуліся з тым, што гук пры запісе голаса быў вельмі ціхім. Гэта адбываецца з-за таго, што MEMS мікрафоны на STM32F7-Discovery неяк дрэнна працуюць на частотах ніжэй за 16000 Hz. Таму выстаўляем 16000 Hz, калі нават прыходзіць 8000 Hz. Для гэтага праўда спатрэбілася дадаць праграмнае пераўтварэнне адной частаты ў іншую.

Далей прыйшлося павялічыць памер кучы, якая размяшчаецца ў RAM. Па нашых падліках, pjsip патрабаваў каля 190 Кб, а ў нас засталося ўсяго каля 100 Кб. Тут прыйшлося задзейнічаць крыху знешняй памяці – SDRAM (каля 128 Кб).

Пасля ўсіх гэтых правак я ўбачыў першыя пакеты паміж Лінукс і Embox, і пачуў гук! Але гук быў жудасны, зусім не такі як на QEMU, нічога нельга было разабраць. Тады мы задумаліся ў чым можа быць справа. Адладка паказала, што Embox проста не паспявае запаўняць/выгружаць аўдыё буферы. Пакуль pjsip апрацоўвае адзін фрэйм, паспявала адбыцца 2 перапыненні аб завяршэнні апрацоўкі буфераў, што занадта шмат. Першай думкай для паскарэння была аптымізацыя кампілятара, але яна была ўжо ўключана ў PJSIP. Другое - апаратная плаваючая кропка, пра яе мы расказвалі ў артыкуле. Але як паказала практыка, FPU не дало істотнага прыросту ў хуткасці. Наступным крокам было выстаўленне прыярытэтаў патокаў. У Embox ёсць розныя стратэгіі планавання, і я ўключыў тую, якая падтрымлівае прыярытэты, і выставіў аўдыё патокам самы максімальны прыярытэт. Гэта таксама не дапамагло.

Наступная была ідэя, што мы працуем са знешняй памяццю і добра б туды перамясціць структуры, да якіх зварот адбываецца вельмі часта. Я правёў папярэдні аналіз таго калі і пад што simple_pjsua вылучае памяць. Аказалася, што з 190 Кб першыя 90 Kб вылучаюцца пад унутраныя патрэбы PJSIP і да іх зварот адбываецца не вельмі часта. Далей падчас уваходнага званка выклікаецца функцыя pjsua_call_answer, у якой затым і вылучаюцца буферы для працы з уваходнымі і выходнымі фрэймамі. Гэта было яшчэ каля 100 Кб. І тут мы паступілі наступным чынам. Да моманту званка дадзеныя размяшчаем у вонкавую памяць. Як толькі званок - адразу падмяняем кучу на іншую - у RAM. Такім чынам, усе "гарачыя" дадзеныя былі перанесены ў хутчэйшую і прадказальную памяць.

У выніку ўсё гэта разам дазволіла запусціць simple_pjsua і патэлефанаваць праз свой сервер. А потым ужо і праз іншыя серверы такія як sip.linphone.org.

Высновы

У выніку атрымалася запусціць simple_pjsua з перадачай голасу ў абодва бакі праз сервер. Праблему з дадаткова выдаткаванымі 128 Кб SDRAM можна вырашыць шляхам выкарыстання крыху больш магутнага Cortex-M7 (напрыклад, STM32F769NI з 512 Кб RAM), але пры гэтым мы яшчэ не пакінулі надзеі ўлезці і ў 256 Кб 🙂 Будзем рады, калі хтосьці зацікавіцца а яшчэ лепш - паспрабуе. Усе зыходнікі, як звычайна, ёсць у нашым рэпазітары.

Крыніца: habr.com

Дадаць каментар