{"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\/sv\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","title":{"rendered":"Vi studerar VoIP-motorn Mediastreamer2. Del 11","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Artikelmaterialet \u00e4r h\u00e4mtat fr\u00e5n min <noindex><a rel=\"nofollow\" href=\"https:\/\/zen.yandex.ru\/profile\/editor\/id\/5e3f8e0751f5346faab4fc7a\">Zen-kanal<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Vi studerar VoIP-motorn Mediastreamer2. Del 11\" src=\"\/wp-content\/uploads\/2020\/04\/b66fab43eb45c626c50f0383dcfa7cca.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Datatransfer mekanism<\/p>\n<p><\/p>\n<ul>\n<li>Data block dblk_t<\/li>\n<li>Message mblk_t<\/li>\n<li>Funktioner f\u00f6r arbete med meddelanden mblk_t<\/li>\n<li>K\u00f6 queue_t<\/li>\n<li>Funktioner f\u00f6r arbete med k\u00f6er queue_t<\/li>\n<li>Filteranslutning<\/li>\n<li>Signalknutpunkt i databehandlingsgrafen<\/li>\n<li>Bakom kulisserna aktivitet av tickern<\/li>\n<li>Buffert (MSBufferizer)<\/li>\n<li>Funktioner f\u00f6r arbete med MSBufferizer<\/li>\n<\/ul>\n<p><\/p>\n<p>Tidigare <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/497932\/\">artikeln<\/a><\/noindex> Vi har utvecklat v\u00e5rt eget filter. Denna artikel kommer att \u00e4gnas \u00e5t strukturen av den interna mekanismen f\u00f6r datatransfer mellan filter i mediastreamern. Detta kommer sedan att m\u00f6jligg\u00f6ra skrivandet av sofistikerade filter med mindre anstr\u00e4ngning.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"mehanizm-peremescheniya-dannyh\">Datatransfer mekanism<\/h2>\n<p><\/p>\n<p>Datatransfer i mediastreamern utf\u00f6rs med hj\u00e4lp av k\u00f6er som beskrivs av strukturen <em>queue_t<\/em>. Genom k\u00f6erna flyttas kedjor av meddelanden av typen <em>mblk_t<\/em>, som i sig sj\u00e4lva inte inneh\u00e5ller signaldata, utan endast referenser till det f\u00f6reg\u00e5ende, n\u00e4sta meddelande och till datablocket. Dessutom vill jag s\u00e4rskilt p\u00e5peka att det finns ett f\u00e4lt f\u00f6r en referens till ett meddelande av samma typ, vilket m\u00f6jligg\u00f6r organiseringen av en enkel l\u00e4nkad lista av meddelanden. En grupp meddelanden, sammanl\u00e4nkade p\u00e5 detta s\u00e4tt, kommer vi att kalla en tupel. S\u00e5ledes kan vilket som helst element i k\u00f6n vara ett enskilt meddelande <em>mblk_t<\/em>, eller ocks\u00e5 vara huvudet p\u00e5 en tupel av meddelanden <em>mblk_t<\/em>. Varje meddelande i tupeln kan ha sitt eget underliggande datablock. Varf\u00f6r vi beh\u00f6ver tupeln kommer vi att diskutera lite senare.<\/p>\n<p><\/p>\n<p>Som n\u00e4mnts ovan inneh\u00e5ller meddelandet i sig ingen datablokk, utan endast en pekare till det minnesomr\u00e5de d\u00e4r blocket lagras. I denna del liknar den \u00f6vergripande bilden av hur mediastreamern fungerar en lagerh\u00e5llning av d\u00f6rrar i filmen \"Monsters, Inc.\", d\u00e4r d\u00f6rrarna (l\u00e4nkar till data \u2014 rum) r\u00f6r sig med galen hastighet p\u00e5 upph\u00e4ngda transportband, medan sj\u00e4lva rummen f\u00f6rblir stilla. <\/p>\n<p><\/p>\n<p>Nu, n\u00e4r vi g\u00e5r igenom hierarkin underifr\u00e5n och upp, l\u00e5t oss utforska detaljerat de n\u00e4mnda entiteterna i datatransfermekanismen i mediastreamern.<\/p>\n<p><\/p>\n<h3 id=\"blok--dannyh-dblk_t\">Datablock <em>dblk_t<\/em><\/h3>\n<p><\/p>\n<p>Datablocket best\u00e5r av en rubrik och en datarbuffert. Rubriken beskrivs av f\u00f6ljande struktur,<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct datab\n{\nunsigned char *db_base; \/\/ Pekare till b\u00f6rjan av databufferten.\nunsigned char *db_lim;  \/\/ Pekare till slutet av databufferten.\nvoid (*db_freefn)(void*); \/\/ Funktion f\u00f6r att frig\u00f6ra minne vid borttagning av block.\nint db_ref; \/\/ Referensr\u00e4knare.\n} dblk_t;<\/code><\/pre>\n<p><\/p>\n<p>Strukturens f\u00e4lt inneh\u00e5ller pekare till b\u00f6rjan av bufferten, slutet av bufferten och funktionen f\u00f6r att ta bort databufferten. Den sista posten i rubriken <em>db_ref<\/em> \u2013 \u00e4r en r\u00e4knare f\u00f6r referenser, n\u00e4r den n\u00e5r noll fungerar det som en signal f\u00f6r att ta bort denna block fr\u00e5n minnet. Om datablocket har skapats av funktionen <em>datab_alloc() <\/em>, kommer databufferten att placeras i minnet direkt efter rubriken. I alla andra fall kan bufferten ligga n\u00e5gon annanstans. I databufferten kommer signaldata eller andra data som vi vill bearbeta med filter att lagras.<\/p>\n<p><\/p>\n<p>Ett nytt instans av datablocket skapas med hj\u00e4lp av funktionen:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">dblk_t *datab_alloc(int size);<\/code><\/pre>\n<p><\/p>\n<p>Som inparametern f\u00e5r den storleken p\u00e5 de data som blocket ska lagra. Minnet allokeras mer, f\u00f6r att i b\u00f6rjan av det allokerade minnet placera rubriken \u2013 strukturen <em>datab<\/em>. Men n\u00e4r andra funktioner anv\u00e4nds s\u00e5 sker det inte alltid, i vissa fall kan databufferten ligga separerat fr\u00e5n datablocket. Strukturens f\u00e4lt konfigureras vid skapandet s\u00e5 att dess f\u00e4lt <em>db_base<\/em> pekar p\u00e5 b\u00f6rjan av datam\u00e4ngden, och <em>db_lim<\/em> p\u00e5 dess slut. Referensr\u00e4knaren <em>db_ref<\/em> st\u00e4lls in p\u00e5 ett. Pekaren till funktionen f\u00f6r att rensa data st\u00e4lls in p\u00e5 noll.<\/p>\n<p><\/p>\n<h3 id=\"soobschenie-mblk_t\">Meddelandet <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Som n\u00e4mnts har k\u00f6ens element typ <em>mblk_t,<\/em> som definieras enligt f\u00f6ljande:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct msgb\n{\n  struct msgb *b_prev;   \/\/ Pekare till f\u00f6reg\u00e5ende element i listan.\n  struct msgb *b_next;   \/\/ Pekare till n\u00e4sta element i listan.\n  struct msgb *b_cont;   \/\/ Pekare f\u00f6r att klistra in andra meddelanden till meddelandet, f\u00f6r att skapa tuple meddelanden.\n  struct datab *b_datap; \/\/ Pekare till datablokens struktur.\n  unsigned char *b_rptr; \/\/ Pekare till b\u00f6rjan av datam\u00e4ngden f\u00f6r att l\u00e4sa data fr\u00e5n bufferten b_datap.\n  unsigned char *b_wptr; \/\/ Pekare till b\u00f6rjan av datam\u00e4ngden f\u00f6r att skriva data till bufferten b_datap.\n  uint32_t reserved1;    \/\/ Reservf\u00e4lt1, mediastreamer placerar d\u00e4r serviceinformation. \n  uint32_t reserved2;    \/\/ Reservf\u00e4lt2, mediastreamer placerar d\u00e4r serviceinformation.\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>Struktur <em>mblk_t<\/em> inneh\u00e5ller i b\u00f6rjan pekare <em>b_prev<\/em>, <em>b_next<\/em>, vilka \u00e4r n\u00f6dv\u00e4ndiga f\u00f6r att organisera en dubbell\u00e4nkad lista (som \u00e4r k\u00f6n <em>queue_t<\/em>). <\/p>\n<p><\/p>\n<p>Sedan f\u00f6ljer pekaren <em>b_cont<\/em>, som endast anv\u00e4nds n\u00e4r meddelandet g\u00e5r in i tuplen. F\u00f6r det sista meddelandet i tuplen f\u00f6rblir denna pekare noll. <\/p>\n<p><\/p>\n<p>H\u00e4r ser vi en pekare till datablocket <em>b_datap<\/em>, vilket \u00e4r anledningen till att meddelandet existerar. D\u00e4refter f\u00f6ljer pekare till omr\u00e5det inom datablocket. F\u00e4ltet <em>b_rptr<\/em> anger platsen fr\u00e5n vilken data kommer att l\u00e4sas fr\u00e5n buffern. F\u00e4ltet <em>b_wptr<\/em> anger platsen d\u00e4r skrivning till buffern kommer att ske. <\/p>\n<p><\/p>\n<p>De \u00e5terst\u00e5ende f\u00e4lten \u00e4r av servicekarakt\u00e4r och relaterar inte till hur datatransmissionsmekanismen fungerar.<\/p>\n<p><\/p>\n<p>Nedan visas ett enskilt meddelande med namnet <em>m1<\/em> och datablocket <em>d1<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Vi studerar VoIP-motorn Mediastreamer2. Del 11\" src=\"\/wp-content\/uploads\/2020\/04\/e6a726b13491832258c1228f03bde802.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nI n\u00e4sta bild visas en tuppel av tre meddelanden <em>m1<\/em>, <em>m1_1<\/em>, <em>m1_2<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Vi studerar VoIP-motorn Mediastreamer2. Del 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\">Funktioner f\u00f6r att hantera meddelanden <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Ett nytt meddelande <em>mblk_t<\/em> skapas av funktionen:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *allocb(int size, int pri); <\/code><\/pre>\n<p><\/p>\n<p>den allokerar ett nytt meddelande <em>mblk_t<\/em> med ett datablock av angiven storlek <em>size<\/em>, den andra argumentet \u2014 <em>pri<\/em> anv\u00e4nds inte i den aktuella versionen av biblioteken. Det ska f\u00f6rbli noll. Under funktionens g\u00e5ng kommer minne att avs\u00e4ttas f\u00f6r strukturen av det nya meddelandet och funktionen <em>mblk_init()<\/em>, som nollst\u00e4ller alla f\u00e4lt i den skapade instansen av strukturen och sedan, med hj\u00e4lp av den n\u00e4mnda tidigare, <em>datab_alloc()<\/em>, skapa databufferten. D\u00e4refter kommer f\u00e4lten i strukturen att st\u00e4llas in: <\/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>Vid utg\u00e5ngen f\u00e5r vi ett nytt meddelande med initierade f\u00e4lt och en tom databuffert. F\u00f6r att l\u00e4gga till data i meddelandet m\u00e5ste man kopiera dem till datablocket:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">memcpy(msg-&gt;b_rptr, data, size);<\/code><\/pre>\n<p><\/p>\n<p>w <em>data<\/em> \u2014 pekaren till datak\u00e4llan, och <em>size<\/em> \u2014 dess storlek.<br \/>\nd\u00e4refter m\u00e5ste man uppdatera pekaren till skrivpunkten s\u00e5 att den \u00e5ter pekar p\u00e5 b\u00f6rjan av det lediga omr\u00e5det i bufferten:<\/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>Om det kr\u00e4vs att skapa ett meddelande fr\u00e5n en redan existerande buffer, utan att kopiera, anv\u00e4nds funktionen:<\/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>Funktionen kommer efter skapandet av meddelandet och datablocket, att st\u00e4lla in dess pekare till data vid adressen <em>buf<\/em>. D.v.s. i detta fall ligger databufferten inte efter f\u00e4lten i datablocket, som det var vid skapandet av datablocket med funktionen <em>datab_alloc()<\/em>Den \u00f6verf\u00f6rda funktionen buffert med data kommer att f\u00f6rbli d\u00e4r den var, men kommer att styra den nyss skapade blockhuvudet via pekare, som i sin tur g\u00e5r till meddelandet.<\/p>\n<p><\/p>\n<p>Ett meddelande <em>mblk_t<\/em> kan ha flera datablok i f\u00f6ljd kopplade till sig. Detta g\u00f6rs av funktionen:<\/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 meddelandet som kommer att f\u00e5 ytterligare ett datablok;<br \/>\n<em>data<\/em> \u2014 en pekare p\u00e5 det blok som en kopia kommer att l\u00e4ggas till i meddelandet;<br \/>\n<em>size<\/em> \u2014 storlek p\u00e5 data;<br \/>\n<em>pad<\/em> \u2014 flagga som anger att den tilldelade minnesstorleken ska justeras till en 4-byte-gr\u00e4ns (fyllning kommer att g\u00f6ras med nollor). <\/p>\n<p><\/p>\n<p>Om det finns tillr\u00e4ckligt med utrymme i den befintliga meddelandebufferten, kommer de nya uppgifterna att kopplas p\u00e5 efter de redan befintliga d\u00e4r. Om det fria utrymmet i meddelandebufferten blir mindre \u00e4n <em>size<\/em>, skapas ett nytt meddelande med tillr\u00e4ckligt stor buffert och data kopieras till dess buffert. Detta nya meddelande kopplas till det ursprungliga via pekaren <em>b_cont<\/em>. I det h\u00e4r fallet omvandlas meddelandet till en tuple. <\/p>\n<p><\/p>\n<p>Om du beh\u00f6ver l\u00e4gga till ytterligare ett datablok i tuplen, m\u00e5ste du anv\u00e4nda funktionen:<\/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>den kommer att hitta det senaste meddelandet i tuplen (det kommer att vara noll) och anropa funktionen <em>b_cont<\/em> appendb() <em>F\u00f6r att ta reda p\u00e5 storleken p\u00e5 uppgifterna i meddelandet eller tuplen kan du anv\u00e4nda funktionen:<\/em>.<\/p>\n<p><\/p>\n<p>int msgdsize(const mblk_t *mp);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">den kommer att g\u00e5 igenom alla meddelanden i tuplen och returnera det totala antalet data i data-bufferarna f\u00f6r dessa meddelanden. F\u00f6r varje meddelande ber\u00e4knas datam\u00e4ngden s\u00e5 h\u00e4r:<\/code><\/pre>\n<p><\/p>\n<p>mp-&gt;b_wptr - mp-&gt;b_rptr<\/p>\n<p><\/p>\n<pre><code class=\"cpp\"> F\u00f6r att f\u00f6rena tv\u00e5 tupler anv\u00e4nds funktionen:<\/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\">den kopplar tuplen<\/code><\/pre>\n<p><\/p>\n<p>newm <em>till slutet av tuplen<\/em> och returnerar en pekare p\u00e5 det senaste meddelandet i den resulterande tuplen. <em>mp<\/em> Vid behov kan tuplen omvandlas till ett enda meddelande med ett enda datablok, detta g\u00f6rs av funktionen:<\/p>\n<p><\/p>\n<p>void msgpullup(mblk_t *mp,int len);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">om argumentet<\/code><\/pre>\n<p><\/p>\n<p>\u00e4r lika med -1, s\u00e5 best\u00e4ms storleken p\u00e5 den tilldelade bufferten automatiskt. Om <em>len<\/em> \u00e4r lika med -1, s\u00e5 best\u00e4ms storleken p\u00e5 den avledda bufferten automatiskt. Om <em>len<\/em> Om det \u00e4r ett positivt tal kommer en buffert av denna storlek att skapas och data fr\u00e5n tuplemeddelandena kommer att kopieras dit. Om bufferten tar slut kommer kopieringen att stoppas. Det f\u00f6rsta meddelandet i tuplen f\u00e5r en buffert av ny storlek med kopierade data. \u00d6vriga meddelanden kommer att raderas och minnet \u00e5terf\u00f6rs till h\u00f6gen.<\/p>\n<p><\/p>\n<p>Vid borttagning av strukturen <em>mblk_t<\/em> beaktas referensr\u00e4knaren f\u00f6r datablocket, om vid anropet <em>freeb()<\/em> den visar sig vara noll, raderas datan fr\u00e5n bufferten tillsammans med instansen <em>mblk_t<\/em>, som pekar p\u00e5 den.<\/p>\n<p><\/p>\n<p>Initialisering av f\u00e4lten i det nya meddelandet:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void mblk_init(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>L\u00e4gg till en ny datam\u00e4ngd till meddelandet: <\/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>Om de nya data inte f\u00e5r plats i det tillg\u00e4ngliga utrymmet i meddelandets datBuffert, kopplas ett separat skapat meddelande med den n\u00f6dv\u00e4ndiga storleken till meddelandet (pekaren till det tillagda meddelandet st\u00e4lls in i det f\u00f6rsta meddelandet) meddelandet blir en tuple.<\/p>\n<p><\/p>\n<p>L\u00e4gg till en datam\u00e4ngd till tuplen:<\/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>Funktionen anropar appendb() i en loop.<\/p>\n<p><\/p>\n<p>Sammanfoga tv\u00e5 tupler till en:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">den kopplar tuplen<\/code><\/pre>\n<p><\/p>\n<p>Meddelandet <em>till slutet av tuplen<\/em> kommer att anslutas till <em>mp<\/em>.<\/p>\n<p><\/p>\n<p>Skapa en kopia av ett enda meddelande:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copyb(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Fullst\u00e4ndig kopiering av tuplen med alla datablokkar:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copymsg(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Elementen i tuplen kopieras med funktionen <em>copyb()<\/em>.<\/p>\n<p><\/p>\n<p>Skapa en l\u00e4tt kopia av meddelandet <em>mblk_t<\/em>. Vid detta kopieras inte datablocket, utan dess referensr\u00e4knare \u00f6kas <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>Skapa en l\u00e4tt kopia av tuplen. Datablokkar kopieras inte, utan endast deras referensr\u00e4knare \u00f6kas <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>Sammanfoga alla meddelanden i tuplen till ett meddelande:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgpullup(mblk_t *mp, size_t len);<\/code><\/pre>\n<p><\/p>\n<p>Om argumentet <em>len<\/em> \u00e4r lika med -1, best\u00e4ms storleken p\u00e5 bufferten automatiskt.<\/p>\n<p><\/p>\n<p>Ta bort meddelandet, tuplen:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void freemsg(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Referensr\u00e4knaren f\u00f6r datablocket minskas med ett. Om den n\u00e5r noll raderas \u00e4ven datablocket.<\/p>\n<p><\/p>\n<p>Ber\u00e4kning av den totala datavolymen i meddelandet eller tuplen.<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">size_t msgdsize(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>H\u00e4mta meddelandet fr\u00e5n k\u00f6ns svans:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *ms_queue_peek_last(q);<\/code><\/pre>\n<p><\/p>\n<p>Kopiera inneh\u00e5llet i de reserverade f\u00e4lten fr\u00e5n ett meddelande till ett annat (det finns i dessa f\u00e4lt flaggor som anv\u00e4nds av mediestr\u00f6mmen):<\/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\">K\u00f6 <em>queue_t<\/em><\/h3>\n<p><\/p>\n<p>K\u00f6-systemet i mediestr\u00f6mmen \u00e4r implementerat som en ringdoubellista. Varje element i listan inneh\u00e5ller en pekare till en datablob med signalavl\u00e4sningar. Det inneb\u00e4r att det bara \u00e4r pekarna till databloben som flyttas i ordning, medan sj\u00e4lva datan f\u00f6rblir stilla. Det vill s\u00e4ga att det endast \u00e4r l\u00e4nkarna till dem som flyttas.<br \/>\nStrukturen som beskriver k\u00f6n <em>queue_t<\/em>, visas nedan:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _queue\n{\n   mblk_t _q_stopper; \/* \"Tom\" element av k\u00f6n, pekar inte p\u00e5 data, anv\u00e4nds endast f\u00f6r att hantera k\u00f6n. Vid initialisering av k\u00f6n (qinit()) st\u00e4lls dess pekare in s\u00e5 att de pekar p\u00e5 sig sj\u00e4lva. *\/\n   int q_mcount;        \/\/ Antal element i k\u00f6n.\n} queue_t;<\/code><\/pre>\n<p><\/p>\n<p>Strukturen inneh\u00e5ller ett f\u00e4lt \u2014 en pekare <em>_q_stopper<\/em> av typen *mblk_t, den pekar p\u00e5 det f\u00f6rsta elementet (meddelandet) i k\u00f6n. Det andra f\u00e4ltet i strukturen \u00e4r en r\u00e4knare f\u00f6r meddelanden som finns i k\u00f6n.<br \/>\nI bilden nedan visas k\u00f6n med namnet q1, som inneh\u00e5ller 4 meddelanden m1,m2, m3, m4.<br \/>\n<img decoding=\"async\" alt=\"Vi studerar VoIP-motorn Mediastreamer2. Del 11\" src=\"\/wp-content\/uploads\/2020\/04\/07fc043861edf15e5eb40e49c8ec5e3e.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nI n\u00e4sta bild visas k\u00f6n med namnet q1, som inneh\u00e5ller 4 meddelanden m1,m2, m3, m4. Meddelandet m2 \u00e4r huvudknuten, som har ytterligare tv\u00e5 meddelanden m2_1 och m2_2.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Vi studerar VoIP-motorn Mediastreamer2. Del 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\">Funktioner f\u00f6r arbete med k\u00f6er queue_t<\/h3>\n<p><\/p>\n<p>Initiering av k\u00f6n:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void qinit(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>F\u00e4ltet <em>_q_stopper<\/em> (nedan kallad \"stopper\") initialiseras med funktionen <em>mblk_init()<\/em>, dess pekare f\u00f6r det f\u00f6reg\u00e5ende elementet och n\u00e4sta element st\u00e4lls in s\u00e5 att de pekar p\u00e5 sig sj\u00e4lva. R\u00e4knaren f\u00f6r element i k\u00f6n nollst\u00e4lls.<\/p>\n<p><\/p>\n<p>Till\u00e4gg av ett nytt element (meddelande):<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void putq(queue_t *q, mblk_t *m);<\/code><\/pre>\n<p><\/p>\n<p>Det nya elementet <em>m<\/em> l\u00e4ggs till i slutet av listan, pekarna f\u00f6r elementet st\u00e4lls in s\u00e5 att stoppare blir dess n\u00e4sta element och det blir det f\u00f6reg\u00e5ende elementet f\u00f6r stoppare. R\u00e4knaren f\u00f6r element i k\u00f6n inkrementeras.<\/p>\n<p><\/p>\n<p>Uttag av ett element fr\u00e5n k\u00f6n:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * getq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>det meddelande som st\u00e5r efter stoppare tas bort, r\u00e4knaren f\u00f6r element minskas. Om det inte finns n\u00e5gra element i k\u00f6n f\u00f6rutom stoppare, returneras 0.<\/p>\n<p><\/p>\n<p>Ins\u00e4ttning av meddelande i k\u00f6n:<\/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> infogas f\u00f6re elementet <em>emp<\/em>. Om <em>emp<\/em>=0, s\u00e5 l\u00e4ggs meddelandet till i slutet av k\u00f6n.<\/p>\n<p><\/p>\n<p>Uttag av meddelande fr\u00e5n huvudet av k\u00f6n:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void remq(queue_t *q, mblk_t *mp); <\/code><\/pre>\n<p><\/p>\n<p>R\u00e4knaren f\u00f6r element minskas.<\/p>\n<p><\/p>\n<p>L\u00e4sa pekaren till det f\u00f6rsta elementet i k\u00f6n:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * peekq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>Borttagning av alla element fr\u00e5n k\u00f6n med radering av sj\u00e4lva elementen:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void flushq(queue_t *q, int how);<\/code><\/pre>\n<p><\/p>\n<p>Argumentet <em>how<\/em> anv\u00e4nds inte. Antalet k\u00f6element s\u00e4tts till noll.<\/p>\n<p><\/p>\n<p>Makro f\u00f6r att l\u00e4sa pekaren p\u00e5 det sista k\u00f6elementet:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * qlast(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>N\u00e4r man arbetar med meddelandek\u00f6er b\u00f6r man komma ih\u00e5g att vid anrop av <em>ms_queue_put(q, m)<\/em> med en nullpekare till meddelandet, slutar funktionen i en o\u00e4ndlig loop. Ditt program kommer att l\u00e5sa sig. Detsamma g\u00e4ller <em>ms_queue_next(q, m)<\/em>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-filtrov\">Filteranslutning<\/h3>\n<p><\/p>\n<p>Den beskrivna k\u00f6n anv\u00e4nds f\u00f6r att \u00f6verf\u00f6ra meddelanden fr\u00e5n en filter till en annan eller fr\u00e5n en till flera filter. Filtren och deras anslutningar bildar en riktad graf. Ing\u00e5ng eller utg\u00e5ng av filtret kallas med det \u00f6vergripande ordet \"pin\". F\u00f6r att beskriva ordningen f\u00f6r anslutningarna mellan filtren anv\u00e4nds i mediastreamern begreppet \"signalpunkt\". Signalpunkten \u00e4r en struktur <em>_MSCPoint<\/em>, som inneh\u00e5ller en pekare p\u00e5 filtret och numret p\u00e5 en av dess pinnar, vilket beskriver anslutningen av en av ing\u00e5ngarna eller utg\u00e5ngarna av filtret. <\/p>\n<p><\/p>\n<h4 id=\"signalnaya-tochka-grafa-obrabotki-dannyh\">Signalknutpunkt i databehandlingsgrafen<\/h4>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _MSCPoint{\nstruct _MSFilter *filter; \/\/ Pekare p\u00e5 mediestr\u00f6mmarfiltret.\nint pin;                        \/\/ Numret p\u00e5 en av ing\u00e5ngarna eller utg\u00e5ngarna av filtret, dvs. pin.\n} MSCPoint;\n<\/code><\/pre>\n<p><\/p>\n<p>Pinnarna p\u00e5 filtren numreras fr\u00e5n noll. <\/p>\n<p><\/p>\n<p>Anslutningen av tv\u00e5 pinnar via en meddelandek\u00f6 beskrivs av strukturen <em>_MSQueue<\/em>, som inneh\u00e5ller meddelandek\u00f6n och pekare p\u00e5 tv\u00e5 signalpunkter som den ansluter:<\/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>Vi kallar denna struktur f\u00f6r en signal-l\u00e4nk. Varje mediestr\u00f6mmarfiltret inneh\u00e5ller en tabell med ing\u00e5ngsl\u00e4nkar och en tabell med utg\u00e5ngsl\u00e4nkar (<em>MSQueue<\/em>). Storleken p\u00e5 tabellerna anges vid skapandet av filtret, detta har vi redan gjort med hj\u00e4lp av den exporterade variabeln av typen <em>MSFilterDesc<\/em>, n\u00e4r vi utvecklade v\u00e5r egen filter. Nedan visas strukturen som beskriver vilket filter som helst i mediestr\u00f6mmaren, <em>MSFilter<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">\nstruct _MSFilter{\n    MSFilterDesc *desc;    \n    \/* Pekare till filterbeskrivningen. *\/\n    \/* Skyddade attribut, de kan inte flyttas eller tas bort, annars fungerar plugins fel. *\/\n    ms_mutex_t lock;      \/* Semafor. *\/\n    MSQueue **inputs;     \/* Tabell med ing\u00e5ngsl\u00e4nkar. *\/\n    MSQueue **outputs;    \/* Tabell med utg\u00e5ngsl\u00e4nkar. *\/\n    struct _MSFactory *factory; \/* Pekare till fabriken som skapade detta instans av filtret. *\/\n    void *padding;              \/* Anv\u00e4nds inte, kommer att anv\u00e4ndas om skyddade f\u00e4lt l\u00e4ggs till. *\/\n    void *data;                 \/* Pekare till en godtycklig struktur f\u00f6r att lagra interna filterdata och mellanresultat. *\/\n    struct _MSTicker *ticker;   \/* Pekare till tickern, som inte f\u00e5r vara null n\u00e4r funktionen process() anropas. *\/\n    \/* privata attribut, de kan flyttas och \u00e4ndras n\u00e4r som helst *\/\n    MSList *notify_callbacks; \/* Lista med \u00e5terkopplingsfunktioner som anv\u00e4nds f\u00f6r att hantera filterh\u00e4ndelser. *\/\n    uint32_t last_tick;       \/* Nummer p\u00e5 den senaste takten n\u00e4r process() anropades. *\/\n    MSFilterStats *stats;     \/* Filterstatistik. *\/\n    int postponed_task; \/* Antal uppskjutna uppgifter. Vissa filter kan skjuta upp databehandling (anrop av process()) \u00f6ver flera takter. *\/\n    bool_t seen;  \/* Flagg som anv\u00e4nds av tickern f\u00f6r att markera att denna instans av filtret redan har hanterats p\u00e5 denna takt. *\/\n};\ntypedef struct _MSFilter MSFilter;\n<\/code><\/pre>\n<p><\/p>\n<p>N\u00e4r vi i C-programmet har kopplat ihop filtren enligt v\u00e5r plan (men inte kopplat tickern), har vi d\u00e4rmed skapat en riktad graf, vars noder \u00e4r instanser av strukturen <em>MSFilter<\/em>, och kanterna \u00e4r instanser av l\u00e4nkar <em>MSQueue<\/em>. <\/p>\n<p><\/p>\n<h3 id=\"zakulisnaya-deyatelnost-tikera\">Bakom kulisserna aktivitet av tickern<\/h3>\n<p><\/p>\n<p>N\u00e4r jag sa till dig att tickern \u00e4r en taktk\u00e4lla f\u00f6r filtren, var det inte hela sanningen om den. Tickern \u00e4r ett objekt som k\u00f6r funktionerna <em>process()<\/em> av alla filter i schemat (grafen) som den \u00e4r ansluten till. N\u00e4r vi i C-programmet ansluter en ticker till ett filter i grafen, visar vi f\u00f6r tickern vilken graf den kommer att styra fr\u00e5n och med nu, tills vi kopplar ifr\u00e5n den. Efter anslutning b\u00f6rjar tickern att inspektera grafen som har anf\u00f6rtrotts den, och uppr\u00e4tta en lista \u00f6ver filter som ing\u00e5r i den. F\u00f6r att inte \"r\u00e4kna\" samma filter tv\u00e5 g\u00e5nger markerar den de uppt\u00e4ckta filtren genom att st\u00e4lla in en flagga <em>seen<\/em>. S\u00f6ket genomf\u00f6rs i l\u00e4nktabeller som varje filter har. <\/p>\n<p><\/p>\n<p>Under sin introduktionstur kontrollerar tickern om det finns \u00e5tminstone ett filter bland filtren som fungerar som en k\u00e4lla f\u00f6r datablokker. Om inga hittas, betraktas grafen som felaktig och tickern avslutar sin funktion.<\/p>\n<p><\/p>\n<p>Om grafen visar sig vara \"korrekt\" kallas initialiseringsfunktioner f\u00f6r varje funnet filter <em>preprocess()<\/em>. S\u00e5 snart det \u00e4r dags f\u00f6r n\u00e4sta bearbetningscykel (som standard var tionde millisekund), anropar tickern en funktion. <em>process()<\/em> f\u00f6r alla tidigare funna k\u00e4llfilter och sedan f\u00f6r de \u00f6vriga filtren i listan. Om filtret har ing\u00e5ngsl\u00e4nkar, upprepas anropet av funktionen <em>process()<\/em> detta upprepas tills k\u00f6erna av ing\u00e5ngsl\u00e4nkar \u00e4r tomma. Efter detta g\u00e5r den vidare till n\u00e4sta filter i listan och \"rullar\" det tills ing\u00e5ngsl\u00e4nkarna \u00e4r fria fr\u00e5n meddelanden. Tickern g\u00e5r fr\u00e5n filter till filter tills listan \u00e4r slut. S\u00e5 avslutas takthanteringen. <\/p>\n<p><\/p>\n<p>Nu g\u00e5r vi tillbaka till tuplarna och pratar om varf\u00f6r en s\u00e5dan entitet lades till i mediestr\u00f6mmen. I allm\u00e4nhet st\u00e4mmer inte datavolymen som algoritmen som arbetar inuti filtret beh\u00f6ver \u00f6verens med storleken p\u00e5 buffrarna f\u00f6r de inkommande datablokkerna. L\u00e5t oss s\u00e4ga att vi skriver ett filter som g\u00f6r snabb Fourier-transformering, vilket per definition bara kan bearbeta datablokker vars storlek \u00e4r en exponent av tv\u00e5. L\u00e5t oss s\u00e4ga 512 prover. Om data genereras fr\u00e5n en telefonlinje, kommer buffern f\u00f6r varje inkommande meddelande att ge oss 160 prover av signalen. Det finns en frestelse att inte h\u00e4mta data fr\u00e5n ing\u00e5ngen f\u00f6rr\u00e4n det finns ett tillr\u00e4ckligt antal data. Men i det h\u00e4r fallet uppst\u00e5r det en konflikt med tickern, som utan framg\u00e5ng kommer att f\u00f6rs\u00f6ka rulla filtret tills ing\u00e5ngsl\u00e4nken \u00e4r tom. Tidigare betecknade vi denna regel som den tredje principen f\u00f6r hur filtret fungerar. I enlighet med denna princip m\u00e5ste funktionen process() f\u00f6r filtret h\u00e4mta alla data fr\u00e5n ing\u00e5ngsk\u00f6erna.<\/p>\n<p><\/p>\n<p>Dessutom kan man inte h\u00e4mta bara 512 v\u00e4rden fr\u00e5n ing\u00e5ngen, eftersom de m\u00e5ste h\u00e4mtas i hela block, det vill s\u00e4ga filtret m\u00e5ste h\u00e4mta 640 v\u00e4rden och anv\u00e4nda 512 av dem, medan resten sparas tills en ny portion data ackumuleras. D\u00e4rf\u00f6r, f\u00f6rutom sin huvudfunktion, m\u00e5ste v\u00e5rt filter ocks\u00e5 tillhandah\u00e5lla st\u00f6djande \u00e5tg\u00e4rder f\u00f6r mellanlagring av ing\u00e5ngsdata. Utvecklarna av mediestr\u00f6mmen och l\u00f6sningen p\u00e5 denna gemensamma uppgift har utvecklat ett speciellt objekt \u2013 MSBufferizer (buffer), som l\u00f6ser denna uppgift med hj\u00e4lp av tuples. <\/p>\n<p><\/p>\n<h3 id=\"buferizator-msbufferizer\">Buffert (MSBufferizer)<\/h3>\n<p><\/p>\n<p>Detta objekt kommer att ackumulera ing\u00e5ngsdata inuti filtret och b\u00f6rja skicka dem f\u00f6r bearbetning s\u00e5 snart m\u00e4ngden information \u00e4r tillr\u00e4cklig f\u00f6r att k\u00f6ra filtreringsalgoritmen. Medan bufferten samlar data kommer filtret att arbeta i tomg\u00e5ngsl\u00e4ge och inte anv\u00e4nda n\u00e5gon processorkraft. Men s\u00e5 snart funktionen f\u00f6r att l\u00e4sa fr\u00e5n bufferten returnerar ett v\u00e4rde som \u00e4r olika fr\u00e5n noll, b\u00f6rjar funktionen process() filtrera och bearbeta data fr\u00e5n bufferten i portioner av r\u00e4tt storlek, tills de \u00e4r utt\u00f6mda.<br \/>\nDe hittills oanv\u00e4nda data f\u00f6rblir i bufferten som det f\u00f6rsta elementet i tuple, till vilket h\u00e4rf\u00f6ljer f\u00f6ljande block av ing\u00e5ngsdata. <\/p>\n<p><\/p>\n<p>Strukturen som beskriver bufferten: <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">struct _MSBufferizer{\nqueue_t q; \/* Meddelandek\u00f6. *\/\nint size; \/* Total storlek p\u00e5 data i bufferten f\u00f6r tillf\u00e4llet. *\/\n};\ntypedef struct _MSBufferizer MSBufferizer;<\/code><\/pre>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-msbufferizer\">Funktioner f\u00f6r arbete med MSBufferizer<\/h3>\n<p><\/p>\n<p>Skapande av en ny instans av bufferten:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">MSBufferizer * ms_bufferizer_new(void);<\/code><\/pre>\n<p><\/p>\n<p>Minnet allokeras, initieras i <em>ms_bufferizer_init()<\/em> och en pekare returneras.<\/p>\n<p><\/p>\n<p>Initieringsfunktion:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_init(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>K\u00f6n <em>q<\/em>, f\u00e4lt <em>size<\/em> initieras till noll.<\/p>\n<p><\/p>\n<p>L\u00e4gg till meddelande:<\/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>Meddelandet m l\u00e4ggs till k\u00f6n. Den ber\u00e4knade storleken av datablokkerna l\u00e4ggs till <em>size<\/em>.<\/p>\n<p><\/p>\n<p>\u00d6verf\u00f6ring till bufferten av alla meddelanden fr\u00e5n datak\u00f6n <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>\u00d6verf\u00f6ring av meddelanden fr\u00e5n k\u00f6n <em>q<\/em> till bufferten g\u00f6rs med hj\u00e4lp av funktionen <em>ms_bufferizer_put()<\/em>.<\/p>\n<p><\/p>\n<p>L\u00e4sa fr\u00e5n bufferten:<\/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>Om storleken p\u00e5 de ackumulerade i bufferten data \u00e4r mindre \u00e4n den beg\u00e4rda storleken (<em>datalen<\/em>), s\u00e5 returnerar funktionen noll, och datakopiering till data utf\u00f6rs inte. Annars utf\u00f6rs sekventiell kopiering av data fr\u00e5n tupplarna som finns i buffertminnet. Efter kopiering tas tupplarna bort och minnet frig\u00f6rs. Kopieringen avslutas n\u00e4r datalen byte har kopierats. Om utrymmet tar slut mitt i en datablokk, kommer i detta meddelande datablokken att f\u00f6rkortas till den \u00e5terst\u00e5ende icke-kopierade delen. Vid n\u00e4sta anrop forts\u00e4tter kopieringen fr\u00e5n denna punkt.<\/p>\n<p><\/p>\n<p>L\u00e4sa antalet data som \u00e4r tillg\u00e4ngliga f\u00f6r n\u00e4rvarande i buffertminnet:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int ms_bufferizer_get_avail(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Returnerar f\u00e4ltet <em>size<\/em> buffertminnet.<\/p>\n<p><\/p>\n<p>Kasta bort en del av data som finns i buffertminnet:<\/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>Det angivna antalet bytes data extraheras och kastas bort. De \u00e4ldsta data kastas bort.<\/p>\n<p><\/p>\n<p>Ta bort alla meddelanden i buffertminnet:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_flush(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Datacounten \u00e5terst\u00e4lls till noll.<\/p>\n<p><\/p>\n<p>Ta bort alla meddelanden i buffertminnet:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_uninit(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>\u00c5terst\u00e4llning av datar\u00e4knaren utf\u00f6rs inte.<\/p>\n<p><\/p>\n<p>Ta bort buffertminnet och frig\u00f6ra minnet:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_destroy(MSBufferizer *obj);  <\/code><\/pre>\n<p><\/p>\n<p>Exempel p\u00e5 anv\u00e4ndning av buffertminnet kan hittas i k\u00e4llkoden f\u00f6r flera mediastreamerfilter. Till exempel i filtret MS_L16_ENC, som utf\u00f6r byteordning i n\u00e4tverksordning, i v\u00e4rdordning:<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>I n\u00e4sta artikel kommer vi att titta p\u00e5 hur man bed\u00f6mer belastningen p\u00e5 tickern och hur man hanterar \u00f6verdriven ber\u00e4kningsbelastning i mediastreamern.<\/p>\n<p>K\u00e4lla: <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.4 - 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\/sv\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sv_SE\" \/>\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\/sv\/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\udd47Utforskar VoIP-motorn Mediastreamer2. Del 11 | ProHoster","description":"Materialet i artikeln \u00e4r h\u00e4mtat fr\u00e5n min Zen-kanal.","canonical_url":"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sv_SE","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\/sv\/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\/sv\/wp-json\/wp\/v2\/posts\/79540","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/comments?post=79540"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts\/79540\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media\/79541"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media?parent=79540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/categories?post=79540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/tags?post=79540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}