Vekolîna motora VoIP ya Mediastreamer2. Beş 11

Madeya gotarê ji min hatiye girtin kanala zen.

Vekolîna motora VoIP ya Mediastreamer2. Beş 11

Mekanîzmaya tevgera daneyê

  • Astengkirina daneyan dblk_t
  • Peyama mblk_t
  • Fonksiyonên ji bo xebata bi peyamên mblk_t
  • Dorê queue_t
  • Fonksiyonên ji bo xebata bi dorên queue_t
  • Parzûnên girêdanê
  • Xala nîşana grafiya hilberandina daneyê
  • Li pişt perdeyê çalakiyên tîkerê
  • Bufferizer (MSBufferizer)
  • Fonksiyonên ji bo xebata bi MSBufferizer

Di ya paşîn de gotara me parzûna xwe pêşxistiye. Ev gotar dê li ser mekanîzmaya navxweyî ya ji bo veguheztina daneyan di navbera fîlterên weşana medyayê de bisekine. Ev ê bihêle ku hûn di pêşerojê de bi hewildanek hindik fîlterên sofîstîke binivîsin.

Mekanîzmaya tevgera daneyê

Tevgera daneyê di stêrka medyayê de bi karanîna rêzikên ku ji hêla avahiyê ve têne diyar kirin têne kirin queue_t. Têlên peyamên mîna mblk_t, ku bixwe daneya sînyalê nagirin, lê tenê bi peyama berê, ya paşîn û bloka daneyê ve girêdidin. Wekî din, ez dixwazim bi taybetî tekez bikim ku di heman demê de qadek ji bo girêdanek peyamek bi heman rengî jî heye, ku destûrê dide we ku hûn navnîşek peyamên bi yek ve girêdayî organîze bikin. Em ê komek peyamên ku ji hêla navnîşek weha ve hatine yek kirin wekî pirjimar bi nav bikin. Bi vî rengî, her hêmanek rêzê dikare bibe peyamek yekane mblk_t, û dibe ku serê tuple message mblk_t. Her peyamek tuple dikare bloka xweya daneya wargehê hebe. Em ê hinekî paşê nîqaş bikin ka çima tuples hewce ne.

Wekî ku li jor behs kir, peyam bixwe bloka daneyê nagire, ew tenê nîşanek li qada bîranînê ya ku bloka lê tê hilanîn vedihewîne. Di vê beşê de, wêneya giştî ya xebata weşangerê medyayê di karîkaturê "Monsters, Inc." de depoya derî tîne bîra xwe, ku derî (girêdanên daneyan - jûreyan) bi leza dîn bi rêgezên jor ve diçin, dema ku jûr bi xwe bêtevger dimînin.

Naha, li ser hiyerarşiyê ji binî ber bi jor ve diçin, werin em bi hûrgulî li ser sazûmanên navnîşkirî yên mekanîzmaya veguheztina daneyê di navgîniya medyayê de binirxînin.

Astengkirina daneyan dblk_t

Bloka daneyê ji serî û tamponek daneyê pêk tê. Sernivîs ji hêla avahiya jêrîn ve tête diyar kirin,

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

Zeviyên avahiyê nîşangirên destpêka tampon, dawiya tampon û fonksiyona jêbirina tampona daneyê vedigirin. Di serî de hêmana dawîn db_ref - jimareya referansê, heke ew bigihîje sifirê, ev wekî nîşanek kar dike ku vê blokê ji bîrê jê bibe. Ger bloka daneyê ji hêla fonksiyonê ve hatî çêkirin datab_alloc() , wê hingê tampona daneyê dê tavilê piştî sernavê di bîranînê de were danîn. Di hemî rewşên din de, tampon dikare li cîhek cûda were bicîh kirin. Tampona daneyê dê nimûneyên sînyalê an daneyên din ên ku em dixwazin bi parzûnan pêvajo bikin vehewîne.

Mînakek nû ya bloka daneyê bi karanîna fonksiyonê tê afirandin:

dblk_t *datab_alloc(int size);

Wekî parametreyek têketinê, mezinahiya daneya ku dê blok hilîne tê dayîn. Zêdetir bîranîn tê veqetandin da ku sernavek - avahî - li destpêka bîranîna veqetandî were danîn datab. Lê dema ku fonksiyonên din bikar tînin, ev her gav di hin rewşan de çênabe, dibe ku tampona daneyê ji sernavê bloka daneyê veqetandî be. Dema ku avahiyek çêbikin, zevî bi vî rengî têne mîheng kirin ku qada wê db_base îşaret bi destpêka qada daneyê kir, û db_lim heta dawiya xwe. Hejmara girêdanê db_ref yek tê danîn. Nîşana fonksiyona zelal a daneyê li ser sifirê hatî danîn.

message mblk_t

Wekî ku hate gotin, hêmanên rêzê celeb in mblk_t, wiha tê pênasekirin:

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;

avahiya mblk_t di destpêkê de nîşangiran dihewîne b_prev, b_next, yên ku ji bo organîzekirina navnîşek bi ducarî ve girêdayî hewce ne (ku rêzek e queue_t).

Paşê nîşander tê b_cont, ku tenê dema ku peyam beşek ji tupleyê be tê bikar anîn. Ji bo peyama paşîn a di pirtikê de, ev nîşanker betal dimîne.

Dûv re em nîşanek bloka daneyê dibînin b_datap, ji bo ku peyam heye. Li dû wê nîşangirên devera hundurê tampona daneya blokê tê. Erd b_rptr cîhê ku dê daneyên tamponê jê were xwendin diyar dike. Erd b_wptr cîhê ku dê ji tamponê re were nivîsandin destnîşan dike.

Zeviyên mayî xwezaya karûbarê ne û bi xebata mekanîzmaya veguheztina daneyê re têkildar nînin.

Li jêr peyamek yekane bi navê heye m1 û bloka daneyê d1.
Vekolîna motora VoIP ya Mediastreamer2. Beş 11
Nîgara jêrîn jimareyek ji sê peyaman nîşan dide m1, m1_1, m1_2.
Vekolîna motora VoIP ya Mediastreamer2. Beş 11

fonksiyonên mesajê mblk_t

Peyamek nû mblk_t ji hêla fonksiyonê ve hatî afirandin:

mblk_t *allocb(int size, int pri); 

ew di bîranînê de peyamek nû dide mblk_t bi bloka daneya mezinahiya diyarkirî mezinayîargumana duyemîn - xelkê di vê guhertoya pirtûkxaneyê de nayê bikaranîn. Divê sifir bimîne. Di dema xebata fonksiyonê de, bîranîn dê ji bo avahiya peyama nû were veqetandin û fonksiyon dê were bang kirin mblk_init(), ku dê hemî qadên mînaka çêkirî ya strukturê ji nû ve bike û dûv re, ya ku li jor hatî destnîşan kirin bikar bîne datab_alloc(), dê tamponek daneyê biafirîne. Piştî wê, zeviyên di strukturê de dê bêne mîheng kirin:

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

Di encam de em peyamek nû bi zeviyên destpêkî û tamponek daneya vala distînin. Ji bo ku hûn daneyê li peyamekê zêde bikin, hûn hewce ne ku wê li tampona bloka daneyê kopî bikin:

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

ko jimare nîşanek ji bo çavkaniya daneyê ye, û mezinayî - mezinahiya wan.
wê hingê hûn hewce ne ku nîşankerê li xala nivîsandinê nûve bikin da ku ew dîsa li destpêka qada azad a di tamponê de destnîşan bike:

msg->b_wptr = msg->b_wptr + size

Heke hûn hewce ne ku ji tamponek heyî, bêyî kopîkirinê peyamek biafirînin, wê hingê fonksiyonê bikar bînin:

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

Fonksîyon, piştî afirandina peyam û strukturê bloka daneyê, dê nîşangirên xwe li daneyên li navnîşanê mîheng bike. buff. Ewan. di vê rewşê de, tampona daneyê li dû qadên sernavê yên bloka daneyê nayê cîh, wekî ku di dema afirandina bloka daneyê bi fonksiyonê re bû. datab_alloc(). Tampona bi daneyên ku ji fonksiyonê re derbas bûne dê li cîhê ku lê bû bimîne, lê bi alîkariya nîşankeran ew ê bi sernavê bloka daneyê ya nû hatî afirandin ve were girêdan, û li gorî vê yekê, bi peyamê re were girêdan.

Ji yek peyamê re mblk_t Gelek blokên daneyê dikarin bi rêzê ve werin girêdan. Ev ji hêla fonksiyonê ve tête kirin:

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

mp - peyamek ku dê bloka daneya din lê zêde bibe;
jimare - nîşana blokê, kopiyek ku dê li peyamê were zêdekirin;
mezinayî - mezinahiya daneyê;
pad - alayek ku mezinahiya bîranîna veqetandî divê li ser sînorek 4-byte were rêz kirin (dakêşandin dê bi sifiran were kirin).

Ger di tampona daneya peyama heyî de cîh têra xwe hebe, wê hingê dê daneyên nû li pişt daneyên ku berê li wir hene werin danîn. Ger di tampona daneya peyamê de cîhê belaş kêmtir ji wê hebe mezinayî, paşê peyamek nû bi mezinahiya tamponek têr tê afirandin û dane li tampona wê tê kopî kirin. Ev peyamek nû ye, bi ya orîjînal re bi karanîna nîşanek ve girêdayî ye b_cont. Di vê rewşê de, peyam vediguhere tuple.

Heke hûn hewce ne ku blokek din a daneyê li tupleyê zêde bikin, wê hingê hûn hewce ne ku fonksiyonê bikar bînin:

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

ew ê peyama paşîn a di kulmê de bibîne (wî heye b_cont dê null be) û dê fonksiyona vê peyamê bang bike pêvek ().

Hûn dikarin bi karanîna fonksiyonê mezinahiya daneya di mesajek an tuple de fêr bibin:

int msgdsize(const mblk_t *mp);

ew ê di nav hemî peyamên di tîrêjê de bigere û tevahiya daneya di tamponên daneya wan peyaman de vegerîne. Ji bo her peyamê, mîqdara daneyê wiha tê hesibandin:

 mp->b_wptr - mp->b_rptr

Ji bo ku du tîpan berhev bikin, fonksiyonê bikar bînin:

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

ew tupleyê pêve dike newm heta dûvikê tupê mp û îşaretek vedigerîne peyama paşîn a qertafa encam.

Ger hewce be, tuple dikare bi yek bloka daneyê ve bibe yek peyam;

void msgpullup(mblk_t *mp,int len);

eger arguman len -1 e, wê hingê mezinahiya tampona veqetandî bixweber tê destnîşankirin. Ger len jimareyek erênî ye, dê tamponek bi vê mezinahiyê were çêkirin û daneyên peyama piralî dê tê de were kopî kirin. Ger tampon xilas bibe, dê kopîkirin li wir raweste. Peyama yekem a tupleyê dê bi daneyên kopî re tamponek mezinahiya nû bistîne. Peyamên mayî dê werin jêbirin û bîranîn vedigere serhev.

Dema ku avahiyek jêbirin mblk_t jimartina referansê ya bloka daneyê tê hesibandin heke, dema ku tê bang kirin belaş () ew sifir derdikeve holê, wê hingê tampona daneyê digel nimûneyê tê jêbirin mblk_t, ku nîşan dide.

Destpêkirina zeviyên peyamek nû:

void mblk_init(mblk_t *mp);

Daneyên din li peyamê zêde bikin:

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

Ger daneyên nû di cîhê belaş a tampona daneya peyamê de cih negirin, wê hingê peyamek veqetandî ya ku bi tamponek mezinahiya pêdivî hatî çêkirin bi peyamê re tê girêdan (nîşanek ji peyama zêdekirî di peyama yekem de tête danîn) û peyam vediguhere kulmekê.

Zêdekirina perçeyek daneyê li tupleyê:

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

Fonksîyona appendb() di hêlekê de bang dike.

Bihevxistina du tîpan di yek de:

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

message newm dê were girêdan mp.

Çêkirina kopiyek ji peyamek yekane:

mblk_t *copyb(const mblk_t *mp);

Kopîkirina bêkêmasî ya tuple bi hemî blokên daneyê re:

mblk_t *copymsg(const mblk_t *mp);

Hêmanên tupleyê ji hêla fonksiyonê ve têne kopî kirin copyb().

Kopiyek hêsan a peyamek çêbikin mblk_t. Di vê rewşê de, bloka daneyê nayê kopî kirin, lê hejmarê referansa wê zêde dibe db_ref:

mblk_t *dupb(mblk_t *mp);

Çêkirina kopiyek sivik a tuple. Blokên daneyê nayên kopî kirin, tenê hejmarên referansa wan zêde dibin db_ref:

mblk_t *dupmsg(mblk_t* m);

Girêdana hemî peyamên tîrêjê di yek peyamê de:

void msgpullup(mblk_t *mp,size_t len);

Ger argumana len -1 e, wê hingê mezinahiya tampona veqetandî bixweber tê destnîşankirin.

Jêbirina peyamekê, piralî:

void freemsg(mblk_t *mp);

Hejmara referansa bloka daneyê bi yek kêm dibe. Ger ew bigihîje sifirê, bloka daneyê jî tê jêbirin.

Hesabkirina giştiya daneya di peyamek an pirtikê de.

size_t msgdsize(const mblk_t *mp);

Vegerandina peyamek ji dûvikê rêzê:

mblk_t *ms_queue_peek_last (q);

Kopîkirina naveroka qadên veqetandî yên yek peyamê ji peyamek din re (bi rastî, van qadan alên ku ji hêla weşana medyayê ve têne bikar anîn hene):

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

Mar queue_t

Rêza peyamê ya di weşana medyayê de wekî navnîşek dorpêvekirî ya ducarî tête bicîh kirin. Her hêmanek navnîşê nîşanek ji bo bloka daneyê bi nimûneyên nîşanê vedihewîne. Derdikeve holê ku tenê nîşangirên bloka daneyê li gorî xwe tevdigerin, dema ku dane bixwe bêtevger dimînin. Ewan. tenê girêdanên wan têne veguhestin.
Structure danasîna dorê queue_t, li jêr tê nîşandan:

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

Avahiyek zeviyek heye - nîşanek _q_stopper *mblk_t binivîsin, ew hêmana yekem (peyam) di rêzê de destnîşan dike. Qada duyemîn a strukturê jimareya peyamên di rêzê de ye.
Di jimareya jêrîn de rêzek bi navê q1 nîşan dide ku tê de 4 peyamên m1, m2, m3, m4 hene.
Vekolîna motora VoIP ya Mediastreamer2. Beş 11
Di jimareya jêrîn de rêzek bi navê q1 nîşan dide ku tê de 4 peyamên m1,m2,m3,m4 hene. Peyama m2 serê tupleyekê ye ku du peyamên din m2_1 û m2_2 dihewîne.

Vekolîna motora VoIP ya Mediastreamer2. Beş 11

Fonksiyonên ji bo xebata bi dorên queue_t

Destpêkirina rêzê:

void qinit(queue_t *q);

warê _q_stopper (li vir em ê jê re bibêjin "stopper") ji hêla fonksiyonê ve hatî destpêkirin mblk_init(), hêmana wê ya berê û nîşana hêmana paşîn ji bo ku xwe nîşan bide têne sererast kirin. Hejmara hêmanên rêzê li sifirê tê vegerandin.

Zêdekirina hêmanek nû (peyam):

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

Hêmana nû m li dawiya lîsteyê tê zêdekirin, nîşangirên hêmanan bi vî rengî têne sererast kirin ku rawestgeh jê re bibe hêmana din, û ew ji bo rawestgehê bibe hêmana berê. Hejmara hêmanên rêzê zêde dibe.

Vegerandina hêmanek ji rêzê:

mblk_t * getq(queue_t *q); 

Peyama ku piştî rawestanê tê tê wergirtin, û jimarvana elementê kêm dibe. Ger di rêzê de ji xeynî rawestanê hêman tune bin, wê hingê 0 tê vegerandin.

Têxistina peyamekê di dorê de:

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

Pêve mp berî hêmanê tê xistin emp. Ger emp=0, wê demê peyam li dûvika dorê tê zêdekirin.

Vegerandina peyamek ji serokê rêzê:

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

Hejmara elementan kêm dibe.

Xwendina nîşanek ji hêmana yekem a di rêzê de:

mblk_t * peekq(queue_t *q); 

Dema ku hêman bixwe jêbirin, hemî hêman ji rêzê derxistin:

void flushq(queue_t *q, int how);

Bersivk çawa nayê bikaranîn. Hejmara hêmanên rêzê li ser sifir tê danîn.

Makro ji bo xwendina nîşanek ji hêmana paşîn a rêzê:

mblk_t * qlast(queue_t *q);

Dema ku bi rêzikên peyaman re dixebitin, hay jê hebin ku gava ku hûn bang dikin ms_queue_put(q, m) bi nîşanek null a peyamê, fonksiyonê vedike. Bernameya we dê cemidîne. bi heman rengî tevdigere ms_queue_next(q, m).

Parzûnên girêdanê

Rêza ku li jor hatî destnîşan kirin ji bo derbaskirina peyaman ji parzûnek din an ji yek ji çend parzûnan tê bikar anîn. Parzûn û girêdanên wan grafikek rêvekirî pêk tînin. Têketin an derketina parzûnê dê bi peyva gelemperî "pin" were gotin. Ji bo danasîna rêza ku fîlter bi hevûdu ve girêdayî ne, weşana medyayê têgeha "xala nîşanê" bikar tîne. Xala sînyalê avahî ye _MSCPpoint, ku nîşanek ji parzûnê û hejmara yek ji pinên wê re li gorî vê yekê vedihewîne, ew pêwendiya yek ji têketin an derketinên parzûnê vedibêje.

Xala nîşana grafiya hilberandina daneyê

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

Pînên Parzûnê ji sifirê dest pê dikin têne jimartin.

Girêdana du pîneyan ji hêla rêzek peyamê ve ji hêla avahiyê ve tête diyar kirin _MSQueue, ku rêzek peyamê û nîşangirên du xalên îşaretê yên ku ew bi hev ve girêdide vedihewîne:

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

Em ê ji vê strukturê re dibêjin girêdanek nîşanek. Her parzûna weşana medyayê tabloyek girêdanên têketinê û tabloyek girêdanên derketinê vedihewîne (MSQueue). Mezinahiya tabloyan dema ku parzûnek diafirîne, me berê bi karanîna guhêrbarek îxrackirî kiriye; MSFilterDesc, dema ku me parzûna xwe pêşxist. Li jêr avahiyek heye ku her fîlterek di weşanek medyayê de vedibêje, 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;

Piştî ku me fîlterên di bernameya C-yê de li gorî plansaziya xwe ve girêda (lê pêvekê bi hev ve girê neda), me bi vî rengî grafiyek rêvekirî çêkir, ku girêkên wê mînakên strukturê ne. MSFilter, û qerax mînakên girêdanan in MSQueue.

Li pişt perdeyê çalakiyên tîkerê

Dema ku min ji we re got ku tikker parzûnek ji bo çavkaniya tikandinê ye, ew ne tevahî rastiya wê bû. Ticker tiştek e ku fonksiyonên li ser demjimêrê dimeşîne doz() hemû parzûnên çerxa (grafîka) ku pê ve girêdayî ye. Dema ku em di bernameyek C-yê de tikerek bi parzûna grafîkê ve girêdidin, em grafika ku ew ê ji nuha û pê ve kontrol bike heya ku em wê qut bikin nîşanî tikkerê didin. Piştî girêdanê, tiker dest bi lêkolîna grafika ku ji lênihêrîna wê re hatî spartin, berhevkirina navnîşek fîlterên ku wê dihewîne berhev dike. Ji bo ku heman fîlterê du caran "hejmar" neke, ew fîlterên hatine tespîtkirin bi danîna qutiyek kontrolê di wan de nîşan dide. dît. Lêgerîn bi karanîna tabloyên girêdanê yên ku her parzûnek heye tê kirin.

Di dema gera xweya danasînê ya grafîkê de, tikker kontrol dike gelo di nav parzûnan de bi kêmanî yek heye ku wekî çavkaniya blokên daneyê tevbigere. Ger yek tune be, wê hingê grafîk xelet tê hesibandin û tîrêj têk diçe.

Ger grafîk wekî "rast" derkeve, ji bo her parzûnek hatî dîtin, fonksiyon ji bo destpêkirinê tê gazî kirin pêşpêvajo (). Hema ku dem tê çerxa pêvajoyê ya din (her 10 milî çirkeyan bi xweber), tikker gazî fonksiyonê dike. doz() ji bo hemî fîlterên çavkaniyê yên berê hatine dîtin, û dûv re ji bo parzûnên mayî yên di navnîşê de. Ger fîlter girêdanên têketinê hebin, wê hingê fonksiyonê bimeşînin doz() dubare dike heta ku rêzikên girêdana têketinê vala nebin. Piştî vê yekê, ew di navnîşê de derbasî parzûna paşîn dibe û "digere" heya ku girêdanên têketinê ji peyaman bêpar in. Tiker ji parzûnê ber bi parzûnê ve diçe heya ku navnîş biqede. Ev pêvajoya çerxê temam dike.

Naha em ê vegerin ser lûtkeyan û biaxivin ka çima saziyek wusa li weşana medyayê hate zêdekirin. Bi gelemperî, mîqdara daneya ku ji algorîtmaya ku di hundurê parzûnê de xebitîne hewce dike li hev nayê û ne pirjimarek mezinahiya tamponên daneyê ye ku di têketinê de têne wergirtin. Mînakî, em parzûnek dinivîsin ku veguherînek bilez a Fourier pêk tîne, ku ji hêla pênase ve tenê dikare blokên daneyê yên ku mezinahiya wan hêza du ye bişopîne. Bila 512 hejmar be. Ger dane ji hêla kanalek têlefonê ve were çêkirin, wê hingê tampona daneya her peyamê di têketinê de dê 160 nimûneyên sînyalê ji me re bîne. Hewldan e ku meriv daneyan ji têketinê berhev neke heya ku hêjmara daneya pêwîst li wir be. Lê di vê rewşê de, dê pevçûnek bi tikerê re çêbibe, ku dê bêserûber hewl bide ku parzûnê bigere heya ku zencîreya têketinê vala nebe. Berê, me ev qaîdeyek wekî prensîba sêyemîn a parzûnê destnîşan kir. Li gorî vê prensîbê, fonksiyona pêvajoya () Parzûnê divê hemî daneyan ji rêzikên têketinê bigire.

Wekî din, ne gengaz e ku meriv tenê 512 nimûneyan ji têketinê bigire, ji ber ku hûn tenê dikarin blokên tevahî bigirin, ango. Parzûn dê 640 nimûneyan bigire û 512 ji wan bikar bîne, yên mayî berî ku beşek nû ya daneyan berhev bike. Ji ber vê yekê, parzûna me, ji bilî xebata wê ya sereke, divê ji bo hilanîna navîn a daneyên têketinê çalakiyên alîkar peyda bike. Pêşdebirên weşana medyayê û çareseriya vê pirsgirêka gelemperî tiştek taybetî pêşve xistine - MSBufferizer (bufferer), ku vê pirsgirêkê bi karanîna tîrêjan çareser dike.

Bufferizer (MSBufferizer)

Ev hêmanek e ku dê daneyên têketinê di hundurê parzûnê de berhev bike û gava ku hêjmara agahiyê bes be ku algorîtmaya fîlterê bixebite, dest bi şandina wê ji bo pêvajoyê bike. Dema ku tampon daneyan berhev dike, parzûn dê di moda bêkêmasî de bixebite, bêyî ku hêza hilberandina pêvajoyê bikar bîne. Lê gava ku fonksiyona xwendinê ji tamponê nirxek ji bilî sifirê vedigerîne, fonksiyona pêvajoyê() ya parzûnê dest pê dike ku daneyan ji tamponê di beşên mezinahiya hewce de bigire û pêvajoyê bike, heya ku biqede.
Daneyên ku hîna ne hewce ne di tamponê de wekî hêmana yekem a tupleyê dimîne, ku blokên paşerojê yên daneya têketinê pê ve girêdayî ne.

Struktura ku tampon rave dike:

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

Fonksiyonên ji bo xebata bi MSBufferizer

Afirandina mînakek tamponek nû:

MSBufferizer * ms_bufferizer_new(void);

Bîr tê veqetandin, di nav de dest pê dike ms_bufferizer_init() û nîşanek tê vegerandin.

Fonksiyona destpêkê:

void ms_bufferizer_init(MSBufferizer *obj); 

Dorê dest pê dike q, zevî mezinayî sifir hatiye danîn.

Zêdekirina peyamek:

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

Peyama m li dorê tê zêdekirin. Mezinahiya hesabkirî ya blokên daneyê tê zêdekirin mezinayî.

Veguheztina hemî peyaman ji rêza daneya girêdanê berbi tamponê q:

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

Veguheztina peyaman ji girêdanek q di tamponê de bi karanîna fonksiyonê tête kirin ms_bufferizer_put().

Xwendina ji tamponê:

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

Ger mezinahiya daneyên ku di tamponê de kom bûne ji ya daxwazkirî kêmtir be (datalen), wê hingê fonksiyon sifir vedigere, dane li daneyê nayên kopî kirin. Wekî din, kopîkirina birêkûpêk a daneyan ji tîpên ku di tamponê de ne têne kirin. Piştî kopîkirinê, tuple tê jêbirin û bîranîn azad dibe. Kopîkirin di dema kopîkirina datalen bytes de bi dawî dibe. Ger cîh di nîvê bloka daneyê de biqede, wê hingê di vê peyamê de, bloka daneyê dê li beşa mayî ya nekopîkirî kêm bibe. Cara din ku hûn bang dikin, wê kopîkirin ji vê nuqteyê bidome.

Xwendina mîqdara daneya ku niha di tamponê de heye:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Vedigere zeviyê mezinayî tampon.

Rakirina beşek daneyan di tamponê de:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Hejmara diyarkirî ya baytên daneyan têne wergirtin û avêtin. Daneyên herî kevn têne avêtin.

Jêbirina hemî peyamên di tamponê de:

void ms_bufferizer_flush(MSBufferizer *obj); 

Berhevkarê daneyan li sifirê tê vegerandin.

Jêbirina hemî peyamên di tamponê de:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Berhevkar nayê vesaz kirin.

Rakirina tampon û azadkirina bîra:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Nimûneyên karanîna tamponê dikarin di koda çavkaniyê ya çend fîlterên weşana medyayê de werin dîtin. Mînakî, di parzûna MS_L16_ENC de, ku baytên di nimûneyan de ji rêza torê berbi fermana mêvandar ji nû ve saz dike: l16.c

Di gotara paşîn de, em ê li mijara texmînkirina barkirina li ser tîrêjê û awayên şerkirina barkirina bargiraniya zêde ya di weşana medyayê de binihêrin.

Source: www.habr.com

Add a comment