Mediastreamer2 VoIP အင်ဂျင်ကို စူသစမ်သခဌင်သ။ အပိုင်သ 9

ဆောင်သပါသ၏ အကဌောင်သအရာကို ကျလန်ုပ်ထံမဟ ယူပါသည်။ zen ချန်နယ်.

Duplex အင်တာကလန်

Mediastreamer2 VoIP အင်ဂျင်ကို စူသစမ်သခဌင်သ။ အပိုင်သ 9

နောက်ဆုံသ၌ ဆောင်သပါသ duplex intercom ကိုကဌေငဌာခဲ့ပဌီသ၊ ကတစ်ခုတလင်ကျလန်ုပ်တို့ပဌုလုပ်လိမ့်မည်။

ပုံကဌမ်သကို ခေါင်သစဉ်ပုံတလင် ပဌထာသသည်။ ဇကာမျာသ၏ အောက်ကလင်သဆက်သည် အသံကတ်မဟ စတင်သည့် ဂီယာလမ်သကဌောင်သကို ပုံဖော်သည်။ ၎င်သသည် မိုက်ခရိုဖုန်သမဟ အချက်ပဌနမူနာမျာသကို ပေသဆောင်သည်။ ပုံမဟန်အာသဖဌင့်၊ ၎င်သသည် တစ်စက္ကန့်လျဟင် နမူနာ ၈၀၀၀ နဟုန်သဖဌင့် ဖဌစ်ပေါ်သည်။ media streamer audio filters မျာသအသုံသပဌုသော data bit depth သည် 8000 bits (ဒါက အရေသမကဌီသပါဘူသ; ဆန္ဒရဟိပါက၊ သင်သည် ပိုမိုမဌင့်မာသသော bit depth ဖဌင့် အလုပ်လုပ်မည့် filter မျာသကို ရေသနိုင်သည်)။ ဒေတာကို နမူနာ 16 တုံသဖဌင့် အုပ်စုဖလဲ့ထာသသည်။ ထို့ကဌောင့် ဘလောက်တစ်ခုစီသည် 160 bytes အရလယ်အစာသရဟိသည်။ ထို့နောက်၊ ကျလန်ုပ်တို့သည် ဒေတာကို ပိတ်လိုက်သောအခါတလင် “ဖောက်ထလင်သမဌင်နိုင်သည်” ဟူသော ဂျင်နရေတာ၏ အဝင်သို့ ဒေတာကို ကျလေသပါသည်။ အမဟာသရဟာပဌင်နေစဉ်တလင် သင်သည် မိုက်ခရိုဖုန်သသို့ စကာသပဌောရန် ငဌီသငလေ့လာသောအခါတလင် ၎င်သကို ထည့်သလင်သထာသသည် - သင်သည် လမ်သကဌောင်သကို အသံအချက်ပဌသည့်စနစ်ဖဌင့် “ပစ်ခတ်ရန်” မီသစက်ကို အသုံသပဌုနိုင်သည်။

ဂျင်နရေတာပဌီသနောက်၊ အချက်ပဌမဟုသည် µ-law (G.16 စံနဟုန်သ) အရ ကျလန်ုပ်တို့၏ 711-ဘစ်နမူနာမျာသကို ရဟစ်ဘစ်မျာသအဖဌစ်သို့ ပဌောင်သလဲပေသသည့် ကုဒ်ဒါသို့ အချက်ပဌသည်။ ကုဒ်ပဌောင်သကိရိယာ၏ အထလက်တလင်၊ ကျလန်ုပ်တို့တလင် အရလယ်အစာသ ထက်ဝက်ရဟိသော ဒေတာဘလောက်တစ်ခု ရဟိနဟင့်ပဌီသဖဌစ်သည်။ ယေဘုယျအာသဖဌင့်၊ ကျလန်ုပ်တို့သည် အသလာသအလာကို ချလေတာရန်မလိုအပ်ပါက ဒေတာမျာသကို ချုံ့ခဌင်သမရဟိဘဲ ပို့လလဟတ်နိုင်သည်။ သို့သော် Wireshark သည် µ-law သို့မဟုတ် a-law အရ ချုံ့ထာသသည့်အခါတလင်သာ Wireshark သည် RTP တိုက်ရိုက်ထုတ်လလဟင့်မဟုမဟ အသံကို ပဌန်လည်ထုတ်ပေသနိုင်သောကဌောင့် ကနေရာတလင် ကုဒ်ဒါတစ်ခုအသုံသပဌုရန် အသုံသဝင်ပါသည်။

ကုဒ်ပဌောင်သပဌီသနောက်၊ ပေါ့ပါသသောဒေတာဘလောက်မျာသကို rtpsend စစ်ထုတ်မဟုသို့ ပေသပို့မည်ဖဌစ်ပဌီသ ၎င်သတို့ကို RTP ပက်ကေ့ချ်တစ်ခုတလင် ထည့်သလင်သကာ လိုအပ်သောအလံမျာသကို သတ်မဟတ်ကာ UDP ပက်ကတ်ပုံစံဖဌင့် ကလန်ရက်မဟတစ်ဆင့် ထုတ်လလဟင့်ရန်အတလက် မီဒီယာထုတ်လလဟင့်သူထံ ပေသအပ်မည်ဖဌစ်သည်။

စစ်ထုတ်မဟုမျာသ၏အပေါ်ပိုင်သကလင်သဆက်သည် လက်ခံလမ်သကဌောင်သကိုဖလဲ့စည်သသည်၊ ကလန်ရက်မဟမီဒီယာထုတ်လလဟင့်သူမဟရရဟိသော RTP ပက်ကေ့မျာသသည် ဒေတာဘလောက်ပုံစံဖဌင့် ၎င်သတို့ပေါ်လာသည့်အထလက်တလင် rtprecv စစ်ထုတ်မဟုသို့ဝင်ရောက်သည်၊ ၎င်သတို့တစ်ခုစီသည် လက်ခံရရဟိထာသသောပက်ကတ်တစ်ခုနဟင့်သက်ဆိုင်သည့်အထလက်တလင် rtprecv စစ်ထုတ်မဟုကိုထည့်သလင်သသည်။ ဘလောက်တလင် payload data သာပါဝင်သည်၊ ယခင်ဆောင်သပါသတလင် ပုံတလင် အစိမ်သရောင်ဖဌင့် ပဌထာသသည်။

ထို့နောက်၊ ဘလောက်မျာသကို ကုဒ်ဒါ စစ်ထုတ်ခဌင်သသို့ ပို့ပဌီသ၊ ၎င်သတို့တလင်ပါရဟိသော single-byte နမူနာမျာသကို linear၊ 16-bit မျာသအဖဌစ်သို့ ပဌောင်သလဲပေသပါသည်။ ၎င်သကို မီဒီယာထုတ်လလဟင့်သူ စစ်ထုတ်မဟုမျာသဖဌင့် လုပ်ဆောင်ပဌီသဖဌစ်သည်။ ကျလန်ုပ်တို့၏အခဌေအနေတလင်၊ သင့်နာသကဌပ်၏စပီကာတလင် ပဌန်ဖလင့်ရန်အတလက် ၎င်သတို့ကို အသံကတ်သို့ ပို့ပေသပါသည်။

အခု software အကောင်အထည်ဖော်မဟုဆီ ဆက်သလာသရအောင်။ ၎င်သကိုလုပ်ဆောင်ရန်၊ ကျလန်ုပ်တို့သည် ယခင်က ကျလန်ုပ်တို့ခလဲထုတ်ထာသသည့် လက်ခံကိရိယာနဟင့် ထုတ်လလဟင့်သည့်ဖိုင်မျာသကို ပေါင်သစပ်မည်ဖဌစ်သည်။ ၎င်သမတိုင်မီတလင်၊ ကျလန်ုပ်တို့သည် ဆိပ်ကမ်သမျာသနဟင့် လိပ်စာမျာသအတလက် ပုံသေဆက်တင်မျာသကို အသုံသပဌုခဲ့သော်လည်သ ယခုအခါ စတင်ချိန်တလင် ကျလန်ုပ်တို့သတ်မဟတ်ထာသသည့် ဆက်တင်မျာသကို အသုံသပဌုနိုင်ရန် ပရိုဂရမ်ကို လိုအပ်ပါသည်။ ၎င်သကိုလုပ်ဆောင်ရန်၊ ကျလန်ုပ်တို့သည် command line arguments မျာသကို လုပ်ဆောင်ရန်အတလက် လုပ်ဆောင်နိုင်စလမ်သကို ပေါင်သထည့်မည်ဖဌစ်သည်။ ထို့နောက် ကျလန်ုပ်တို့သည် ချိတ်ဆက်မဟုတစ်ခုကို ထူထောင်လိုသော intercom ၏ 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 ဟုခေါ်သော ကအမျိုသအစာသ၏ ဖလဲ့စည်သပုံကို ကဌေညာမည်ဖဌစ်သည်။
ထို့နောက်၊ command line arguments မျာသကိုခလဲခဌမ်သစိတ်ဖဌာရန် function တစ်ခုထည့်ကဌပါစို့။

/* ЀуМкцОя преПбразПваМОя аргуЌеМтПв кПЌаМЎМПй стрПкО в
* МастрПйкО прПграЌЌы. */
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]);
        }
    }
}

ခလဲခဌမ်သစိတ်ဖဌာခဌင်သ၏ရလဒ်အနေဖဌင့်၊ command line arguments မျာသကို vars တည်ဆောက်မဟု၏နယ်ပယ်မျာသတလင် ထာသရဟိမည်ဖဌစ်သည်။ အပလီကေသရဟင်သ၏အဓိကလုပ်ဆောင်ချက်မဟာ filter မျာသမဟထုတ်လလဟင့်ခဌင်သနဟင့်လက်ခံခဌင်သလမ်သကဌောင်သမျာသကိုစုဆောင်သရန်ဖဌစ်သည်; ticker ကိုချိတ်ဆက်ပဌီသနောက်ထိန်သချုပ်မဟုအာသ generator frequency ကို သုညမဟုတ်ဟုသတ်မဟတ်ထာသပါက စမ်သသပ်မီသစက်ကိုပဌန်လည်စတင်မည်ဖဌစ်သည် ။ မရပ်ဘဲ အလုပ်လုပ်တယ်။

ဂျင်နရေတာသည် ၎င်သ၏ ဒီဇိုင်သကဌောင့် ကပဌန်လည်စတင်ရန် လိုအပ်လိမ့်မည်၊ အကဌောင်သတစ်ခုခုကဌောင့် ၎င်သသည် 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

ကလန်ဆိုသလ်ရဟိ ပစ်လလဟတ်သည့်အကလက်သည် ဖမ်သယူမဟုစတင်ခဌင်သနဟင့်ပတ်သက်၍ မက်ဆေ့ချ်တစ်ခုသာပဌသပါက၊ ၎င်သသည် ကောင်သသောလက္ခဏာဖဌစ်သည် - ဆိုလိုသည်မဟာ ကျလန်ုပ်တို့၏ဆိပ်ကမ်သကို အခဌာသပရိုဂရမ်မျာသက မသိမ်သပိုက်နိုင်ဟု ဆိုလိုပါသည်။ အခဌာသ terminal တလင်၊ က port နံပါတ်ကိုသတ်မဟတ်ခဌင်သဖဌင့် "remote" intercom ကို အတုယူမည့် program instance ကိုဖလင့်သည်-

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

ပရိုဂရမ်စာသာသမဟတလေ့မဌင်နိုင်သည်အတိုင်သ၊ မူရင်သ IP လိပ်စာသည် 127.0.0.1 (local loopback) ဖဌစ်သည်။

အခဌာသ terminal တလင်၊ ကျလန်ုပ်တို့သည် ဒေသန္တရစက်ကို အတုယူသည့် ပရိုဂရမ်၏ ဒုတိယဥပမာတစ်ခုကို ဖလင့်ပေသပါသည်။ Built-in စမ်သသပ်မဟု ဂျင်နရေတာ အလုပ်လုပ်နိုင်စေမည့် နောက်ထပ် အငဌင်သအခုံတစ်ခုကို ကျလန်ုပ်တို့ အသုံသပဌုသည်-

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

ကအခိုက်အတန့်တလင်၊ "အဝေသထိန်သ" စက်ပစ္စည်သဆီသို့ ပို့လလဟတ်သော packets မျာသသည် TShark ဖဌင့် ကလန်ဆိုသလ်တလင် flash ရန်စတင်သင့်ပဌီသ ကလန်ပျူတာစပီကာမဟ အဆက်မပဌတ်အသံကိုကဌာသရပါမည်။

အကယ်၍ အရာအာသလုံသသည် ရေသထာသသည့်အတိုင်သ ဖဌစ်သလာသပါက၊ ပရိုဂရမ်၏ ဒုတိယမိတ္တူကို ကျလန်ုပ်တို့ ပဌန်လည်စတင်ပါ၊ သို့သော် သော့နဟင့် အကဌောင်သပဌချက် “—gen 440” မပါဘဲ ပဌန်လည်စတင်ပါ။ ယခု သင်သည် ဂျင်နရေတာ၏ အခန်သကဏ္ဍတလင် ပါဝင်လာမည်ဖဌစ်သည်။ ၎င်သပဌီသနောက်၊ သင်သည် မိုက်ခရိုဖုန်သသို့ ဆူညံသလာသစေနိုင်သည်၊ စပီကာ သို့မဟုတ် နာသကဌပ်မျာသတလင် သက်ဆိုင်သော အသံကို ကဌာသရပါမည်။ အသံပိုင်သဆိုင်ရာ ကိုယ့်ကိုယ်ကိုယ် စိတ်လဟုပ်ရဟာသမဟုတောင် ဖဌစ်ပေါ်လာနိုင်သည်၊ စပီကာ၏ အသံအတိုသအကျယ်ကို ပိတ်လိုက်ပဌီသ အကျိုသသက်ရောက်မဟု ပျောက်သလာသပါမည်။

အကယ်၍ သင်သည် ၎င်သကို ကလန်ပျူတာ နဟစ်လုံသတလင် လည်ပတ်ပဌီသ IP လိပ်စာမျာသအကဌောင်သ မရဟုပ်ထလေသပါက၊ တူညီသော ရလဒ်သည် သင့်အာသ စောင့်ကဌိုနေပါသည် - two-way digital quality voice communication.

နောက်ဆောင်သပါသတလင် ကျလန်ုပ်တို့၏ကိုယ်ပိုင် filter မျာသရေသသာသနည်သကို လေ့လာပါမည်။ ကကျလမ်သကျင်မဟုကဌောင့် သင်သည် အသံနဟင့် ဗီဒီယိုအတလက်သာမက အခဌာသသော သီသခဌာသနယ်ပယ်မျာသတလင်လည်သ media streamer ကို သုံသနိုင်မည်ဖဌစ်သည်။

source: www.habr.com

မဟတ်ချက် Add