Ferkenne de Mediastreamer2 VoIP-motor. Diel 11

It materiaal fan it artikel is nommen út myn zen kanaal.

Ferkenne de Mediastreamer2 VoIP-motor. Diel 11

Data beweging meganisme

  • Gegevensblok dblk_t
  • Berjocht mblk_t
  • Funksjes foar wurkjen mei berjochten mblk_t
  • Wachtrige wachtrige_t
  • Funksjes foar wurkjen mei queues queue_t
  • Ferbine filters
  • Signal punt fan gegevens ferwurkjen grafyk
  • Achter de skermen aktiviteiten fan de ticker
  • Bufferizer (MSBufferizer)
  • Funksjes foar wurkjen mei MSBufferizer

Yn de lêste artikel wy hawwe ús eigen filter ûntwikkele. Dit artikel sil rjochtsje op it ynterne meganisme foar it ferpleatsen fan gegevens tusken mediastreamerfilters. Hjirmei kinne jo yn 'e takomst ferfine filters skriuwe mei minder ynspanning.

Data beweging meganisme

Gegevensbeweging yn 'e mediastreamer wurdt útfierd mei wachtrijen beskreaun troch de struktuer wachtrige_t. Strings fan berjochten lykas mblk_t, dy't sels gjin sinjaalgegevens befetsje, mar allinich keppelings nei it foarige, folgjende berjocht en nei it gegevensblok. Dêrneist wol ik benammen beklamje dat der ek in fjild is foar in keppeling nei in berjocht fan itselde type, wêrmei jo in inkeld keppele list mei berjochten organisearje kinne. Wy neame in groep berjochten ferienige troch sa'n list in tuple. Sa kin elk elemint fan 'e wachtrige in inkeld berjocht wêze mblk_t, en miskien de kop fan in berjocht tuple mblk_t. Elk tupleberjocht kin in eigen wykgegevensblok hawwe. Wy sille beprate wêrom't tuples binne nedich in bytsje letter.

Lykas hjirboppe neamd, befettet it berjocht sels gjin gegevensblok; ynstee befettet it allinich in oanwizer nei it ûnthâldgebiet wêr't it blok is opslein. Yn dit diel docht it algemiene byld fan it wurk fan 'e mediastreamer tinken oan it doarpakhûs yn' e cartoon "Monsters, Inc.," wêr't doarren (keppelings nei gegevens - keamers) mei in dwylsinnige snelheid bewege lâns boppe-transporteurs, wylst de keamers sels bliuw roerloos.

No, troch de hiërargy fan ûnderen nei boppen lâns te bewegen, litte wy yn detail de neamde entiteiten fan it datatransmissionmeganisme yn 'e mediastreamer beskôgje.

Data blok dblk_t

It gegevensblok bestiet út in koptekst en in gegevensbuffer. De koptekst wurdt beskreaun troch de folgjende struktuer,

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

De fjilden fan 'e struktuer befetsje oanwizers nei it begjin fan' e buffer, de ein fan 'e buffer, en de funksje foar it wiskjen fan de gegevensbuffer. Lêste elemint yn koptekst db_ref - ferwizing teller, as it berikt nul, dit tsjinnet as in sinjaal te wiskjen dit blok út it ûnthâld. As it gegevensblok is makke troch de funksje data_alloc() , dan wurdt de gegevensbuffer fuortendaliks nei de koptekst yn it ûnthâld pleatst. Yn alle oare gefallen kin de buffer earne apart sitte. De gegevensbuffer sil sinjaalmonsters of oare gegevens befetsje dy't wy wolle ferwurkje mei filters.

In nij eksimplaar fan in gegevensblok wurdt makke mei de funksje:

dblk_t *datab_alloc(int size);

As ynfierparameter wurdt it de grutte fan 'e gegevens jûn dy't it blok sil opslaan. Mear ûnthâld wurdt tawiisd om in koptekst - struktuer - oan it begjin fan it tawiisde ûnthâld te pleatsen datab. Mar by it brûken fan oare funksjes bart dit net altyd; yn guon gefallen kin de gegevensbuffer apart lizze fan 'e koptekst foar gegevensblok. By it meitsjen fan in struktuer, de fjilden wurde konfigurearre sadat syn fjild db_base wiisde op it begjin fan de gegevens gebiet, en db_lim oan syn ein. Link count db_ref is ynsteld op ien. De gegevens dúdlik funksje pointer is ynsteld op nul.

Jo berjocht mblk_t

Lykas sein, wachtrige eleminten binne fan type mblk_t, it wurdt definiearre as folget:

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;

struktuer mblk_t befettet oanwizings oan it begjin b_foarige, b_folgjende, dy't nedich binne om in dûbelkeppele list te organisearjen (dat is in wachtrige wachtrige_t).

Dan komt de oanwizer b_kont, dat allinnich brûkt wurdt as it berjocht diel is fan in tuple. Foar it lêste berjocht yn 'e tuple bliuwt dizze oanwizer nul.

Folgjende sjogge wy in oanwizer nei in gegevensblok b_datap, wêrfoar it berjocht bestiet. It wurdt folge troch oanwizers nei it gebiet binnen de blokgegevensbuffer. Fjild b_rptr spesifisearret de lokaasje wêrfan gegevens út de buffer lêzen wurde. Fjild b_wptr jout de lokaasje oan wêrfan skriuwt nei de buffer útfierd wurdt.

De oerbleaune fjilden binne fan in tsjinst aard en net relatearje oan de wurking fan de gegevens oerdracht meganisme.

Hjirûnder is in inkeld berjocht mei de namme m1 en gegevensblok d1.
Ferkenne de Mediastreamer2 VoIP-motor. Diel 11
De folgjende figuer lit in tuple fan trije berjochten sjen m1, m1_1, m1_2.
Ferkenne de Mediastreamer2 VoIP-motor. Diel 11

Messaging funksjes mblk_t

In nij berjocht mblk_t makke troch de funksje:

mblk_t *allocb(int size, int pri); 

se pleatst in nij berjocht yn it ûnthâld mblk_t mei in gegevensblok fan de oantsjutte grutte grutte, twadde argumint - pri net brûkt yn dizze ferzje fan de bibleteek. It moat nul bliuwe. Tidens de operaasje fan de funksje sil ûnthâld wurde tawiisd foar de struktuer fan it nije berjocht en de funksje wurdt neamd mblk_init(), dy't alle fjilden fan 'e oanmakke eksimplaar fan' e struktuer weromsette sil en dan, mei it hjirboppe neamde data_alloc(), sil in gegevensbuffer oanmeitsje. Hjirnei wurde de fjilden yn 'e struktuer konfigureare:

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

By de útfier krije wy in nij berjocht mei inisjalisearre fjilden en in lege gegevensbuffer. Om gegevens ta te foegjen oan in berjocht, moatte jo it kopiearje nei de gegevensblokbuffer:

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

wêr data is in oanwizer nei de gegevens boarne, en grutte - harren grutte.
dan moatte jo de oanwizer bywurkje nei it skriuwpunt, sadat it wer nei it begjin fan it frije gebiet yn 'e buffer wiist:

msg->b_wptr = msg->b_wptr + size

As jo ​​​​in berjocht moatte oanmeitsje fan in besteande buffer, sûnder te kopiearjen, brûk dan de funksje:

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

De funksje, nei it meitsjen fan it berjocht en de struktuer fan it gegevensblok, sil har oanwizers konfigurearje nei de gegevens op it adres buff. Dy. yn dit gefal sit de gegevensbuffer net efter de koptekstfjilden fan it gegevensblok, lykas it gefal wie by it meitsjen fan in gegevensblok mei de funksje data_alloc(). De buffer mei gegevens trochjûn oan 'e funksje sil bliuwe wêr't it wie, mar mei help fan pointers sil it wurde hechte oan 'e nij oanmakke koptekst fan it gegevensblok, en dat, dus, oan it berjocht.

Oan ien berjocht mblk_t Ferskate gegevensblokken kinne opienfolgjend wurde gearfoege. Dit wurdt dien troch de funksje:

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

mp - in berjocht wêryn in oar gegevensblok sil wurde tafoege;
data - oanwizer nei it blok, wêrfan in kopy sil wurde tafoege oan it berjocht;
grutte - gegevens grutte;
pad - in flagge dat de grutte fan it tawiisd ûnthâld moat wurde ôfstimd lâns in 4-byte grins (padding sil dien wurde mei nullen).

As der genôch romte is yn 'e besteande berjochtgegevensbuffer, dan wurde de nije gegevens efter de gegevens dy't der al binne plakt. As der minder frije romte yn it berjocht gegevens buffer as grutte, dan wurdt in nij berjocht makke mei in foldwaande buffergrutte en de gegevens wurde kopiearre nei har buffer. Dit is in nij berjocht, keppele oan it orizjinele mei in oanwizer b_kont. Yn dit gefal feroaret it berjocht yn in tuple.

As jo ​​​​in oare blok gegevens moatte tafoegje oan 'e tuple, dan moatte jo de funksje brûke:

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

sy sil it lêste berjocht fine yn 'e tuple (hy hat b_kont sil nul wêze) en sil de funksje foar dit berjocht neame appendb().

Jo kinne de grutte fan gegevens fine yn in berjocht of tuple mei de funksje:

int msgdsize(const mblk_t *mp);

it sil troch alle berjochten yn 'e tuple loopje en de totale hoemannichte gegevens weromjaan yn' e gegevensbuffers fan dy berjochten. Foar elk berjocht wurdt de hoemannichte gegevens as folget berekkene:

 mp->b_wptr - mp->b_rptr

Om twa tupels te kombinearjen, brûk de funksje:

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

se heakket de tupel oan nijm oan 'e sturt fan 'e tupel mp en jout in oanwizer werom nei it lêste berjocht fan 'e resultearjende tuple.

As it nedich is, kin in tuple wurde omset yn ien berjocht mei ien blok gegevens; dit wurdt dien troch de funksje:

void msgpullup(mblk_t *mp,int len);

as argumint len is -1, dan wurdt de grutte fan 'e tawiisde buffer automatysk bepaald. As len is in posityf getal, in buffer fan dizze grutte sil wurde makke en de tuple berjocht gegevens wurde kopiearre yn it. As de buffer op is, sil it kopiearjen dêr stopje. It earste berjocht fan 'e tuple sil in nije grutte buffer krije mei de kopieare gegevens. De oerbleaune berjochten wurde wiske en it ûnthâld werom nei de heap.

By it wiskjen fan in struktuer mblk_t de referinsjetelling fan it gegevensblok wurdt rekken holden as, by it roppen freeb() it blykt nul te wêzen, dan wurdt de gegevensbuffer tegearre mei it eksimplaar wiske mblk_t, dy't derop wiist.

De fjilden fan in nij berjocht inisjalisearje:

void mblk_init(mblk_t *mp);

In oar stikje gegevens tafoegje oan it berjocht:

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

As de nije gegevens net passe yn 'e frije romte fan 'e berjochtgegevensbuffer, dan wurdt in apart oanmakke berjocht mei in buffer fan 'e fereaske grutte oan it berjocht taheakke (in oanwizer nei it tafoege berjocht wurdt yn it earste berjocht ynsteld) en de berjocht feroaret yn in tuple.

In stikje gegevens tafoegje oan in tuple:

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

De funksje ropt appendb () yn in loop.

Kombinearje twa tuples yn ien:

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

Jo berjocht nijm sil wurde hechte oan mp.

In kopy meitsje fan ien berjocht:

mblk_t *copyb(const mblk_t *mp);

Folsleine kopiearje fan in tuple mei alle gegevensblokken:

mblk_t *copymsg(const mblk_t *mp);

De eleminten fan 'e tuple wurde kopiearre troch de funksje copyb().

Meitsje in maklike kopy fan in berjocht mblk_t. Yn dit gefal wurdt it gegevensblok net kopiearre, mar de referinsjeteller wurdt ferhege db_ref:

mblk_t *dupb(mblk_t *mp);

It meitsjen fan in lichtgewicht kopy fan in tuple. Gegevensblokken wurde net kopiearre, allinich har referinsjetellers wurde ferhege db_ref:

mblk_t *dupmsg(mblk_t* m);

Alle berjochten fan in tuple plakke yn ien berjocht:

void msgpullup(mblk_t *mp,size_t len);

As it argumint len is -1, dan wurdt de grutte fan 'e tawiisde buffer automatysk bepaald.

In berjocht wiskje, tuple:

void freemsg(mblk_t *mp);

De referinsjetelling fan it gegevensblok wurdt mei ien fermindere. As it nul berikt, wurdt it gegevensblok ek wiske.

Berekkening fan de totale hoemannichte gegevens yn in berjocht of tuple.

size_t msgdsize(const mblk_t *mp);

In berjocht ophelje út 'e sturt fan' e wachtrige:

mblk_t *ms_queue_peek_last (q);

It kopiearjen fan de ynhâld fan de reservearre fjilden fan ien berjocht nei in oar berjocht (feitlik befetsje dizze fjilden flaggen dy't brûkt wurde troch de mediastreamer):

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

Rigel wachtrige_t

De berjochtwachtrige yn 'e mediastreamer wurdt ymplementearre as in sirkulêre dûbelkeppele list. Elts list elemint befettet in oanwizer nei in gegevens blok mei sinjaal samples. It docht bliken dat allinich oanwizers nei it gegevensblok beurtelings bewege, wylst de gegevens sels bewegingleas bliuwe. Dy. allinnich keppelings nei harren wurde ferpleatst.
Struktuer dy't de wachtrige beskriuwt wachtrige_t, hjirûnder werjûn:

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

De struktuer befettet in fjild - in oanwizer _q_stopper typ *mblk_t, it wiist nei it earste elemint (berjocht) yn 'e wachtrige. It twadde fjild fan 'e struktuer is de teller fan berjochten yn' e wachtrige.
De figuer hjirûnder lit in wachtrige mei de namme q1 sjen mei 4 berjochten m1, m2, m3, m4.
Ferkenne de Mediastreamer2 VoIP-motor. Diel 11
De folgjende figuer lit in wachtrige mei de namme q1 sjen mei 4 berjochten m1,m2,m3,m4. Berjocht m2 is de kop fan in tuple dy't noch twa berjochten m2_1 en m2_2 befettet.

Ferkenne de Mediastreamer2 VoIP-motor. Diel 11

Funksjes foar wurkjen mei queues queue_t

Inisjalisaasje fan wachtrige:

void qinit(queue_t *q);

fjild _q_stopper (hjirnei sille wy it "stopper" neame) wurdt inisjalisearre troch de funksje mblk_init(), syn foarige elemint en folgjende elemint pointer wurde oanpast om te wizen op himsels. De wachtrige elemint teller wurdt weromset nei nul.

In nij elemint tafoegje (berjochten):

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

Nij elemint m wurdt tafoege oan 'e ein fan' e list, de elemint pointers wurde oanpast sadat de stopper wurdt it folgjende elemint foar it, en it wurdt it foarige elemint foar de stopper. De wachtrige elemint teller wurdt ferhege.

In elemint ophelje út 'e wachtrige:

mblk_t * getq(queue_t *q); 

It berjocht dat komt nei de stopper wurdt ophelle, en it elemint teller wurdt decremented. As d'r gjin eleminten yn 'e wachtrige binne útsein de stopper, dan wurdt 0 weromjûn.

In berjocht ynfoegje yn in wachtrige:

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

Element mp ynfoege foar it elemint Link. As Link=0, dan wurdt it berjocht tafoege oan 'e sturt fan' e wachtrige.

In berjocht ophelje fan 'e kop fan' e wachtrige:

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

De elemintteller wurdt fermindere.

In oanwizer lêze nei it earste elemint yn 'e wachtrige:

mblk_t * peekq(queue_t *q); 

Alle eleminten út 'e wachtrige fuortsmite by it wiskjen fan de eleminten sels:

void flushq(queue_t *q, int how);

Argumint hoe net brûkt. De wachtrige elemint teller is ynsteld op nul.

Makro foar it lêzen fan in oanwizer nei it lêste elemint fan 'e wachtrige:

mblk_t * qlast(queue_t *q);

As jo ​​wurkje mei berjochtenwachtrige, wês bewust dat as jo belje ms_queue_put(q, m) mei in nul oanwizer nei it berjocht, de funksje loops. Jo programma sil befrieze. gedraacht itselde ms_wachtrige_next(q, m).

Ferbine filters

De hjirboppe beskreaune wachtrige wurdt brûkt om berjochten fan it iene filter nei it oare of fan ien nei ferskate filters troch te jaan. Filters en harren ferbinings foarmje in rjochte grafyk. De ynfier of útfier fan it filter wurdt it algemiene wurd "pin" neamd. Om de folchoarder te beskriuwen wêryn filters mei elkoar ferbûn binne, brûkt de mediastreamer it konsept fan in "sinjaalpunt". Sinjaal punt is struktuer _MSCPoint, dy't in oanwizer nei it filter befettet en it nûmer fan ien fan syn pins; dêrom beskriuwt it de ferbining fan ien fan 'e yn- of útgongen fan it filter.

Signal punt fan gegevens ferwurkjen grafyk

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

Filterpinnen binne nûmere fan nul.

De ferbining fan twa pins troch in berjochtwachtrige wurdt beskreaun troch de struktuer _MSQueue, dy't in berjochtwachtrige befettet en oanwizers nei de twa sinjaalpunten dy't it ferbynt:

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

Wy sille dizze struktuer in sinjaalferbining neame. Elk mediastreamerfilter befettet in tabel mei ynfierkeppelings en in tabel mei útfierkeppelings (MSQueue). De grutte fan tabellen wurdt ynsteld by it meitsjen fan in filter; wy hawwe dit al dien mei in eksportearre fariabele fan type MSFilterDesc, doe't wy ús eigen filter ûntwikkele. Hjirûnder is in struktuer dy't elk filter yn in mediastreamer beskriuwt, 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;

Nei't wy de filters yn it C-programma ferbûn hawwe yn oerienstimming mei ús plan (mar hawwe de ticker net ferbûn), hawwe wy dêrmei in rjochte grafyk makke, wêrfan de knopen eksimplaren binne fan 'e struktuer MSFilter, en rânen binne eksimplaren fan keppelings MSQueue.

Achter de skermen aktiviteiten fan de ticker

Doe't ik jo fertelde dat de ticker in filter is foar de boarne fan teken, wie it der net de hiele wierheid oer. In ticker is in objekt dat funksjes op 'e klok útfiert proses() alle filters fan it circuit (grafyk) dêr't it is ferbûn. As wy in ticker ferbine mei in grafykfilter yn in C-programma, litte wy de ticker de grafyk sjen dy't it fan no ôf sil kontrolearje oant wy it útsette. Nei it ferbinen begjint de ticker de grafyk te ûndersiikjen dy't oan syn soarch is tawiisd, en kompilearret in list mei filters dy't it omfetsje. Om itselde filter net twa kear te "tellen", markearret it de ûntdutsen filters troch in karfakje yn te pleatsen sjoen. De sykopdracht wurdt útfierd mei de keppeling tabellen dy't elk filter hat.

Tidens syn ynliedende rûnlieding troch de grafyk kontrolearret de ticker oft der ûnder de filters op syn minst ien is dy't fungearret as boarne fan gegevensblokken. As d'r gjin binne, dan wurdt de grafyk as ferkeard beskôge en crasht de ticker.

As de grafyk "korrekt" blykt te wêzen, wurdt foar elke fûn filter de funksje neamd foar inisjalisaasje foarferwurking(). Sadree't it momint komt foar de folgjende ferwurkingssyklus (elke 10 millisekonden standert), ropt de ticker de funksje proses() foar alle earder fûn boarne filters, en dan foar de oerbleaune filters yn de list. As it filter ynfierkeppelings hat, dan útfiere de funksje proses() werhellet oant de wachtrige foar ynfierlinks leech binne. Hjirnei giet it troch nei it folgjende filter yn 'e list en "scrollt" it oant de ynfierkeppelings frij binne fan berjochten. De ticker ferpleatst fan filter nei filter oant de list einiget. Dit foltôget de ferwurking fan 'e syklus.

No sille wy weromgean nei tuples en prate oer wêrom't sa'n entiteit waard tafoege oan 'e mediastreamer. Yn 't algemien komt de hoemannichte gegevens dy't nedich binne troch it algoritme dat binnen it filter wurket net gear en is net in mearfâld fan' e grutte fan 'e gegevensbuffers ûntfongen by de ynfier. Wy skriuwe bygelyks in filter dat in flugge Fourier-transform útfiert, dy't per definysje allinich gegevensblokken kin ferwurkje wêrfan de grutte in macht fan twa is. Lit it 512 tellen wêze. As de gegevens wurde oanmakke troch in telefoanysk kanaal, dan sil de gegevensbuffer fan elk berjocht by de ynfier ús 160 sinjaalmonsters bringe. It is ferliedlik om gjin gegevens te sammeljen fan 'e ynfier oant de fereaske hoemannichte gegevens der is. Mar yn dit gefal sil in botsing foarkomme mei de ticker, dy't sûnder súkses besykje it filter te rôljen oant de ynfierkeppeling leech is. Earder hawwe wy dizze regel oanwiisd as it tredde prinsipe fan it filter. Neffens dit prinsipe moat it filter syn proses () funksje nimme alle gegevens út de ynfier wachtrijen.

Derneist sil it net mooglik wêze om allinich 512 samples fan 'e ynfier te nimmen, om't jo allinich folsleine blokken kinne nimme, d.w.s. it filter sil 640 samples moatte nimme en 512 dêrfan brûke, de rest foardat in nij diel fan gegevens sammele wurdt. Sa moat ús filter, neist syn haadwurk, auxiliary aksjes foar tuskenlizzende opslach fan ynfiergegevens leverje. De ûntwikkelders fan 'e mediastreamer en oplossing foar dit algemiene probleem hawwe in spesjaal foarwerp ûntwikkele - MSBufferizer (buffer), dy't dit probleem oplost mei tuples.

Bufferizer (MSBufferizer)

Dit is in objekt dat ynfiergegevens binnen it filter sil sammelje en begjinne mei it yntsjinjen foar ferwurking sa gau as de hoemannichte ynformaasje genôch is om it filteralgoritme út te fieren. Wylst de buffer gegevens sammelet, sil it filter wurkje yn idle modus, sûnder de ferwurkingskrêft fan 'e prosessor te brûken. Mar sa gau as it lêzen funksje út de buffer jout in wearde oars as nul, begjint it proses () funksje fan it filter te nimmen en ferwurkje gegevens út de buffer yn dielen fan de fereaske grutte, oant it is útput.
Gegevens dy't noch net nedich binne, bliuwe yn 'e buffer as it earste elemint fan' e tuple, dêr't folgjende blokken fan ynfiergegevens oan hechte binne.

De struktuer dy't de buffer beskriuwt:

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

Funksjes foar wurkjen mei MSBufferizer

In nije buffer-eksimplaar oanmeitsje:

MSBufferizer * ms_bufferizer_new(void);

Unthâld wurdt tawiisd, inisjalisearre yn ms_bufferizer_init() en in oanwizer wurdt weromjûn.

Inisjalisaasjefunksje:

void ms_bufferizer_init(MSBufferizer *obj); 

De wachtrige wurdt inisjalisearre q, fjild grutte is ynsteld op nul.

In berjocht tafoegje:

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

Berjocht m wurdt tafoege oan de wachtrige. De berekkene grutte fan gegevens blokken wurdt tafoege oan grutte.

It oerbringen fan alle berjochten fan 'e keppeling gegevenswachtrige nei de buffer q:

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

Berjochten oermeitsje fan in keppeling q yn de buffer wurdt útfierd mei help fan de funksje ms_bufferizer_put().

Lêze fanút de buffer:

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

As de grutte fan 'e gegevens sammele yn' e buffer minder is dan de frege ien (datalen), dan jout de funksje nul, gegevens wurde net kopiearre nei gegevens. Oars wurdt sekwinsjele kopiearjen fan gegevens fan tupels yn 'e buffer útfierd. Nei it kopiearjen wurdt de tuple wiske en wurdt it ûnthâld frijmakke. It kopiearjen einiget op it momint dat datalenbytes wurde kopiearre. As romte rint op yn 'e midden fan in gegevens blok, dan yn dit berjocht, it gegevens blok wurdt redusearre nei it oerbleaune net kopiearre diel. De folgjende kear as jo belje, sil it kopiearjen fanôf dit punt trochgean.

It lêzen fan de hoemannichte gegevens dy't op it stuit beskikber is yn 'e buffer:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Jout it fjild werom grutte buffer.

In diel fan 'e gegevens yn 'e buffer ferwiderje:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

It opjûne oantal bytes fan gegevens wurdt ophelle en ferwidere. De âldste gegevens wurde ferwidere.

Alle berjochten yn 'e buffer wiskje:

void ms_bufferizer_flush(MSBufferizer *obj); 

De gegevensteller wurdt weromset nei nul.

Alle berjochten yn 'e buffer wiskje:

void ms_bufferizer_uninit(MSBufferizer *obj); 

De teller is net weromset.

De buffer fuortsmite en ûnthâld frijmeitsje:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Foarbylden fan it brûken fan de bufferer kinne fûn wurde yn 'e boarnekoade fan ferskate mediastreamerfilters. Bygelyks, yn it MS_L16_ENC-filter, dat de bytes yn 'e samples fan' e netwurkopdracht nei de hostopdracht opnij regelet: l16.c

Yn it folgjende artikel sille wy sjen nei de kwestje fan it skatten fan 'e lading op in ticker en manieren om te bestriden fan oermjittige komputerlast yn in mediastreamer.

Boarne: www.habr.com

Add a comment