Explorarea motorului VoIP Mediastreamer2. Partea 2

Materialul articolului este preluat de pe mine canal zen.

Explorarea motorului VoIP Mediastreamer2. Partea 2

Crearea unui generator de tonuri

În anteriorul articol Am instalat biblioteca media streamer, instrumentele de dezvoltare și le-am testat funcționalitatea prin construirea unei aplicații de probă.

Astăzi vom crea o aplicație care poate genera un semnal de ton pe o placă de sunet. Pentru a rezolva această problemă, trebuie să conectăm filtrele la circuitul generator de sunet prezentat mai jos:

Explorarea motorului VoIP Mediastreamer2. Partea 2

Citim diagrama de la stânga la dreapta, aceasta este direcția în care se mișcă fluxul nostru de date. Săgețile sugerează, de asemenea, acest lucru. Dreptunghiurile indică filtre care procesează blocuri de date și scot rezultatul. În interiorul dreptunghiului este indicat rolul acestuia, iar tipul de filtru este indicat cu majuscule chiar dedesubt. Săgețile care leagă dreptunghiurile sunt cozi de date prin care blocuri de date sunt livrate de la filtru la filtru. În general, un filtru poate avea multe intrări și ieșiri.

Totul începe cu sursa ceasului, care stabilește tempo-ul la care datele sunt calculate în filtre. În funcție de ciclul său de ceas, fiecare filtru procesează toate blocurile de date care sunt la intrarea sa. Și pune blocuri cu rezultatul în coadă. În primul rând, filtrul cel mai apropiat de sursa ceasului efectuează calcule, apoi filtrele conectate la ieșirile sale (pot fi multe ieșiri) și așa mai departe. După ce ultimul filtru din lanț termină procesarea, execuția se oprește până când sosește un nou ceas. Beats, implicit, urmează un interval de 10 milisecunde.

Să revenim la diagrama noastră. Ciclurile de ceas ajung la intrarea sursei de tăcere; acesta este un filtru, care este ocupat să genereze un bloc de date care conține zerouri la ieșirea sa pentru fiecare ciclu de ceas. Dacă considerăm acest bloc ca un bloc de mostre de sunet, atunci acesta nu este altceva decât tăcere. La prima vedere, pare ciudat să generezi blocuri de date cu tăcere - la urma urmei, nu se aude, dar aceste blocuri sunt necesare pentru funcționarea generatorului de semnal sonor. Generatorul folosește aceste blocuri ca pe o foaie goală de hârtie, înregistrând mostre de sunet în ele. În starea sa normală, generatorul este oprit și pur și simplu trimite blocurile de intrare la ieșire. Astfel, blocurile de liniște trec neschimbate prin întregul circuit de la stânga la dreapta, ajungând în placa de sunet. Care preia în tăcere blocuri din coada conectată la intrarea sa.

Dar totul se schimbă dacă generatorului i se dă o comandă de redare a sunetului, începe să genereze mostre de sunet și le înlocuiește cu mostre în blocurile de intrare și pune blocurile modificate la ieșire. Placa de sunet începe să redă sunet. Mai jos este un program care implementează schema de lucru descrisă mai sus:

/* Файл 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);   
}

După inițializarea streamer-ului media, sunt create trei filtre: voidsource, dtmfgen, snd_card_write. Este creată o sursă de ceas.

Apoi, trebuie să conectați filtrele în conformitate cu circuitul nostru, iar sursa ceasului trebuie conectată ultima, deoarece după aceasta circuitul va începe imediat să funcționeze. Dacă conectați o sursă de ceas la un circuit neterminat, se poate întâmpla ca streamerul media să se blocheze dacă detectează cel puțin un filtru din lanț cu toate intrările sau toate ieșirile „atârnând în aer” (neconectate).

Conectarea filtrelor se face folosind funcția

ms_filter_link(src, src_out, dst, dst_in)

unde primul argument este un pointer către filtrul sursă, al doilea argument este numărul de ieșire sursă (rețineți că intrările și ieșirile sunt numerotate începând de la zero). Al treilea argument este un pointer către filtrul receptorului, al patrulea este numărul de intrare al receptorului.

Toate filtrele sunt conectate și sursa ceasului este conectată ultima (în continuare o vom numi pur și simplu un ticker). După care circuitul nostru de sunet începe să funcționeze, dar încă nu se aude nimic în difuzoarele computerului - generatorul de sunet este oprit și pur și simplu trece prin blocurile de date de intrare cu tăcere. Pentru a începe să generați un ton, trebuie să rulați metoda de filtrare a generatorului.

Vom genera un semnal în două tonuri (DTMF) corespunzător apăsării butonului „1” de pe telefon. Pentru a face acest lucru, folosim funcția ms_filter_call_method() Numim metoda MS_DTMF_GEN_PLAY, trecând-o ca argument un pointer către codul căruia ar trebui să îi corespundă semnalul de redare.

Tot ce rămâne este să compilați programul:

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

Și fugi:

$ ./mstest2

După pornirea programului, veți auzi un scurt semnal sonor format din două tonuri în difuzorul computerului.

Am construit și lansat primul nostru circuit de sunet. Am văzut cum să creăm instanțe de filtrare, cum să le conectăm și cum să le apelăm metodele. Deși suntem mulțumiți de succesul nostru inițial, trebuie totuși să acordăm atenție faptului că programul nostru nu eliberează memoria alocată înainte de a ieși. În urmatoarele articol vom învăța să facem curat după noi înșine.

Sursa: www.habr.com

Adauga un comentariu