„Mediastreamer2 VoIP“ variklio tyrinėjimas. 2 dalis

Straipsnio medžiaga paimta iš mano zen kanalas.

„Mediastreamer2 VoIP“ variklio tyrinėjimas. 2 dalis

Tonų generatoriaus kūrimas

Ankstesniame straipsnis Įdiegėme medijos srautų biblioteką, kūrimo įrankius ir išbandėme jų funkcionalumą kurdami bandomąją programą.

Šiandien mes sukursime programą, kuri gali generuoti tono signalą garso plokštėje. Norėdami išspręsti šią problemą, turime prijungti filtrus prie toliau nurodytos garso generatoriaus grandinės:

„Mediastreamer2 VoIP“ variklio tyrinėjimas. 2 dalis

Mes skaitome diagramą iš kairės į dešinę, tai yra kryptis, kuria juda mūsų duomenų srautas. Apie tai užsimena ir rodyklės. Stačiakampiai nurodo filtrus, kurie apdoroja duomenų blokus ir išveda rezultatą. Stačiakampio viduje nurodomas jo vaidmuo, o filtro tipas – didžiosiomis raidėmis, žemiau. Stačiakampius jungiančios rodyklės yra duomenų eilės, per kurias duomenų blokai perduodami iš filtro į filtrą. Apskritai filtras gali turėti daug įėjimų ir išėjimų.

Viskas prasideda nuo laikrodžio šaltinio, kuris nustato tempą, kuriuo duomenys skaičiuojami filtruose. Pagal savo laikrodžio ciklą kiekvienas filtras apdoroja visus duomenų blokus, esančius jo įvestyje. Ir deda blokus su rezultatu į eilę. Pirmiausia skaičiavimus atlieka arčiausiai laikrodžio šaltinio esantis filtras, tada prie jo išėjimų prijungiami filtrai (išėjimų gali būti daug) ir pan. Kai paskutinis filtras grandinėje baigia apdoroti, vykdymas sustabdomas, kol pasirodys naujas laikrodis. Pagal numatytuosius nustatymus ritmai seka 10 milisekundžių intervalą.

Grįžkime prie mūsų diagramos. Laikrodžio ciklai patenka į tylos šaltinio įvestį; tai yra filtras, kuris generuoja duomenų bloką, kurio išvestyje yra nuliai kiekvienam laikrodžio ciklui. Jei laikysime šį bloką kaip garso pavyzdžių bloką, tai yra ne kas kita, kaip tyla. Iš pirmo žvilgsnio atrodo keista duomenų blokus generuoti tyla – juk to nesigirdi, bet šie blokai būtini garso signalų generatoriaus veikimui. Generatorius naudoja šiuos blokus kaip tuščią popieriaus lapą, įrašydamas į juos garso pavyzdžius. Įprastoje būsenoje generatorius yra išjungtas ir tiesiog persiunčia įvesties blokus į išvestį. Taigi tylos blokai nepakitę pereina per visą grandinę iš kairės į dešinę ir patenka į garso plokštę. Kuris tyliai paima blokus iš eilės, prijungtos prie jo įvesties.

Bet viskas pasikeičia, jei generatoriui duodama komanda groti garsą, jis pradeda generuoti garso pavyzdžius ir įvesties blokuose juos pakeičia pavyzdžiais, o pakeistus blokus deda į išvestį. Garso plokštė pradeda leisti garsą. Žemiau yra programa, kuri įgyvendina aukščiau aprašytą darbo schemą:

/* Файл mstest2.c */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
int main()
{
    ms_init();

    /* Создаем экземпляры фильтров. */
    MSFilter  *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
    MSFilter  *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
    MSSndCard *card_playback = ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
    MSFilter  *snd_card_write = ms_snd_card_create_writer(card_playback);

    /* Создаем тикер. */
    MSTicker *ticker = ms_ticker_new();

    /* Соединяем фильтры в цепочку. */
    ms_filter_link(voidsource, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, snd_card_write, 0);

   /* Подключаем источник тактов. */
   ms_ticker_attach(ticker, voidsource);

   /* Включаем звуковой генератор. */
   char key='1';
   ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY, (void*)&key);

   /* Даем, время, чтобы все блоки данных были получены звуковой картой.*/
   ms_sleep(2);   
}

Pradėjus medijos transliuotoją, sukuriami trys filtrai: voidsource, dtmfgen, snd_card_write. Sukuriamas laikrodžio šaltinis.

Tada reikia prijungti filtrus pagal mūsų grandinę, o laikrodžio šaltinis turi būti prijungtas paskutinis, nes po to grandinė iškart pradės veikti. Jei prijungsite laikrodžio šaltinį prie nebaigtos grandinės, gali atsitikti taip, kad medijos transliuotojas sugenda, jei grandinėje aptiks bent vieną filtrą, kurio visi įėjimai arba visi išėjimai „kabo ore“ (neprijungtas).

Filtrų prijungimas atliekamas naudojant funkciją

ms_filter_link(src, src_out, dst, dst_in)

kur pirmasis argumentas yra rodyklė į šaltinio filtrą, antrasis argumentas yra šaltinio išvesties numeris (atkreipkite dėmesį, kad įėjimai ir išėjimai numeruojami pradedant nuo nulio). Trečiasis argumentas yra rodyklė į imtuvo filtrą, ketvirtasis yra imtuvo įvesties numeris.

Visi filtrai yra prijungti, o laikrodžio šaltinis yra prijungtas paskutinis (toliau mes tiesiog vadinsime jį ticker). Po to pradeda veikti mūsų garso grandinė, tačiau kompiuterio garsiakalbiuose dar nieko nesigirdi - garso generatorius išsijungia ir tiesiog tyliai pereina per įvesties duomenų blokus. Norėdami pradėti generuoti toną, turite paleisti generatoriaus filtro metodą.

Sugeneruosime dviejų tonų (DTMF) signalą, atitinkantį „1“ mygtuko paspaudimą telefone. Norėdami tai padaryti, naudojame funkciją ms_filter_call_method() Mes vadiname MS_DTMF_GEN_PLAY metodą, perduodame jį kaip argumentą rodyklę į kodą, kurį turėtų atitikti atkūrimo signalas.

Belieka tik sukompiliuoti programą:

$ gcc mstest2.c -o mstest2 `pkg-config mediastreamer --libs --cflags`

Ir paleisti:

$ ./mstest2

Paleidę programą, kompiuterio garsiakalbyje išgirsite trumpą garso signalą, susidedantį iš dviejų tonų.

Sukūrėme ir paleidome pirmąją garso grandinę. Pamatėme, kaip sukurti filtrų egzempliorius, kaip juos sujungti ir kaip iškviesti jų metodus. Nors džiaugiamės pradine sėkme, vis tiek turime atkreipti dėmesį į tai, kad mūsų programa neatlaisvina skirtos atminties prieš išeidama. Kitame straipsnis mokysimės apsitvarkyti.

Šaltinis: www.habr.com

Добавить комментарий