Mediastreamer2 VoIP இன்ஜினை ஆராய்கிறது. பகுதி 9

கட்டுரையின் பொருள் என்னுடையது ஜென் சேனல்.

இரட்டை இண்டர்காம்

Mediastreamer2 VoIP இன்ஜினை ஆராய்கிறது. பகுதி 9

கடந்த காலத்தில் கட்டுரை ஒரு இரட்டை இண்டர்காம் அறிவிக்கப்பட்டது, இதில் நாங்கள் அதை உருவாக்குவோம்.

வரைபடம் தலைப்பு படத்தில் காட்டப்பட்டுள்ளது. வடிப்பான்களின் கீழ் சங்கிலி ஒலி அட்டையிலிருந்து தொடங்கும் பரிமாற்ற பாதையை உருவாக்குகிறது. இது மைக்ரோஃபோனில் இருந்து சமிக்ஞை மாதிரிகளை வழங்குகிறது. இயல்பாக, இது ஒரு வினாடிக்கு 8000 மாதிரிகள் என்ற விகிதத்தில் நிகழ்கிறது. மீடியா ஸ்ட்ரீமர் ஆடியோ வடிப்பான்கள் பயன்படுத்தும் டேட்டா பிட் ஆழம் 16 பிட்கள் (இது முக்கியமில்லை; நீங்கள் விரும்பினால், அதிக பிட் ஆழத்துடன் வேலை செய்யும் வடிப்பான்களை எழுதலாம்). தரவு 160 மாதிரிகளின் தொகுதிகளாக தொகுக்கப்பட்டுள்ளது. இவ்வாறு, ஒவ்வொரு தொகுதியும் 320 பைட்டுகள் அளவில் உள்ளது. அடுத்து, ஜெனரேட்டரின் உள்ளீட்டிற்கு தரவை ஊட்டுகிறோம், இது அணைக்கப்படும் போது, ​​தரவுக்கு "வெளிப்படையானது". பிழைத்திருத்தத்தின் போது மைக்ரோஃபோனில் பேசுவதில் நீங்கள் சோர்வடைந்துவிட்டால் நான் அதைச் சேர்த்துள்ளேன் - டோன் சிக்னலுடன் பாதையை "சுட" ஜெனரேட்டரைப் பயன்படுத்தலாம்.

ஜெனரேட்டருக்குப் பிறகு, சிக்னல் குறியாக்கிக்குச் செல்கிறது, இது எங்கள் 16-பிட் மாதிரிகளை µ-சட்டத்தின் (G.711 தரநிலை) படி எட்டு பிட்களாக மாற்றுகிறது. குறியாக்கியின் வெளியீட்டில், எங்களிடம் ஏற்கனவே பாதி அளவு தரவுத் தொகுதி உள்ளது. பொதுவாக, டிராஃபிக்கைச் சேமிக்கத் தேவையில்லை என்றால், சுருக்கம் இல்லாமல் தரவை அனுப்பலாம். ஆனால் இங்கே குறியாக்கியைப் பயன்படுத்துவது பயனுள்ளது, ஏனெனில் வயர்ஷார்க் µ-சட்டம் அல்லது சட்டத்தின்படி சுருக்கப்பட்டால் மட்டுமே RTP ஸ்ட்ரீமில் இருந்து ஆடியோவை மீண்டும் உருவாக்க முடியும்.

குறியாக்கிக்குப் பிறகு, தரவுகளின் இலகுவான தொகுதிகள் 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;

நிரல் 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]);
        }
    }
}

பாகுபடுத்தலின் விளைவாக, கட்டளை வரி வாதங்கள் vars கட்டமைப்பின் புலங்களில் வைக்கப்படும். பயன்பாட்டின் முக்கிய செயல்பாடு வடிப்பான்களிலிருந்து அனுப்பும் மற்றும் பெறும் பாதைகளை சேகரிப்பதாகும்; டிக்கரை இணைத்த பிறகு, கட்டுப்பாடு எல்லையற்ற வளையத்திற்கு மாற்றப்படும், இது ஜெனரேட்டர் அதிர்வெண் பூஜ்ஜியமாக அமைக்கப்பட்டால், சோதனை ஜெனரேட்டரை மறுதொடக்கம் செய்யும். அது நிற்காமல் வேலை செய்கிறது.

ஜெனரேட்டருக்கு அதன் வடிவமைப்பு காரணமாக இந்த மறுதொடக்கம் தேவைப்படும்; சில காரணங்களால் அது 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

நிரல் உரையிலிருந்து பார்க்க முடிந்தால், இயல்புநிலை IP முகவரி 127.0.0.1 (உள்ளூர் லூப்பேக்) ஆகும்.

மற்றொரு முனையத்தில், நிரலின் இரண்டாவது நிகழ்வைத் தொடங்குகிறோம், இது உள்ளூர் சாதனத்தை உருவகப்படுத்துகிறது. உள்ளமைக்கப்பட்ட சோதனை ஜெனரேட்டரை வேலை செய்ய அனுமதிக்கும் கூடுதல் வாதத்தைப் பயன்படுத்துகிறோம்:

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

இந்த நேரத்தில், “ரிமோட்” சாதனத்தை நோக்கி அனுப்பப்படும் பாக்கெட்டுகள் TShark உடன் கன்சோலில் ஒளிரத் தொடங்க வேண்டும், மேலும் கணினி ஸ்பீக்கரிலிருந்து தொடர்ச்சியான தொனி கேட்கப்படும்.

எல்லாம் எழுதப்பட்டபடி நடந்தால், நிரலின் இரண்டாவது நகலை மறுதொடக்கம் செய்கிறோம், ஆனால் விசை மற்றும் வாதம் இல்லாமல் “—gen 440”. நீங்கள் இப்போது ஜெனரேட்டரின் பாத்திரத்தை வகிப்பீர்கள். இதற்குப் பிறகு, நீங்கள் மைக்ரோஃபோனில் சத்தம் போடலாம்; ஸ்பீக்கர் அல்லது ஹெட்ஃபோன்களில் தொடர்புடைய ஒலியை நீங்கள் கேட்க வேண்டும். ஒலி சுய-உற்சாகம் கூட ஏற்படலாம்; ஸ்பீக்கரின் ஒலியைக் குறைக்கவும், விளைவு மறைந்துவிடும்.

நீங்கள் அதை இரண்டு கணினிகளில் இயக்கி, ஐபி முகவரிகளைப் பற்றி குழப்பமடையவில்லை என்றால், அதே முடிவு உங்களுக்குக் காத்திருக்கிறது - இருவழி டிஜிட்டல் தரமான குரல் தொடர்பு.

அடுத்த கட்டுரையில், எங்கள் சொந்த வடிப்பான்கள் - செருகுநிரல்களை எவ்வாறு எழுதுவது என்பதைக் கற்றுக்கொள்வோம், இந்த திறமைக்கு நன்றி, நீங்கள் ஆடியோ மற்றும் வீடியோவுக்கு மட்டுமல்லாமல், வேறு சில குறிப்பிட்ட பகுதிகளிலும் மீடியா ஸ்ட்ரீமரைப் பயன்படுத்த முடியும்.

ஆதாரம்: www.habr.com

கருத்தைச் சேர்