{"id":79540,"date":"2020-04-28T07:42:01","date_gmt":"2020-04-28T05:42:01","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11"},"modified":"2020-04-28T07:42:01","modified_gmt":"2020-04-28T05:42:01","slug":"izuchaem-voip-dvizhok-mediastreamer2-chast-11","status":"publish","type":"post","link":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","title":{"rendered":"Uurime VoIP-mootorit Mediastreamer2. Osa 11","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Artikli sisu on p\u00e4rit minu <noindex><a rel=\"nofollow\" href=\"https:\/\/zen.yandex.ru\/profile\/editor\/id\/5e3f8e0751f5346faab4fc7a\">zen-kanalist<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uurime VoIP-mootorit Mediastreamer2. Osa 11\" src=\"\/wp-content\/uploads\/2020\/04\/b66fab43eb45c626c50f0383dcfa7cca.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Andmete liikumismehhanism<\/p>\n<p><\/p>\n<ul>\n<li>Andmeplokk dblk_t<\/li>\n<li>S\u00f5num mblk_t<\/li>\n<li>S\u00f5numitega t\u00f6\u00f6tamise funktsioonid mblk_t<\/li>\n<li>J\u00e4rjekord queue_t<\/li>\n<li>J\u00e4rjekordadega t\u00f6\u00f6tamise funktsioonid queue_t<\/li>\n<li>Filtrite \u00fchendamine<\/li>\n<li>Andmete t\u00f6\u00f6tlemise graafi signaalpunkt<\/li>\n<li>Tickere tagumine tegevus<\/li>\n<li>Vahem\u00e4lu (MSBufferizer)<\/li>\n<li>MSBufferizeri t\u00f6\u00f6tamise funktsioonid<\/li>\n<\/ul>\n<p><\/p>\n<p>Eelmises osas <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/497932\/\">artiklis<\/a><\/noindex> Oleme v\u00e4lja t\u00f6\u00f6tanud oma filtri. Selles artiklis p\u00fchendame t\u00e4helepanu andmete liikumismehhanismi sisesele ehitusele, mis toimub meediastreameri filtrite vahel. See v\u00f5imaldab tulevikus kirjutada keerukamaid filtreid v\u00e4iksema vaevaga.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"mehanizm-peremescheniya-dannyh\">Andmete liikumismehhanism<\/h2>\n<p><\/p>\n<p>Andmete liikumine meediastreameris toimub kirjeldatud struktuuri kaudu <em>queue_t<\/em>. Andmete liikumine toimub s\u00f5numite jada kaudu, mille t\u00fc\u00fcp on <em>mblk_t<\/em>, mis ei sisalda enda sees signaali andmeid, vaid ainult lingid eelmise, j\u00e4rgmise s\u00f5numi ja andmeploki peale. Lisaks tahan r\u00f5hutada, et on olemas ka v\u00e4li, mis viitab sama t\u00fc\u00fcpi s\u00f5numile, mis v\u00f5imaldab korraldada s\u00f5numite \u00fchekordset loetelu. S\u00f5numite r\u00fchma, mida \u00fchendab see loetelu, nimetame kimpuks. Seega v\u00f5ib iga j\u00e4rjekorra element olla kas \u00fcksik s\u00f5num <em>mblk_t<\/em>, v\u00f5i kimpude pea <em>mblk_t<\/em>. Igal kimpude s\u00f5numil v\u00f5ib olla oma andmeplokk. Miks on kimbud vajalikud, arutame hiljem.<\/p>\n<p><\/p>\n<p>Nagu eelnevalt mainitud, ei sisalda s\u00f5num endas andmeplokki, vaid ainult viidet m\u00e4lupiirkonnale, kus andmeplokk on salvestatud. Selles osas sarnaneb meediastriimija t\u00f6\u00f6 p\u00f5hiliselt joonistamisfilmi \"Koletiste Korporatsioon\" uksehoidmisega, kus uksed (andmete lingid \u2014 toad) liiguvad hullumeelsel kiirusel rippuvatel konveieritel, samas kui toad endid j\u00e4\u00e4vad paigale. <\/p>\n<p><\/p>\n<p>N\u00fc\u00fcd, liikumine alt \u00fclesse, vaatame \u00fcksikasjalikult meediastreameris andmete edastamise mehhanismi elemente.<\/p>\n<p><\/p>\n<h3 id=\"blok--dannyh-dblk_t\">Andmeplokk <em>dblk_t<\/em><\/h3>\n<p><\/p>\n<p>Andmeplokk koosneb p\u00e4isest ja andmevahemikust. Pealkiri on kirjeldatud j\u00e4rgmise struktuuriga:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct datab\n{\nunsigned char *db_base; \/\/ N\u00e4idik andmevahemiku algusele.\nunsigned char *db_lim;  \/\/ N\u00e4idik andmevahemiku l\u00f5pule.\nvoid (*db_freefn)(void*); \/\/ M\u00e4lua vabastamise funktsioon ploki eemaldamisel.\nint db_ref; \/\/ Viidete loendur.\n} dblk_t;<\/code><\/pre>\n<p><\/p>\n<p>Struktuuri v\u00e4ljad sisaldavad n\u00e4idikuid andmevahemiku algusele, l\u00f5ppu, andmevahemiku vabastamisefunktsiooni. Viimane element pealkirjas <em>db_ref<\/em> \u2014 viidete loendur, ja kui see j\u00f5uab nulli, on see signaal andmeploki eemaldamiseks m\u00e4lust. Kui andmeplokk loodi funktsiooni <em>datab_alloc() <\/em>, siis paigutatakse andmevahemik m\u00e4llu vahetult p\u00e4rast pealkirja. K\u00f5igil muudel juhtudel v\u00f5ib andmevahemik paikneda kuskil eraldi. Andmevahemikus asuvad signaali n\u00e4idud v\u00f5i muud andmed, mida soovime filtritega t\u00f6\u00f6delda.<\/p>\n<p><\/p>\n<p>Uus andmeploki eksemplar luuakse j\u00e4rgnevaga:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">dblk_t *datab_alloc(int size);<\/code><\/pre>\n<p><\/p>\n<p>Sellele antakse sisendparameetrina andmete suurus, mida plokk hoiustab. M\u00e4lu eraldatakse rohkem, et alguses eraldatud m\u00e4lus asetada pealkiri \u2014 struktuur <em>datab<\/em>. Kuid teiste funktsioonide puhul ei toimu see alati, m\u00f5ningatel juhtudel v\u00f5ib andmevahemik asuda eraldi andmeplokist. Struktuuri v\u00e4ljad luuakse selliselt, et selle v\u00e4li <em>db_base<\/em> osutaks andmevahemiku algusele ja <em>db_lim<\/em> l\u00f5pule. Viidete loendur <em>db_ref<\/em> seatakse \u00fchte. Andmete puhastamise n\u00e4idik seatakse nullile.<\/p>\n<p><\/p>\n<h3 id=\"soobschenie-mblk_t\">Teade <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Nagu juba \u00f6eldud, on j\u00e4rjekorra elemendid t\u00fc\u00fcpi <em>mblk_t,<\/em> mille definirime j\u00e4rgmiselt:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct msgb\n{\n  struct msgb *b_prev;   \/\/ N\u00e4idik eelmisele loendi elemendile.\n  struct msgb *b_next;   \/\/ N\u00e4idik j\u00e4rgmisele loendi elemendile.\n  struct msgb *b_cont;   \/\/ N\u00e4idik teiste s\u00f5numite lisamisest s\u00f5numile, kimpude loomiseks.\n  struct datab *b_datap; \/\/ N\u00e4idik andmeploki struktuurile.\n  unsigned char *b_rptr; \/\/ N\u00e4idik andmevahemiku algusele b_datap andmete lugemiseks.\n  unsigned char *b_wptr; \/\/ N\u00e4idik andmevahemiku algusele b_datap andmete kirjutamiseks.\n  uint32_t reserved1;    \/\/ Reserveeritud v\u00e4li1, meediastreamer paneb sinna teenindusteabe.\n  uint32_t reserved2;    \/\/ Reserveeritud v\u00e4li2, meediastreamer paneb sinna teenindusteabe.\n  #if defined(ORTP_TIMESTAMP)\n  struct timeval timestamp;\n  #endif\n  ortp_recv_addr_t recv_addr;\n} mblk_t;<\/code><\/pre>\n<p><\/p>\n<p>Struktuur <em>mblk_t<\/em> alguses sisaldab n\u00e4idikud <em>b_prev<\/em>, <em>b_next<\/em>, mis on vajalikud kahekordse loendi korraldamiseks (millega on j\u00e4rjekord <em>queue_t<\/em>). <\/p>\n<p><\/p>\n<p>Seej\u00e4rel on n\u00e4idik <em>b_cont<\/em>, mis kasutatakse ainult siis, kui s\u00f5num kuulub kimpude. Viimase s\u00f5numi puhul kimpude j\u00e4\u00e4b see n\u00e4idik nulliks. <\/p>\n<p><\/p>\n<p>Edasi n\u00e4eme n\u00e4idiku andmeploki <em>b_datap<\/em>, mille, mille jaoks s\u00f5num eksisteerib. Selle j\u00e4rel on n\u00e4idikud andmebloki sisemisele andmepuhvrile. V\u00e4li <em>b_rptr<\/em> osutab kohale, kust andmeid loetakse puhvrisse. V\u00e4li <em>b_wptr<\/em> osutab kohale, kust andmeid kirjutatakse puhvrisse. <\/p>\n<p><\/p>\n<p>\u00dclej\u00e4\u00e4nud v\u00e4ljad on teenindava iseloomuga ja ei seondu andmete edastamise mehhanismiga.<\/p>\n<p><\/p>\n<p>Allpool on n\u00e4idatud \u00fchekordne s\u00f5num nimega <em>m1<\/em> ja andmeblokk <em>d1<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Uurime VoIP-mootorit Mediastreamer2. Osa 11\" src=\"\/wp-content\/uploads\/2020\/04\/e6a726b13491832258c1228f03bde802.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJ\u00e4rgmises joonises on kujutatud kolme s\u00f5numi kopleksi <em>m1<\/em>, <em>m1_1<\/em>, <em>m1_2<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Uurime VoIP-mootorit Mediastreamer2. Osa 11\" src=\"\/wp-content\/uploads\/2020\/04\/9613feefe9684b9551cd98115faa9a08.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-soobscheniyami--mblk_t\">S\u00f5numitega t\u00f6\u00f6tamise funktsioonid <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Uue s\u00f5numi <em>mblk_t<\/em> loob funktsioon:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *allocb(int size, int pri); <\/code><\/pre>\n<p><\/p>\n<p>see eraldab m\u00e4lus uue s\u00f5numi <em>mblk_t<\/em> n\u00e4idatud suurusega andmebloki. <em>size<\/em>Teine argument \u2014 <em>pri<\/em> ei kasutata arutatava versiooni raamatukogus. See peaks j\u00e4\u00e4ma nulliks. Funktsiooni t\u00f6\u00f6s eraldatakse m\u00e4lu uue s\u00f5numi struktuuri jaoks ja kutsutakse v\u00e4lja funktsioon <em>mblk_init()<\/em>, mis nullib loodud struktuuri k\u00f5ik v\u00e4ljad ja seej\u00e4rel, eelnevalt mainitud, loob andmepuhvri. Seej\u00e4rel seadistatakse struktuuri v\u00e4ljad: <em>datab_alloc()<\/em>mp-&gt;b_datap=datab;\nmp-&gt;b_rptr=mp-&gt;b_wptr=datab-&gt;db_base;\nmp-&gt;b_next=mp-&gt;b_prev=mp-&gt;b_cont=NULL; <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">Saame v\u00e4lja uue s\u00f5numi alginitseeritud v\u00e4ljadega ja t\u00fchja andmepuvriga. Andmete lisamiseks s\u00f5numisse tuleb need kopeerida andmebloki puhvrisse:<\/code><\/pre>\n<p><\/p>\n<p>memcpy(msg-&gt;b_rptr, data, size);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">\u2014 n\u00e4itaja andmeallikale, ja<\/code><\/pre>\n<p><\/p>\n<p>kus <em>data<\/em> \u2014 nende suurus. <em>size<\/em> j\u00e4rel tuleb uuendada kirjutamiskoha n\u00e4itajat, et see n\u00e4itaks j\u00e4lle vaba ala algusesse puhvrisse:<br \/>\nmsg-&gt;b_wptr = msg-&gt;b_wptr + size<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">Kui on vajalik luua s\u00f5num juba olemasolevast puhvrist, ilma kopeerimiseta, siis kasutatakse selleks funktsiooni:<\/code><\/pre>\n<p><\/p>\n<p>mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*));<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">Funktsioon p\u00e4rast s\u00f5numi ja andmeploki struktuuri loomist seadistab andmete n\u00e4itajad aadressile <\/code><\/pre>\n<p><\/p>\n<p>buf <em>. St. sel juhul andmepuvr ei asu andmeploki p\u00e4ise v\u00e4ljade taga, nagu see oli andmeploki loomisel funktsiooni abil<\/em>. Funktsioonile edastatud andmepuvr j\u00e4\u00e4b sinna, kus see oli, kuid n\u00e4itajate kaudu suunatakse see just loodud andmeploki p\u00e4isele, ja see vastavalt s\u00f5numile. <em>datab_alloc()<\/em>\u00dchele s\u00f5numile<\/p>\n<p><\/p>\n<p>v\u00f5ivad j\u00e4rjestikku kinnituda mitu andmeplokki. See toimub funktsiooni abil: <em>mblk_t<\/em> mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mp <\/code><\/pre>\n<p><\/p>\n<p><em>\u2014 s\u00f5num, millele lisatakse veel \u00fcks andmeplokk;<\/em> \u2014 n\u00e4itaja plokile, mille koopia lisatakse s\u00f5numisse;<br \/>\n<em>data<\/em> \u2014 andmete suurus;<br \/>\n<em>size<\/em> pad<br \/>\n<em>\u2014 lipp, et eraldatava m\u00e4lu suurus peaks olema joondatud 4-baidise piiri j\u00e4rgi (t\u00e4iendamine toimub nullidega).<\/em> Kui antud s\u00f5numi andmepuvrisse on piisavalt ruumi, siis uued andmed kinnitatakse seal juba olemasolevate andmete taha. Kui s\u00f5numi andmepuvrisse on ruumi v\u00e4hem kui <\/p>\n<p><\/p>\n<p>, luuakse uus s\u00f5num piisava suurusega puhvri jaoks ja andmed kopeeritakse selle puhvri sisse. See uus s\u00f5num kinnitatakse algsele l\u00e4bi n\u00e4itaja <em>size<\/em>. Sel juhul muutub s\u00f5num kopleksiks. <em>b_cont<\/em>Kui kopleksile on vaja lisada veel \u00fcks andmeplokk, siis tuleb kasutada funktsiooni: <\/p>\n<p><\/p>\n<p>void msgappend(mblk_t *mp, const char *data, int size, bool_t pad);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">see otsib kopleksi viimast s\u00f5numit (sel on<\/code><\/pre>\n<p><\/p>\n<p>oleb null) ja kutsub sellele s\u00f5numile v\u00e4lja funktsiooni <em>b_cont<\/em> appendb() <em>Andmete suuruse m\u00e4\u00e4ramine s\u00f5numis v\u00f5i kopleksis toimub funktsiooni abil:<\/em>.<\/p>\n<p><\/p>\n<p>int msgdsize(const mblk_t *mp);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">see l\u00e4bib k\u00f5ik kopleksi s\u00f5numid ja tagastab nende s\u00f5numite andmepuvirite kogusumma. Iga s\u00f5numi andmete maht arvutatakse j\u00e4rgmiselt:<\/code><\/pre>\n<p><\/p>\n<p>mp-&gt;b_wptr - mp-&gt;b_rptr<\/p>\n<p><\/p>\n<pre><code class=\"cpp\"> Kahte kopleksi \u00fchendamiseks kasutatakse funktsiooni:<\/code><\/pre>\n<p><\/p>\n<p>mblk_t *concatb(mblk_t *mp, mblk_t *newm);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">see lisab kopleksi<\/code><\/pre>\n<p><\/p>\n<p>newm <em>kopleksi l\u00f5ppu<\/em> ja tagastab n\u00e4itaja saadud kopleksi viimasele s\u00f5numile. <em>\u2014 s\u00f5num, millele lisatakse veel \u00fcks andmeplokk;<\/em> Vajadusel v\u00f5ib kopleksi muuta \u00fcheks s\u00f5numiks, millel on ainus andmeplokk, milleks on funktsioon:<\/p>\n<p><\/p>\n<p>void msgpullup(mblk_t *mp,int len);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">kui argument<\/code><\/pre>\n<p><\/p>\n<p>on -1, siis m\u00e4\u00e4ratakse andmepuhvri suurus automaatselt. Kui <em>len<\/em> on positiivne number, siis luuakse selle suurusega puhvri ja kopeeritakse kopleksi s\u00f5numite andmed. Kui puhv tasuta l\u00f5peb, siis kopeerimine peatub. Kopleksi esimene s\u00f5num saab uue suurusega puhvri kopeeritud andmetega. \u00dclej\u00e4\u00e4nud s\u00f5numid kaovad ja m\u00e4lu tagastatakse kuhja. <em>len<\/em> Struktuuri eemaldamisel<\/p>\n<p><\/p>\n<p>arvestatakse andmeploki viidete arvu, kui selle v\u00e4\u00e4rtus on v\u00e4ljundite kutsumise ajal <em>mblk_t<\/em> freeb() <em>on null, siis eemaldatakse andmepuhver koos struktuuriga, mis sellele viitab.<\/em> Uue s\u00f5numi v\u00e4ljade alginitseerimine: <em>mblk_t<\/em>void mblk_init(mblk_t *mp);<\/p>\n<p><\/p>\n<p>Andmete lisamine s\u00f5numisse veel \u00fche portion:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void mblk_init(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>S\u00f5numile lisatakse veel \u00fcks andmeosa: <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * appendb(mblk_t *mp, const char *data, size_t size, bool_t pad);<\/code><\/pre>\n<p><\/p>\n<p>Kui uued andmed ei mahu teate andmebufferisse, siis lisatakse teatele eraldi loodud s\u00f5num, millel on vajalik suurus. (esimeses s\u00f5numis seadistatakse n\u00e4itaja lisatud s\u00f5numile) s\u00f5num muutub tupiks.<\/p>\n<p><\/p>\n<p>Andmepartiis tupisse lisamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgappend(mblk_t *mp, const char *data, size_t size, bool_t pad); <\/code><\/pre>\n<p><\/p>\n<p>Funktsioon kutsub appendb() v\u00e4lja ts\u00fcklis.<\/p>\n<p><\/p>\n<p>Kahe tupiku \u00fchendamine \u00fcheks:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">see lisab kopleksi<\/code><\/pre>\n<p><\/p>\n<p>Teade <em>kopleksi l\u00f5ppu<\/em> lisatakse <em>\u2014 s\u00f5num, millele lisatakse veel \u00fcks andmeplokk;<\/em>.<\/p>\n<p><\/p>\n<p>\u00dche s\u00f5numi koopia loomine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copyb(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Terve tupiku koopia koos k\u00f5igi andmeblokidega:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copymsg(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Tupiku elemendid kopeeritakse funktsiooni <em>copyb()<\/em>.<\/p>\n<p><\/p>\n<p>Kerge s\u00f5numi koopia loomine <em>mblk_t<\/em>. Samal ajal andmeplokki ei kopeerita, vaid selle viidete arvu suurendatakse. <em>db_ref<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *dupb(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Kerge tupiku koopia loomine. Andmeblokke ei kopeerita, ainult nende viidete arvu suurendatakse. <em>db_ref<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *dupmsg(mblk_t* m);<\/code><\/pre>\n<p><\/p>\n<p>K\u00f5ikide tupiku s\u00f5numite liitmine \u00fcheks s\u00f5numiks:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgpullup(mblk_t *mp,size_t len);<\/code><\/pre>\n<p><\/p>\n<p>Kui argumendi <em>len<\/em> v\u00e4\u00e4rtus on -1, siis m\u00e4\u00e4ratakse eraldatud bufferi suurus automaatselt.<\/p>\n<p><\/p>\n<p>S\u00f5numi, tupiku eemaldamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void freemsg(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Andmeploki viidete arv v\u00e4heneb \u00fche v\u00f5rra. Kui see saavutab nulli, siis eemaldatakse ka andmeplokk.<\/p>\n<p><\/p>\n<p>Teate v\u00f5i tupiku andmete kogumahu arvestamine.<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">size_t msgdsize(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>S\u00f5numi v\u00e4ljav\u00f5tmine j\u00e4rjekorra sabast:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *ms_queue_peek_last (q);<\/code><\/pre>\n<p><\/p>\n<p>Teise s\u00f5numi reservitud v\u00e4ljade sisu kopeerimine teise s\u00f5numisse (t\u00f5epoolest sisaldavad need v\u00e4ljad m\u00e4rke, mida meediavoog kasutab):<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_meta_copy(const mblk_t *source, mblk *dest);<\/code><\/pre>\n<p><\/p>\n<h3 id=\"ochered-queue_t\">J\u00e4rjekord <em>queue_t<\/em><\/h3>\n<p><\/p>\n<p>Meediavoogude s\u00f5numite j\u00e4rjekord on rakendatud kui ringikujuline kahekordne lingitud loend. Iga loendi element sisaldab viidatud andmeplokki signaali n\u00e4itudega. Seega liiguvad j\u00e4rjekorras vaid viidatud andmeplokid, samas kui tegelikud andmed j\u00e4\u00e4vad liikumatuks. Ehkki liigutatakse ainult nende viiteid.<br \/>\nJ\u00e4rjekorra struktureerimine <em>queue_t<\/em>, nagu n\u00e4idatud allpool:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _queue\n{\n   mblk_t _q_stopper; \/* \"T\u00fchi\" j\u00e4rjekorraelement, mis ei viita andmetele, kasutatakse ainult j\u00e4rjekorra haldamiseks. J\u00e4rjekorra initsialiseerimisel (qinit()) seadistatakse selle viidate nii, et need viitavad tagasi iseendale. *\/\n   int q_mcount;        \/\/ Elementide arv j\u00e4rjekorras.\n} queue_t;<\/code><\/pre>\n<p><\/p>\n<p>Struktuur sisaldab v\u00e4lja - viidatud <em>_q_stopper<\/em> t\u00fc\u00fcpi *mblk_t, see viitab esimesele elemendile (s\u00f5num) j\u00e4rjekorras. Teine v\u00e4lja struktuuris on s\u00f5numite arv j\u00e4rjekorras.<br \/>\nAlloleval joonisel on j\u00e4rjekord nimega q1, mis sisaldab 4 s\u00f5numit m1,m2, m3, m4.<br \/>\n<img decoding=\"async\" alt=\"Uurime VoIP-mootorit Mediastreamer2. Osa 11\" src=\"\/wp-content\/uploads\/2020\/04\/07fc043861edf15e5eb40e49c8ec5e3e.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJ\u00e4rgmine joonis n\u00e4itab j\u00e4rjekorda nimega q1, mis sisaldab 4 s\u00f5numit m1,m2, m3, m4. S\u00f5num m2 on tupiku pea, kuhu viivad veel kaks s\u00f5numit m2_1 ja m2_2.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uurime VoIP-mootorit Mediastreamer2. Osa 11\" src=\"\/wp-content\/uploads\/2020\/04\/8fa7667f3690674a2ee321b4a6c39e1d.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-ocheredyami-queue_t\">J\u00e4rjekordadega t\u00f6\u00f6tamise funktsioonid queue_t<\/h3>\n<p><\/p>\n<p>J\u00e4rjekorra initsialiseerimine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void qinit(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>V\u00e4li <em>_q_stopper<\/em> (edaspidi nimetame seda \"peatumiseks\") initsialiseeritakse funktsiooni kaudu <em>mblk_init()<\/em>, mille eelmine element ja j\u00e4rgmine element seadistatakse nii, et nad viitavad iseendale. J\u00e4rjekorra elementide arvu loendit nullitakse.<\/p>\n<p><\/p>\n<p>Uue elementi (s\u00f5numi) lisamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void putq(queue_t *q, mblk_t *m);<\/code><\/pre>\n<p><\/p>\n<p>Uus element <em>m<\/em> lisatakse loendi l\u00f5ppu, elemendi n\u00e4itajad seadistatakse nii, et stopp muutub selle j\u00e4rgmiseks elemendiks ja tema eelmine element on stopp. J\u00e4rjekorra elementide arvu suurendatakse.<\/p>\n<p><\/p>\n<p>Elemendi v\u00e4lja t\u00f5mbamine j\u00e4rjekorrast:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * getq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>v\u00e4lja t\u00f5mmatakse see s\u00f5num, mis on stoppist j\u00e4rgmisel kohal, elemendi loendit v\u00e4hendatakse. Kui j\u00e4rjekorras pole muud elemente peale stoppi, siis tagastatakse 0.<\/p>\n<p><\/p>\n<p>S\u00f5numi j\u00e4rjekorras sisestamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void insq(queue_t *q, mblk_t *emp, mblk_t *mp); <\/code><\/pre>\n<p><\/p>\n<p>Element <em>\u2014 s\u00f5num, millele lisatakse veel \u00fcks andmeplokk;<\/em> sisestatakse elemendi <em>emp<\/em>. Kui <em>emp<\/em>=0, siis s\u00f5num lisatakse j\u00e4rjekorra sabasse.<\/p>\n<p><\/p>\n<p>S\u00f5numi eemaldamine j\u00e4rjekorra peast:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void remq(queue_t *q, mblk_t *mp); <\/code><\/pre>\n<p><\/p>\n<p>Elemendi loendit v\u00e4hendatakse.<\/p>\n<p><\/p>\n<p>Viidatud esimese elemendi lugemine j\u00e4rjekorras:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * peekq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>K\u00f5ikide elementide eemaldamine j\u00e4rjekorrast koos elementide enda eemaldamisega:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void flushq(queue_t *q, int how);<\/code><\/pre>\n<p><\/p>\n<p>Argument <em>how<\/em> ei kasutata. J\u00e4rjekorra elementide arvu seadistatakse nulli.<\/p>\n<p><\/p>\n<p>Makro viidatud viimase j\u00e4rjekorra elemendi lugemiseks:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * qlast(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>Teatestrateegiate t\u00f6\u00f6piirkondadega tuleb arvestada, et <em>ms_queue_put(q, m)<\/em> nullse n\u00e4itajaga s\u00f5numile kutse ts\u00fckeldub. Teie programm hangub. Sarnaselt k\u00e4itub <em>ms_queue_next(q, m)<\/em>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-filtrov\">Filtrite \u00fchendamine<\/h3>\n<p><\/p>\n<p>\u00dclaltoodud j\u00e4rjekorda kasutatakse s\u00f5numite edastamiseks \u00fchelt filtrilt teisele v\u00f5i \u00fchest mitmele filtrile. Filtrid ja nende \u00fchendused moodustavad suunatud graafi. Filtri sisenemist v\u00f5i v\u00e4ljumist nimetame \u00fcldiselt \"pinnaks\". Filtrite \u00fchenduste j\u00e4rjekorra kirjeldamiseks kasutatakse meediastriimijas m\u00f5istet \"signaalipunkt\". Signaalipunkt on struktuur <em>_MSCPoint<\/em>, mis sisaldab viidatud filtrit ja \u00fche selle pin-i numbrit, kirjeldades seega \u00fchendust \u00fche filtri sisendi v\u00f5i v\u00e4ljundi vahel. <\/p>\n<p><\/p>\n<h4 id=\"signalnaya-tochka-grafa-obrabotki-dannyh\">Andmete t\u00f6\u00f6tlemise graafi signaalpunkt<\/h4>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _MSCPoint{\nstruct _MSFilter *filter; \/\/ Viit filteri meediastrateegis.\nint pin;                        \/\/ \u00dche filtrisisendi v\u00f5i -v\u00e4ljundi number, s.t. pin.\n} MSCPoint;\n<\/code><\/pre>\n<p><\/p>\n<p>Filtrite pinnad nummerdatakse alates nullist. <\/p>\n<p><\/p>\n<p>Kahte pin-i s\u00f5numite j\u00e4rjekorraga \u00fchendust kirjeldab struktuur <em>_MSQueue<\/em>, mis sisaldab s\u00f5numite j\u00e4rjekorda ja viiteid kahe signaalpunkti vahel, mida see \u00fchendab:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _MSQueue\n{\nqueue_t q;\nMSCPoint prev;\nMSCPoint next;\n}MSQueue;\n<\/code><\/pre>\n<p><\/p>\n<p>Kutsume seda struktuuri signaallinkiks. Igal meediastrateegifiltril on sisend- ja v\u00e4ljundlinkide tabelid (<em>MSQueue<\/em>). Tabelite suurus m\u00e4\u00e4ratakse filtri loomisel, mida me juba tegime eksportimise abil, kasutades muutujat t\u00fc\u00fcbi <em>MSFilterDesc<\/em>, kui arendasime oma filtrit. Allpool on n\u00e4idatud struktuur, mis kirjeldab k\u00f5iki filtreid meediastrateegis, <em>MSFilter<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">\nstruct _MSFilter{\n    MSFilterDesc *desc;    \/* Viit filtri descriptor-ile. *\/\n    \/* Kaitstud atribuudid, neid ei tohi nihutada v\u00f5i eemaldada, muidu rikutakse pluginatega t\u00f6\u00f6tamist. *\/\n    ms_mutex_t lock;      \/* Semafor. *\/\n    MSQueue **inputs;     \/* Sisendlinkide tabel. *\/\n    MSQueue **outputs;    \/* V\u00e4ljundlinkide tabel. *\/\n    struct _MSFactory *factory; \/* Viit tehasele, mis l\u00f5i antud filtrieksampli. *\/\n    void *padding;              \/* Ei kasutata, kasutatakse \u00e4ra, kui kaitstud v\u00e4ljad on lisatud. *\/\n    void *data;                 \/* Viit suvalisele struktuurile filtri sisemise oleku ja vaheandmete salvestamiseks. *\/\n    struct _MSTicker *ticker;   \/* Viit ticker-erille, mis ei tohi olla null, kui kutsutakse funktsiooni process(). *\/\n    \/* eraatribuudid, neid saab viia ja muuta igal ajal *\/\n    MSList *notify_callbacks; \/* Tagasikutsumiste loend, mida kasutatakse filtri s\u00fcndmuste t\u00f6\u00f6tlemiseks. *\/\n    uint32_t last_tick;       \/* Viimane tehke number, kui viidi l\u00e4bi process() kutse. *\/ \n    MSFilterStats *stats;     \/* Filtri t\u00f6\u00f6statistika. *\/\n    int postponed_task; \/* Edasil\u00fckatud \u00fclesannete arv. M\u00f5ned filtrid v\u00f5ivad edasil\u00fckata andmete t\u00f6\u00f6tlemist (process() kutse) mitme taktiga. *\/\n    bool_t seen;  \/* Lipp, mida ticker kasutab selleks, et t\u00e4histada, et antud filtri eksemplar on juba teenindatud antud taktiga. *\/\n};\ntypedef struct _MSFilter MSFilter;\n<\/code><\/pre>\n<p><\/p>\n<p>P\u00e4rast seda, kui oleme C-programmis filtrid vastavalt meie kavandile kokku \u00fchendanud (aga tickerit ei \u00fchendanud), oleme loonud suunatud graafi, mille s\u00f5lmed on struktuuri eksemplarid <em>MSFilter<\/em>, ning servad on linkide eksemplarid. <em>MSQueue<\/em>. <\/p>\n<p><\/p>\n<h3 id=\"zakulisnaya-deyatelnost-tikera\">Tickere tagumine tegevus<\/h3>\n<p><\/p>\n<p>Kui \u00fctlesin teile, et ticker on taktiallikas, siis see ei olnud kogu t\u00f5de tema kohta. Ticker on objekt, mis k\u00e4itada k\u00f5iki filtreid protsesside (graafik) k\u00e4ivitavat funktsiooni <em>process()<\/em> k\u00f5igi filtritega, millega see on \u00fchendatud, graafis. Kui me C-programmis \u00fchendame tikri graafi filtriga, n\u00e4itame tikrile graafi, mida ta edaspidi haldab, kuni me selle eemaldame. \u00dchendamise j\u00e4rel hakkab tikker vaatama \u00fcle talle usaldatud graafi, koostades loetelu filtritest, mis sellesse kuuluvad. Et mitte \"loendada\" sama filtrit kaks korda, m\u00e4rgistab ta avastatud filtrid, seades neisse lipu <em>seen<\/em>. Otsing toimub iga filtri linkide tabelite kaudu. <\/p>\n<p><\/p>\n<p>Oma sissejuhatava ekskursiooni ajal graafis kontrollib ticker, kas filtrite seas on v\u00e4hemalt \u00fcks, mis t\u00e4idab andmeplokkide allika rolli. Kui selliseid ei leita, loetakse graaf vale ja ticker l\u00f5petab h\u00e4daolukorraga oma t\u00f6\u00f6.<\/p>\n<p><\/p>\n<p>Kui graaf osutub \"\u00f5igeks\", kutsutakse iga leidud filtri initsialiseerimiseks funktsioon <em>preprocess()<\/em>. Niipea kui saabub aeg j\u00e4rgmise t\u00f6\u00f6tlemise taktiks (vaikimisi iga 10 millisekundi j\u00e4rel), kutsub ticker v\u00e4lja funktsiooni <em>process()<\/em> k\u00f5igi eelnevalt leitud allikafiltrite jaoks ja seej\u00e4rel ka \u00fclej\u00e4\u00e4nud filtrile loendis. Kui filtril on sisendlinke, siis invokeeritakse funktsiooni <em>process()<\/em> kordub seni, kuni sisendlinkide j\u00e4rjekorrad on t\u00fchjad. P\u00e4rast seda liigub ta j\u00e4rgmise filtrini loendis ja \"p\u00f6\u00f6rab\" selle, et vabastada sisendlingid s\u00f5numitest. Tikker liigub filtrilt filtrile, kuni loetelu l\u00f5ppeb. Sellega l\u00f5ppeb takti t\u00f6\u00f6tlemine. <\/p>\n<p><\/p>\n<p>N\u00fc\u00fcd naaseme tuplede juurde ja r\u00e4\u00e4gime, miks selline entiteet on lisatud mediastreamerisse. \u00dcldiselt on andmemaht, mida algoritm, mis t\u00f6\u00f6tab filtri sees, vajab, erinev ega ole suhtega ning ei ole kordne sisenemise andmebufferite suurusega. N\u00e4iteks, kui kirjutame filtri, mis teostab kiiret Fourier' muundamist, siis see v\u00f5ib t\u00f6\u00f6delda ainult andmeplokke, mille suurus on 2 astmes. Olgu see 512 n\u00e4idist. Kui andmed genereeritakse telefonikanali kaudu, siis sisenemise igas s\u00f5numis andmebuffer toob meile 160 n\u00e4idist signaalist. On kiusatus mitte v\u00f5tta andmeid sisenemisest, kuni seal on vajalik hulk andmeid. Kuid sel juhul tekib konflikt ticker'iga, mis p\u00fc\u00fcab filtri t\u00fchjaks ajada. Varem m\u00e4rkasime seda reeglit filtrite kolmanda t\u00f6\u00f6printsiibina. Selle printsiibi kohaselt peab filtri process() funktsioon v\u00f5tma k\u00f5ik andmed sisenemise j\u00e4rjekordadest.<\/p>\n<p><\/p>\n<p>Lisaks ei saa sisenemisest v\u00f5tta lihtsalt 512 n\u00e4idist, kuna andmeid saab v\u00f5tta ainult t\u00e4istehnikas, st filter peab v\u00f5tma 640 n\u00e4idist ja kasutama neist 512, j\u00e4ttes \u00fclej\u00e4\u00e4nud uute andmepakkide kogunemiseks. Seega peab meie filter, lisaks oma peamisele t\u00f6\u00f6le, tagama abifunktsioonid sisenemise andmete vahepealseks s\u00e4ilitamiseks. Mediastreameri arendajad lahendasid selle \u00fcldise \u00fclesande jaoks spetsiaalse objekti \u2013 MSBufferizer (vahebuffer), mis lahendab selle \u00fclesande tuplede abil. <\/p>\n<p><\/p>\n<h3 id=\"buferizator-msbufferizer\">Vahem\u00e4lu (MSBufferizer)<\/h3>\n<p><\/p>\n<p>See on objekt, mis hakkab akumuleerima sisenemise andmeid filtri sees ja hakkab edastama neid t\u00f6\u00f6tlemiseks, kui teabe hulk on piisav filtri algoritmi k\u00e4ivitamiseks. Kui vahebuffer kogub andmeid, t\u00f6\u00f6tab filter t\u00fchja re\u017eiimis, raiskamata protsessori arvutusv\u00f5imet. Kuid niipea, kui lugemine vahebufferist tagastab v\u00e4\u00e4rtuse, mis pole null, hakkab filtri process() funktsioon v\u00f5tma ja t\u00f6\u00f6tlema vahebufferist andmeid vajalikus suuruses kuni nende l\u00f5puni.<br \/>\nKasuta k\u00e4sitletud andmed j\u00e4\u00e4vad vahebufferisse kui esimene element tuple'ist, millele liituvad j\u00e4rgmised sisenemisandmete plokid. <\/p>\n<p><\/p>\n<p>Struktuur, mis kirjeldab vahebufferit: <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">struct _MSBufferizer{\nqueue_t q; \/* S\u00f5numite j\u00e4rjekord. *\/\nint size; \/* Vahebufferis olevate andmete kogus hetkel. *\/\n};\ntypedef struct _MSBufferizer MSBufferizer;<\/code><\/pre>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-msbufferizer\">MSBufferizeri t\u00f6\u00f6tamise funktsioonid<\/h3>\n<p><\/p>\n<p>Uue vahebufferi eksemplari loomine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">MSBufferizer * ms_bufferizer_new(void);<\/code><\/pre>\n<p><\/p>\n<p>M\u00e4lu eraldatakse, initsialiseeritakse <em>ms_bufferizer_init()<\/em> ja tagastatakse viide.<\/p>\n<p><\/p>\n<p>Initsialiseerimise funktsioon:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_init(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Initsialiseeritakse j\u00e4rjekord <em>q<\/em>, v\u00e4li <em>size<\/em> seatakse nulliks.<\/p>\n<p><\/p>\n<p>S\u00f5numi lisamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m); <\/code><\/pre>\n<p><\/p>\n<p>S\u00f5num m lisatakse j\u00e4rjekorda. Arvutatud andmeplokkide suurus liidetakse <em>size<\/em>.<\/p>\n<p><\/p>\n<p>T\u00f5lge vahebufferisse k\u00f5igist s\u00f5numitest, mis on andmej\u00e4rjekorras <em>q<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q);   <\/code><\/pre>\n<p><\/p>\n<p>S\u00f5numite edasiviimine andmej\u00e4rjekorrast <em>q<\/em> vahebufferisse toimub funktsiooni kaudu <em>ms_bufferizer_put()<\/em>.<\/p>\n<p><\/p>\n<p>Lugemine vahebufferist:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen); <\/code><\/pre>\n<p><\/p>\n<p>Kui kogus vahebufferis olevatest andmetest on v\u00e4iksem kui n\u00f5utud (<em>datalen<\/em>), tagastab funktsioon nulli, andmete kopeerimine data'i ei toimu. Vastupidisel juhul toimub j\u00e4rjestikune andmete kopeerimine vahebufferis olevatest tuple'idest. P\u00e4rast kopeerimist tuple eemaldatakse ja m\u00e4lu vabastatakse. Kopeerimine l\u00f5ppeb hetkel, kui kopeeritakse datalen baitide suurus. Kui koht l\u00f5peb andmeploki keskel, siis.antud s\u00f5numis v\u00e4hendatakse andmeploki suurust allesj\u00e4\u00e4nud kopeerimata osale. J\u00e4rgmise kutsumise korral j\u00e4tkub kopeerimine sealt.<\/p>\n<p><\/p>\n<p>Andmete lugemine, mis on hetkel vahebufferis saadaval:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int ms_bufferizer_get_avail(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Tagastab vahebufferi. <em>size<\/em> Andmete osa ignoreerimine, mis asub vahebufferis:<\/p>\n<p><\/p>\n<p>void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">M\u00e4\u00e4ratud andmebaite kogus eemaldatakse ja k\u00f5rvaldatakse. Eemaldatakse vanimad andmed.<\/code><\/pre>\n<p><\/p>\n<p>K\u00f5igi vahebufferis olevate s\u00f5numite eemaldamine:<\/p>\n<p><\/p>\n<p>void ms_bufferizer_flush(MSBufferizer *obj);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">Andmete loendurit nullitakse. <\/code><\/pre>\n<p><\/p>\n<p>void ms_bufferizer_uninit(MSBufferizer *obj);<\/p>\n<p><\/p>\n<p>void ms_bufferizer_flush(MSBufferizer *obj);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">Loenduri nullimine ei toimu. <\/code><\/pre>\n<p><\/p>\n<p>Vahebufferi eemaldamine ja m\u00e4lukaartide vabastamine:<\/p>\n<p><\/p>\n<p>void ms_bufferizer_destroy(MSBufferizer *obj);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">N\u00e4iteid vahebufferi kasutamisest v\u00f5ib leida mitme mediastreameri filtri allikakoodist. N\u00e4iteks filter MS_L16_ENC, mis teostab baitide aubristikul j\u00e4rgset \u00fcmberpaigutust, saates neid v\u00f5rgukorra k\u00e4tte:  <\/code><\/pre>\n<p><\/p>\n<p>l16.c<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/BelledonneCommunications\/mediastreamer2\/blob\/1a9e8dec369a65ed10db975f5b77b92dc999b096\/src\/audiofilters\/l16.c\"> l16.c<\/a><\/noindex><\/p>\n<p><\/p>\n<p>J\u00e4rgmises artiklis k\u00e4sitleme koormuse hindamist tikkeril ja viise \u00fcleliigse arvutuskoormuse v\u00e4hendamiseks meediastreameris.<\/p>\n<p>Allikas: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/499010\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430. \u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0411\u043b\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 dblk_t \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 mblk_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 mblk_t \u041e\u0447\u0435\u0440\u0435\u0434\u044c queue_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u044f\u043c\u0438 queue_t \u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0421\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0433\u0440\u0430\u0444\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0417\u0430\u043a\u0443\u043b\u0438\u0441\u043d\u0430\u044f \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0438\u043a\u0435\u0440\u0430 \u0411\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0442\u043e\u0440 (MSBufferizer) \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 MSBufferizer \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440. \u042d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u044b \u043f\u043e\u0441\u0432\u0435\u0442\u0438\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79541,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79540","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430. \u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0411\u043b\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 dblk_t \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 mblk_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 mblk_t \u041e\u0447\u0435\u0440\u0435\u0434\u044c queue_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u044f\u043c\u0438 queue_t \u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0421\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0433\u0440\u0430\u0444\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0417\u0430\u043a\u0443\u043b\u0438\u0441\u043d\u0430\u044f \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0438\u043a\u0435\u0440\u0430 \u0411\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0442\u043e\u0440 (MSBufferizer) \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 MSBufferizer \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440. \u042d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u044b \u043f\u043e\u0441\u0432\u0435\u0442\u0438\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0418\u0437\u0443\u0447\u0430\u0435\u043c VoIP-\u0434\u0432\u0438\u0436\u043e\u043a Mediastreamer2. \u0427\u0430\u0441\u0442\u044c 11 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430. \u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0411\u043b\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 dblk_t \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 mblk_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 mblk_t \u041e\u0447\u0435\u0440\u0435\u0434\u044c queue_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u044f\u043c\u0438 queue_t \u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0421\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0433\u0440\u0430\u0444\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0417\u0430\u043a\u0443\u043b\u0438\u0441\u043d\u0430\u044f \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0438\u043a\u0435\u0440\u0430 \u0411\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0442\u043e\u0440 (MSBufferizer) \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 MSBufferizer \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440. \u042d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u044b \u043f\u043e\u0441\u0432\u0435\u0442\u0438\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-04-28T05:42:01+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-04-28T05:42:01+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Uurime VoIP mootorit Mediastreamer2. Osa 11 | ProHoster","description":"Artikli materjal on v\u00f5etud minu Dzen-kanalist. Andmete edastamise mehhanism Block andmed dblk_t S\u00f5num mblk_t S\u00f5numitega t\u00f6\u00f6tamise funktsioonid mblk_t Ootej\u00e4rjekord queue_t Ootej\u00e4rjekordadega t\u00f6\u00f6tamise funktsioonid queue_t Filtreerimise \u00fchendamine Andmete t\u00f6\u00f6tlemisse graafi signaalpunkt Tikkri tagantpoolne tegevus Puhver (MSBufferizer) Funktsioonid MSBufferizeriga t\u00f6\u00f6tamiseks Eelmises artiklis l\u00f5ime oma filtri. Selles artiklis keskendume seadistusele.","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0418\u0437\u0443\u0447\u0430\u0435\u043c VoIP-\u0434\u0432\u0438\u0436\u043e\u043a Mediastreamer2. \u0427\u0430\u0441\u0442\u044c 11 | ProHoster","og:description":"\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430. \u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0411\u043b\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 dblk_t \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 mblk_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 mblk_t \u041e\u0447\u0435\u0440\u0435\u0434\u044c queue_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u044f\u043c\u0438 queue_t \u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0421\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0433\u0440\u0430\u0444\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0417\u0430\u043a\u0443\u043b\u0438\u0441\u043d\u0430\u044f \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0438\u043a\u0435\u0440\u0430 \u0411\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0442\u043e\u0440 (MSBufferizer) \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 MSBufferizer \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440. \u042d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u044b \u043f\u043e\u0441\u0432\u0435\u0442\u0438\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443","og:url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-04-28T05:42:01+00:00","article:modified_time":"2020-04-28T05:42:01+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79540","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 12:40:33","updated":"2022-10-06 16:26:59"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/79540","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=79540"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/79540\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media\/79541"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=79540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=79540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=79540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}