Mediastreamer2 VoIP انجڻ جي ڳولا. حصو 9

مضمون جو مواد منهنجي طرفان ورتو ويو آهي زين چينل.

ڊپلڪس انٽرڪام

Mediastreamer2 VoIP انجڻ جي ڳولا. حصو 9

آخري ۾ مضمون هڪ ڊپلڪس انٽرڪام جو اعلان ڪيو ويو، ۽ ان ۾ اسان ان کي ٺاهينداسين.

ڊراگرام عنوان جي شڪل ۾ ڏيکاريل آهي. فلٽر جي هيٺين زنجير ٽرانسميشن جو رستو ٺاهي ٿو، جيڪو آواز ڪارڊ کان شروع ٿئي ٿو. اهو مائڪروفون مان سگنل نموني مهيا ڪري ٿو. ڊفالٽ طور، اهو في سيڪنڊ 8000 نموني جي شرح تي ٿئي ٿو. ڊيٽا بٽ ڊيپٿ جيڪا ميڊيا اسٽريمر آڊيو فلٽر استعمال ڪندا آهن 16 بِٽ آهي (اها اهم ناهي؛ جيڪڏهن توهان چاهيو ته، توهان فلٽر لکي سگهو ٿا جيڪي وڌيڪ بٽ ڊيپٿ سان ڪم ڪندا). ڊيٽا کي 160 نمونن جي بلاڪ ۾ گروپ ڪيو ويو آهي. اهڙيء طرح، هر بلاڪ سائيز ۾ 320 بائيٽ آهي. اڳيون، اسان ڊيٽا کي فيڊ ڪريون ٿا جنريٽر جي ان پٽ تي، جيڪو، جڏهن بند ڪيو ويو، ڊيٽا کي "شفاف" آهي. مون ان کي شامل ڪيو ان صورت ۾ جڏهن توهان ڊيبگنگ دوران مائڪروفون ۾ ڳالهائڻ کان ٿڪجي پيا آهيو - توهان ٽون سگنل سان رستي کي ”شوٽ“ ڪرڻ لاءِ جنريٽر استعمال ڪري سگهو ٿا.

جنريٽر کان پوءِ، سگنل انڪوڊر ڏانھن وڃي ٿو، جيڪو اسان جي 16-bit نمونن کي µ-قانون (G.711 معيار) جي مطابق اٺ-بٽ وارن ۾ تبديل ڪري ٿو. انڪوڊر جي آئوٽ تي، اسان وٽ اڳ ۾ ئي ڊيٽا بلاڪ اڌ سائيز آهي. عام طور تي، جيڪڏهن اسان کي ٽرئفڪ کي بچائڻ جي ضرورت ناهي ته اسان ڊيٽا کي بغير دٻاء جي منتقلي ڪري سگهون ٿا. پر هتي انڪوڊر استعمال ڪرڻ ڪارآمد آهي، ڇاڪاڻ ته Wireshark صرف RTP اسٽريم مان آڊيو ٻيهر پيدا ڪري سگهي ٿو جڏهن ان کي µ-law يا a-law جي مطابق ڪمپريس ڪيو وڃي.

انڪوڊر کان پوءِ، ڊيٽا جا لائٽر بلاڪ rtpsend فلٽر ڏانهن موڪليا ويندا آهن، جيڪو انهن کي RTP پيڪٽ ۾ رکندو، ضروري جھنڊو مقرر ڪندو ۽ يو ڊي پي پيڪٽ جي صورت ۾ نيٽ ورڪ تي ٽرانسميشن لاءِ ميڊيا اسٽريمر کي ڏيندو.

فلٽرن جو مٿئين زنجير وصول ڪرڻ وارو رستو ٺاهيندو آهي؛ نيٽ ورڪ مان ميڊيا اسٽريمر پاران مليل RTP پيڪٽس rtprecv فلٽر ۾ داخل ٿين ٿا، جنهن جي آئوٽ پٽ تي اهي ڊيٽا بلاڪ جي صورت ۾ ظاهر ٿين ٿا، جن مان هر هڪ وصول ٿيل پيڪٽ سان ملندڙ جلندڙ آهي. بلاڪ ۾ صرف پيل لوڊ ڊيٽا شامل آهي؛ پوئين مضمون ۾ اهي ڏيکاريا ويا آهن سائي ۾ مثال ۾.

اڳيون، بلاڪ ڊيڪوڊر فلٽر ڏانهن موڪليا ويا آهن، جيڪي انهن ۾ موجود واحد بائيٽ نمونن کي لڪير، 16-بٽ ۾ تبديل ڪري ٿو. جنهن کي اڳ ۾ ئي ميڊيا اسٽريمر فلٽر ذريعي پروسيس ڪري سگهجي ٿو. اسان جي صورت ۾، اسان صرف انهن کي توهان جي هيڊ سيٽ جي اسپيڪر تي پلے بیک لاء آواز ڪارڊ ڏانهن موڪليندا آهيون.

هاڻي اچو ته سافٽ ويئر تي عمل ڪرڻ تي. هن کي ڪرڻ لاء، اسان وصول ڪندڙ ۽ ٽرانسميٽر فائلن کي گڏ ڪنداسين جيڪي اسان اڳ ۾ الڳ ڪيا هئا. هن کان اڳ، اسان بندرگاهن ۽ پتي لاء مقرر ڪيل سيٽنگون استعمال ڪندا هئا، پر هاڻي اسان کي پروگرام جي ضرورت آهي ته اسان سيٽنگون استعمال ڪرڻ جي قابل ٿي سگهون ٿا جيڪي اسان شروع ڪرڻ تي بيان ڪيون ٿا. هن کي ڪرڻ لاء، اسان ڪمانڊ لائن دليلن جي پروسيسنگ لاء ڪارڪردگي شامل ڪنداسين. جنهن کان پوءِ اسان انٽرڪام جو IP پتو ۽ پورٽ سيٽ ڪري سگهنداسين جنهن سان اسان ڪنيڪشن قائم ڪرڻ چاهيون ٿا.

پهرين، اچو ته پروگرام ۾ هڪ ڍانچي شامل ڪريو جيڪو ان جي سيٽنگن کي محفوظ ڪندو:

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

typedef struct _app_vars app_vars;

پروگرام ھن قسم جي ھڪڙي جوڙجڪ جو اعلان ڪندو جنھن کي 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]);
        }
    }
}

parsing جي نتيجي ۾، ڪمانڊ لائن دليلن کي vars جي جوڙجڪ جي شعبن ۾ رکيو ويندو. ايپليڪيشن جو بنيادي ڪم فلٽرن مان منتقلي ۽ وصول ڪرڻ جا رستا گڏ ڪرڻ هوندو؛ ٽڪر کي ڳنڍڻ کان پوء، ڪنٽرول هڪ لامحدود لوپ ڏانهن منتقل ڪيو ويندو، جيڪو، جيڪڏهن جنريٽر جي تعدد غير صفر تي مقرر ڪئي وئي هئي، ٽيسٽ جنريٽر کي ٻيهر شروع ڪندو. اهو بغير بغير ڪم ڪري ٿو.

جنريٽر کي ان جي ڊيزائن جي ڪري ٻيهر شروع ڪرڻ جي ضرورت پوندي؛ ڪجهه سببن لاءِ اهو 16 سيڪنڊن کان وڌيڪ وقت تائين سگنل پيدا نٿو ڪري سگهي. اها ڳالهه نوٽ ڪرڻ گهرجي ته ان جي مدت هڪ 32-bit نمبر جي وضاحت ڪئي وئي آهي.

سڄو پروگرام هن طرح نظر ايندو:

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

جيئن پروگرام جي متن مان ڏسي سگھجي ٿو، ڊفالٽ IP پتو 127.0.0.1 (مقامي لوپ بيڪ) آھي.

ٻئي ٽرمينل ۾، اسان پروگرام جو ٻيو مثال لانچ ڪيو، جيڪو مقامي ڊوائيس کي نقل ڪري ٿو. اسان هڪ اضافي دليل استعمال ڪندا آهيون جيڪا اجازت ڏئي ٿي بلٽ ان ٽيسٽ جنريٽر کي ڪم ڪرڻ لاءِ:

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

هن وقت، "ريموٽ" ڊوائيس ڏانهن منتقل ٿيل پيڪيٽس کي ڪنسول ۾ TShark سان چمڪائڻ شروع ڪرڻ گهرجي، ۽ ڪمپيوٽر جي اسپيڪر مان هڪ مسلسل آواز ٻڌي ويندي.

جيڪڏهن سڀ ڪجهه لکيو ويو آهي، پوء اسان پروگرام جي ٻئي ڪاپي کي ٻيهر شروع ڪندا آهيون، پر بغير "-جين 440" جي اهم ۽ دليل جي. توھان ھاڻي جنريٽر جو ڪردار ادا ڪندا. ان کان پوء، توهان مائڪروفون ۾ شور ڪري سگهو ٿا؛ توهان کي اسپيڪر يا هيڊفون ۾ لاڳاپيل آواز ٻڌڻ گهرجي. صوتي خود حوصلا شايد ٿي سگھي ٿي؛ اسپيڪر حجم کي بند ڪريو ۽ اثر غائب ٿي ويندو.

جيڪڏهن توهان ان کي ٻن ڪمپيوٽرن تي هلائي ڇڏيو ۽ IP پتي جي باري ۾ پريشان نه ٿيو، ته پوء ساڳيو نتيجو توهان جي انتظار ۾ آهي - ٻه طرفي ڊجيٽل معيار آواز مواصلات.

ايندڙ آرٽيڪل ۾ اسين سکنداسين ته اسان جا پنهنجا فلٽر ڪيئن لکجن - پلگ ان، هن مهارت جي مهرباني توهان ميڊيا اسٽريمر کي نه صرف آڊيو ۽ وڊيو لاءِ استعمال ڪري سگهندا، پر ڪجهه ٻين مخصوص علائقن ۾ پڻ.

جو ذريعو: www.habr.com

تبصرو شامل ڪريو