{"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 materjal on saadud minu <noindex><a rel=\"nofollow\" href=\"https:\/\/zen.yandex.ru\/profile\/editor\/id\/5e3f8e0751f5346faab4fc7a\">Dzen-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 \u00fclekande mehhanism<\/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>Filterite \u00fchendamine<\/li>\n<li>Signaalipunkt andmeprotsessi graafikus<\/li>\n<li>Tickere kulisside tegevus<\/li>\n<li>M\u00e4buffer (MSBufferizer)<\/li>\n<li>MSBufferizeriga t\u00f6\u00f6tamise funktsioonid<\/li>\n<\/ul>\n<p><\/p>\n<p>Eelmisel <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/497932\/\">artiklis<\/a><\/noindex> Oleme arendanud oma filtri. Selle artikli p\u00fchendame meedia edastusfiltrite vaheliste andmete \u00fclekande sisemiste mehhanismide seadmele. See v\u00f5imaldab tulevikus kirjutada keerukaid filtreid v\u00e4iksema vaevaga.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"mehanizm-peremescheniya-dannyh\">Andmete \u00fclekande mehhanism<\/h2>\n<p><\/p>\n<p>Andmete \u00fclekande protsess meedia edastusfiltris toimub j\u00e4rjekordade abil, mille struktuuri kirjeldatakse <em>queue_t<\/em>. J\u00e4rjekordades liigutatakse s\u00f5numite jadad, mis on t\u00fc\u00fcbi <em>mblk_t<\/em>, mis ise ei sisaldanud signaalide andmeid, vaid ainult viite eelnenud ja j\u00e4rgmise s\u00f5numi ja andmeploki juurde. Lisaks tahan eraldi r\u00f5hutada, et on olemas ka v\u00e4li sama t\u00fc\u00fcpi s\u00f5numite viitamiseks, mis v\u00f5imaldab korraldada seotud s\u00f5numite nimekirja. Kogumit s\u00f5numeid, mis on sellesse nimekirja koondunud, nimetame tupleks. Seega v\u00f5ib iga elemendi j\u00e4rjekorras olla kas \u00fcksik s\u00f5num <em>mblk_t<\/em>, v\u00f5i tuple s\u00f5numite pea <em>mblk_t<\/em>. Igal tuple s\u00f5numil v\u00f5ib olla oma seotud andmeplokk. Miks me vajame tupleid, arutame veidi hiljem.<\/p>\n<p><\/p>\n<p>Nagu eespool mainitud, ei sisalda s\u00f5num iseenesest andmeplokki, vaid sisaldab ainult viidet m\u00e4lupiirkonnale, kus andmeplokk asub. Selles osas meenutab meediumivoogude t\u00f6\u00f6 \u00fcldine pilt multfilmi \"Koletiste \u00dching\" ustega ladu, kus uksed (andmeviidud - toad) liiguvad hullumeelse kiirusel rippuvatest konveieritest, samal ajal kui toad ise j\u00e4\u00e4vad paigale. <\/p>\n<p><\/p>\n<p>N\u00fc\u00fcd, liikudes hierarhias alt \u00fcles, vaatame l\u00e4hemalt andmete edastamise mehhanismis loetletud \u00fcksusi meedia edastusfiltris.<\/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 andmebufferist. Pealkiri m\u00e4\u00e4ratletakse j\u00e4rgmise struktuuri abil,<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct datab\n{\nunsigned char *db_base; \/\/ Viidatud andmebufferi algus.\nunsigned char *db_lim;  \/\/ Viidatud andmebufferi l\u00f5pp.\nvoid (*db_freefn)(void*); \/\/ Funktsioon m\u00e4lu vabastamiseks ploki kustutamisel.\nint db_ref; \/\/ Viidete loendur.\n} dblk_t;<\/code><\/pre>\n<p><\/p>\n<p>Struktuuri valdkonnad sisaldavad viiteid puut\u00f6\u00f6 algusele, puut\u00f6\u00f6 l\u00f5ppule ja andmete puhastamise funktsiooni. Peamine element on pealkirjas <em>db_ref<\/em> \u2014 viidete loendur, kui see j\u00f5uab nullini, on see signaal, et see plokk tuleks m\u00e4lust eemaldada. Kui andmeplokk loodi funktsiooni <em>datab_alloc() <\/em>, siis andmepuhver paigutatakse m\u00e4llu kohe pealkirja j\u00e4rele. K\u00f5igil muudel juhtudel v\u00f5ib puhver asuda kuskil eraldi. Andmepuhvrisse paigutatakse signaali andmed v\u00f5i muud andmed, mida soovime filtreerimisega t\u00f6\u00f6delda.<\/p>\n<p><\/p>\n<p>Uus andmeploki eksemplar luuakse funktsiooni abil:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">dblk_t *datab_alloc(int size);<\/code><\/pre>\n<p><\/p>\n<p>Sisendparameetrina edastatakse sellele andmete suurus, mida plokk talletab. M\u00e4lu eraldatakse rohkem, et eraldatud m\u00e4lu algusesse paigutada pealkiri \u2014 struktuur <em>datab<\/em>. Kuid teiste funktsioonide kasutamisel ei pruugi see alati nii olla, m\u00f5nel juhul v\u00f5ib andmepuhver asuda eraldi andmeploki pealkirjast. Struktuuri v\u00e4ljad seadistatakse loomisel nii, et tema v\u00e4li <em>db_base<\/em> osutaks andmeala algusele ja <em>db_lim<\/em> tema l\u00f5ppu. Viidete loendur <em>db_ref<\/em> seatakse \u00fchele. Andmete puhastamise funktsiooni viidatakse nulli.<\/p>\n<p><\/p>\n<h3 id=\"soobschenie-mblk_t\">Teade <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Nagu \u00f6eldud, j\u00e4rjekorra elemendid on t\u00fc\u00fcpi <em>mblk_t,<\/em> see on m\u00e4\u00e4ratletud j\u00e4rgmiselt:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct msgb\n{\n  struct msgb *b_prev;   \/\/ Viidatud eelmine elemendi nimekiri.\n  struct msgb *b_next;   \/\/ Viidatud j\u00e4rgmine elemendi nimekiri.\n  struct msgb *b_cont;   \/\/ Viidatud, et kleepida teistele s\u00f5numitele, et luua s\u00f5numite kombinatsioon.\n  struct datab *b_datap; \/\/ Viidatud andmeploki struktuurile.\n  unsigned char *b_rptr; \/\/ Viidatud andmeala algusele andmete lugemiseks b_datap puhvrist.\n  unsigned char *b_wptr; \/\/ Viidatud andmeala algusele andmete salvestamiseks b_datap puhvrist.\n  uint32_t reserved1;    \/\/ Reserveeritud v\u00e4li1, meedia voogedastaja paigutab sinna teenuseinformatsiooni. \n  uint32_t reserved2;    \/\/ Reserveeritud v\u00e4li2, meedia voogedastaja paigutab sinna teenuseinformatsiooni.\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 viidatud <em>b_prev<\/em>, <em>b_next<\/em>, mis on vajalikud kahekordse lingi loomiseks (milleks on j\u00e4rjekord <em>queue_t<\/em>). <\/p>\n<p><\/p>\n<p>Seej\u00e4rel tuleb viidatud <em>b_cont<\/em>, mis seda kasutatakse ainult siis, kui s\u00f5num siseneb tuplesse. Viimase s\u00f5numi jaoks tuples j\u00e4\u00e4b viitamine nulliks. <\/p>\n<p><\/p>\n<p>J\u00e4rgmisena n\u00e4eme viidet andmeblokkile <em>b_datap<\/em>, mille t\u00f5ttu ja eksisteerib s\u00f5num. Selle j\u00e4rel tulevad viidatud blokkide andmebufferi sees. V\u00e4lja <em>b_rptr<\/em> n\u00e4itab kohta, kust andmed luetakse bufferist. V\u00e4lja <em>b_wptr<\/em> n\u00e4itab kohta, kust andmed kirjutatakse bufferisse. <\/p>\n<p><\/p>\n<p>\u00dclej\u00e4\u00e4nud v\u00e4ljad on teenuslikud ja ei seostu andmete edastamise mehhanismi toimingutega.<\/p>\n<p><\/p>\n<p>Allpool on n\u00e4idatud \u00fcksik 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 tupliku <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\u00f5numite t\u00f6\u00f6tlemise funktsioonid <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Uus s\u00f5num <em>mblk_t<\/em> loodakse funktsiooni abil:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *allocb(int size, int pri); <\/code><\/pre>\n<p><\/p>\n<p>see allotab m\u00e4lus uue s\u00f5numi <em>mblk_t<\/em> mooduliga, mille andmeblokki suurus on <em>size<\/em>, teine argument \u2014 <em>pri<\/em> ei kasutata antud teegi versioonis. See peab j\u00e4\u00e4ma nulliks. Funktsiooni t\u00f6\u00f6 k\u00e4igus eraldatakse m\u00e4lu uue s\u00f5numi struktuuri jaoks ja kutsutakse v\u00e4lja funktsioon <em>mblk_init()<\/em>, mis nullib k\u00f5ik loodud struktuuri v\u00e4ljad ja seej\u00e4rel, kasutades eelpool mainitud, <em>datab_alloc()<\/em>loob andmebufferi. P\u00e4rast seda seadistatakse v\u00e4ljad struktuuris: <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">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;<\/code><\/pre>\n<p><\/p>\n<p>V\u00e4ljundina saame uue s\u00f5numi initsialiseeritud v\u00e4ljade ja t\u00fchja andmebufferiga. Andmete lisamiseks s\u00f5numisse tuleb nad kopeerida andmebloki bufferisse:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">memcpy(msg-&gt;b_rptr, data, size);<\/code><\/pre>\n<p><\/p>\n<p>kus <em>data<\/em> \u2014 viit andmeallikale, ja <em>size<\/em> \u2014 nende suurus.<br \/>\nsiis tuleb uuendada kirjutamise viit, et see osutaks taas vaba ala algusele bufferis:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">msg-&gt;b_wptr = msg-&gt;b_wptr + size<\/code><\/pre>\n<p><\/p>\n<p>Kui on vaja luua s\u00f5num juba olemasolevast bufferist, ilma kopeerimiseta, siis selleks kasutatakse funktsiooni:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*)); <\/code><\/pre>\n<p><\/p>\n<p>Funktsioon seadistab p\u00e4rast s\u00f5numi ja andmebloki struktuuri loomist selle viidete andmed aadressil <em>buf<\/em>. St. sel juhul ei asu andmebuffer headeri v\u00e4ljade j\u00e4rel, nagu see oli andmebloki loomisel funktsiooni abil. <em>datab_alloc()<\/em>K\u00e4ivitatud funktsioonile edastatud andmepuhver j\u00e4\u00e4b sinna, kus ta oli, kuid n\u00e4idikute abil suunatakse see just loodud andmeploki p\u00e4isele, mis omakorda suunatakse s\u00f5numile.<\/p>\n<p><\/p>\n<p>\u00dche s\u00f5numiga <em>mblk_t<\/em> v\u00f5ib j\u00e4rjestikku liita mitu andmeplokki. Seda teeb funktsioon:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad); <\/code><\/pre>\n<p><\/p>\n<p><em>mp<\/em> \u2014 s\u00f5num, millele lisatakse veel \u00fcks andmeplokk;<br \/>\n<em>data<\/em> \u2014 n\u00e4idik plokile, mille koopia lisatakse s\u00f5numisse;<br \/>\n<em>size<\/em> \u2014 andmete suurus;<br \/>\n<em>pad<\/em> \u2014 lipp, et m\u00e4\u00e4ratud m\u00e4luruumi suurus peaks olema jagatav 4 baidi piiriga (t\u00e4iendamine toimub nullidega). <\/p>\n<p><\/p>\n<p>Kui olemasolevas s\u00f5numi andmepuhveres on piisavalt ruumi, siis uued andmed liidetakse seal juba olevatele andmetele. Kui s\u00f5numi andmepuvris on v\u00e4hem ruumi kui <em>size<\/em>, siis luuakse uus s\u00f5num, millel on piisava suurusega puhver ja andmed kopeeritakse selle puhpvrisse. See uus s\u00f5num kinnitatakse algsega n\u00e4idiku abil <em>b_cont<\/em>. Sel juhul muutub s\u00f5num tupleks. <\/p>\n<p><\/p>\n<p>Kui tuplekusse tuleb lisada veel \u00fcks andmeplokk, tuleb kasutada funktsiooni:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgappend(mblk_t *mp, const char *data, int size, bool_t pad);<\/code><\/pre>\n<p><\/p>\n<p>see leiab tuple l\u00f5pus oleva viimase s\u00f5numi (tal <em>b_cont<\/em> on null) ja kutsub selle s\u00f5numi jaoks v\u00e4lja funktsiooni <em>appendb()<\/em>.<\/p>\n<p><\/p>\n<p>Andmete suurust s\u00f5numis v\u00f5i tupleksis saab teada funktsiooni abil:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int msgdsize(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>see l\u00e4bib k\u00f5ik tuple s\u00f5numid ja tagastab andmete koguhulga nende s\u00f5numite andmepuvrites. Iga s\u00f5numi andmete hulga arvutamine toimub nii:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\"> mp-&gt;b_wptr - mp-&gt;b_rptr<\/code><\/pre>\n<p><\/p>\n<p>Kaks tuplekust \u00fchendamiseks kasutatakse funktsiooni:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *concatb(mblk_t *mp, mblk_t *newm);<\/code><\/pre>\n<p><\/p>\n<p>see liidab tuple <em>newm<\/em> tuple l\u00f5ppu <em>mp<\/em> ja tagastab n\u00e4idiku saadud tuple viimasele s\u00f5numile.<\/p>\n<p><\/p>\n<p>Kui on vajalik, v\u00f5ib tuple muundada \u00fcheks s\u00f5numiks \u00fche andmeplokiga, seda teeb funktsioon:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgpullup(mblk_t *mp,int len);<\/code><\/pre>\n<p><\/p>\n<p>kui argument <em>len<\/em> on -1, siis m\u00e4\u00e4ratakse eraldatud puhvri suurus automaatselt. Kui <em>len<\/em> Kui see on positiivne number, luuakse selle suuruse puhver ja sinna kopeeritakse s\u00f5numite tupikandja andmed. Kui puhver t\u00e4itub, siis kopeerimine l\u00f5petatakse. Esimene tupikus\u00f5num saab uue suurusega puhvri koos kopeeritud andmetega. \u00dclej\u00e4\u00e4nud s\u00f5numid kustutatakse ja m\u00e4lu tagastatakse kuhja.<\/p>\n<p><\/p>\n<p>Struktuuri eemaldamisel <em>mblk_t<\/em> arvestatakse andmeploki viidete loendit, kui kutse ajal <em>freeb()<\/em> on see null, siis andmepuhver eemaldatakse koos eksemplariga <em>mblk_t<\/em>, millele see viitab.<\/p>\n<p><\/p>\n<p>Uue s\u00f5numi v\u00e4ljade initsialiseerimine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void mblk_init(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Andmete lisamine s\u00f5numile: <\/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 s\u00f5numi andmepuhvri vabasse ruumi, lisatakse s\u00f5numile eraldi loodud s\u00f5num soovitud suurusega puhvri jaoks (esimeses s\u00f5numis m\u00e4\u00e4ratakse viit lisatud s\u00f5numile) ja s\u00f5num muutub tupikuks.<\/p>\n<p><\/p>\n<p>Andmete lisamine tupikusse:<\/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() ts\u00fcklis.<\/p>\n<p><\/p>\n<p>Kahte tupikut liitmine \u00fcheks:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *concatb(mblk_t *mp, mblk_t *newm);<\/code><\/pre>\n<p><\/p>\n<p>Teade <em>newm<\/em> seda lisatakse <em>mp<\/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 t\u00e4ielik kopeerimine koos k\u00f5ikide andmeplokkidega:<\/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 koopia loomine s\u00f5numist. <em>mblk_t<\/em>Siinjuures andmeplokk ei kopeerita, vaid selle viidete loend suurendab. <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 koopia loomine tupikust. Andmeplokke ei kopeerita, ainult nende viidete loendid suurenevad. <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 argument <em>len<\/em> on -1, siis m\u00e4\u00e4ratakse puhvri 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 loend v\u00e4heneb \u00fche v\u00f5rra. Kui see saavutab nulli, eemaldatakse ka andmeplokk.<\/p>\n<p><\/p>\n<p>S\u00f5numi v\u00f5i tupiku andmemahtude koguse arvutamine.<\/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 eemaldamine rea sabast:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *ms_queue_peek_last (q);<\/code><\/pre>\n<p><\/p>\n<p>\u00dche s\u00f5numi reserveeritud v\u00e4ljade sisu kopeerimine teise s\u00f5numisse (neis v\u00e4ljad on t\u00f5eliselt lipud, mida meediavooluote 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>S\u00f5numite j\u00e4rjekord meediastreamer'is on teostatud kui ringikujuline kahekordne seotud loend. Iga loendi element sisaldab n\u00e4idikut andm blokkide kohta signaali n\u00e4idudega. Tulemuseks on see, et liigutatakse ainult viiteid andm blokkidele, samas kui andmed j\u00e4\u00e4vad liikumatuks. St. liiguvad ainult viidatud.<br \/>\nJ\u00e4rjekorra struktuur <em>queue_t<\/em>, on toodud allpool:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _queue\n{\n   mblk_t _q_stopper; \/* \"T\u00fchi\" j\u00e4rjekorra element, ei osuta andmetele, kasutatakse ainult j\u00e4rjekorra juhtimiseks. J\u00e4rjekorra (qinit()) initsialiseerimisel seadistatakse selle viidud nii, et need osutaksid sellele endale. *\/\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\u00fcbist *mblk_t, mis osutab esimesele elemendile (s\u00f5numile) j\u00e4rjekorras. Struktuuri teine v\u00e4li on s\u00f5numite loendur, mis asub j\u00e4rjekorras.<br \/>\nAlloleval joonisel on kujutatud 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\u00e4rgmises joonises on kujutatud j\u00e4rjekord nimega q1, mis sisaldab 4 s\u00f5numit m1, m2, m3, m4. S\u00f5num m2 on paarituse pea, kuhu sisenevad 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 algatamine:<\/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 nimeta seda \"stopperiks\") initsialiseeritakse funktsiooniga <em>mblk_init()<\/em>, tema eelmine ja j\u00e4rgmine elemendi viidatud seadistatakse nii, et nad osutavad sellele endale. J\u00e4rjekorra elementide loendur nullitakse.<\/p>\n<p><\/p>\n<p>Uue elemendi (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 viidatud seadistatakse nii, et peatus muutub selle j\u00e4rgneks elemendiks ja tema jaoks peatus eelneks. J\u00e4rjekorra elementide loendurit suurendatakse.<\/p>\n<p><\/p>\n<p>Elemendi eemaldamine j\u00e4rjekorrast:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * getq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>eemaldatakse see s\u00f5num, mis on peatusest j\u00e4rgmine, j\u00e4rjekorra elementide loendurit v\u00e4hendatakse. Kui j\u00e4rjekorras, peale peatuse, elemente pole, tagastatakse 0.<\/p>\n<p><\/p>\n<p>S\u00f5numi sisestamine j\u00e4rjekorda:<\/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>mp<\/em> sisestatakse enne elementi <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>Elementide loendurit v\u00e4hendatakse.<\/p>\n<p><\/p>\n<p>Viidatud esimesele elemendile 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\u00fcsimise k\u00f5ikide elementide eemaldamine j\u00e4rjekorrast koos elementide eemaldamisega:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void flushq(queue_t *q, int how);<\/code><\/pre>\n<p><\/p>\n<p>Argumendiks <em>how<\/em> ei kasutata. Ooteelemendi arv loenduri seadistamine toimub nulli.<\/p>\n<p><\/p>\n<p>Makro lugemisn\u00e4itaja viimase ooteelemendi jaoks:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * qlast(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>Kasutades s\u00f5numi j\u00e4rjekordi, tuleb meeles pidada, et kutsudes <em>ms_queue_put(q, m)<\/em> nulln\u00e4idikuga s\u00f5numile, sumbub funktsioon. Teie programm hangub. Samuti k\u00e4itub <em>ms_queue_next(q, m)<\/em>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-filtrov\">Filterite \u00fchendamine<\/h3>\n<p><\/p>\n<p>\u00dclaltoodud j\u00e4rjekorda kasutatakse s\u00f5numite edastamiseks \u00fche filtrilt teise filtrile v\u00f5i \u00fchelt mitmele filtrile. Filtrid ja nende \u00fchendused omavahel moodustavad suunatud graafi. Filtri sisendit v\u00f5i v\u00e4ljundit nimetame \u00fcldistavalt \"pinnaks\". Filtrite omavahelise \u00fchendamise j\u00e4rjekorra kirjeldamiseks kasutatakse meediumivoogudes m\u00f5istet \"signaalpunkt\". Signaalpunkt on struktuur <em>_MSCPoint<\/em>, mis sisaldab n\u00e4idikut filtrile ja numbri \u00fche oma pin'ist, seega kirjeldab see \u00fche filtri sisendi v\u00f5i v\u00e4ljundi \u00fchendust. <\/p>\n<p><\/p>\n<h4 id=\"signalnaya-tochka-grafa-obrabotki-dannyh\">Signaalipunkt andmeprotsessi graafikus<\/h4>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _MSCPoint{\nstruct _MSFilter *filter; \/\/ N\u00e4idik meediastreameri filtrile.\nint pin;                        \/\/ \u00dche filtri sisendi v\u00f5i v\u00e4ljundi number, st pin.\n} MSCPoint;\n<\/code><\/pre>\n<p><\/p>\n<p>Filtri pins on nummerdatud alates nullist. <\/p>\n<p><\/p>\n<p>Kahte pinni \u00fchendav s\u00f5numij\u00e4rjekord on kirjeldatud struktuuris <em>_MSQueue<\/em>, mis sisaldab s\u00f5numij\u00e4rjekorda ja n\u00e4idikuid 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 signaallingiks. Igal meediastreameri filtril on sisendi linkide tabel ja v\u00e4ljundi linkide tabel (<em>MSQueue<\/em>). Tabelite suurus m\u00e4\u00e4ratakse filtri loomisel, seda oleme juba teinud eksporditud muutuja t\u00fc\u00fcbi abil <em>MSFilterDesc<\/em>, kui t\u00f6\u00f6tasime v\u00e4lja oma filtri. Allpool on toodud struktuur, mis kirjeldab igat filtrit meediastreameris, <em>MSFilter<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">\nstruct _MSFilter{\n    MSFilterDesc *desc;    \n    \/* N\u00e4idik filtrile. *\/\n    \/* Kaitstud atribuudid, neid ei tohi nihutada ega eemaldada, vastasel juhul lakkab pluginatega t\u00f6\u00f6tamine. *\/\n    ms_mutex_t lock;      \/* Semafor. *\/\n    MSQueue **inputs;     \/* Sissep\u00e4\u00e4sude lingid. *\/\n    MSQueue **outputs;    \/* V\u00e4ljundite lingid. *\/\n    struct _MSFactory *factory; \/* N\u00e4idik tehasele, mis l\u00f5i selle filtrite j\u00e4lje. *\/\n    void *padding;              \/* Mitte kasutatav, kasutatakse, kui lisatakse kaitstud v\u00e4ljad. *\/\n    void *data;                 \/* N\u00e4idik suvalisele struktuurile filtrite sisemise oleku ja vahepealsete arvutuste andmete hoidmiseks. *\/\n    struct _MSTicker *ticker;   \/* N\u00e4idik tikker-objektile, mis ei tohi olla null, kui kutsutakse v\u00e4lja funktsiooni process(). *\/\n    \/*privaatsed atribuudid, neid saab igal ajal nihutada ja muuta*\/\n    MSList *notify_callbacks; \/* Tagasiside nimekiri, mida kasutatakse filtrite s\u00fcndmuste t\u00f6\u00f6tlemiseks. *\/\n    uint32_t last_tick;       \/* Viimane takti number, mil process() funktsiooni kutsuti. *\/\n    MSFilterStats *stats;     \/* Filtri t\u00f6\u00f6statistika.*\/\n    int postponed_task; \/*\u00d5htukeelustatud \u00fclesannete arv. M\u00f5ned filtrid v\u00f5ivad edasil\u00fckata andmete t\u00f6\u00f6tlemist (process() funktsiooni kutse) mitmeks taktimiseks.*\/\n    bool_t seen;  \/* Lipp, mida tikker kasutab, et t\u00e4histada, et see filtrite j\u00e4lgimine on selle takti jooksul m\u00f6\u00f6dunud.*\/\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 (kuid tikkerit ei ole \u00fchendatud), oleme loonud suunatud graafi, mille s\u00f5lmed on struktuuri eksemplarid <em>MSFilter<\/em>, ja servad on lingi eksemplarid <em>MSQueue<\/em>. <\/p>\n<p><\/p>\n<h3 id=\"zakulisnaya-deyatelnost-tikera\">Tickere kulisside tegevus<\/h3>\n<p><\/p>\n<p>Kui ma \u00fctlesin, et tikker on taktimine filtri allikas, siis see polnud kogu t\u00f5de tema kohta. Tikker on objekt, mis k\u00e4ivitab funktsioone vastavalt kellale <em>process()<\/em> k\u00f5igi filtrite skeemis (graafis), millega see on \u00fchendatud. Kui me C-programmis \u00fchendame tickeri graafi filtriga, n\u00e4itame tickerile graafi, mida ta alates sellest hetkest hakkab juhtima, kuni me selle lahti \u00fchendame. P\u00e4rast \u00fchendamist hakkab ticker j\u00e4lgima talle usaldatud graafi, koostades loendi filtritest, kuhu ta kuulub. Et mitte \"arvata\" sama filtrit kaks korda, m\u00e4rgib ta avastatud filtrid, seades neisse lipu <em>seen<\/em>. Otsing toimub iga filtri lingi tabelite kaudu. <\/p>\n<p><\/p>\n<p>Ekskursiooni ajal kontrollib ticker, kas filtrite seas on v\u00e4hemalt \u00fcks, mis t\u00e4idab andmeplokkide allika rolli. Kui selliseid ei leidu, tunnistatakse graaf v\u00e4\u00e4raks ja ticker l\u00f5petab t\u00f6\u00f6.<\/p>\n<p><\/p>\n<p>Kui graaf osutub \"\u00f5igeks\", kutsutakse iga leitud filtrile initsialiseerimiseks v\u00e4lja funktsioon <em>preprocess()<\/em>. Kui tuleb aeg j\u00e4rgmise t\u00f6\u00f6tlemise ts\u00fckli jaoks (vaikimisi iga 10 millisecondi j\u00e4rel), kutsub ticker v\u00e4lja funktsiooni <em>process()<\/em> k\u00f5igi varem leitud allikafilterite jaoks ning seej\u00e4rel ka \u00fclej\u00e4\u00e4nud filtrite loendis. Kui filtril on sisendlingid, siis k\u00e4ivitatakse funktsioon <em>process()<\/em> kordub seni, kuni sisenemisringide j\u00e4rjekorrad t\u00fchjenevad. P\u00e4rast seda liigub see j\u00e4rgmise filtrini loendis ja \"kerib\" selle l\u00e4bi, kuni sisenemisringid on s\u00f5numitest vabastatud. Ticker liigub filtrilt filtrile, kuni loend otsa saab. Sellega l\u00f5ppeb takti t\u00f6\u00f6tlemine. <\/p>\n<p><\/p>\n<p>N\u00fc\u00fcd p\u00f6\u00f6rdume tupikute juurde ja r\u00e4\u00e4gime, miks on meediastreamerisse lisatud selline entiteet. \u00dcldiselt ei \u00fchti ja ei ole proportsionaalne algoritmi jaoks vajalik andmemahu suurus, mis t\u00f6\u00f6tab filtris, sisenevate andmebufferite suurusega. N\u00e4iteks kirjutame filtri, mis teostab kiire Fourier' transformatsiooni, mis definitsiooni kohaselt suudab t\u00f6\u00f6delda ainult andmeplokke, mille suurus on kahe astme. Olgu see 512 n\u00e4idust. Kui andmed genereeritakse telefoni\u00fchenduse kaudu, toob iga s\u00f5numi sisenemise buffer andmed meile 160 n\u00e4idust signaalist. On kiusatus mitte v\u00f5tta andmeid sisse, kuni vajalik andmemahu hulk on t\u00e4is. Kuid sel juhul tekib konflikt tickeriga, mis \u00fcritab tulutult kerida filtrit, kuni sisendlink on t\u00fchjendatud. Oleme varem m\u00e4\u00e4ratlenud selle reegli kui filtri t\u00f6\u00f6 kolmanda p\u00f5him\u00f5tte. Selle p\u00f5him\u00f5tte kohaselt peab filtri funktsioon process() v\u00f5tma k\u00f5ik andmed sisendjoontest.<\/p>\n<p><\/p>\n<p>Lisaks ei saa sissevoolust v\u00f5tta ainult 512 arvestust, kuna neid v\u00f5ib v\u00f5tta ainult t\u00e4isarvudena, st filter peab v\u00f5tma 640 arvestust ja kasutades neist 512, j\u00e4\u00e4b \u00fclej\u00e4\u00e4k uue andmepartiini kogumiseks. Seega peab meie filter, peale oma p\u00f5hifunktsioonide, tagama ka abitegevused sisendandmete vahepealseks salvestamiseks. Meediavoodetootjate lahenduste jaoks selle \u00fcldise \u00fclesande t\u00e4itmiseks on v\u00e4lja t\u00f6\u00f6tatud spetsiaalne objekt - MSBufferizer (puhvritaja), mis lahendab selle \u00fclesande kasutades tuplette. <\/p>\n<p><\/p>\n<h3 id=\"buferizator-msbufferizer\">M\u00e4buffer (MSBufferizer)<\/h3>\n<p><\/p>\n<p>See on objekt, mis kogub sisendandmeid filtri sees ja hakkab neid t\u00f6\u00f6tlemiseks andma, kui informatsiooni kogus on piisav filtri algoritmi k\u00e4ivitamiseks. Seni, kuni puhvritaja kogub andmeid, t\u00f6\u00f6tab filter t\u00fchja re\u017eiimis, mitte raisates protsessori arvutusv\u00f5imet. Kuid niipea kui funktsioon, mis loeb puhvritajast, tagastab v\u00e4\u00e4rtuse, mis ei ole null, alustab filtri process() funktsioon ekraanilolliste andmete kogumist ja t\u00f6\u00f6tlemist t\u00e4pses koguses kuni nende l\u00f5ppemiseni.<br \/>\nKasutamata andmed j\u00e4\u00e4vad puhvritajas esimeseks elementiks tupletes, kuhu kinnitatakse j\u00e4rgmised sisendandmeplokid. <\/p>\n<p><\/p>\n<p>Struktuur, mis kirjeldab puhvritajat: <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">struct _MSBufferizer{\nqueue_t q; \/* Teate j\u00e4rjekord. *\/\nint size; \/* Kokku andmete suurus, mis asub praegu puhvritajas. *\/\n};\ntypedef struct _MSBufferizer MSBufferizer;<\/code><\/pre>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-msbufferizer\">MSBufferizeriga t\u00f6\u00f6tamise funktsioonid<\/h3>\n<p><\/p>\n<p>Uue puhvritaja 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 osuti.<\/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> seadistatakse nulliks.<\/p>\n<p><\/p>\n<p>Teate 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>Teade m lisatakse j\u00e4rjekorda. Arvutatud plokkide andmete suurus lisatakse <em>size<\/em>.<\/p>\n<p><\/p>\n<p>K\u00f5ik teated, mis on j\u00e4rjekorras andmelingis, ummistuvad puhvritajasse <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>Teate edastamine lingist <em>q<\/em> puhvritajasse toimub funktsiooni kaudu <em>ms_bufferizer_put()<\/em>.<\/p>\n<p><\/p>\n<p>Lugemine puhvritajast:<\/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 puhvritajasse kogutud andmete suurus on v\u00e4iksem kui n\u00f5utud (<em>datalen<\/em>), siis funktsioon tagastab null, andmete kopeerimine data ei toimu. Vastupidisel juhul toimub j\u00e4rjestikune andmete kopeerimine puhvrisse salvestatud tuple'itest. P\u00e4rast kopeerimist eemaldatakse tuple ja m\u00e4lu vabastatakse. Kopeerimine l\u00f5ppeb hetkel, kui on kopeeritud datalen bait'i. Kui koht l\u00f5ppeb andmeploki keskel, siis piiratakse selle s\u00f5numi andmeplokk j\u00e4relej\u00e4\u00e4nud kopeerimata osani. J\u00e4rgmise kutse ajal j\u00e4tkatakse kopeerimist sellest kohast.<\/p>\n<p><\/p>\n<p>Andmete hulga lugemine, mis on praegu puhvris 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 valdkonna <em>size<\/em> puhvrisse.<\/p>\n<p><\/p>\n<p>Puhvri andmete osa mahaviskamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);<\/code><\/pre>\n<p><\/p>\n<p>M\u00e4\u00e4ratud hulga baite andmeid eemaldatakse ja mahaviskatakse. Mahaviskamine toimub vanematest andmetest.<\/p>\n<p><\/p>\n<p>Kogu puhvris olevate s\u00f5numite eemaldamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_flush(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Andmete loendur l\u00e4htestatakse nulli.<\/p>\n<p><\/p>\n<p>Kogu puhvris olevate s\u00f5numite eemaldamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_uninit(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Loenduri nullimist ei toimu.<\/p>\n<p><\/p>\n<p>Puhvri eemaldamine ja m\u00e4lu vabastamine:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_destroy(MSBufferizer *obj);  <\/code><\/pre>\n<p><\/p>\n<p>Puhvrile kasutamise n\u00e4iteid v\u00f5ib leida mitmest meediastrimmeri filtri l\u00e4htekoodist. N\u00e4iteks filtris MS_L16_ENC, mis teostab baitide \u00fcmberkorraldamist v\u00f5rguj\u00e4rjekorrast hosti j\u00e4rjestusse:<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 hindamise k\u00fcsimust tickeril ja viise, kuidas v\u00e4ltida \u00fclem\u00e4\u00e4rast arvutuskoormust meediastrimmeris.<\/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 5.0.1.1 - 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.\" \/>\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) 5.0.1.1\" \/>\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.\" \/>\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\udd47Tutvume VoIP-mootoriga Mediastreamer2. Osa 11 | ProHoster","description":"Artikli materjal on v\u00f5etud minu zen-kanalist.","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.","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","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"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}]}}