{"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\/sk\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","title":{"rendered":"Presk\u00famavame VoIP engine Mediastreamer2. \u010cas\u0165 11","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Materi\u00e1l \u010dl\u00e1nku je prevzat\u00fd z m\u00f4jho <noindex><a rel=\"nofollow\" href=\"https:\/\/zen.yandex.ru\/profile\/editor\/id\/5e3f8e0751f5346faab4fc7a\">zen kan\u00e1la<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Presk\u00famavame VoIP engine Mediastreamer2. \u010cas\u0165 11\" src=\"\/wp-content\/uploads\/2020\/04\/b66fab43eb45c626c50f0383dcfa7cca.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mechanizmovanie d\u00e1t<\/p>\n<p><\/p>\n<ul>\n<li>Blok d\u00e1t dblk_t<\/li>\n<li>Spr\u00e1va mblk_t<\/li>\n<li>Funkcie spr\u00e1vy spr\u00e1v mblk_t<\/li>\n<li>Fronta queue_t<\/li>\n<li>Funkcie spr\u00e1vy front queue_t<\/li>\n<li>Spojenie filtrov<\/li>\n<li>Sign\u00e1lny bod grafu spracovania d\u00e1t<\/li>\n<li>Z\u00e1kulisn\u00e1 \u010dinnos\u0165 tickeru<\/li>\n<li>Buffer (MSBufferizer)<\/li>\n<li>Funkcie spr\u00e1vy MSBufferizer<\/li>\n<\/ul>\n<p><\/p>\n<p>V minulosti <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/497932\/\">\u010dl\u00e1nku<\/a><\/noindex> Vyvinuli sme vlastn\u00fd filter. Tento \u010dl\u00e1nok venujeme zariadeniu vn\u00fatorn\u00e9ho mechanizmu presunu d\u00e1t medzi filtrami mediastreamera. To umo\u017en\u00ed v bud\u00facnosti p\u00edsa\u0165 sofistikovan\u00e9 filtre s men\u0161\u00edmi n\u00e1mahou.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"mehanizm-peremescheniya-dannyh\">Mechanizmovanie d\u00e1t<\/h2>\n<p><\/p>\n<p>Presun d\u00e1t v mediastreameri sa vykon\u00e1va pomocou front, ktor\u00e9 s\u00fa pop\u00edsan\u00e9 \u0161trukt\u00farou <em>queue_t<\/em>. Po front\u00e1ch sa pres\u00favaj\u00fa re\u0165azce spr\u00e1v typu <em>mblk_t<\/em>, ktor\u00e9 samy o sebe neobsahuj\u00fa d\u00e1ta sign\u00e1lu, ale iba odkazy na predch\u00e1dzaj\u00facu, nasleduj\u00facu spr\u00e1vu a na blok d\u00e1t. Okrem toho chcem osobitne zd\u00f4razni\u0165, \u017ee existuje aj pole na odkaz na spr\u00e1vu rovnak\u00e9ho typu, ktor\u00e9 umo\u017e\u0148uje usporiada\u0165 jednosmern\u00fd zoznam spr\u00e1v. Skupinu spr\u00e1v, spojen\u00fdch tak\u00fdmto zoznamom, budeme naz\u00fdva\u0165 tuple. T\u00fdmto sp\u00f4sobom sa ak\u00fdko\u013evek prvok fronty m\u00f4\u017ee ocitn\u00fa\u0165 ako jedin\u00e1 spr\u00e1va <em>mblk_t<\/em>, ale m\u00f4\u017ee by\u0165 aj hlavou tuple spr\u00e1v <em>mblk_t<\/em>. Ka\u017ed\u00e1 spr\u00e1va tuple m\u00f4\u017ee ma\u0165 svoj podriaden\u00fd blok d\u00e1t. Pre\u010do s\u00fa tuple potrebn\u00e9, prediskutujeme o nie\u010do nesk\u00f4r.<\/p>\n<p><\/p>\n<p>Ako bolo uveden\u00e9 vy\u0161\u0161ie, spr\u00e1vu sama o sebe neobsahuje blok d\u00e1t, namiesto toho obsahuje iba ukazovate\u013e na oblas\u0165 pam\u00e4te, kde je blok ulo\u017een\u00fd. V tejto \u010dasti celkov\u00fd obraz fungovania mediastreamera pripom\u00edna sklad dver\u00ed v animovanom filme \"Korpor\u00e1cia mon\u0161tier\", kde dvere (odkazy na d\u00e1ta \u2014 miestnosti) sa \u0161ialenou r\u00fdchlos\u0165ou pohybuj\u00fa po zavesen\u00fdch dopravn\u00edkoch, pri\u010dom samotn\u00e9 miestnosti zost\u00e1vaj\u00fa nehybn\u00e9. <\/p>\n<p><\/p>\n<p>Teraz sa, id\u00fac hierarchiou zdola nahor, podrobne pozrime na uveden\u00e9 entity mechanizmu prenosu d\u00e1t v mediastreameri.<\/p>\n<p><\/p>\n<h3 id=\"blok--dannyh-dblk_t\">Blok d\u00e1t <em>dblk_t<\/em><\/h3>\n<p><\/p>\n<p>Blok d\u00e1t pozost\u00e1va z hlavi\u010dky a d\u00e1tov\u00e9ho buffera. Hlavi\u010dka je pop\u00edsan\u00e1 nasleduj\u00facou \u0161trukt\u00farou,<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct datab\n{\nunsigned char *db_base; \/\/ Ukazovate\u013e na za\u010diatok d\u00e1tov\u00e9ho bufferu.\nunsigned char *db_lim;  \/\/ Ukazovate\u013e na koniec d\u00e1tov\u00e9ho bufferu.\nvoid (*db_freefn)(void*); \/\/ Funkcia na uvo\u013enenie pam\u00e4te pri odstr\u00e1nen\u00ed bloku.\nint db_ref; \/\/ Po\u010d\u00edtadlo odkazov.\n} dblk_t;<\/code><\/pre>\n<p><\/p>\n<p>Polia \u0161trukt\u00fary obsahuj\u00fa ukazovatele na za\u010diatok vyrovn\u00e1vacej pam\u00e4te, koniec vyrovn\u00e1vacej pam\u00e4te a funkciu na odstr\u00e1nenie d\u00e1tovej vyrovn\u00e1vacej pam\u00e4te. Posledn\u00fd prvok v hlavi\u010dke <em>db_ref<\/em> \u2014 \u010d\u00edta\u010d odkazov, ak dosiahne nulu, sl\u00fa\u017ei ako sign\u00e1l na odstr\u00e1nenie tohto bloku z pam\u00e4te. Ak bol blok d\u00e1t vytvoren\u00fd funkciou <em>datab_alloc() <\/em>, tak vyrovn\u00e1vacia pam\u00e4\u0165 bude umiestnen\u00e1 v pam\u00e4ti hne\u010f za hlavi\u010dkou. Vo v\u0161etk\u00fdch ostatn\u00fdch pr\u00edpadoch m\u00f4\u017ee by\u0165 vyrovn\u00e1vacia pam\u00e4\u0165 umiestnen\u00e1 niekde inde. V d\u00e1tovej vyrovn\u00e1vacej pam\u00e4ti bud\u00fa ulo\u017een\u00e9 odpo\u010dty sign\u00e1lu alebo in\u00e9 \u00fadaje, ktor\u00e9 chceme spracov\u00e1va\u0165 filtrami.<\/p>\n<p><\/p>\n<p>Nov\u00fd exempl\u00e1r bloku d\u00e1t sa vytv\u00e1ra pomocou funkcie:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">dblk_t *datab_alloc(int size);<\/code><\/pre>\n<p><\/p>\n<p>Ako vstupn\u00fd parameter sa odovzd\u00e1va ve\u013ekos\u0165 d\u00e1t, ktor\u00e9 bude blok uchov\u00e1va\u0165. Pam\u00e4\u0165 sa vy\u010dlen\u00ed v\u00e4\u010d\u0161ia, aby sa na za\u010diatku vy\u010dlenenej pam\u00e4te umiestnila hlavi\u010dka \u2014 \u0161trukt\u00fara <em>datab<\/em>. Av\u0161ak pri pou\u017eit\u00ed in\u00fdch funkci\u00ed to tak v\u017edy neplat\u00ed, v niektor\u00fdch pr\u00edpadoch m\u00f4\u017ee by\u0165 vyrovn\u00e1vacia pam\u00e4\u0165 umiestnen\u00e1 oddelene od hlavi\u010dky bloku d\u00e1t. Polia \u0161trukt\u00fary sa pri vytvoren\u00ed nastavuj\u00fa tak, aby pole <em>db_base<\/em> ukazovalo na za\u010diatok oblasti d\u00e1t a <em>db_lim<\/em> na jej koniec. \u010c\u00edta\u010d odkazov <em>db_ref<\/em> sa nastav\u00ed na jednu. Ukazovate\u013e funkcie na vy\u010distenie d\u00e1t sa nastav\u00ed na nulu.<\/p>\n<p><\/p>\n<h3 id=\"soobschenie-mblk_t\">Spr\u00e1va <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Ako u\u017e bolo spomenut\u00e9, prvky frontu maj\u00fa typ <em>mblk_t,<\/em> je definovan\u00fd nasledovne:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct msgb\n{\n  struct msgb *b_prev;   \/\/ Ukazovate\u013e na predch\u00e1dzaj\u00faci prvok zoznamu.\n  struct msgb *b_next;   \/\/ Ukazovate\u013e na nasleduj\u00faci prvok zoznamu.\n  struct msgb *b_cont;   \/\/ Ukazovate\u013e na prip\u00e1janie in\u00fdch spr\u00e1v k spr\u00e1ve, na vytvorenie zlo\u017eenia spr\u00e1v.\n  struct datab *b_datap; \/\/ Ukazovate\u013e na \u0161trukt\u00faru bloku d\u00e1t.\n  unsigned char *b_rptr; \/\/ Ukazovate\u013e na za\u010diatok oblasti d\u00e1t na \u010d\u00edtanie \u00fadajov z vyrovn\u00e1vacej pam\u00e4te b_datap.\n  unsigned char *b_wptr; \/\/ Ukazovate\u013e na za\u010diatok oblasti d\u00e1t na z\u00e1pis \u00fadajov do vyrovn\u00e1vacej pam\u00e4te b_datap.\n  uint32_t reserved1;    \/\/ Rezervovan\u00e9 pole1, mediastreamer tam umiest\u0148uje pomocn\u00e9 inform\u00e1cie.\n  uint32_t reserved2;    \/\/ Rezervovan\u00e9 pole2, mediastreamer tam umiest\u0148uje pomocn\u00e9 inform\u00e1cie.\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>Struktura <em>mblk_t<\/em> na za\u010diatku obsahuje ukazovatele <em>b_prev<\/em>, <em>b_next<\/em>, ktor\u00e9 s\u00fa potrebn\u00e9 na organiz\u00e1ciu dvojit\u00e9ho zoznamu (ktor\u00fdm je front <em>queue_t<\/em>). <\/p>\n<p><\/p>\n<p>Potom nasleduje ukazovate\u013e <em>b_cont<\/em>, ktor\u00fd sa pou\u017e\u00edva iba vtedy, ke\u010f spr\u00e1va vstupuje do k\u00f3tu. Pre posledn\u00fa spr\u00e1vu v k\u00f3te zost\u00e1va tento ukazovate\u013e nulov\u00fd. <\/p>\n<p><\/p>\n<p>\u010ealej vid\u00edme ukazovate\u013e na blok \u00fadajov <em>b_datap<\/em>, kv\u00f4li ktor\u00e9mu spr\u00e1va existuje. Za n\u00edm nasleduj\u00fa ukazovatele na oblas\u0165 v r\u00e1mci vyrovn\u00e1vacej pam\u00e4te bloku. Pole <em>b_rptr<\/em> ukazuje miesto, z ktor\u00e9ho sa bud\u00fa \u00fadaje \u010d\u00edta\u0165 z vyrovn\u00e1vacej pam\u00e4te. Pole <em>b_wptr<\/em> ukazuje miesto, z ktor\u00e9ho sa bude zapisova\u0165 do vyrovn\u00e1vacej pam\u00e4te. <\/p>\n<p><\/p>\n<p>Zvy\u0161n\u00e9 polia maj\u00fa administrat\u00edvny charakter a net\u00fdkaj\u00fa sa fungovania mechanizmu prenosu \u00fadajov.<\/p>\n<p><\/p>\n<p>Ni\u017e\u0161ie je zobrazen\u00e1 jednotliv\u00e1 spr\u00e1va s n\u00e1zvom <em>m1<\/em> a blokom \u00fadajov <em>d1<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Presk\u00famavame VoIP engine Mediastreamer2. \u010cas\u0165 11\" src=\"\/wp-content\/uploads\/2020\/04\/e6a726b13491832258c1228f03bde802.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNa nasleduj\u00facom obr\u00e1zku je zobrazen\u00fd k\u00f3t zo troch spr\u00e1v <em>m1<\/em>, <em>m1_1<\/em>, <em>m1_2<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Presk\u00famavame VoIP engine Mediastreamer2. \u010cas\u0165 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\">Funkcie na pr\u00e1cu so spr\u00e1vami <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Nov\u00e1 spr\u00e1va <em>mblk_t<\/em> sa vytv\u00e1ra funkciou:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *allocb(int size, int pri); <\/code><\/pre>\n<p><\/p>\n<p>zalo\u017e\u00ed nov\u00fa spr\u00e1vu v pam\u00e4ti <em>mblk_t<\/em> s blokom \u00fadajov po\u017eadovanej ve\u013ekosti <em>size<\/em>, druh\u00fd argument \u2014 <em>pri<\/em> sa v sk\u00famanej verzii kni\u017enice nepou\u017e\u00edva. Mal by zosta\u0165 nulov\u00fd. Po\u010das fungovania funkcie bude pridelen\u00e1 pam\u00e4\u0165 pre \u0161trukt\u00faru novej spr\u00e1vy a bude zavolan\u00e1 funkcia <em>mblk_init()<\/em>, ktor\u00e1 vyma\u017ee v\u0161etky polia vytvorenej \u0161trukt\u00fary a potom, pomocou uvedenej vy\u0161\u0161ie, <em>datab_alloc()<\/em>vytvor\u00ed vyrovn\u00e1vaciu pam\u00e4\u0165. Potom sa vykon\u00e1 konfigur\u00e1cia pol\u00ed v \u0161trukt\u00fare: <\/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>Na v\u00fdstupe z\u00edskame nov\u00fa spr\u00e1vu s inicializovan\u00fdmi poliami a pr\u00e1zdnou vyrovn\u00e1vacou pam\u00e4\u0165ou. Aby sa do spr\u00e1vy pridali \u00fadaje, je potrebn\u00e9 vykona\u0165 ich kop\u00edrovanie do vyrovn\u00e1vacej pam\u00e4te bloku \u00fadajov:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">memcpy(msg-&gt;b_rptr, data, size);<\/code><\/pre>\n<p><\/p>\n<p>kde <em>data<\/em> \u2014 ukazovate\u013e na zdroj \u00fadajov, a <em>size<\/em> \u2014 ich ve\u013ekos\u0165.<br \/>\nn\u00e1sledne je potrebn\u00e9 aktualizova\u0165 ukazovate\u013e na miesto z\u00e1pisu, aby op\u00e4\u0165 ukazoval na za\u010diatok vo\u013enej oblasti v vyrovn\u00e1vacej pam\u00e4ti:<\/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>Ak je potrebn\u00e9 vytvori\u0165 spr\u00e1vu z u\u017e existuj\u00facej vyrovn\u00e1vacej pam\u00e4te bez kop\u00edrovania, tak sa na to pou\u017e\u00edva funkcia:<\/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>Funkcia po vytvoren\u00ed spr\u00e1vy a \u0161trukt\u00fary bloku \u00fadajov nastav\u00ed jeho ukazovatele na \u00fadaje na adresu <em>buf<\/em>. T.j. v tomto pr\u00edpade sa vyrovn\u00e1vacia pam\u00e4\u0165 \u00fadajov nenach\u00e1dza za po\u013eami hlavi\u010dky bloku \u00fadajov, ako to bolo pri vytvoren\u00ed bloku \u00fadajov funkciou <em>datab_alloc()<\/em>Predan\u00e1 funkcii vyrovn\u00e1vacia pam\u00e4\u0165 s \u00fadajmi zostane tam, kde bola, ale pomocou ukazovate\u013eov bude posunut\u00e1 na pr\u00e1ve vytvoren\u00fd hlavi\u010dku bloku \u00fadajov, a t\u00e1 bude smerova\u0165 na spr\u00e1vu.<\/p>\n<p><\/p>\n<p>K jednej spr\u00e1ve <em>mblk_t<\/em> m\u00f4\u017eu by\u0165 postupne pripojen\u00e9 viacer\u00e9 bloky \u00fadajov. To sa uskuto\u010d\u0148uje funkciou:<\/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 spr\u00e1va, ku ktorej sa prid\u00e1 \u010fal\u0161\u00ed blok \u00fadajov;<br \/>\n<em>data<\/em> \u2014 ukazovate\u013e na blok, ktor\u00e9ho k\u00f3pia bude pridan\u00e1 do spr\u00e1vy;<br \/>\n<em>size<\/em> \u2014 ve\u013ekos\u0165 \u00fadajov;<br \/>\n<em>pad<\/em> \u2014 vlajka, \u017ee ve\u013ekos\u0165 pridelen\u00e9ho priestoru mus\u00ed by\u0165 vyrovnan\u00e1 na hranicu 4 bajtov (doplnok bude vykonan\u00fd nulami). <\/p>\n<p><\/p>\n<p>Ak v existuj\u00facej vyrovn\u00e1vacej pam\u00e4ti spr\u00e1vy je dostatok miesta, nov\u00e9 \u00fadaje bud\u00fa pripojen\u00e9 za u\u017e existuj\u00face \u00fadaje. Ak sa zist\u00ed, \u017ee vo vyrovn\u00e1vacej pam\u00e4ti spr\u00e1vy je menej ako <em>size<\/em>, vytvor\u00ed sa nov\u00e1 spr\u00e1va, s dostato\u010dnou ve\u013ekos\u0165ou vyrovn\u00e1vacej pam\u00e4ti a \u00fadaje sa skop\u00edruj\u00fa do jej vyrovn\u00e1vacej pam\u00e4te. T\u00e1to nov\u00e1 spr\u00e1va sa pripoj\u00ed k p\u00f4vodnej pomocou ukazovate\u013ea <em>b_cont<\/em>. V tomto pr\u00edpade sa spr\u00e1va premen\u00ed na k\u00f4pku. <\/p>\n<p><\/p>\n<p>Ak do k\u00f4pky treba prida\u0165 \u010fal\u0161\u00ed blok \u00fadajov, treba pou\u017ei\u0165 funkciu:<\/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>t\u00e1 n\u00e1jde posledn\u00fa spr\u00e1vu v k\u00f4pke (m\u00e1 <em>b_cont<\/em> nula) a pre t\u00fato spr\u00e1vu vyvol\u00e1 funkciu <em>appendb()<\/em>.<\/p>\n<p><\/p>\n<p>Zisti\u0165 ve\u013ekos\u0165 \u00fadajov v spr\u00e1ve alebo k\u00f4pke m\u00f4\u017eeme pomocou funkcie:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int msgdsize(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>t\u00e1 prejde v\u0161etk\u00fdmi spr\u00e1vami k\u00f4pky a vr\u00e1ti celkov\u00e9 mno\u017estvo \u00fadajov v vyrovn\u00e1vac\u00edch pam\u00e4tiach t\u00fdchto spr\u00e1v. Pre ka\u017ed\u00fa spr\u00e1vu sa mno\u017estvo \u00fadajov vypo\u010d\u00edtava takto:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\"> mp-&gt;b_wptr - mp-&gt;b_rptr<\/code><\/pre>\n<p><\/p>\n<p>Na zl\u00fa\u010denie dvoch k\u00f4pok sa pou\u017e\u00edva funkcia:<\/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>t\u00e1 pripoj\u00ed k\u00f4pku <em>newm<\/em> na koniec k\u00f4pky <em>mp<\/em> a vr\u00e1ti ukazovate\u013e na posledn\u00fa spr\u00e1vu v\u00fdslednej k\u00f4pky.<\/p>\n<p><\/p>\n<p>Ak je to potrebn\u00e9, k\u00f4pku mo\u017eno premeni\u0165 na jednu spr\u00e1vu s jedn\u00fdm blokom \u00fadajov, to sa rob\u00ed funkciou:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgpullup(mblk_t *mp,int len);<\/code><\/pre>\n<p><\/p>\n<p>ak je argument <em>len<\/em> rovn\u00fd -1, ve\u013ekos\u0165 pridelen\u00e9ho vyrovn\u00e1vacieho priestoru sa ur\u010duje automaticky. Ak <em>len<\/em> Ak je to kladn\u00e9 \u010d\u00edslo, vytvor\u00ed sa vyrovn\u00e1vacia pam\u00e4\u0165 tejto ve\u013ekosti a do nej sa skop\u00edruj\u00fa \u00fadaje spr\u00e1v k\u00f3ty. Ak sa vyrovn\u00e1vacia pam\u00e4\u0165 napln\u00ed, kop\u00edrovanie sa ukon\u010d\u00ed. Prv\u00e1 spr\u00e1va k\u00f3ty dostane vyrovn\u00e1vaciu pam\u00e4\u0165 novej ve\u013ekosti so skop\u00edrovan\u00fdmi \u00fadajmi. Ostatn\u00e9 spr\u00e1vy bud\u00fa odstr\u00e1nen\u00e9 a pam\u00e4\u0165 vr\u00e1ten\u00e1 do haldy.<\/p>\n<p><\/p>\n<p>Pri odstra\u0148ovan\u00ed \u0161trukt\u00fary <em>mblk_t<\/em> sa zoh\u013ead\u0148uje \u010d\u00edta\u010d odkazov bloku \u00fadajov, ak pri vyvolan\u00ed <em>freeb()<\/em> je rovn\u00fd nule, blok \u00fadajov sa odstr\u00e1ni spolu s in\u0161tanciou <em>mblk_t<\/em>, na ktor\u00fa odkazuje.<\/p>\n<p><\/p>\n<p>Inicializ\u00e1cia pol\u00ed novej spr\u00e1vy:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void mblk_init(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Pridanie \u010fal\u0161ej d\u00e1vky \u00fadajov k spr\u00e1ve: <\/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>Ak sa nov\u00e9 \u00fadaje nezmestia do vo\u013en\u00e9ho miesta vyrovn\u00e1vacej pam\u00e4te spr\u00e1vy, k spr\u00e1ve sa pripoj\u00ed samostatne vytvoren\u00e1 spr\u00e1va s potrebnou ve\u013ekos\u0165ou vyrovn\u00e1vacej pam\u00e4te (v prvej spr\u00e1ve sa nastav\u00ed ukazovate\u013e na pridan\u00fa spr\u00e1vu) spr\u00e1va sa premen\u00ed na k\u00f3tu.<\/p>\n<p><\/p>\n<p>Pridanie d\u00e1vky \u00fadajov do k\u00f3ty:<\/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>Funkcia vol\u00e1 appendb() v cykle.<\/p>\n<p><\/p>\n<p>Spojenie dvoch k\u00f3t do jednej:<\/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>Spr\u00e1va <em>newm<\/em> bude pripojen\u00e9 k <em>mp<\/em>.<\/p>\n<p><\/p>\n<p>Vytvorenie k\u00f3pie jednotliv\u00e9 spr\u00e1vy:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copyb(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>\u00dapln\u00e9 skop\u00edrovanie k\u00f3ty so v\u0161etk\u00fdmi blokmi \u00fadajov:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copymsg(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Prvky k\u00f3ty sa kop\u00edruj\u00fa funkciou <em>copyb()<\/em>.<\/p>\n<p><\/p>\n<p>Vytvorenie \u013eahkej k\u00f3pie spr\u00e1vy. <em>mblk_t<\/em>Pri tom sa blok \u00fadajov nekop\u00edruje, ale zvy\u0161uje sa \u010d\u00edta\u010d jeho odkazov. <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>Vytvorenie \u013eahkej k\u00f3pie k\u00f3ty. Bloky \u00fadajov sa nekop\u00edruj\u00fa, iba sa zvy\u0161uj\u00fa ich \u010d\u00edta\u010de odkazov. <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>Zlepenie v\u0161etk\u00fdch spr\u00e1v k\u00f3ty do jednej spr\u00e1vy:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgpullup(mblk_t *mp,size_t len);<\/code><\/pre>\n<p><\/p>\n<p>Ak je argument <em>len<\/em> rovn\u00fd -1, ve\u013ekos\u0165 rezerva\u010dnej vyrovn\u00e1vacej pam\u00e4te sa ur\u010duje automaticky.<\/p>\n<p><\/p>\n<p>Odstr\u00e1nenie spr\u00e1vy, k\u00f3ty:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void freemsg(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>\u010c\u00edta\u010d odkazov bloku \u00fadajov sa zn\u00ed\u017ei o jeden. Ak pritom dosiahne nulu, blok \u00fadajov sa tie\u017e odstr\u00e1ni.<\/p>\n<p><\/p>\n<p>S\u010d\u00edtanie celkov\u00e9ho objemu \u00fadajov v spr\u00e1ve alebo k\u00f3te.<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">size_t msgdsize(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Vyberanie spr\u00e1vy z chvosta fronty:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *ms_queue_peek_last (q);<\/code><\/pre>\n<p><\/p>\n<p>Kop\u00edrovanie obsahu rezervovan\u00fdch pol\u00ed jednej spr\u00e1vy do druhej spr\u00e1vy (v skuto\u010dnosti tieto polia obsahuj\u00fa vlajky, ktor\u00e9 sa pou\u017e\u00edvaj\u00fa mediastreamerom):<\/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\">Fronta <em>queue_t<\/em><\/h3>\n<p><\/p>\n<p>Riadkov\u00e1 fronta v mediastreamere je realizovan\u00e1 ako kruhov\u00fd obojsmern\u00fd zoznam. Ka\u017ed\u00fd prvok zoznamu obsahuje ukazovate\u013e na blok d\u00e1t s odpo\u010dtami sign\u00e1lu. To znamen\u00e1, \u017ee sa pos\u00favaj\u00fa len ukazovatele na blok d\u00e1t, zatia\u013e \u010do samotn\u00e9 d\u00e1ta zost\u00e1vaj\u00fa nepohybovan\u00e9. T.j. sa pos\u00favaj\u00fa len odkazy na ne.<br \/>\n\u0160trukt\u00fara popisuj\u00faca frontu <em>queue_t<\/em>, je zobrazen\u00e1 ni\u017e\u0161ie:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _queue\n{\n   mblk_t _q_stopper; \/* \"Pr\u00e1zdny\" prvok fronty, neukazuje na d\u00e1ta, pou\u017e\u00edva sa len na ovl\u00e1danie fronty. Pri inicializ\u00e1cii fronty (qinit()) sa jeho ukazovatele nastavuj\u00fa tak, aby ukazovali na\u0148 sam\u00e9ho. *\/\n   int q_mcount;        \/\/ Po\u010det prvkov vo fronte.\n} queue_t;<\/code><\/pre>\n<p><\/p>\n<p>\u0160trukt\u00fara obsahuje pole \u2014 ukazovate\u013e <em>_q_stopper<\/em> typu *mblk_t, ktor\u00fd ukazuje na prv\u00fd prvok (spr\u00e1vu) vo fronte. Druh\u00e9 pole \u0161trukt\u00fary je \u010d\u00edta\u010d spr\u00e1v nach\u00e1dzaj\u00facich sa vo fronte.<br \/>\nNa obr\u00e1zku ni\u017e\u0161ie je zobrazen\u00e1 fronta s n\u00e1zvom q1, obsahuj\u00faca 4 spr\u00e1vy m1,m2, m3, m4.<br \/>\n<img decoding=\"async\" alt=\"Presk\u00famavame VoIP engine Mediastreamer2. \u010cas\u0165 11\" src=\"\/wp-content\/uploads\/2020\/04\/07fc043861edf15e5eb40e49c8ec5e3e.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNa nasleduj\u00facom obr\u00e1zku je zobrazen\u00e1 fronta s n\u00e1zvom q1, obsahuj\u00faca 4 spr\u00e1vy m1,m2, m3, m4. Spr\u00e1va m2 je hlavou n-tice, do ktorej ved\u00fa \u010fal\u0161ie dve spr\u00e1vy m2_1 a m2_2.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Presk\u00famavame VoIP engine Mediastreamer2. \u010cas\u0165 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\">Funkcie spr\u00e1vy front queue_t<\/h3>\n<p><\/p>\n<p>Inicializ\u00e1cia fronty:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void qinit(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>Pole <em>_q_stopper<\/em> (\u010falej budeme naz\u00fdva\u0165 \"stopper\") inicializuje funkcia <em>mblk_init()<\/em>, jeho ukazovate\u013e predch\u00e1dzaj\u00faceho prvku a nasleduj\u00faceho prvku sa nastavuj\u00fa tak, aby ukazovali na neho sam\u00e9ho. \u010c\u00edta\u010d prvkov fronty sa nulov\u00e1.<\/p>\n<p><\/p>\n<p>Pridanie nov\u00e9ho prvku (spr\u00e1vy):<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void putq(queue_t *q, mblk_t *m);<\/code><\/pre>\n<p><\/p>\n<p>Nov\u00fd prvok <em>m<\/em> sa prid\u00e1va na koniec zoznamu, ukazovatele prvku sa nastavuj\u00fa tak, aby stopor sa stal pre neho nasleduj\u00facim prvkom a on pre stopor predch\u00e1dzaj\u00facim. \u010c\u00edta\u010d prvkov fronty sa zvy\u0161uje.<\/p>\n<p><\/p>\n<p>Odznenie prvku z fronty:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * getq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>sa odstra\u0148uje t\u00e1 spr\u00e1va, ktor\u00e1 stoj\u00ed za stoporom, \u010d\u00edta\u010d prvkov sa zni\u017euje. Ak vo fronte, okrem stopora, nie s\u00fa \u017eiadne prvky, vracia sa 0.<\/p>\n<p><\/p>\n<p>Vlo\u017eenie spr\u00e1vy do fronty:<\/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>Prvok <em>mp<\/em> sa vklad\u00e1 pred prvok <em>emp<\/em>. Ak <em>emp<\/em>=0, spr\u00e1va sa prid\u00e1va na koniec fronty.<\/p>\n<p><\/p>\n<p>Odznenie spr\u00e1vy z hlavy fronty:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void remq(queue_t *q, mblk_t *mp); <\/code><\/pre>\n<p><\/p>\n<p>\u010c\u00edta\u010d prvkov sa zni\u017euje.<\/p>\n<p><\/p>\n<p>\u010c\u00edtanie ukazovate\u013ea na prv\u00fd prvok vo fronte:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * peekq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>Odstr\u00e1nenie v\u0161etk\u00fdch prvkov z fronty s odstr\u00e1nen\u00edm samotn\u00fdch prvkov:<\/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> nie je pou\u017e\u00edvan\u00fd. Po\u010d\u00edtadlo prvkov fronty sa nastavuje na nulu.<\/p>\n<p><\/p>\n<p>Makro na \u010d\u00edtanie ukazovate\u013ea na posledn\u00fd prvok fronty:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * qlast(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>Pri pr\u00e1ci s frontami spr\u00e1v je potrebn\u00e9 ma\u0165 na pam\u00e4ti, \u017ee pri volan\u00ed <em>ms_queue_put(q, m)<\/em> s nulov\u00fdm ukazovate\u013eom na spr\u00e1vu sa funkcia zacykl\u00ed. Va\u0161a aplik\u00e1cia zamrzne. Podobne sa spr\u00e1va <em>ms_queue_next(q, m)<\/em>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-filtrov\">Spojenie filtrov<\/h3>\n<p><\/p>\n<p>Pop\u00edsan\u00e1 fronta sa pou\u017e\u00edva na prenos spr\u00e1v z jedn\u00e9ho filtra na druh\u00fd alebo z jedn\u00e9ho na nieko\u013eko filtrov. Filtres a ich prepojenia tvoria orientovan\u00fd graf. Vstup alebo v\u00fdstup filtra budeme naz\u00fdva\u0165 zov\u0161eobecnuj\u00facim slovom \"pin\". Na opis poradia prepojen\u00ed filtrov medzi sebou sa v mediastreameri pou\u017e\u00edva pojem \"sign\u00e1lna bodka\". Sign\u00e1lna bodka je \u0161trukt\u00fara <em>_MSCPoint<\/em>, ktor\u00e1 obsahuje ukazovate\u013e na filter a \u010d\u00edslo jedn\u00e9ho z jeho pinov, \u010d\u00edm opisuje spojenie jedn\u00e9ho z vstupov alebo v\u00fdstupov filtra. <\/p>\n<p><\/p>\n<h4 id=\"signalnaya-tochka-grafa-obrabotki-dannyh\">Sign\u00e1lny bod grafu spracovania d\u00e1t<\/h4>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _MSCPoint{\nstruct _MSFilter *filter; \/\/ Ukazovate\u013e na filter mediastreamera.\nint pin;                        \/\/ \u010c\u00edslo jedn\u00e9ho z vstupov alebo v\u00fdstupov filtra, t.j. pin.\n} MSCPoint;\n<\/code><\/pre>\n<p><\/p>\n<p>Piny filtrov s\u00fa \u010d\u00edslovan\u00e9 od nuly. <\/p>\n<p><\/p>\n<p>Spojenie dvoch pinov frontou spr\u00e1v je op\u00edsan\u00e9 \u0161trukt\u00farou <em>_MSQueue<\/em>, ktor\u00e1 obsahuje frontu spr\u00e1v a ukazovatele na dva sign\u00e1lne body, ktor\u00e9 sp\u00e1ja:<\/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>Naz\u00fdvame t\u00fato \u0161trukt\u00faru sign\u00e1lnym linkom. Ka\u017ed\u00fd filter mediastreamera obsahuje tabu\u013eku vstupn\u00fdch liniek a tabu\u013eku v\u00fdstupn\u00fdch liniek (<em>MSQueue<\/em>). Ve\u013ekos\u0165 tabuliek je ur\u010den\u00e1 pri vytv\u00e1ran\u00ed filtra, \u010do sme u\u017e robili pomocou exportovanej premennej typu <em>MSFilterDesc<\/em>, ke\u010f sme vyv\u00edjali n\u00e1\u0161 vlastn\u00fd filter. Ni\u017e\u0161ie je zobrazen\u00e1 \u0161trukt\u00fara opisuj\u00faca ak\u00fdko\u013evek filter v mediastreameri, <em>MSFilter<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">\nstruct _MSFilter{\n    MSFilterDesc *desc;    \n    \/* Ukazovate\u013e na popisova\u010d filtra. *\/\n    \/* Chr\u00e1nen\u00e9 atrib\u00faty, ktor\u00e9 nemo\u017eno pres\u00fava\u0165 ani odstra\u0148ova\u0165, inak bude naru\u0161en\u00e1 pr\u00e1ca s pluginmi. *\/\n    ms_mutex_t lock;      \/* Semafor. *\/\n    MSQueue **inputs;     \/* Tabu\u013eka vstupn\u00fdch liniek. *\/\n    MSQueue **outputs;    \/* Tabu\u013eka v\u00fdstupn\u00fdch liniek. *\/\n    struct _MSFactory *factory; \/* Ukazovate\u013e na tov\u00e1re\u0148, ktor\u00e1 vytvorila tento pr\u00edklad filtra. *\/\n    void *padding;              \/* Nepou\u017e\u00edva sa, bude zapojen\u00fd, ak bud\u00fa pridan\u00e9 chr\u00e1nen\u00e9 polia. *\/\n    void *data;                 \/* Ukazovate\u013e na \u013eubovo\u013en\u00fa \u0161trukt\u00faru na uchov\u00e1vanie d\u00e1t vn\u00fatornej stavu filtra a medzi v\u00fdpo\u010dtov. *\/\n    struct _MSTicker *ticker;   \/* Ukazovate\u013e na objekt tikera, ktor\u00fd by nemal by\u0165 nulov\u00fd, ke\u010f sa vol\u00e1 funkcia process(). *\/\n    \/*s\u00fakromn\u00e9 atrib\u00faty, m\u00f4\u017eu sa pres\u00fava\u0165 a meni\u0165 kedyko\u013evek*\/\n    MSList *notify_callbacks; \/* Zoznam sp\u00e4tn\u00fdch volan\u00ed, pou\u017e\u00edvan\u00fdch na spracovanie udalost\u00ed filtra. *\/\n    uint32_t last_tick;       \/* \u010c\u00edslo posledn\u00e9ho tiketu, ke\u010f bol vykonan\u00fd hovor process(). *\/\n    MSFilterStats *stats;     \/* \u0160tatistika pr\u00e1ce filtra.*\/\n    int postponed_task; \/*Po\u010det odlo\u017een\u00fdch \u00faloh. Niektor\u00e9 filtre m\u00f4\u017eu odklada\u0165 spracovanie d\u00e1t (volanie process()) o nieko\u013eko tikov.*\/\n    bool_t seen;  \/* Pr\u00edznak, ktor\u00fd pou\u017e\u00edva tikar na ozna\u010denie, \u017ee tento pr\u00edklad filtra u\u017e bol spracovan\u00fd v danom tikete.*\/\n};\ntypedef struct _MSFilter MSFilter;\n<\/code><\/pre>\n<p><\/p>\n<p>Po tom, \u010do sme vo svojej C-programu prepojili filtre pod\u013ea na\u0161ich predst\u00e1v (ale neprepojili sme tikar), sme t\u00fdm vytvorili orientovan\u00fd graf, ktor\u00e9ho uzly s\u00fa pr\u00edklady \u0161trukt\u00fary <em>MSFilter<\/em>, a hrany s\u00fa pr\u00edklady liniek <em>MSQueue<\/em>. <\/p>\n<p><\/p>\n<h3 id=\"zakulisnaya-deyatelnost-tikera\">Z\u00e1kulisn\u00e1 \u010dinnos\u0165 tickeru<\/h3>\n<p><\/p>\n<p>Ke\u010f som v\u00e1m povedal, \u017ee tikar je filtrovan\u00fd zdroj tikotov, nebola to cel\u00e1 pravda o \u0148om. Tikar je objekt, ktor\u00fd sp\u00fa\u0161\u0165a funkcie <em>process()<\/em> v\u0161etk\u00fdch filtrov sch\u00e9my (grafu), ku ktorej je pripojen\u00fd. Ke\u010f v programe C pripoj\u00edme ticker k filtru grafu, ukazujeme tickeru graf, ktor\u00fdm bude od tohto momentu riadi\u0165, k\u00fdm ho neodpoj\u00edme. Po pripojen\u00ed za\u010d\u00edna ticker presk\u00famava\u0165 zveren\u00fd mu graf, zostavuj\u00fac zoznam filtrov, do ktor\u00fdch vstupuje. Aby \"nepo\u010d\u00edta\u0165\" ten ist\u00fd filter dvakr\u00e1t, ozna\u010duje n\u00e1jden\u00e9 filtre, nastavuj\u00fac v nich pr\u00edznak <em>seen<\/em>. H\u013eadanie sa vykon\u00e1va pod\u013ea tabuliek liniek, ktor\u00e9 m\u00e1 ka\u017ed\u00fd filter. <\/p>\n<p><\/p>\n<p>Po\u010das svojej oboznamovacej prehliadky grafu tick nadob\u00fad\u00e1, \u010di je medzi filtrami aspo\u0148 jeden, ktor\u00fd pln\u00ed \u00falohu zdroja d\u00e1tov\u00fdch blokov. Ak sa tak\u00fdto nen\u00e1jde, graf je pova\u017eovan\u00fd za nespr\u00e1vny a ticker n\u00fatene ukon\u010d\u00ed svoju \u010dinnos\u0165.<\/p>\n<p><\/p>\n<p>Ak sa graf uk\u00e1zal by\u0165 \"spr\u00e1vnym\", pre ka\u017ed\u00fd n\u00e1jden\u00fd filter sa na inicializ\u00e1ciu vol\u00e1 funkcia <em>preprocess()<\/em>. Akon\u00e1hle nastane \u010das na \u010fal\u0161\u00ed cyklus spracovania (predvolene ka\u017ed\u00fdch 10 milisek\u00fand), tick vyvol\u00e1 funkciu <em>process()<\/em> pre v\u0161etky predt\u00fdm n\u00e1jden\u00e9 filtre zdrojov a potom aj pre ostatn\u00e9 filtre zo zoznamu. Ak filter m\u00e1 vstupn\u00e9 linky, tak spustenie funkcie <em>process()<\/em> opakovan\u00edm, k\u00fdm sa fronty vstupn\u00fdch odkazov nevyprazdnia. Potom prech\u00e1dza na \u010fal\u0161\u00ed filter zo zoznamu a \"preto\u010d\u00ed\" ho, k\u00fdm neoslobod\u00ed vstupn\u00e9 odkazy od spr\u00e1v. Ticker prech\u00e1dza od filtra k filtru, k\u00fdm sa zoznam neskon\u010d\u00ed. T\u00fdmto kon\u010d\u00ed spracovanie taktu. <\/p>\n<p><\/p>\n<p>Teraz sa vr\u00e1time k n-tic\u00edm a prediskutujeme, na \u010do bola v mediastreameri pridan\u00e1 tak\u00e1to entita. Vo v\u0161eobecnosti objem d\u00e1t potrebn\u00fd algoritmu p\u00f4sobiacemu vo filtri nezhoduje a nie je kr\u00e1tky s ve\u013ekos\u0165ou d\u00e1tov\u00fdch bufferov prich\u00e1dzaj\u00facich na vstupe. Napr\u00edklad p\u00ed\u0161eme filter, ktor\u00fd vykon\u00e1va r\u00fdchlu Fourierovu transform\u00e1ciu, ktor\u00e1 pod\u013ea defin\u00edcie m\u00f4\u017ee spracov\u00e1va\u0165 iba bloky d\u00e1t, ktor\u00fdch ve\u013ekos\u0165 je mocninou dvoch. Nech je to 512 vzoriek. Ak s\u00fa d\u00e1ta generovan\u00e9 telef\u00f3nnym kan\u00e1lom, buffer d\u00e1t ka\u017edej spr\u00e1vy na vstupe bude prin\u00e1\u0161a\u0165 po 160 vzork\u00e1ch sign\u00e1lu. Existuje poku\u0161enie neber\u00fa\u0165 d\u00e1ta z vchodu, k\u00fdm tam nebude po\u017eadovan\u00e9 mno\u017estvo d\u00e1t. Ale v tomto pr\u00edpade vznikne kol\u00edzia s tickerom, ktor\u00fd bude neuspe\u0161ne sna\u017ei\u0165 sa \u201eprehr\u00e1va\u0165\u201c filter do vypr\u00e1zdnenia vstupn\u00e9ho linku. Predt\u00fdm sme tento pravidlo ozna\u010dili ako tret\u00ed princ\u00edp fungovania filtra. Pod\u013ea tohto princ\u00edpu funkcia process() filtra by mala zobra\u0165 v\u0161etky d\u00e1ta z vstupn\u00fdch frontov.<\/p>\n<p><\/p>\n<p>Okrem toho z vstupu nebude mo\u017en\u00e9 z\u00edska\u0165 iba 512 s\u00fa\u010dtov, preto\u017ee je mo\u017en\u00e9 zbera\u0165 len cel\u00e9 bloky, t.j. filter bude musie\u0165 z\u00edska\u0165 640 s\u00fa\u010dtov a pou\u017eit\u00edm 512 z nich zvy\u0161ok a\u017e do nahromadenia novej d\u00e1vky \u00fadajov. T\u00fdmto sp\u00f4sobom n\u00e1\u0161 filter, okrem vykon\u00e1vania svojej hlavnej \u00falohy, mus\u00ed zabezpe\u010di\u0165 pomocn\u00e9 \u010dinnosti na medziskladovanie vstupn\u00fdch \u00fadajov. V\u00fdvoj\u00e1ri mediastreamera na vyrie\u0161enie tejto v\u0161eobecnej \u00falohy vyvinuli \u0161peci\u00e1lny objekt \u2014 MSBufferizer (bufferiz\u00e1tor), ktor\u00fd t\u00fato \u00falohu rie\u0161i pomocou n-t\u00edc. <\/p>\n<p><\/p>\n<h3 id=\"buferizator-msbufferizer\">Buffer (MSBufferizer)<\/h3>\n<p><\/p>\n<p>Tento objekt bude akumulova\u0165 vstupn\u00e9 d\u00e1ta vo vn\u00fatri filtra a za\u010dne ich odovzd\u00e1va\u0165 na spracovanie hne\u010f, ako sa mno\u017estvo inform\u00e1ci\u00ed stane dostato\u010dn\u00fdm na spustenie algoritmu filtra. K\u00fdm bufferiz\u00e1tor hromad\u00ed d\u00e1ta, filter bude fungova\u0165 v pr\u00e1zdnom re\u017eime, neutr\u00e1ciac v\u00fdpo\u010dtov\u00fa kapacitu procesora. Ale hne\u010f ako funkcia \u010d\u00edtania z bufferiz\u00e1tora vr\u00e1ti hodnotu odli\u0161n\u00fa od nuly, funkcia process() filtra za\u010dne z\u00edskava\u0165 a spracov\u00e1va\u0165 z bufferiz\u00e1tora d\u00e1ta po d\u00e1vkach potrebnej ve\u013ekosti, a\u017e do ich vy\u010derpania.<br \/>\nNezvy\u010dajn\u00e9 d\u00e1ta zatia\u013e zostan\u00fa v bufferiz\u00e1tore ako prv\u00fd prvok n-tice, ku ktor\u00e9mu sa pripoja nasleduj\u00face bloky vstupn\u00fdch \u00fadajov. <\/p>\n<p><\/p>\n<p>\u0160trukt\u00fara, ktor\u00e1 popisuje bufferiz\u00e1tor: <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">struct _MSBufferizer{\nqueue_t q; \/* Fronta spr\u00e1v. *\/\nint size; \/* Celkov\u00e1 ve\u013ekos\u0165 \u00fadajov nach\u00e1dzaj\u00facich sa v bufferiz\u00e1tore v danom momente. *\/\n};\ntypedef struct _MSBufferizer MSBufferizer;<\/code><\/pre>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-msbufferizer\">Funkcie spr\u00e1vy MSBufferizer<\/h3>\n<p><\/p>\n<p>Vytvorenie nov\u00e9ho pr\u00edkladu bufferiz\u00e1tora:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">MSBufferizer * ms_bufferizer_new(void);<\/code><\/pre>\n<p><\/p>\n<p>Pam\u00e4\u0165 sa vydel\u00ed, inicializuje v <em>ms_bufferizer_init()<\/em> a vr\u00e1ti ukazovate\u013e.<\/p>\n<p><\/p>\n<p>Funkcia inicializ\u00e1cie:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_init(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Inicializuje sa fronta <em>q<\/em>, pole <em>size<\/em> nastav\u00ed sa na nulu.<\/p>\n<p><\/p>\n<p>Pridanie spr\u00e1vy:<\/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>Spr\u00e1va m sa prid\u00e1va do fronty. Vypo\u010d\u00edtan\u00e1 ve\u013ekos\u0165 blokov \u00fadajov sa prid\u00e1va k <em>size<\/em>.<\/p>\n<p><\/p>\n<p>Presun v\u0161etk\u00fdch spr\u00e1v z fronty spr\u00e1vy linky do bufferiz\u00e1tora <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>Prenos spr\u00e1v z linky <em>q<\/em> do bufferiz\u00e1tora sa vykon\u00e1va pomocou funkcie <em>ms_bufferizer_put()<\/em>.<\/p>\n<p><\/p>\n<p>\u010c\u00edtanie z bufferiz\u00e1tora:<\/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>Ak je ve\u013ekos\u0165 akumulovan\u00fdch v bufferiz\u00e1tore \u00fadajov men\u0161ia ako po\u017eadovan\u00e1 (<em>datalen<\/em>), funkcia vr\u00e1ti nulu, kop\u00edrovanie \u00fadajov do data sa neuskuto\u010dn\u00ed. V opa\u010dnom pr\u00edpade sa vykon\u00e1 po sebe id\u00face kop\u00edrovanie \u00fadajov z n-t\u00edc nach\u00e1dzaj\u00facich sa vo vyrovn\u00e1vacej pam\u00e4ti. Po skop\u00edrovan\u00ed sa n-tica odstr\u00e1ni a pam\u00e4\u0165 sa uvo\u013en\u00ed. Kop\u00edrovanie sa skon\u010d\u00ed v okamihu, ke\u010f bude skop\u00edrovan\u00fdch datalen bajtov. Ak sa miesto minie uprostred bloku \u00fadajov, v tejto spr\u00e1ve sa blok \u00fadajov skr\u00e1ti na zost\u00e1vaj\u00facu nekop\u00edrovan\u00fa \u010das\u0165. Pri \u010fal\u0161om volan\u00ed sa kop\u00edrovanie obnov\u00ed od tohto miesta.<\/p>\n<p><\/p>\n<p>\u010c\u00edtanie po\u010dtu \u00fadajov, ktor\u00e9 s\u00fa moment\u00e1lne dostupn\u00e9 vo vyrovn\u00e1vacej pam\u00e4ti:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int ms_bufferizer_get_avail(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Vracia pole <em>size<\/em> vyrovn\u00e1vacej pam\u00e4te.<\/p>\n<p><\/p>\n<p>Zahodenie \u010dasti \u00fadajov nach\u00e1dzaj\u00facich sa vo vyrovn\u00e1vacej pam\u00e4ti:<\/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>Ur\u010den\u00e9 mno\u017estvo bajtov \u00fadajov sa extrahuje a zahod\u00ed. Vyhadzuj\u00fa sa najstar\u0161ie \u00fadaje.<\/p>\n<p><\/p>\n<p>Odstr\u00e1nenie v\u0161etk\u00fdch spr\u00e1v nach\u00e1dzaj\u00facich sa vo vyrovn\u00e1vacej pam\u00e4ti:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_flush(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Po\u010d\u00edtadlo \u00fadajov sa resetuje na nulu.<\/p>\n<p><\/p>\n<p>Odstr\u00e1nenie v\u0161etk\u00fdch spr\u00e1v nach\u00e1dzaj\u00facich sa vo vyrovn\u00e1vacej pam\u00e4ti:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_uninit(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Resetovanie po\u010d\u00edtadla sa neuskuto\u010dn\u00ed.<\/p>\n<p><\/p>\n<p>Odstr\u00e1nenie vyrovn\u00e1vacej pam\u00e4te a uvo\u013enenie pam\u00e4ti:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_destroy(MSBufferizer *obj);  <\/code><\/pre>\n<p><\/p>\n<p>Pr\u00edklady pou\u017eitia vyrovn\u00e1vacej pam\u00e4te n\u00e1jdete v zdrojovom k\u00f3de nieko\u013ek\u00fdch filtrov mediastreamera. Napr\u00edklad vo filtri MS_L16_ENC, ktor\u00fd vykon\u00e1va preusporiadanie bajtov v odmeran\u00fdch hodnot\u00e1ch zo sie\u0165ov\u00e9ho poriadku do poriadku hostite\u013ea:<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>V nasleduj\u00facom \u010dl\u00e1nku presk\u00famame ot\u00e1zku hodnotenia za\u0165a\u017eenia na ticker a sp\u00f4soby boja s nadmernou v\u00fdpo\u010dtovou z\u00e1\u0165a\u017eou v mediastreameri.<\/p>\n<p>Zdroj: <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\/sk\/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=\"sk_SK\" \/>\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\/sk\/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\udd47Objavujeme VoIP engine Mediastreamer2. \u010cas\u0165 11 | ProHoster","description":"Materi\u00e1l \u010dl\u00e1nku je prevzat\u00fd z m\u00f4jho kan\u00e1la na Dzene.","canonical_url":"https:\/\/prohoster.info\/sk\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sk_SK","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\/sk\/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\/sk\/wp-json\/wp\/v2\/posts\/79540","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/comments?post=79540"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/posts\/79540\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/media\/79541"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/media?parent=79540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/categories?post=79540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/tags?post=79540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}