Binciko injin Mediastreamer2 VoIP. Kashi na 9

An ɗauko kayan labarin daga nawa zen channel.

Duplex intercom

Binciko injin Mediastreamer2 VoIP. Kashi na 9

A karshe labarin An sanar da intercom duplex, kuma a cikin wannan za mu yi shi.

Ana nuna hoton a cikin hoton take. Ƙananan sarkar tacewa suna samar da hanyar watsawa, wanda ke farawa daga katin sauti. Yana ba da samfuran sigina daga makirufo. Ta hanyar tsoho, wannan yana faruwa a ƙimar samfuran 8000 a sakan daya. Zurfin bit ɗin bayanan da masu tace sauti na kafofin watsa labaru ke amfani da shi shine rago 16 (wannan ba shi da mahimmanci; idan kuna so, zaku iya rubuta matatun da za su yi aiki tare da zurfin bit mafi girma). An haɗa bayanan zuwa cikin tubalan samfurori 160. Don haka, kowane toshe yana da girman 320 bytes. Na gaba, muna ciyar da bayanan zuwa shigar da janareta, wanda, lokacin da aka kashe, yana "m" ga bayanan. Na kara da shi idan kun gaji da yin magana a cikin makirufo yayin gyara kurakurai - zaku iya amfani da janareta don "harbi" hanya tare da siginar sauti.

Bayan janareta, siginar yana zuwa mai ɓoyewa, wanda ke canza samfuran mu 16-bit bisa ga μ-law (G.711 misali) zuwa takwas-bit. A fitowar mai rikodin, mun riga mun sami toshe bayanai rabin girman. Gabaɗaya, za mu iya watsa bayanai ba tare da matsawa ba idan ba ma buƙatar adana zirga-zirga. Amma a nan yana da amfani a yi amfani da maɓalli, tunda Wireshark na iya sake yin sauti daga rafin RTP kawai lokacin da aka matsa shi bisa ga µ-law ko a-law.

Bayan encoder, ana aika mafi sauƙi na bayanan bayanai zuwa matatar rtpsend, wanda zai sanya su a cikin fakitin RTP, saita tutocin da suka dace kuma a ba su ga mai watsa shirye-shiryen watsa labarai don watsawa akan hanyar sadarwa ta hanyar fakitin UDP.

Babban sarkar tacewa yana samar da hanyar karba; Fakitin RTP da masu watsa shirye-shiryen watsa labarai suka karba daga hanyar sadarwa suna shigar da tacewa rtprecv, a fitowar su ta hanyar toshe bayanai, kowannensu yayi daidai da fakiti daya karba. Toshe yana ƙunshe da bayanan biyan kuɗi kawai; a cikin labarin da ya gabata an nuna su da kore a cikin hoton.

Bayan haka, ana aika tubalan zuwa tacewa, wanda ke canza samfuran-byte guda ɗaya da ke cikin su zuwa layin layi, 16-bit. Wanda tuni ana iya sarrafa shi ta hanyar tacewa mai rafi mai ratsawa. A cikin yanayinmu, muna aika su kawai zuwa katin sauti don sake kunnawa akan lasifikan naúrar ku.

Yanzu bari mu matsa zuwa aiwatar da software. Don yin wannan, za mu haɗa fayilolin mai karɓa da masu watsawa waɗanda muka rabu a baya. Kafin wannan, mun yi amfani da kafaffen saitunan don tashar jiragen ruwa da adireshi, amma yanzu muna buƙatar shirin don samun damar amfani da saitunan da muka ƙayyade a farawa. Don yin wannan, za mu ƙara ayyuka don sarrafa muhawarar layin umarni. Bayan haka za mu iya saita adireshin IP da tashar jiragen ruwa na intercom wanda muke son kafa haɗin gwiwa tare da shi.

Da farko, bari mu ƙara wani tsari a cikin shirin wanda zai adana saitunansa:

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

typedef struct _app_vars app_vars;

Shirin zai bayyana tsarin irin wannan da ake kira vars.
Na gaba, bari mu ƙara aiki don rarraba gardamar layin umarni:

/* Функция преобразования аргументов командной строки в
* настройки программы. */
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]);
        }
    }
}

Sakamakon tantancewa, za a sanya gardamar layin umarni a cikin fagagen tsarin vars. Babban aikin aikace-aikacen shine tattara watsawa da karɓar hanyoyi daga masu tacewa; bayan haɗa ticker, za a canza wurin sarrafawa zuwa madauki mara iyaka wanda, idan mitar janareta ya kasance mara sifili, zai sake kunna janareta na gwaji don haka. yana aiki ba tare da tsayawa ba.

Janareta zai buƙaci waɗannan sake kunnawa saboda ƙirar sa; saboda wasu dalilai ba zai iya samar da sigina mai tsayi fiye da daƙiƙa 16 ba. Ya kamata a lura cewa tsawon lokacin da aka ƙayyade ta lamba 32-bit.

Dukkanin shirin zai yi kama da haka:

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

Mu tattara. Sannan ana iya tafiyar da shirin akan kwamfutoci guda biyu. Ko kuma a daya, kamar yadda zan yi yanzu. Mun ƙaddamar da TShark tare da dalilai masu zuwa:

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

Idan filin ƙaddamarwa a cikin na'ura wasan bidiyo kawai yana nuna saƙo game da farkon kamawa, to wannan alama ce mai kyau - yana nufin ba zai yiwu a shagaltar da tashar jiragen ruwa da wasu shirye-shirye ba. A wani tashar tashar, muna ƙaddamar da misalin shirin da zai kwaikwayi intercom na "remote" ta hanyar tantance wannan lambar tashar jiragen ruwa:

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

Kamar yadda ake iya gani daga rubutun shirin, adireshin IP na asali shine 127.0.0.1 (local loopback).

A wani tashar tashar, muna ƙaddamar da misali na biyu na shirin, wanda ke kwatanta na'urar gida. Muna amfani da ƙarin hujja wanda ke ba da damar ginannen janareta na gwaji yayi aiki:

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

A wannan lokacin, fakitin da aka watsa zuwa na'urar "na nesa" yakamata su fara walƙiya a cikin na'urar wasan bidiyo tare da TShark, kuma za a ji sautin ci gaba daga lasifikar kwamfuta.

Idan duk abin ya faru kamar yadda aka rubuta, to, za mu sake farawa kwafin na biyu na shirin, amma ba tare da maɓalli da gardama ba "- Gen 440". Yanzu zaku taka rawar janareta. Bayan haka, zaku iya yin surutu a cikin makirufo; yakamata ku ji sautin daidai a cikin lasifikar ko belun kunne. Ƙaunar motsa jiki na iya faruwa har ma; kashe ƙarar lasifikar kuma tasirin zai ɓace.

Idan kun kunna shi akan kwamfutoci guda biyu kuma ba ku ruɗe game da adiresoshin IP ba, to sakamakon iri ɗaya yana jiran ku - sadarwar murya mai inganci ta dijital ta hanyoyi biyu.

A cikin labarin na gaba za mu koyi yadda za a rubuta namu masu tacewa - plugins, godiya ga wannan fasaha za ku sami damar yin amfani da mai watsa shirye-shiryen watsa labaru ba kawai don sauti da bidiyo ba, har ma a wasu takamaiman yanki.

source: www.habr.com

Add a comment