Pagsuhid sa Mediastreamer2 VoIP engine. Bahin 9

Ang materyal sa artikulo gikuha gikan sa akong zen channel.

Duplex intercom

Pagsuhid sa Mediastreamer2 VoIP engine. Bahin 9

Sa ulahi artikulo usa ka duplex intercom ang gipahibalo, ug niining usa atong himoon kini.

Ang diagram gipakita sa numero sa ulohan. Ang ubos nga kadena sa mga filter nagporma sa agianan sa transmission, nga nagsugod gikan sa sound card. Naghatag kini og mga sampol sa signal gikan sa mikropono. Sa kasagaran, kini mahitabo sa gikusgon nga 8000 ka sample kada segundo. Ang data bit depth nga gigamit sa media streamer audio filters mao ang 16 bits (kini dili importante; kung gusto nimo, mahimo nimong isulat ang mga filter nga magamit sa mas taas nga bit depth). Ang datos gi-grupo sa mga bloke sa 160 ka mga sample. Busa, ang matag block kay 320 bytes ang gidak-on. Sunod, gipakaon namon ang datos sa input sa generator, nga, kung gipalong, "transparent" sa datos. Gidugang ko kini kung gikapoy ka sa pagsulti sa mikropono sa panahon sa pag-debug - mahimo nimong gamiton ang generator aron "pana" ang agianan nga adunay signal sa tono.

Human sa generator, ang signal moadto sa encoder, nga mag-convert sa atong 16-bit nga mga sample sumala sa µ-law (G.711 standard) ngadto sa walo ka bit. Sa output sa encoder, aduna na kitay data block nga katunga sa gidak-on. Sa kinatibuk-an, mahimo namon nga ipadala ang data nga wala’y pag-compress kung dili namon kinahanglan nga i-save ang trapiko. Apan dinhi mapuslanon ang paggamit sa usa ka encoder, tungod kay ang Wireshark makahimo sa pagkopya sa audio gikan sa usa ka RTP stream lamang kung kini gi-compress sumala sa µ-law o usa ka balaod.

Human sa encoder, ang mas gaan nga mga bloke sa data ipadala ngadto sa rtpsend filter, nga ibutang kini sa usa ka RTP packet, ibutang ang gikinahanglan nga mga bandila ug ihatag kini sa media streamer alang sa transmission sa network sa porma sa usa ka UDP packet.

Ang taas nga kadena sa mga pagsala nagporma sa agianan sa pagdawat; Ang mga pakete sa RTP nga nadawat sa media streamer gikan sa network mosulod sa rtprecv filter, sa output diin kini makita sa porma sa mga bloke sa datos, nga ang matag usa katumbas sa usa nga nadawat nga pakete. Ang block naglangkob lamang sa datos sa payload; sa miaging artikulo gipakita kini nga berde sa ilustrasyon.

Sunod, ang mga bloke gipadala ngadto sa decoder filter, nga nag-convert sa single-byte nga mga sample nga anaa niini ngadto sa linear, 16-bit nga mga. Nga mahimo nang maproseso sa mga filter sa streamer sa media. Sa among kaso, ipadala lang namo sila sa sound card para sa playback sa mga speaker sa imong headset.

Karon magpadayon kita sa pagpatuman sa software. Aron mahimo kini, among i-combine ang receiver ug transmitter files nga among gibulag kaniadto. Sa wala pa kini, gigamit namon ang mga naayos nga setting alang sa mga pantalan ug mga adres, apan karon kinahanglan namon ang programa aron magamit ang mga setting nga among gipiho sa pagsugod. Aron mahimo kini, magdugang kami og gamit para sa pagproseso sa mga argumento sa command line. Pagkahuman mahimo namon nga itakda ang IP address ug pantalan sa intercom diin gusto namon nga magtukod usa ka koneksyon.

Una, magdugang ta og istruktura sa programa nga magtipig sa mga setting niini:

struct _app_vars
{
  int  local_port;              /* Локальный порт. */
  int  remote_port;             /* Порт переговорного устройства на удаленном компьютере. */
  char remote_addr[128];        /* IP-адрес удаленного компьютера. */
  MSDtmfGenCustomTone dtmf_cfg; /* Настройки тестового сигнала генератора. */
};

typedef struct _app_vars app_vars;

Ang programa magpahayag ug usa ka istruktura niini nga matang nga gitawag ug vars.
Sunod, magdugang kita usa ka function aron ma-parse ang mga argumento sa command line:

/* Функция преобразования аргументов командной строки в
* настройки программы. */
void  scan_args(int argc, char *argv[], app_vars *v)
{
    char i;
    for (i=0; i<argc; i++)
    {
        if (!strcmp(argv[i], "--help"))
        {
            char *p=argv[0]; p=p + 2;
            printf("  %s walkie talkienn", p);
            printf("--help      List of options.n");
            printf("--version   Version of application.n");
            printf("--addr      Remote abonent IP address string.n");
            printf("--port      Remote abonent port number.n");
            printf("--lport     Local port number.n");
            printf("--gen       Generator frequency.n");
            exit(0);
        }

        if (!strcmp(argv[i], "--version"))
        {
            printf("0.1n");
            exit(0);
        }

        if (!strcmp(argv[i], "--addr"))
        {
            strncpy(v->remote_addr, argv[i+1], 16);
            v->remote_addr[16]=0;
            printf("remote addr: %sn", v->remote_addr);
        }

        if (!strcmp(argv[i], "--port"))
        {
            v->remote_port=atoi(argv[i+1]);
            printf("remote port: %in", v->remote_port);
        }

        if (!strcmp(argv[i], "--lport"))
        {
            v->local_port=atoi(argv[i+1]);
            printf("local port : %in", v->local_port);
        }

        if (!strcmp(argv[i], "--gen"))
        {
            v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
                printf("gen freq : %in", v -> dtmf_cfg.frequencies[0]);
        }
    }
}

Isip resulta sa pag-parse, ang mga argumento sa command line ibutang sa mga field sa vars structure. Ang nag-unang function sa aplikasyon mao ang pagkolekta sa pagpadala ug pagdawat sa mga agianan gikan sa mga filter; pagkahuman sa pagkonektar sa ticker, ang kontrol ibalhin sa usa ka walay katapusan nga loop nga, kung ang frequency sa generator gitakda sa non-zero, i-restart ang test generator aron nga kini molihok nga walay paghunong.

Ang generator magkinahanglan niini nga mga restart tungod sa disenyo niini; sa pipila ka rason dili kini makahimo og signal nga molungtad og sobra sa 16 segundos. Kinahanglan nga hinumdoman nga ang gidugayon niini gipiho sa usa ka 32-bit nga numero.

Ang tibuok nga programa mahimong sama niini:

/* Файл mstest8.c Имитатор переговорного устройства. */

#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>

/* Подключаем файл общих функций. */
#include "mstest_common.c"

/*----------------------------------------------------------*/
struct _app_vars
{
    int  local_port;              /* Локальный порт. */
    int  remote_port;             /* Порт переговорного устройства на удаленном компьютере. */
    char remote_addr[128];        /* IP-адрес удаленного компьютера. */
    MSDtmfGenCustomTone dtmf_cfg; /* Настройки тестового сигнала генератора. */
};

typedef struct _app_vars app_vars;

/*----------------------------------------------------------*/
/* Создаем дуплексную RTP-сессию. */
RtpSession* create_duplex_rtp_session(app_vars v)
{
    RtpSession *session = create_rtpsession (v.local_port, v.local_port + 1, FALSE, RTP_SESSION_SENDRECV);
    rtp_session_set_remote_addr_and_port(session, v.remote_addr, v.remote_port, v.remote_port + 1);
    rtp_session_set_send_payload_type(session, PCMU);
    return session;
}

/*----------------------------------------------------------*/
/* Функция преобразования аргументов командной строки в
* настройки программы. */
void  scan_args(int argc, char *argv[], app_vars *v)
{
    char i;
    for (i=0; i<argc; i++)
    {
        if (!strcmp(argv[i], "--help"))
        {
            char *p=argv[0]; p=p + 2;
            printf("  %s walkie talkienn", p);
            printf("--help      List of options.n");
            printf("--version   Version of application.n");
            printf("--addr      Remote abonent IP address string.n");
            printf("--port      Remote abonent port number.n");
            printf("--lport     Local port number.n");
            printf("--gen       Generator frequency.n");
            exit(0);
        }

        if (!strcmp(argv[i], "--version"))
        {
            printf("0.1n");
            exit(0);
        }

        if (!strcmp(argv[i], "--addr"))
        {
            strncpy(v->remote_addr, argv[i+1], 16);
            v->remote_addr[16]=0;
            printf("remote addr: %sn", v->remote_addr);
        }

        if (!strcmp(argv[i], "--port"))
        {
            v->remote_port=atoi(argv[i+1]);
            printf("remote port: %in", v->remote_port);
        }

        if (!strcmp(argv[i], "--lport"))
        {
            v->local_port=atoi(argv[i+1]);
            printf("local port : %in", v->local_port);
        }

        if (!strcmp(argv[i], "--gen"))
        {
            v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
                printf("gen freq : %in", v -> dtmf_cfg.frequencies[0]);
        }
    }
}

/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
    /* Устанавливаем настройки по умолчанию. */
    app_vars vars={5004, 7010, "127.0.0.1", {0}};

    /* Устанавливаем настройки настройки программы в
     * соответствии с аргументами командной строки. */
    scan_args(argc, argv, &vars);

    ms_init();

    /* Создаем экземпляры фильтров передающего тракта. */
    MSSndCard *snd_card =
        ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
    MSFilter *snd_card_read = ms_snd_card_create_reader(snd_card);
    MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
    MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID);

    /* Создаем фильтр кодера. */
    MSFilter *encoder = ms_filter_create_encoder("PCMU");

    /* Регистрируем типы нагрузки. */
    register_payloads();

    /* Создаем дуплексную RTP-сессию. */
    RtpSession* rtp_session= create_duplex_rtp_session(vars);
    ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, rtp_session);

    /* Соединяем фильтры передатчика. */
    ms_filter_link(snd_card_read, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, encoder, 0);
    ms_filter_link(encoder, 0, rtpsend, 0);

    /* Создаем фильтры приемного тракта. */
    MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
    ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rtp_session);

    /* Создаем фильтр декодера, */
    MSFilter *decoder=ms_filter_create_decoder("PCMU");

    /* Создаем фильтр звуковой карты. */
    MSFilter *snd_card_write = ms_snd_card_create_writer(snd_card);

    /* Соединяем фильтры приёмного тракта. */
    ms_filter_link(rtprecv, 0, decoder, 0);
    ms_filter_link(decoder, 0,  snd_card_write, 0);

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

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

    /* Если настройка частоты генератора отлична от нуля, то запускаем генератор. */   
    if (vars.dtmf_cfg.frequencies[0])
    {
        /* Настраиваем структуру, управляющую выходным сигналом генератора. */
        vars.dtmf_cfg.duration = 10000;
        vars.dtmf_cfg.amplitude = 1.0;
    }

    /* Организуем цикл перезапуска генератора. */
    while(TRUE)
    {
        if(vars.dtmf_cfg.frequencies[0])
        {
            /* Включаем звуковой генератор. */
            ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
                    (void*)&vars.dtmf_cfg);
        }
        /* Укладываем тред в спячку на 20мс, чтобы другие треды
         * приложения получили время на работу. */
        ms_usleep(20000);
    }
}

Mag-compile ta. Unya ang programa mahimong modagan sa duha ka kompyuter. O sa usa, sama sa akong buhaton karon. Gilunsad namo ang TShark uban ang mosunod nga mga argumento:

$ sudo tshark -i lo -f "udp dst port 7010" -P -V -O RTP -o rtp.heuristic_rtp:TRUE -x

Kung ang natad sa paglansad sa console nagpakita lamang sa usa ka mensahe bahin sa pagsugod sa pagdakop, nan kini usa ka maayong timaan - kini nagpasabut nga ang among pantalan lagmit nga wala giokupahan sa ubang mga programa. Sa laing terminal, naglunsad kami og usa ka pananglitan sa programa nga magsundog sa usa ka "hilit nga" intercom pinaagi sa pagtino niini nga numero sa pantalan:

$ ./mstest8 --port 9010 --lport 7010

Ingon sa makita gikan sa teksto sa programa, ang default IP address mao ang 127.0.0.1 (lokal nga loopback).

Sa laing terminal, naglunsad kami og ikaduhang higayon sa programa, nga nagsundog sa usa ka lokal nga device. Gigamit namon ang dugang nga argumento nga nagtugot sa built-in nga test generator nga molihok:

$ ./mstest8  --port 7010 --lport 9010 --gen 440

Niining higayona, ang mga pakete nga gipasa sa "hilit" nga aparato kinahanglan magsugod sa pag-flash sa console gamit ang TShark, ug usa ka padayon nga tono ang madungog gikan sa mamumulong sa kompyuter.

Kung ang tanan nahitabo sama sa nahisulat, nan atong i-restart ang ikaduhang kopya sa programa, apan wala ang yawe ug argumento "-gen 440". Ikaw na karon ang magdula sa papel sa generator. Pagkahuman niini, mahimo ka nga maghimo kasaba sa mikropono; kinahanglan nimo nga madungog ang katugbang nga tunog sa speaker o headphone. Ang acoustic self-excitation mahimo pa nga mahitabo; ipaubos ang volume sa speaker ug ang epekto mawala.

Kung gipadagan nimo kini sa duha ka mga kompyuter ug wala maglibog bahin sa mga adres sa IP, nan ang parehas nga sangputanan naghulat kanimo - duha ka paagi nga digital nga kalidad nga komunikasyon sa tingog.

Sa sunod nga artikulo mahibal-an namon kung giunsa pagsulat ang among kaugalingon nga mga pagsala - mga plugin, salamat sa kini nga kahanas mahimo nimong magamit ang streamer sa media dili lamang alang sa audio ug video, apan usab sa pipila nga piho nga lugar.

Source: www.habr.com

Idugang sa usa ka comment