探索 Mediastreamer2 VoIP 引擎。 第 2 部分

文章素材取自我 禅频道.

探索 Mediastreamer2 VoIP 引擎。 第 2 部分

创建音调发生器

在以前 文章 我们安装了媒体流媒体库、开发工具,并通过构建试用应用程序测试了它们的功能。

今天我们将创建一个可以在声卡上生成音调信号的应用程序。 为了解决这个问题,我们需要将滤波器连接到声音发生器电路中,如下所示:

探索 Mediastreamer2 VoIP 引擎。 第 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)

其中第一个参数是指向源过滤器的指针,第二个参数是源输出编号(请注意,输入和输出从零开始编号)。 第三个参数是指向接收器过滤器的指针,第四个参数是接收器输入数。

所有滤波器均已连接,最后连接的是时钟源(下文中我们将简称为“ticker”)。 之后我们的声音电路开始工作,但计算机扬声器中还听不到任何声音 - 声音发生器被关闭,只是安静地通过输入数据块。 要开始生成音调,您需要运行生成器过滤器方法。

我们将生成与按下电话上的“1”按钮相对应的双音 (DTMF) 信号。 为此,我们使用该函数 ms_filter_call_method() 我们调用 MS_DTMF_GEN_PLAY 方法,将其作为参数传递给播放信号应对应的代码。

剩下的就是编译程序:

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

并运行:

$ ./mstest2

启动程序后,您将在计算机扬声器中听到由两声组成的短声音信号。

我们建造并推出了我们的第一个声音电路。 我们了解了如何创建过滤器实例、如何连接它们以及如何调用它们的方法。 虽然我们对最初的成功感到满意,但我们仍然需要注意这样一个事实:我们的程序在退出之前不会释放分配的内存。 下一个 文章 我们将学会自己清理。

来源: habr.com

添加评论