Entdeckt de Mediastreamer2 VoIP-Motor. Deel 11

D'Material vum Artikel ass aus mengem zen Kanal.

Entdeckt de Mediastreamer2 VoIP-Motor. Deel 11

Datebewegungsmechanismus

  • Dateblock dblk_t
  • Message mblk_t
  • Funktiounen fir mat Messagen ze schaffen mblk_t
  • Queue queue_t
  • Funktiounen fir mat Schlaangen ze schaffen queue_t
  • Filteren verbannen
  • Signal Punkt vun Daten Veraarbechtung Grafik
  • Hannert de Kulissen Aktivitéite vun der Ticker
  • Bufferizer (MSBufferizer)
  • Funktiounen fir mat MSBufferizer ze schaffen

An der leschter Artikel mir hunn eisen eegene Filter entwéckelt. Dësen Artikel konzentréiert sech op den internen Mechanismus fir Daten tëscht Medien Streamer Filteren ze bewegen. Dëst erlaabt Iech raffinéiert Filtere mat manner Effort an Zukunft ze schreiwen.

Datebewegungsmechanismus

Datebewegung am Medienstreamer gëtt mat Schlaangen ausgefouert, déi vun der Struktur beschriwwe ginn queue_t. Strings vu Messagen wéi mblk_t, déi selwer keng Signaldaten enthalen, awer nëmmen Linken op de fréiere, nächste Message an op den Dateblock. Zousätzlech wëll ech besonnesch ënnersträichen datt et och e Feld ass fir e Link op e Message vum selwechten Typ, wat Iech erlaabt eng eenzeg verlinkt Lëscht vu Messagen ze organiséieren. Mir ruffen eng Grupp vu Messagen, déi vun esou enger Lëscht vereenegt sinn, en Tupel. Also kann all Element vun der Schlaang eng eenzeg Message sinn mblk_t, a vläicht de Kapp vun engem Message tuple mblk_t. All tuple Message kann seng eege Ward Dateblock hunn. Mir wäerten diskutéieren firwat Tuples e bësse méi spéit gebraucht ginn.

Wéi uewen ernimmt, enthält de Message selwer keen Block vun Daten; amplaz enthält et nëmmen e Pointer op d'Erënnerungsberäich wou de Block gespäichert ass. An dësem Deel erënnert d'Gesamtbild vun der Aarbecht vum Medienstreamer un d'Dierlager am Cartoon "Monsters, Inc.", wou Dieren (Linken op Daten - Zëmmer) mat enger verréckter Geschwindegkeet laanscht d'Overhead Fërderer bewegen, während d'Zëmmer selwer onbeweeglech bleiwen.

Elo, laanscht d'Hierarchie vun ënnen no uewen bewegt, loosst eis am Detail déi opgezielt Entitéite vum Datetransmissionsmechanismus am Medienstreamer betruechten.

Dateblock dblk_t

Den Dateblock besteet aus engem Header an engem Datebuffer. Den Header gëtt vun der folgender Struktur beschriwwen,

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

D'Felder vun der Struktur enthalen Hiweiser op den Ufank vum Puffer, d'Enn vum Puffer, an d'Funktioun fir den Datebuffer ze läschen. Lescht Element am Header db_ref - Referenz Konter, wann et null erreecht, dëst déngt als Signal dëse Spär aus Erënnerung ze läschen. Wann den Dateblock vun der Funktioun erstallt gouf datab_alloc() , da gëtt den Datebuffer direkt nom Header an d'Erënnerung gesat. An all anere Fäll kann de Puffer iergendwou getrennt sinn. Den Datebuffer enthält Signalproben oder aner Daten déi mir mat Filtere veraarbecht wëllen.

Eng nei Instanz vun engem Dateblock gëtt mat der Funktioun erstallt:

dblk_t *datab_alloc(int size);

Als Inputparameter gëtt et d'Gréisst vun den Daten uginn, déi de Block späichert. Méi Erënnerung gëtt zougewisen fir en Header - Struktur - am Ufank vun der zougewisener Erënnerung ze placéieren daten. Awer wann Dir aner Funktiounen benotzt, geschitt dat net ëmmer; an e puer Fäll kann den Datebuffer separat vum Dateblock Header lokaliséiert sinn. Wann Dir eng Struktur erstellt, sinn d'Felder sou konfiguréiert datt säi Feld db_base weist op den Ufank vun der daten Beräich, an db_lim zu sengem Enn. Link Zuel db_ref ass op eng gesat. D'Date kloer Funktioun Pointer ass op Null gesat.

Сообщение mblk_t

Wéi gesot, Schlaangelementer si vun Typ mblk_t, et ass wéi follegt definéiert:

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;

Struktur mblk_t enthält Hiweiser am Ufank b_virdrun, b_nächst, déi néideg sinn fir eng duebel verlinkt Lëscht ze organiséieren (wat eng Schlaang ass queue_t).

Da kënnt de Pointer b_cont, déi nëmme benotzt gëtt wann de Message Deel vun engem Tupel ass. Fir de leschte Message am Tupel bleift dësen Zeiger null.

Als nächst gesi mir e Pointer op en Dateblock b_dat, fir déi de Message existéiert. Et gëtt gefollegt vun Hiweiser op d'Gebitt am Blockdatenbuffer. Feld b_rptr spezifizéiert de Standuert vun deem Daten aus dem Puffer gelies ginn. Feld b_wptr weist de Standort un, aus deem d'Schreiwen an de Puffer ausgefouert ginn.

Déi reschtlech Felder sinn vun enger Service Natur a bezéien sech net op d'Operatioun vum Datetransfermechanismus.

Drënner ass eng eenzeg Message mam Numm m1 an Dateblock d1.
Entdeckt de Mediastreamer2 VoIP-Motor. Deel 11
Déi folgend Figur weist eng tuple vun dräi Messagen m1, m1_1, m1_2.
Entdeckt de Mediastreamer2 VoIP-Motor. Deel 11

Messagerie Funktiounen mblk_t

En neie Message mblk_t erstallt vun der Funktioun:

mblk_t *allocb(int size, int pri); 

si stellt en neie Message an Erënnerung mblk_t mat engem Dateblock vun der spezifizéierter Gréisst Gréisst, zweet Argument - pri net an dëser Versioun vun der Bibliothéik benotzt. Et soll null bleiwen. Wärend der Operatioun vun der Funktioun gëtt Erënnerung fir d'Struktur vum neie Message zougewisen an d'Funktioun gëtt genannt mblk_init(), déi all Felder vun der erstallt Instanz vun der Struktur zrécksetzen an dann, mat der uewen ernimmt datab_alloc(), wäert en Datebuffer erstellen. Duerno ginn d'Felder an der Struktur konfiguréiert:

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

Um Ausgang kréien mir en neie Message mat initialiséierte Felder an engem eidelen Datebuffer. Fir Daten an e Message ze addéieren, musst Dir se an den Dateblockbuffer kopéieren:

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

wou Donnéeën ass e Pointer op d'Datenquell, an Gréisst - hir Gréisst.
da musst Dir de Pointer op de Schreifpunkt aktualiséieren, sou datt et erëm op den Ufank vum fräie Gebitt am Puffer weist:

msg->b_wptr = msg->b_wptr + size

Wann Dir e Message vun engem existente Puffer erstellen musst, ouni ze kopéieren, da benotzt d'Funktioun:

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

D'Funktioun, nodeems d'Botschaft an d'Struktur vum Dateblock erstallt goufen, konfiguréiert seng Pointer op d'Donnéeën op der Adress bouf. Déi. an dësem Fall läit den Datebuffer net no den Headerfelder vum Dateblock, sou wéi et de Fall war wann en Dateblock mat der Funktioun erstallt gouf. datab_alloc(). De Puffer mat Daten, déi un d'Funktioun passéiert sinn, bleift do wou se war, awer mat Hëllef vun Indikatoren gëtt et un den nei erstallten Header vum Dateblock befestegt, an dat deementspriechend un de Message.

Zu engem Message mblk_t Verschidde Dateblocker kënne sequenziell verlinkt ginn. Dëst gëtt duerch d'Funktioun gemaach:

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

mp - e Message un deem en aneren Dateblock bäigefüügt gëtt;
Donnéeën - Zeiger op de Block, eng Kopie vun deem gëtt an de Message bäigefüügt;
Gréisst - Daten Gréisst;
Heft sinn - e Fändel datt d'Gréisst vum zougewisen Erënnerung muss laanscht eng 4-Byte Grenz ausgeriicht ginn (padding gëtt mat Nullen gemaach).

Wann et genuch Plaz am bestehend Message Datebuffer ass, da ginn déi nei Donnéeën hannert den Donnéeën déi schonn do gepecht ginn. Wann et manner fräi Plaz am Message Daten Prellbock wéi Gréisst, da gëtt en neie Message mat enger genuch Puffergréisst erstallt an d'Donnéeën op säi Puffer kopéiert. Dëst ass en neie Message, verbonne mat dem Original mat engem Pointer b_cont. An dësem Fall gëtt de Message an en Tupel.

Wann Dir en anere Block vun Daten un den Tupel addéiere musst, da musst Dir d'Funktioun benotzen:

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

hatt fënnt de leschte Message am Tupel (hien huet b_cont wäert null sinn) a rufft d'Funktioun fir dëse Message un appendb().

Dir kënnt d'Gréisst vun den Donnéeën an engem Message oder Tupel erausfannen mat der Funktioun:

int msgdsize(const mblk_t *mp);

et wäert duerch all d'Messagen am Tupel schloen an d'Gesamtbetrag vun Daten an den Datebuffer vun dëse Messagen zréckginn. Fir all Message gëtt d'Quantitéit un Daten wéi follegt berechent:

 mp->b_wptr - mp->b_rptr

Fir zwee Tupelen ze kombinéieren, benotzt d'Funktioun:

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

si setzt den Tupel un neiem zum Schwanz vum Tupel mp a gëtt e Pointer op de leschte Message vun der doraus resultéierend tuple.

Wann néideg, kann en Tupel an ee Message mat engem eenzege Block vun Daten ëmgewandelt ginn; dëst gëtt duerch d'Funktioun gemaach:

void msgpullup(mblk_t *mp,int len);

wann Argument Len ass -1, da gëtt d'Gréisst vum zougewisen Puffer automatesch bestëmmt. Wann Len ass eng positiv Zuel, e Puffer vun dëser Gréisst gëtt erstallt an d'Tuple Message Daten ginn an et kopéiert. Wann de Puffer leeft, stoppt d'Kopie do. Den éischte Message vum Tupel kritt en neie Gréisstbuffer mat de kopéierten Donnéeën. Déi reschtlech Messagen ginn geläscht an d'Erënnerung zréck an de Koup.

Wann Dir eng Struktur läschen mblk_t d'Referenzzuel vum Dateblock gëtt berücksichtegt wann, wann Dir rufft freeb() et stellt sech eraus als Null, da gëtt den Datebuffer zesumme mat der Instanz geläscht mblk_t, wat drop hiweist.

D'Felder vun engem neie Message initialiséieren:

void mblk_init(mblk_t *mp);

Füügt en anert Stéck Daten un de Message:

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

Wann déi nei Donnéeën net an de fräie Raum vum Message Datebuffer passen, da gëtt e separat erstallt Message mat engem Puffer vun der erfuerderter Gréisst un d'Botschaft befestegt (e Pointer op den addéierte Message gëtt am éischte Message gesat) an de Message gëtt an en Tupel.

Füügt e Stéck Daten zu engem Tupel:

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

D'Funktioun rifft appendb () an enger Loop.

Kombinéiert zwee Tupelen an een:

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

Сообщение neiem wäert ugeschloss ginn mp.

Eng Kopie vun engem eenzege Message maachen:

mblk_t *copyb(const mblk_t *mp);

Komplett Kopie vun engem Tupel mat all Datenblocken:

mblk_t *copymsg(const mblk_t *mp);

D'Elementer vum Tupel ginn duerch d'Funktioun kopéiert copyb().

Erstellt eng einfach Kopie vun engem Message mblk_t. An dësem Fall gëtt den Dateblock net kopéiert, awer säi Referenzziel gëtt erhéicht db_ref:

mblk_t *dupb(mblk_t *mp);

Maacht eng liicht Kopie vun engem Tupel. Dateblocken ginn net kopéiert, nëmmen hir Referenzzieler ginn eropgebaut db_ref:

mblk_t *dupmsg(mblk_t* m);

All Messagen vun engem Tupel an ee Message klicken:

void msgpullup(mblk_t *mp,size_t len);

Wann d'Argument Len ass -1, da gëtt d'Gréisst vum zougewisen Puffer automatesch bestëmmt.

E Message läschen, tuple:

void freemsg(mblk_t *mp);

D'Referenzzuel vum Dateblock gëtt ëm ee reduzéiert. Wann et Null erreecht, gëtt den Dateblock och geläscht.

Berechnung vun der Gesamtbetrag vun Daten an engem Message oder tuple.

size_t msgdsize(const mblk_t *mp);

E Message aus dem Schwanz vun der Schlaang zréckzéien:

mblk_t *ms_queue_peek_last (q);

Kopéiert den Inhalt vun de reservéierte Felder vun engem Message an en anere Message (tatsächlech enthalen dës Felder Fändelen déi vum Media Streamer benotzt ginn):

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

Queue queue_t

D'Messageschlaang am Media Streamer gëtt als eng kreesfërmeg duebel verlinkt Lëscht ëmgesat. All Lëscht Element enthält en Zeigefanger zu engem Dateblock mat Signal Echantillon. Et stellt sech eraus datt nëmmen Hiweiser op den Dateblock sech am Tour bewegen, während d'Donnéeën selwer onbeweeglech bleiwen. Déi. nëmmen Linken op si geplënnert.
Struktur déi d'Schlaang beschreiwen queue_t, hei ënnen gewisen:

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

D'Struktur enthält e Feld - e Pointer _q_stopper Typ *mblk_t, et weist op dat éischt Element (Message) an der Schlaang. Dat zweet Feld vun der Struktur ass de Konter vu Messagen an der Schlaang.
D'Figur hei ënnen weist eng Schlaang mam Numm q1 mat 4 Messagen m1, m2, m3, m4.
Entdeckt de Mediastreamer2 VoIP-Motor. Deel 11
Déi folgend Figur weist eng Schlaang mam Numm q1 mat 4 Messagen m1,m2,m3,m4. Message m2 ass de Kapp vun engem Tupel deen zwee méi Messagen m2_1 an m2_2 enthält.

Entdeckt de Mediastreamer2 VoIP-Motor. Deel 11

Funktiounen fir mat Schlaangen ze schaffen queue_t

Queue Initialiséierung:

void qinit(queue_t *q);

Beräich _q_stopper (nodréiglech nenne mir et "Stopper") gëtt vun der Funktioun initialiséiert mblk_init(), Säi virdrun Element an den nächsten Element Pointer ginn ugepasst fir op sech selwer ze weisen. De Schlaangelementteller gëtt op Null zréckgesat.

En neit Element derbäisetzen (Messagen):

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

Neit Element m gëtt um Enn vun der Lëscht bäigefüügt, ginn d'Elementpointer ugepasst sou datt de Stopper dat nächst Element fir et gëtt, an et gëtt de fréiere Element fir de Stopper. De Queue Element Konter gëtt eropgebaut.

En Element aus der Schlaang zréckzéien:

mblk_t * getq(queue_t *q); 

De Message, deen no der Stopper kënnt, ass erëmfonnt, an den Element Konter gëtt ofgebaut. Wann et keng Elementer an der Schlaang sinn ausser de Stopper, da gëtt 0 zréck.

E Message an eng Schlaang setzen:

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

Element mp virum Element agebaut EMP. Wann EMP=0, da gëtt de Message un de Schwanz vun der Schlaang bäigefüügt.

E Message vum Chef vun der Schlaang zréckzéien:

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

Den Element Konter gëtt ofgebaut.

Liest e Pointer op dat éischt Element an der Schlaang:

mblk_t * peekq(queue_t *q); 

Ewechzehuelen all Elementer aus der Schlaang iwwerdeems d'Elementer selwer läschen:

void flushq(queue_t *q, int how);

Argument wéi net benotzt. De Schlaangelementteller ass op Null gesat.

Macro fir e Pointer op dat lescht Element vun der Schlaang ze liesen:

mblk_t * qlast(queue_t *q);

Wann Dir mat Message Schlaangen schafft, bewosst datt wann Dir rufft ms_queue_put(q, m) mat engem Null-Zeiger op de Message, gëtt d'Funktioun Loop. Äre Programm wäert afréieren. behuelen sech ähnlech ms_queue_next(q, m).

Filteren verbannen

Déi uewe beschriwwe Schlaang gëtt benotzt fir Messagen vun engem Filter an en anert oder vun engem op e puer Filtere weiderzeginn. Filteren an hir Verbindunge bilden eng geriicht Grafik. Den Input oder Ausgang vum Filter gëtt dat allgemengt Wuert "Pin" genannt. Fir d'Uerdnung ze beschreiwen, an där d'Filtere matenee verbonne sinn, benotzt de Medienstreamer d'Konzept vun engem "Signalpunkt". Signal Punkt ass Struktur _MSCPoint, deen e Pointer zum Filter an d'Zuel vun engem vu senge Pins enthält; deementspriechend beschreift et d'Verbindung vun engem vun den Inputen oder Ausgänge vum Filter.

Signal Punkt vun Daten Veraarbechtung Grafik

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

Filterpins sinn nummeréiert vun Null un.

D'Verbindung vun zwee Pins duerch eng Messageschlaang gëtt vun der Struktur beschriwwen _MSQueue, déi eng Messageschlaang an Hiweiser op déi zwee Signalpunkte enthält déi se verbënnt:

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

Mir wäerten dës Struktur e Signal Link nennen. All Media Streamer Filter enthält eng Tabell vun Input Linken an eng Tabell vun Output Linken (MSQueue). D'Gréisst vun den Dëscher gëtt festgeluegt wann Dir e Filter erstellt; Mir hunn dat scho mat enger exportéierter Variabel vun Typ gemaach MSFilterDesc, wéi mir eisen eegene Filter entwéckelt hunn. Drënner ass eng Struktur déi all Filter an engem Media Streamer beschreift, 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;

Nodeems mir d'Filtere am C Programm am Aklang mat eisem Plang verbonnen hunn (awer den Ticker net verbonnen hunn), hu mir doduerch eng geriicht Grafik erstallt, d'Node vun deenen Instanzen vun der Struktur sinn MSFilter, a Kante sinn Instanzen vu Linken MSQueue.

Hannert de Kulissen Aktivitéite vun der Ticker

Wéi ech Iech gesot hunn datt den Ticker e Filter fir d'Quell vun den Zecken ass, war et net déi ganz Wourecht doriwwer. En Ticker ass en Objet deen Funktiounen op der Auer leeft Prozess () all Filtere vum Circuit (Grafik) mat deem et verbonnen ass. Wa mir en Ticker un e Graffilter an engem C Programm verbannen, weisen mir dem Ticker d'Grafik déi se vun elo un kontrolléiert bis mir se ausschalten. Nom Uschloss fänkt den Ticker un d'Grafik ze iwwerpréiwen, déi u seng Betreiung uvertraut ass, eng Lëscht vu Filtere kompiléiert déi et enthalen. Fir dee selwechte Filter net zweemol ze "zielen", markéiert et déi detektéiert Filteren andeems se e Checkbox an hinnen setzen gesinn. D'Sich gëtt mat de Linktabellen duerchgefouert, déi all Filter huet.

Wärend senger Aféierungstour duerch d'Grafik iwwerpréift den Ticker ob ënner de Filtere op d'mannst een ass deen als Quell vun Datenblocken handelt. Wann et keng sinn, gëtt d'Grafik als falsch ugesinn an den Ticker klappt.

Wann d'Grafik "korrekt" ass, fir all fonnt Filter, gëtt d'Funktioun fir d'Initialiséierung opgeruff preprocess(). Soubal de Moment fir den nächsten Veraarbechtungszyklus ukomm ass (standard all 10 Millisekonnen), rifft den Ticker d'Funktioun Prozess () fir all virdrun fonnt Quell Filter, an dann fir déi reschtlech Filtere an der Lëscht. Wann de Filter Input Linken huet, da lafen d'Funktioun Prozess () widderhuelen bis d'Input Link Schlaangen eidel sinn. Duerno geet et op den nächste Filter an der Lëscht a "scrollt" et bis d'Input Links fräi vu Messagen sinn. Den Ticker bewegt vu Filter op Filter bis d'Lëscht eriwwer ass. Dëst fäerdeg d'Veraarbechtung vum Zyklus.

Elo wäerte mir zréck op Tuples a schwätzen iwwer firwat sou eng Entitéit un de Medienstreamer bäigefüügt gouf. Allgemeng fällt d'Quantitéit un Daten erfuerderlech vum Algorithmus, deen am Filter funktionnéiert, net zesummen an ass net e Multiple vun der Gréisst vun den Datebuffer, déi um Input kritt ginn. Zum Beispill schreiwen mir e Filter deen e schnelle Fourier-Transform ausféiert, deen per Definitioun nëmmen Dateblocken veraarbecht kann, deenen hir Gréisst eng Kraaft vun zwee ass. Loosst et 512 Konte sinn. Wann d'Donnéeën vun engem Telefonkanal generéiert ginn, da bréngt den Datebuffer vun all Message um Input eis 160 Signal Echantillon. Et ass verlockend net Daten aus dem Input ze sammelen bis déi erfuerderlech Quantitéit un Daten do ass. Awer an dësem Fall wäert eng Kollisioun mam Ticker optrieden, deen ouni Erfolleg probéiert de Filter ze scrollen bis den Input Link eidel ass. Virdrun hu mir dës Regel als drëtt Prinzip vum Filter bezeechent. No dësem Prinzip, muss de Filter Prozess () Funktioun all Daten aus der Input Schlaangen huelen.

Zousätzlech wäert et net méiglech sinn nëmmen 512 Proben aus dem Input ze huelen, well Dir kënnt nëmme ganz Blöcke huelen, d.h. de Filter muss 640 Echantillon huelen an 512 vun hinnen benotzen, de Rescht ier en neien Deel vun Daten accumuléiert. Also muss eise Filter, nieft senger Haaptaarbecht, Hëllefsaktioune fir d'Tëschespäicherung vun Inputdaten ubidden. D'Entwéckler vum Media Streamer an d'Léisung vun dësem allgemenge Problem hunn e speziellen Objet entwéckelt - MSBufferizer (Puffer), deen dëse Problem mat Tuples léist.

Bufferizer (MSBufferizer)

Dëst ass en Objet deen Inputdaten am Filter accumuléiert an ufänkt se fir d'Veraarbechtung ofzeginn soubal d'Quantitéit un Informatioun genuch ass fir de Filteralgorithmus auszeféieren. Wärend de Puffer Daten accumuléiert, funktionnéiert de Filter am Idle Modus, ouni d'Veraarbechtungskraaft vum Prozessor ze benotzen. Awer soubal d'Liesfunktioun vum Puffer e Wäert anescht wéi null zréckkënnt, fänkt de Prozess () Funktioun vum Filter un Daten aus dem Puffer an Portiounen vun der erfuerderter Gréisst ze huelen an ze veraarbecht, bis se erschöpft ass.
Donnéeën, déi nach net erfuerderlech sinn, bleiwen am Puffer als dat éischt Element vum Tupel, un deem spéider Blöcke vun Inputdaten befestegt sinn.

D'Struktur déi de Puffer beschreift:

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

Funktiounen fir mat MSBufferizer ze schaffen

Eng nei Pufferinstanz erstellen:

MSBufferizer * ms_bufferizer_new(void);

Erënnerung gëtt zougewisen, initialiséiert an ms_bufferizer_init() an e Pointer gëtt zréck.

Initialiséierungsfunktioun:

void ms_bufferizer_init(MSBufferizer *obj); 

D'Schlaang gëtt initialiséiert q, Feld Gréisst ass op null gesat.

E Message derbäisetzen:

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

Message m gëtt an d'Schlaang bäigefüügt. Déi berechent Gréisst vun Datenblocken gëtt derbäigesat Gréisst.

Transfert all Messagen aus der Linkdatenschlaang op de Puffer q:

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

Transfermaart Messagen vun engem Link q am Puffer gëtt mat der Funktioun duerchgefouert ms_bufferizer_put().

Aus dem Puffer liesen:

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

Wann d'Gréisst vun den Daten am Puffer gesammelt ass manner wéi déi ugefrote (datalen), da gëtt d'Funktioun Null zréck, Daten ginn net op Daten kopéiert. Soss gëtt sequenziell Kopie vun Daten aus Tuples, déi am Puffer lokaliséiert sinn, gemaach. No der Kopie gëtt den Tupel geläscht an d'Erënnerung befreit. D'Kopie endet am Moment wou datalen Bytes kopéiert ginn. Wann de Raum an der Mëtt vun engem Dateblock leeft, da gëtt an dësem Message den Dateblock op de verbleiwen net kopéierten Deel reduzéiert. Déi nächst Kéier wann Dir urufft, gëtt d'Kopie vun dësem Punkt weider.

Liest d'Quantitéit un Daten déi am Moment am Puffer verfügbar ass:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Gitt d'Feld zréck Gréisst Buffer.

Entwerfen en Deel vun den Donnéeën am Puffer:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Déi spezifizéiert Zuel vu Bytes vun Daten ginn zréckgezunn a verworf. Déi eelst Donnéeën ginn verworf.

All Messagen am Puffer läschen:

void ms_bufferizer_flush(MSBufferizer *obj); 

Den Dateteller gëtt op Null zréckgesat.

All Messagen am Puffer läschen:

void ms_bufferizer_uninit(MSBufferizer *obj); 

De Comptoir gëtt net zréckgesat.

De Puffer erofhuelen an d'Erënnerung befreien:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Beispiller fir de Pufferer ze benotzen kënnen am Quellcode vu verschiddene Media Streamer Filtere fonnt ginn. Zum Beispill, am MS_L16_ENC Filter, deen d'Bytes an de Proben aus der Netzbestellung an d'Hostbestellung nei arrangéiert: l16.c

Am nächsten Artikel wäerte mir d'Thema vun der Ticker-Laaschtschätzung kucken a wéi Dir mat exzessiver Rechenbelaaschtung am Media Streamer ëmgeet.

Source: will.com

Setzt e Commentaire