የ Mediastreamer2 VoIP ሞተርን ማሰስ። ክፍል 9

የጽሁፉ ይዘት ከኔ የተወሰደ ነው። የዜን ቻናል.

Duplex intercom

የ Mediastreamer2 VoIP ሞተርን ማሰስ። ክፍል 9

በመጨረሻው ጽሑፍ ባለ ሁለትዮሽ ኢንተርኮም ታውቋል፣ እና በዚህ ውስጥ እናደርገዋለን።

ስዕሉ በርዕሱ ምስል ላይ ይታያል. የታችኛው የማጣሪያዎች ሰንሰለት የማስተላለፊያ መንገድን ይመሰርታል, ይህም ከድምጽ ካርዱ ይጀምራል. ከማይክሮፎን የሲግናል ናሙናዎችን ያቀርባል. በነባሪ, ይህ በሴኮንድ 8000 ናሙናዎች ፍጥነት ይከሰታል. የሚዲያ ዥረት ኦዲዮ ማጣሪያዎች የሚጠቀሙት የውሂብ ቢት ጥልቀት 16 ቢት ነው (ይህ አስፈላጊ አይደለም፣ ከፈለጉ፣ ከፍ ካለው ትንሽ ጥልቀት ጋር የሚሰሩ ማጣሪያዎችን መጻፍ ይችላሉ።) መረጃው ወደ 160 ናሙናዎች ብሎኮች ተመድቧል። ስለዚህ, እያንዳንዱ እገዳ 320 ባይት መጠኑ ነው. በመቀጠል, ውሂቡን ወደ ጄነሬተር ግቤት እንመግባለን, ሲጠፋ, ለውሂቡ "ግልጽ" ነው. በማረም ጊዜ ወደ ማይክሮፎን ማውራት ሰልችቶዎት እንደሆነ ጨምሬዋለሁ - ጄኔሬተሩን በድምጽ ምልክት መንገዱን “መተኮስ” ይችላሉ።

ከጄነሬተሩ በኋላ ምልክቱ ወደ ኢንኮደሩ ይሄዳል፣ ይህም ባለ 16-ቢት ናሙናዎቻችንን በµ-law (G.711 ስታንዳርድ) ወደ ስምንት-ቢት ይቀይራል። በመቀየሪያው ውፅዓት ላይ እኛ ቀድሞውኑ የግማሽ መጠኑን የውሂብ እገዳ አለን። በአጠቃላይ ትራፊክ መቆጠብ ካላስፈለገን ያለጭመቅ መረጃ ማስተላለፍ እንችላለን። እዚህ ግን ኢንኮደርን መጠቀም ጠቃሚ ነው፣ ምክንያቱም Wireshark ከRTP ዥረት ኦዲዮን ማባዛት የሚችለው በµ-law ወይም a-law መሰረት ሲጨመቅ ብቻ ነው።

ከመቀየሪያው በኋላ ቀለሉ የውሂብ ብሎኮች ወደ rtpsend ማጣሪያ ይላካሉ ፣ ይህም በ RTP ፓኬት ውስጥ ያስቀምጣቸዋል ፣ አስፈላጊዎቹን ባንዲራዎች ያዘጋጃል እና በ UDP ፓኬት መልክ በአውታረ መረቡ ላይ ለማስተላለፍ ለሚዲያ ዥረት ይሰጣል ።

የላይኛው የማጣሪያዎች ሰንሰለት የመቀበያ መንገዱን ይመሰርታል ፣ ከአውታረ መረቡ በሚዲያ ዥረቱ የተቀበሉት የ RTP እሽጎች ወደ rtprecv ማጣሪያ ውስጥ ይገባሉ ፣ በውጤታቸውም በውሂብ ብሎኮች መልክ ይታያሉ ፣ እያንዳንዱም ከተቀበለው ፓኬት ጋር ይዛመዳል። እገዳው የመጫኛ መረጃን ብቻ ይዟል፤ በቀደመው መጣጥፍ ላይ በምሳሌው ላይ በአረንጓዴ ታይተዋል።

በመቀጠል, ብሎኮች ወደ ዲኮደር ማጣሪያ ይላካሉ, ይህም በውስጣቸው ያሉትን ነጠላ-ባይት ናሙናዎችን ወደ መስመራዊ, 16-ቢት ይቀይራል. የትኛው አስቀድሞ በሚዲያ ዥረት ማጣሪያዎች ሊሰራ ይችላል። በእኛ ሁኔታ፣ በጆሮ ማዳመጫዎ ድምጽ ማጉያዎች ላይ መልሶ ለማጫወት በቀላሉ ወደ ድምጽ ካርድ እንልካቸዋለን።

አሁን ወደ ሶፍትዌር ትግበራ እንሂድ. ይህንን ለማድረግ ከዚህ በፊት የለየናቸውን ተቀባይ እና አስተላላፊ ፋይሎችን እናጣምራለን። ከዚህ በፊት ለወደቦች እና አድራሻዎች ቋሚ መቼቶችን እንጠቀም ነበር, አሁን ግን በጅምር ላይ የገለጽናቸውን መቼቶች ለመጠቀም ፕሮግራሙ ያስፈልገናል. ይህንን ለማድረግ የትእዛዝ መስመር ነጋሪ እሴቶችን ለማስኬድ ተግባር እንጨምራለን ። ከዚያ በኋላ ግንኙነት መመስረት የምንፈልገውን የኢንተርኮም አይፒ አድራሻ እና ወደብ ማዘጋጀት እንችላለን።

በመጀመሪያ ፣ ቅንብሮቹን የሚያከማችበትን መዋቅር ወደ ፕሮግራሙ እንጨምር-

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

typedef struct _app_vars app_vars;

ፕሮግራሙ ቫርስ የሚባል የዚህ አይነት መዋቅር ያውጃል።
በመቀጠል፣ የትእዛዝ መስመር ነጋሪ እሴቶችን ለመተንተን ተግባር እንጨምር፡-

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

በመተንተን ምክንያት, የትእዛዝ መስመር ግቤቶች በቫርስ መዋቅር መስኮች ውስጥ ይቀመጣሉ. የመተግበሪያው ዋና ተግባር ከማጣሪያዎች የማስተላለፊያ እና የመቀበያ መንገዶችን መሰብሰብ ይሆናል ፣ ምልክት ማድረጊያውን ካገናኙ በኋላ መቆጣጠሪያው ወደ ማለቂያ ወደሌለው ዑደት ይተላለፋል ፣ ይህም የጄነሬተር ድግግሞሽ ወደ ዜሮ ከተዋቀረ የሙከራ ጄነሬተርን እንደገና ያስጀምረዋል ። ያለማቋረጥ ይሠራል.

ጄኔሬተሩ በዲዛይኑ ምክንያት እነዚህን ዳግም ማስጀመር ያስፈልገዋል፤ በሆነ ምክንያት ከ16 ሰከንድ በላይ የሚቆይ ምልክት መስራት አይችልም። የእሱ ቆይታ በ 32-ቢት ቁጥር መገለጹን ልብ ሊባል ይገባል.

አጠቃላይ ፕሮግራሙ ይህን ይመስላል።

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

እናጠናቅቅ። ከዚያ ፕሮግራሙ በሁለት ኮምፒተሮች ላይ ሊሠራ ይችላል. ወይም በአንደኛው, አሁን እንደማደርገው. TSharkን በሚከተሉት ነጋሪ እሴቶች እንጀምራለን፡

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

በኮንሶሉ ውስጥ ያለው የማስጀመሪያ መስክ ስለ ቀረጻ ጅምር መልእክት ብቻ ካሳየ ይህ ጥሩ ምልክት ነው - ይህ ማለት ወደባችን በሌሎች ፕሮግራሞች ያልተያዘ ነው ማለት ነው። በሌላ ተርሚናል ላይ፣ ይህንን የወደብ ቁጥር በመግለጽ “የርቀት” ኢንተርኮምን የሚያስመስል የፕሮግራም ምሳሌ እንጀምራለን፡-

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

ከፕሮግራሙ ጽሑፍ ላይ እንደሚታየው, ነባሪው የአይፒ አድራሻ 127.0.0.1 (አካባቢያዊ loopback) ነው.

በሌላ ተርሚናል ውስጥ የፕሮግራሙን ሁለተኛ ምሳሌ እንጀምራለን, ይህም የአካባቢያዊ መሳሪያን ያስመስላል. አብሮገነብ የሙከራ ጀነሬተር እንዲሰራ የሚያስችል ተጨማሪ ነጋሪ እሴት እንጠቀማለን፡-

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

በዚህ ጊዜ ወደ "ርቀት" መሳሪያው የሚተላለፉ እሽጎች በኮንሶሉ ውስጥ በ TShark መብረቅ መጀመር አለባቸው እና ከኮምፒዩተር ድምጽ ማጉያው የማያቋርጥ ድምጽ ይሰማል.

ሁሉም ነገር እንደተፃፈ ከሆነ, የፕሮግራሙን ሁለተኛ ቅጂ እንደገና እንጀምራለን, ነገር ግን ያለ ቁልፍ እና ክርክር "- Gen 440". አሁን የጄነሬተር ሚና ትጫወታለህ. ከዚህ በኋላ ወደ ማይክሮፎኑ ድምጽ ማሰማት ይችላሉ, በድምጽ ማጉያው ወይም በጆሮ ማዳመጫው ውስጥ ያለውን ተዛማጅ ድምጽ መስማት አለብዎት. የአኮስቲክ ራስን መነቃቃት እንኳን ሊከሰት ይችላል፤ የተናጋሪውን ድምጽ ይቀንሱ እና ውጤቱ ይጠፋል።

በሁለት ኮምፒውተሮች ላይ ከሮጡ እና ስለ አይፒ አድራሻዎች ግራ ካልጋቡ ፣ ከዚያ ተመሳሳይ ውጤት ይጠብቀዎታል - ባለ ሁለት መንገድ ዲጂታል ጥራት ያለው የድምፅ ግንኙነት።

በሚቀጥለው ርዕስ ውስጥ የራሳችንን ማጣሪያዎች - ፕለጊኖች እንዴት እንደሚጽፉ እንማራለን, ለዚህ ችሎታ ምስጋና ይግባውና የሚዲያ ዥረቱን ለድምጽ እና ለቪዲዮ ብቻ ሳይሆን በሌላ የተወሰነ አካባቢም መጠቀም ይችላሉ.

ምንጭ: hab.com

አስተያየት ያክሉ