Raziskovanje mehanizma VoIP Mediastreamer2. 11. del

Gradivo članka je vzeto iz mojega zen kanal.

Raziskovanje mehanizma VoIP Mediastreamer2. 11. del

Mehanizem premikanja podatkov

  • Podatkovni blok dblk_t
  • Sporočilo mblk_t
  • Funkcije za delo s sporočili mblk_t
  • Čakalna vrsta queue_t
  • Funkcije za delo s čakalnimi vrstami queue_t
  • Priključni filtri
  • Signalna točka grafa obdelave podatkov
  • Dejavnosti tickerja v zakulisju
  • Medpomnilnik (MSBufferizer)
  • Funkcije za delo z MSBufferizer

V preteklosti članek razvili smo lasten filter. Ta članek se bo osredotočil na notranji mehanizem za premikanje podatkov med filtri pretočnih medijev. To vam bo v prihodnosti omogočilo pisanje zahtevnih filtrov z manj truda.

Mehanizem premikanja podatkov

Premikanje podatkov v medijskem pretakalniku se izvaja z uporabo čakalnih vrst, ki jih opisuje struktura queue_t. Nizi sporočil, kot so mblk_t, ki sami ne vsebujejo signalnih podatkov, temveč le povezavo do prejšnjega, naslednjega sporočila in do podatkovnega bloka. Poleg tega želim posebej poudariti, da obstaja tudi polje za povezavo do sporočila iste vrste, ki vam omogoča organiziranje enojno povezanega seznama sporočil. Skupino sporočil, združenih s takšnim seznamom, bomo imenovali tuple. Tako je lahko kateri koli element čakalne vrste eno samo sporočilo mblk_tin morda glavo nabora sporočil mblk_t. Vsako sporočilo torke ima lahko svoj blok podatkov oddelka. Zakaj so tuple potrebne, bomo razpravljali nekoliko kasneje.

Kot že omenjeno, samo sporočilo ne vsebuje bloka podatkov, temveč le kazalec na pomnilniško območje, kjer je blok shranjen. V tem delu celotna slika dela medijskega streamerja spominja na skladišče vrat v risanki Monsters, Inc., kjer se vrata (povezave do podatkov - sob) premikajo z noro hitrostjo po nadzemnih tekočih trakovih, medtem ko se same sobe ostanejo nepremični.

Zdaj, ko se premikamo po hierarhiji od spodaj navzgor, podrobno razmislimo o navedenih entitetah mehanizma za prenos podatkov v medijskem pretakalniku.

Podatkovni blok dblk_t

Podatkovni blok je sestavljen iz glave in podatkovnega medpomnilnika. Glava je opisana z naslednjo strukturo,

typedef struct datab
{
unsigned char *db_base; // Указатель на начало буфер данных.
unsigned char *db_lim;  // Указатель на конец буфер данных.
void (*db_freefn)(void*); // Функция освобождения памяти при удалении блока.
int db_ref; // Счетчик ссылок.
} dblk_t;

Polja strukture vsebujejo kazalce na začetek medpomnilnika, konec medpomnilnika in funkcijo za brisanje podatkovnega medpomnilnika. Zadnji element v glavi db_ref — referenčni števec, če doseže nič, to služi kot signal za izbris tega bloka iz pomnilnika. Če je podatkovni blok ustvarila funkcija datab_alloc() , potem bo podatkovni medpomnilnik postavljen v pomnilnik takoj za glavo. V vseh drugih primerih se medpomnilnik lahko nahaja nekje ločeno. Podatkovni medpomnilnik bo vseboval vzorce signalov ali druge podatke, ki jih želimo obdelati s filtri.

Nov primerek podatkovnega bloka se ustvari s funkcijo:

dblk_t *datab_alloc(int size);

Kot vhodni parameter je podana velikost podatkov, ki jih bo blok shranil. Več pomnilnika je dodeljeno, da se glava - struktura - postavi na začetek dodeljenega pomnilnika datab. Toda pri uporabi drugih funkcij se to ne zgodi vedno; v nekaterih primerih se podatkovni medpomnilnik lahko nahaja ločeno od glave podatkovnega bloka. Pri ustvarjanju strukture so polja konfigurirana tako, da njeno polje db_base pokazal na začetek podatkovnega območja in db_lim do svojega konca. Število povezav db_ref je nastavljen na eno. Kazalec funkcije brisanja podatkov je nastavljen na nič.

Sporočilo mblk_t

Kot rečeno, so elementi čakalne vrste vrste mblk_t, opredeljena je na naslednji način:

typedef struct msgb
{
  struct msgb *b_prev;   // Указатель на предыдущий элемент списка.
  struct msgb *b_next;   // Указатель на следующий элемент списка.
  struct msgb *b_cont;   // Указатель для подклейки к сообщению других сообщений, для создания кортежа сообщений.
  struct datab *b_datap; // Указатель на структуру блока данных.
  unsigned char *b_rptr; // Указатель на начало области данных для чтения данных буфера b_datap.
  unsigned char *b_wptr; // Указатель на начало области данных для записи данных буфера b_datap.
  uint32_t reserved1;    // Зарезервированное поле1, медиастример помещает туда служебную информацию. 
  uint32_t reserved2;    // Зарезервированное поле2, медиастример помещает туда служебную информацию.
  #if defined(ORTP_TIMESTAMP)
  struct timeval timestamp;
  #endif
  ortp_recv_addr_t recv_addr;
} mblk_t;

Struktura mblk_t vsebuje kazalce na začetku b_prej, b_naslednji, ki so potrebni za organizacijo dvojno povezanega seznama (ki je čakalna vrsta queue_t).

Potem pride kazalec b_nadaljevanje, ki se uporablja le, če je sporočilo del tuple. Za zadnje sporočilo v tupleu ta kazalec ostane nič.

Nato vidimo kazalec na podatkovni blok b_datap, za katero sporočilo obstaja. Sledijo mu kazalci na področje znotraj medpomnilnika podatkov bloka. Polje b_rptr določa lokacijo, s katere bodo prebrani podatki iz medpomnilnika. Polje b_wptr označuje lokacijo, s katere se bo izvajalo pisanje v medpomnilnik.

Ostala polja so storitvene narave in se ne nanašajo na delovanje mehanizma za prenos podatkov.

Spodaj je eno samo sporočilo z imenom m1 in podatkovni blok d1.
Raziskovanje mehanizma VoIP Mediastreamer2. 11. del
Naslednja slika prikazuje niz treh sporočil m1, m1_1, m1_2.
Raziskovanje mehanizma VoIP Mediastreamer2. 11. del

Funkcije sporočanja mblk_t

Novo sporočilo mblk_t ustvarjena s funkcijo:

mblk_t *allocb(int size, int pri); 

v spomin vnese novo sporočilo mblk_t s podatkovnim blokom določene velikosti velikost, drugi argument - pri ni uporabljen v tej različici knjižnice. Ostati mora nič. Med delovanjem funkcije bo pomnilnik dodeljen za strukturo novega sporočila in funkcija bo poklicana mblk_init(), ki bo ponastavil vsa polja ustvarjenega primerka strukture in nato z uporabo zgoraj omenjenega datab_alloc(), bo ustvaril podatkovni medpomnilnik. Po tem bodo polja v strukturi konfigurirana:

mp->b_datap=datab;
mp->b_rptr=mp->b_wptr=datab->db_base;
mp->b_next=mp->b_prev=mp->b_cont=NULL;

Na izhodu prejmemo novo sporočilo z inicializiranimi polji in praznim medpomnilnikom podatkov. Če želite sporočilu dodati podatke, jih morate kopirati v medpomnilnik podatkovnega bloka:

memcpy(msg->b_rptr, data, size);

če datum je kazalec na vir podatkov in velikost - njihova velikost.
potem morate posodobiti kazalec na točko pisanja, tako da bo znova kazal na začetek prostega območja v medpomnilniku:

msg->b_wptr = msg->b_wptr + size

Če morate ustvariti sporočilo iz obstoječega medpomnilnika brez kopiranja, uporabite funkcijo:

mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*)); 

Funkcija bo po ustvarjanju sporočila in strukture podatkovnega bloka konfigurirala svoje kazalce na podatke na naslovu buf. Tisti. v tem primeru se medpomnilnik podatkov ne nahaja za polji glave podatkovnega bloka, kot je bilo pri ustvarjanju podatkovnega bloka s funkcijo datab_alloc(). Medpomnilnik s podatki, posredovanimi funkciji, bo ostal tam, kjer je bil, vendar bo s pomočjo kazalcev pritrjen na novo ustvarjeno glavo podatkovnega bloka in s tem na sporočilo.

Na eno sporočilo mblk_t Več podatkovnih blokov je mogoče združiti zaporedno. To naredi funkcija:

mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad); 

mp — sporočilo, ki mu bo dodan drug podatkovni blok;
datum — kazalec na blok, katerega kopija bo dodana v sporočilo;
velikost — velikost podatkov;
pad — zastavica, da mora biti velikost dodeljenega pomnilnika poravnana vzdolž 4-bajtne meje (polnjenje bo izvedeno z ničlami).

Če je v obstoječem podatkovnem medpomnilniku sporočila dovolj prostora, bodo novi podatki prilepljeni za podatki, ki so že tam. Če je v medpomnilniku podatkov manj prostega prostora kot velikost, potem se ustvari novo sporočilo z zadostno velikostjo vmesnega pomnilnika in podatki se kopirajo v njegov medpomnilnik. To je novo sporočilo, povezano s prvotnim s kazalcem b_nadaljevanje. V tem primeru se sporočilo spremeni v tuple.

Če morate v tulp dodati še en blok podatkov, potem morate uporabiti funkcijo:

void msgappend(mblk_t *mp, const char *data, int size, bool_t pad);

ona bo našla zadnje sporočilo v tuple (on ima b_nadaljevanje bo nič) in bo poklical funkcijo za to sporočilo appendb().

Velikost podatkov v sporočilu ali nizu lahko ugotovite s funkcijo:

int msgdsize(const mblk_t *mp);

preletela bo vsa sporočila v tuple in vrnila skupno količino podatkov v podatkovnih medpomnilnikih teh sporočil. Za vsako sporočilo se količina podatkov izračuna na naslednji način:

 mp->b_wptr - mp->b_rptr

Če želite združiti dve tuple, uporabite funkcijo:

mblk_t *concatb(mblk_t *mp, mblk_t *newm);

ona doda tuple nov do repa tuple mp in vrne kazalec na zadnje sporočilo nastale tuple.

Če je potrebno, lahko tuple spremenite v eno sporočilo z enim blokom podatkov; to stori funkcija:

void msgpullup(mblk_t *mp,int len);

če argument len je -1, potem se velikost dodeljenega medpomnilnika določi samodejno. če len je pozitivno število, bo medpomnilnik te velikosti ustvarjen in vanj bodo prekopirani podatki o sporočilu tuple. Če medpomnilnika zmanjka, se kopiranje tam ustavi. Prvo sporočilo tuple bo prejelo medpomnilnik nove velikosti s kopiranimi podatki. Preostala sporočila bodo izbrisana in pomnilnik vrnjen v kopico.

Pri brisanju strukture mblk_t število sklicev podatkovnega bloka se upošteva, če pri klicu freeb() se izkaže, da je nič, potem se podatkovni medpomnilnik izbriše skupaj s primerkom mblk_t, ki kaže na to.

Inicializacija polj novega sporočila:

void mblk_init(mblk_t *mp);

Dodajanje drugega podatka v sporočilo:

mblk_t * appendb(mblk_t *mp, const char *data, size_t size, bool_t pad);

Če se novi podatki ne prilegajo v prosti prostor podatkovnega medpomnilnika sporočila, se sporočilu priloži ločeno ustvarjeno sporočilo z medpomnilnikom zahtevane velikosti (v prvem sporočilu je nastavljen kazalec na dodano sporočilo) in sporočilo se spremeni v tulp.

Dodajanje podatka v tulp:

void msgappend(mblk_t *mp, const char *data, size_t size, bool_t pad); 

Funkcija pokliče appendb() v zanki.

Združevanje dveh tulp v eno:

mblk_t *concatb(mblk_t *mp, mblk_t *newm);

Sporočilo nov bo priložen mp.

Izdelava kopije enega sporočila:

mblk_t *copyb(const mblk_t *mp);

Popolno kopiranje tuple z vsemi podatkovnimi bloki:

mblk_t *copymsg(const mblk_t *mp);

Elemente tuple kopira funkcija copyb().

Ustvarite preprosto kopijo sporočila mblk_t. V tem primeru se podatkovni blok ne kopira, poveča pa se njegov referenčni števec db_ref:

mblk_t *dupb(mblk_t *mp);

Izdelava lahke kopije tuple. Podatkovni bloki se ne kopirajo, povečajo se le njihovi referenčni števci db_ref:

mblk_t *dupmsg(mblk_t* m);

Lepljenje vseh sporočil tulp v eno sporočilo:

void msgpullup(mblk_t *mp,size_t len);

Če argument len je -1, potem se velikost dodeljenega medpomnilnika določi samodejno.

Brisanje sporočila, tuple:

void freemsg(mblk_t *mp);

Število referenc podatkovnega bloka se zmanjša za eno. Če doseže nič, se izbriše tudi podatkovni blok.

Izračun skupne količine podatkov v sporočilu ali množici.

size_t msgdsize(const mblk_t *mp);

Pridobivanje sporočila z repa čakalne vrste:

mblk_t *ms_queue_peek_last (q);

Kopiranje vsebine rezerviranih polj enega sporočila v drugo sporočilo (pravzaprav ta polja vsebujejo zastavice, ki jih uporablja medijski pretočnik):

mblk_meta_copy(const mblk_t *source, mblk *dest);

Čakalna vrsta queue_t

Čakalna vrsta sporočil v medijskem pretakalniku je implementirana kot krožni dvojno povezani seznam. Vsak element seznama vsebuje kazalec na podatkovni blok z vzorci signalov. Izkazalo se je, da se premikajo samo kazalci na podatkovni blok, medtem ko sami podatki ostanejo nepremični. Tisti. premaknejo se samo povezave do njih.
Struktura, ki opisuje čakalno vrsto queue_t, prikazano spodaj:

typedef struct _queue
{
   mblk_t _q_stopper; /* "Холостой" элемент очереди, не указывает на данные, используется только для управления очередью. При инициализации очереди (qinit()) его указатели настраиваются так, чтобы они указывали на него самого. */
   int q_mcount;        // Количество элементов в очереди.
} queue_t;

Struktura vsebuje polje - kazalec _q_zamašek tip *mblk_t, kaže na prvi element (sporočilo) v čakalni vrsti. Drugo polje strukture je števec sporočil v čakalni vrsti.
Spodnja slika prikazuje čakalno vrsto z imenom q1, ki vsebuje 4 sporočila m1, m2, m3, m4.
Raziskovanje mehanizma VoIP Mediastreamer2. 11. del
Naslednja slika prikazuje čakalno vrsto z imenom q1, ki vsebuje 4 sporočila m1,m2,m3,m4. Sporočilo m2 je glava tuple, ki vsebuje še dve sporočili m2_1 in m2_2.

Raziskovanje mehanizma VoIP Mediastreamer2. 11. del

Funkcije za delo s čakalnimi vrstami queue_t

Inicializacija čakalne vrste:

void qinit(queue_t *q);

Polje _q_zamašek (v nadaljevanju ga bomo imenovali »zamašek«) inicializira funkcija mblk_init(), njegov prejšnji element in kazalec naslednjega elementa sta prilagojena tako, da kažeta nase. Števec elementov čakalne vrste se ponastavi na nič.

Dodajanje novega elementa (sporočila):

void putq(queue_t *q, mblk_t *m);

Nov element m doda na konec seznama, se kazalci elementov prilagodijo tako, da zamašek zanj postane naslednji element, za zamašek pa postane prejšnji element. Števec elementov čakalne vrste se poveča.

Pridobivanje elementa iz čakalne vrste:

mblk_t * getq(queue_t *q); 

Sporočilo, ki pride po zamašku, je pridobljeno, števec elementov pa se zmanjša. Če v čakalni vrsti ni elementov razen zamaška, se vrne 0.

Vstavljanje sporočila v čakalno vrsto:

void insq(queue_t *q, mblk_t *emp, mblk_t *mp); 

Element mp vstavljen pred element emp. Če emp=0, potem je sporočilo dodano na rep čakalne vrste.

Pridobivanje sporočila iz glave čakalne vrste:

void remq(queue_t *q, mblk_t *mp); 

Števec elementov se zmanjša.

Branje kazalca na prvi element v čakalni vrsti:

mblk_t * peekq(queue_t *q); 

Odstranjevanje vseh elementov iz čakalne vrste ob brisanju samih elementov:

void flushq(queue_t *q, int how);

Prepir kako se ne uporablja. Števec elementov čakalne vrste je nastavljen na nič.

Makro za branje kazalca na zadnji element čakalne vrste:

mblk_t * qlast(queue_t *q);

Ko delate s čakalnimi vrstami sporočil, se zavedajte, da ko kličete ms_queue_put(q, m) z ničelnim kazalcem na sporočilo se funkcija vrne v zanko. Vaš program bo zamrznil. obnaša podobno ms_queue_next(q, m).

Priključni filtri

Zgoraj opisana čakalna vrsta se uporablja za posredovanje sporočil iz enega filtra v drugega ali iz enega v več filtrov. Filtri in njihove povezave tvorijo usmerjen graf. Vhod ali izhod filtra se bo imenoval splošna beseda "pin". Za opis vrstnega reda, v katerem so filtri povezani med seboj, medijski pretočni program uporablja koncept "signalne točke". Signalna točka je struktura _MSCPoint, ki vsebuje kazalec na filter in številko enega od njegovih pinov, v skladu s tem opisuje povezavo enega od vhodov ali izhodov filtra.

Signalna točka grafa obdelave podatkov

typedef struct _MSCPoint{
struct _MSFilter *filter; // Указатель на фильтр медиастримера.
int pin;                        // Номер одного из входов или выходов фильтра, т.е. пин.
} MSCPoint;

Zatiči filtra so oštevilčeni od nič.

Povezavo dveh pinov s čakalno vrsto sporočil opisuje struktura _MSQueue, ki vsebuje čakalno vrsto sporočil in kazalce na dve signalni točki, ki ju povezuje:

typedef struct _MSQueue
{
queue_t q;
MSCPoint prev;
MSCPoint next;
}MSQueue;

To strukturo bomo imenovali signalna povezava. Vsak filter medijskega pretakalnika vsebuje tabelo vhodnih povezav in tabelo izhodnih povezav (MSQueue). Velikost tabel se nastavi ob izdelavi filtra, to smo že storili z izvoženo spremenljivko tipa MSFilterDesc, ko smo razvili lasten filter. Spodaj je struktura, ki opisuje poljuben filter v medijskem pretakalniku, MSFilter:


struct _MSFilter{
    MSFilterDesc *desc;    /* Указатель на дескриптор фильтра. */
    /* Защищенные атрибуты, их нельзя сдвигать или убирать иначе будет нарушена работа с плагинами. */
    ms_mutex_t lock;      /* Семафор. */
    MSQueue **inputs;     /* Таблица входных линков. */
    MSQueue **outputs;    /* Таблица выходных линков. */
    struct _MSFactory *factory; /* Указатель на фабрику, которая создала данный экземпляр фильтра. */
    void *padding;              /* Не используется, будет задействован если добавятся защищенные поля. */
    void *data;                 /* Указатель на произвольную структуру для хранения данных внутреннего состояния фильтра и промежуточных вычислений. */
    struct _MSTicker *ticker;   /* Указатель на объект тикера, который не должен быть нулевым когда вызывается функция process(). */
    /*private attributes, they can be moved and changed at any time*/
    MSList *notify_callbacks; /* Список обратных вызовов, используемых для обработки событий фильтра. */
    uint32_t last_tick;       /* Номер последнего такта, когда выполнялся вызов process(). */ 
    MSFilterStats *stats;     /* Статистика работы фильтра.*/
    int postponed_task; /*Количество отложенных задач. Некоторые фильтры могут откладывать обработку данных (вызов process()) на несколько тактов.*/
    bool_t seen;  /* Флаг, который использует тикер, чтобы помечать что этот экземпляр фильтра он уже обслужил на данном такте.*/
};
typedef struct _MSFilter MSFilter;

Ko smo v programu C povezali filtre v skladu z našim načrtom (vendar nismo povezali tickerja), smo s tem ustvarili usmerjen graf, katerega vozlišča so primerki strukture MSFilter, robovi pa so primerki povezav MSQueue.

Dejavnosti tickerja v zakulisju

Ko sem vam rekel, da je ticker filter za vir klopov, to ni bila vsa resnica. Ticker je predmet, ki izvaja funkcije na uri proces() vse filtre vezja (grafa), na katerega je priključen. Ko ticker povežemo s filtrom grafa v programu C, tickerju pokažemo graf, ki ga bo nadzoroval od zdaj naprej, dokler ga ne izklopimo. Po vzpostavitvi povezave ticker začne pregledovati graf, ki mu je zaupan, in sestavi seznam filtrov, ki ga vključujejo. Da istega filtra ne bi "šteli" dvakrat, zaznane filtre označi tako, da jih potrdi. videl. Iskanje poteka s povezovalnimi tabelami, ki jih ima vsak filter.

Ticker med uvodnim ogledom grafa preveri, ali je med filtri vsaj eden, ki deluje kot vir podatkovnih blokov. Če jih ni, se graf šteje za napačnega in ticker se zruši.

Če se graf izkaže za »pravilnega«, se za vsak najdeni filter pokliče funkcija za inicializacijo predproces (). Takoj, ko pride trenutek za naslednji cikel obdelave (privzeto vsakih 10 milisekund), ticker pokliče funkcijo proces() za vse prej najdene izvorne filtre in nato za preostale filtre na seznamu. Če ima filter vhodne povezave, se funkcija izvaja proces() ponavlja, dokler čakalne vrste vhodnih povezav niso prazne. Po tem se premakne na naslednji filter na seznamu in ga »pomika«, dokler vhodne povezave niso brez sporočil. Oznaka se premika od filtra do filtra, dokler se seznam ne konča. S tem je obdelava cikla zaključena.

Zdaj se bomo vrnili k tuplem in govorili o tem, zakaj je bila taka entiteta dodana medijskemu pretakalniku. Na splošno količina podatkov, ki jih zahteva algoritem, ki deluje znotraj filtra, ne sovpada in ni večkratnik velikosti medpomnilnikov podatkov, prejetih na vhodu. Pišemo na primer filter, ki izvaja hitro Fourierjevo transformacijo, ki po definiciji lahko obdeluje le bloke podatkov, katerih velikost je potenca števila dva. Naj bo 512 točk. Če podatke generira telefonski kanal, nam podatkovni medpomnilnik vsakega sporočila na vhodu prinese 160 vzorcev signala. Mamljivo je ne zbirati podatkov iz vnosa, dokler ni zahtevana količina podatkov. Toda v tem primeru bo prišlo do kolizije s tickerjem, ki bo neuspešno poskušal pomikati filter, dokler vhodna povezava ne bo prazna. Prej smo to pravilo označili kot tretje načelo filtra. V skladu s tem načelom mora funkcija filtra process() prevzeti vse podatke iz vhodnih čakalnih vrst.

Poleg tega iz vnosa ne bo mogoče vzeti samo 512 vzorcev, saj lahko vzamete le cele bloke, tj. filter bo moral vzeti 640 vzorcev in jih uporabiti 512, preostanek pa bo moral nabrati nov del podatkov. Tako mora naš filter poleg svojega glavnega dela zagotavljati pomožna dejanja za vmesno shranjevanje vhodnih podatkov. Razvijalci medijskega pretakalnika in rešitve te splošne težave so razvili poseben objekt - MSBufferizer (medpomnilnik), ki to težavo rešuje s pomočjo tuples.

Medpomnilnik (MSBufferizer)

To je objekt, ki bo zbiral vhodne podatke znotraj filtra in jih začel pošiljati v obdelavo takoj, ko bo količina informacij zadostna za zagon algoritma filtra. Medtem ko medpomnilnik zbira podatke, bo filter deloval v stanju mirovanja, ne da bi porabil procesorsko moč. Toda takoj ko bralna funkcija iz medpomnilnika vrne vrednost, ki ni nič, začne funkcija process() filtra jemati in obdelovati podatke iz medpomnilnika v delih zahtevane velikosti, dokler niso izčrpani.
Podatki, ki še niso potrebni, ostanejo v medpomnilniku kot prvi element tuple, na katerega so pripeti naslednji bloki vhodnih podatkov.

Struktura, ki opisuje medpomnilnik:

struct _MSBufferizer{
queue_t q; /* Очередь сообщений. */
int size; /* Суммарный размер данных находящихся в буферизаторе в данный момент. */
};
typedef struct _MSBufferizer MSBufferizer;

Funkcije za delo z MSBufferizer

Ustvarjanje novega primerka medpomnilnika:

MSBufferizer * ms_bufferizer_new(void);

Pomnilnik je dodeljen, inicializiran v ms_bufferizer_init() in kazalec je vrnjen.

Funkcija inicializacije:

void ms_bufferizer_init(MSBufferizer *obj); 

Čakalna vrsta se inicializira q, polje velikost je nastavljen na nič.

Dodajanje sporočila:

void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m); 

Sporočilo m je dodano v čakalno vrsto. Doda se izračunana velikost podatkovnih blokov velikost.

Prenos vseh sporočil iz čakalne vrste podatkov povezave v medpomnilnik q:

void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q);   

Prenos sporočil s povezave q v medpomnilniku se izvaja s funkcijo ms_bufferizer_put().

Branje iz medpomnilnika:

int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen); 

Če je velikost podatkov, zbranih v medpomnilniku, manjša od zahtevane (datalen), potem funkcija vrne nič, podatki se ne kopirajo v podatke. V nasprotnem primeru se izvede zaporedno kopiranje podatkov iz tulp, ki se nahajajo v medpomnilniku. Po kopiranju se torka izbriše in pomnilnik sprosti. Kopiranje se konča v trenutku, ko se prekopirajo podatkovni bajti. Če na sredini podatkovnega bloka zmanjka prostora, se bo v tem sporočilu podatkovni blok zmanjšal na preostali neprekopirani del. Ko naslednjič pokličete, se bo kopiranje nadaljevalo od te točke.

Branje količine podatkov, ki so trenutno na voljo v medpomnilniku:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Vrne polje velikost medpomnilnik.

Zavrženje dela podatkov v medpomnilniku:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Določeno število bajtov podatkov se pridobi in zavrže. Najstarejši podatki se zavržejo.

Brisanje vseh sporočil v medpomnilniku:

void ms_bufferizer_flush(MSBufferizer *obj); 

Števec podatkov se ponastavi na nič.

Brisanje vseh sporočil v medpomnilniku:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Števec ni ponastavljen.

Odstranitev medpomnilnika in sprostitev pomnilnika:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Primere uporabe vmesnega pomnilnika lahko najdete v izvorni kodi več filtrov medijskih pretokov. Na primer v filtru MS_L16_ENC, ki prerazporedi bajte v vzorcih iz omrežnega vrstnega reda v gostiteljski vrstni red: l16.c

V naslednjem članku si bomo ogledali vprašanje ocenjevanja obremenitve tickerja in načine za boj proti čezmerni računalniški obremenitvi v medijskem pretakalniku.

Vir: www.habr.com

Dodaj komentar