Вивчаємо VoIP-движок Mediastreamer2. Частина 2

Матеріал статті взято з мого дзен-каналу.

Вивчаємо VoIP-движок Mediastreamer2. Частина 2

Створюємо тональний генератор

У попередній статті ми виконали встановлення бібліотеки медіастрімера, інструментів розробки та перевірили їх функціонування, зібравши пробний додаток.

Сьогодні ми створимо додаток, який зможе пропилювати на звуковій карті тональний сигнал. Щоб вирішити це завдання нам потрібно з'єднати фільтри у наведену нижче схему звукового генератора:

Вивчаємо VoIP-движок Mediastreamer2. Частина 2

Читаємо схему зліва направо, саме у цьому напрямі у нас рухається потік даних. Стрілки теж на це натякають. Прямокутниками позначені фільтри, які обробляють блоки даних та виставляють результат на вихід. Усередині прямокутника вказана його роль і трохи нижче за великими літерами тип фільтра. Стрілки, що з'єднують прямокутники, це черги даних, якими блоки даних доставляються від фільтра до фільтра. Загалом, входів та виходів у фільтра може бути чимало.

Починається все з джерела тактів, яке задає темп, у якому відбувається облік даних у фільтрах. За його тактом, кожен фільтр обробляє всі блоки даних, які знаходяться у нього на вході. І виставляє блоки з результатом на вихід у чергу. Спочатку виконує обрахунок найближчий до джерела тактів фільтр, потім фільтри підключені до його виходів (виходів може бути багато) і таке інше. Після того, як останній фільтр у ланцюжку закінчить обрахунок, виконання зупиняється до того моменту, поки не надійде новий такт. Такти, за умовчанням, йдуть з інтервалом 10 мілісекунд.

Повернімося до нашої схеми. Такти надходять на вхід джерела тиші, це фільтр, зайнятий тим, що на кожен такт генерує на своєму виході блок даних, що містять нулі. Якщо розглядати цей блок як блок звукових відліків, то це ніщо інше, як тиша. На перший погляд, здається дивним, генерувати блоки даних з тишею — адже її не можна почути, але ці блоки необхідні для роботи генератора звукового сигналу. Генератор використовує ці блоки як чистий аркуш паперу, записуючи в них звукові відліки. У звичайному стані, генератор вимкнений і просто прокидає вхідні блоки на вихід. Таким чином, блоки тиші проходять без змін через усю схему ліворуч, потрапляючи в звукову карту. Яка беззвучно забирає блоки з черги, підключеної до її входу.

Але все змінюється, якщо генератору подати команду на відтворення звуку, він починає генерувати звукові відліки та заміщає ними відліки у вхідних блоках та виставляє змінені блоки на вихід. Звукова карта починає відтворювати звук. Нижче наведена програма, яка реалізує описану вище схему роботи:

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

Після ініціалізації медіастрімера виконується створення трьох фільтрів: voidsource, dtmfgen, snd_card_write. Створюється джерело тактового сигналу.

Потім потрібно виконати з'єднання фільтрів відповідно до нашої схеми, причому джерело тактів потрібно підключати останнім, оскільки після цього відразу розпочнеться робота схеми. Якщо підключити джерело тактів до незакінченої схеми, то може статися так, що медіастример аварійно завершиться, якщо виявить у ланцюжку хоча б один фільтр, у якого всі входи або всі виходи "висять у повітрі" (не підключені).

З'єднання фільтрів виконується за допомогою функції

ms_filter_link(src, src_out, dst, dst_in)

де перший аргумент це покажчик на фільтр-джерело, другий аргумент - номер виходу джерела (зверніть увагу, що входи та виходи нумеруються починаючи з нуля). Третій аргумент це покажчик на фільтр-приймач, четвертий номер входу приймача.

Всі фільтри з'єднані і останнім підключається джерело тактів (далі просто називатимемо його тикером). Після чого наша звукова схема запускається в роботу, але в динаміці комп'ютера поки що нічого не чути - звуковий генератор вимкнений і просто прокидає через себе вхідні блоки даних з тишею. Щоб запустити генерацію тонального сигналу, необхідно виконати метод фільтра генератора.

Ми будемо генерувати двотональний (DTMF) сигнал, що відповідає натисканню на телефоні кнопки "1". Для цього ми за допомогою функції ms_filter_call_method() викликаємо метод MS_DTMF_GEN_PLAY, передаючи йому як аргумент покажчик на код, якому повинен відповідати сигнал, що відтворюється.

Залишається програму скомпілювати:

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

І запустити:

$ ./mstest2

Після запуску програми ви почуєте в динаміці комп'ютера короткий звуковий сигнал, що складається з двох тонів.

Ми спорудили та запустили в роботу нашу першу звукову схему. Побачили, як створювати екземпляри фільтрів, як з'єднувати і як викликати їх методи. Порадівши першому успіху, нам все ж таки потрібно звернути увагу на те, що наша програма не звільняє виділену пам'ять перед завершенням. У наступному статті ми навчимося прибирати за собою.

Джерело: habr.com

Додати коментар або відгук