Archwilio peiriant VoIP Mediastreamer2. Rhan 11

Mae deunydd yr erthygl yn cael ei gymryd o fy sianel zen.

Archwilio peiriant VoIP Mediastreamer2. Rhan 11

Mecanwaith symud data

  • Bloc data dblk_t
  • Neges mblk_t
  • Swyddogaethau ar gyfer gweithio gyda negeseuon mblk_t
  • Ciw ciw_t
  • Swyddogaethau ar gyfer gweithio gyda ciw queue_t
  • Cysylltu hidlwyr
  • Pwynt signal graff prosesu data
  • Gweithgareddau tu ôl i'r llenni y ticiwr
  • Clustogydd (MSBufferizer)
  • Swyddogaethau ar gyfer gweithio gyda MSBufferizer

Yn yr olaf Erthygl rydym wedi datblygu ein hidlydd ein hunain. Bydd yr erthygl hon yn canolbwyntio ar y mecanwaith mewnol ar gyfer symud data rhwng hidlwyr ffrydio cyfryngau. Bydd hyn yn caniatáu ichi ysgrifennu hidlwyr soffistigedig gyda llai o ymdrech yn y dyfodol.

Mecanwaith symud data

Perfformir symudiad data yn y ffrwdiwr cyfryngau gan ddefnyddio ciwiau a ddisgrifir gan y strwythur ciw_t. Llinynnau o negeseuon fel mblk_t, nad ydynt eu hunain yn cynnwys data signal, ond dim ond dolenni i'r neges flaenorol, nesaf ac i'r bloc data. Yn ogystal, hoffwn bwysleisio'n arbennig fod yna hefyd faes ar gyfer dolen i neges o'r un math, sy'n caniatáu ichi drefnu rhestr o negeseuon sy'n cysylltu'n unigol. Byddwn yn galw grŵp o negeseuon unedig gan restr o'r fath yn tuple. Felly, gall unrhyw elfen o'r ciw fod yn un neges mblk_t, ac efallai y pennaeth tuple neges mblk_t. Gall pob neges tuple gael ei bloc data ward ei hun. Byddwn yn trafod pam mae angen tuples ychydig yn ddiweddarach.

Fel y soniwyd uchod, nid yw'r neges ei hun yn cynnwys bloc o ddata; yn hytrach, dim ond pwyntydd i'r ardal cof lle mae'r bloc yn cael ei storio y mae'n ei gynnwys. Yn y rhan hon, mae'r darlun cyffredinol o waith y ffrwdiwr cyfryngau yn atgoffa rhywun o'r warws drws yn y cartŵn “Monsters, Inc.,” lle mae drysau (cysylltiadau â data - ystafelloedd) yn symud ar gyflymder gwallgof ar hyd cludwyr uwchben, tra bod yr ystafelloedd eu hunain aros yn llonydd.

Nawr, gan symud ar hyd yr hierarchaeth o'r gwaelod i'r brig, gadewch i ni ystyried yn fanwl endidau rhestredig y mecanwaith trosglwyddo data yn y streamer cyfryngau.

Bloc data dblk_t

Mae'r bloc data yn cynnwys pennawd a byffer data. Disgrifir y pennawd gan y strwythur canlynol,

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

Mae meysydd y strwythur yn cynnwys awgrymiadau i ddechrau'r byffer, diwedd y byffer, a'r swyddogaeth ar gyfer dileu'r byffer data. Elfen olaf yn y pennawd db_ref — rhifydd cyfeirio, os yw'n cyrraedd sero, mae hwn yn signal i ddileu'r bloc hwn o'r cof. Os cafodd y bloc data ei greu gan y swyddogaeth datab_alloc() , yna bydd y byffer data yn cael ei osod yn y cof yn syth ar ôl y pennawd. Ym mhob achos arall, gellir lleoli'r byffer yn rhywle ar wahân. Bydd y byffer data yn cynnwys samplau signal neu ddata arall yr ydym am ei brosesu gyda hidlwyr.

Mae enghraifft newydd o floc data yn cael ei greu gan ddefnyddio'r swyddogaeth:

dblk_t *datab_alloc(int size);

Fel paramedr mewnbwn, rhoddir maint y data y bydd y bloc yn ei storio. Mae mwy o gof yn cael ei ddyrannu er mwyn gosod pennawd - strwythur - ar ddechrau'r cof a neilltuwyd datab. Ond wrth ddefnyddio swyddogaethau eraill, nid yw hyn bob amser yn digwydd; mewn rhai achosion, gellir lleoli'r byffer data ar wahân i bennawd y bloc data. Wrth greu strwythur, mae'r meysydd yn cael eu ffurfweddu fel bod ei faes db_sylfaen cyfeiriodd at ddechrau'r maes data, a db_lim i'w diwedd. Cyfrif cyswllt db_ref yn cael ei osod i un. Mae'r pwyntydd swyddogaeth clir data wedi'i osod i sero.

Neges mblk_t

Fel y dywedwyd, mae elfennau ciw o fath mblk_t, caiff ei ddiffinio fel a ganlyn:

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;

Strwythur mblk_t yn cynnwys awgrymiadau ar y dechrau b_cynt, b_nesaf, sy'n angenrheidiol i drefnu rhestr â chysylltiadau dwbl (sef ciw ciw_t).

Yna daw'r pwyntydd b_cont, a ddefnyddir dim ond pan fydd y neges yn rhan o tuple. Ar gyfer y neges olaf yn y tuple, mae'r pwyntydd hwn yn parhau i fod yn null.

Nesaf gwelwn bwyntydd i floc data b_datap, y mae'r neges yn bodoli amdano. Fe'i dilynir gan awgrymiadau i'r ardal y tu mewn i'r byffer data bloc. Maes b_rptr yn nodi o ba leoliad y darllenir data o'r byffer. Maes b_wptr yn nodi o ba leoliad y bydd ysgrifennu at y byffer yn cael ei berfformio.

Mae'r meysydd sy'n weddill o natur gwasanaeth ac nid ydynt yn ymwneud â gweithrediad y mecanwaith trosglwyddo data.

Isod mae neges sengl gyda'r enw m1 a bloc data d1.
Archwilio peiriant VoIP Mediastreamer2. Rhan 11
Mae'r ffigwr canlynol yn dangos tuple o dair neges m1, m1_1, m1_2.
Archwilio peiriant VoIP Mediastreamer2. Rhan 11

Swyddogaethau negeseuon mblk_t

Neges newydd mblk_t a grëwyd gan y swyddogaeth:

mblk_t *allocb(int size, int pri); 

mae hi'n gosod neges newydd yn y cof mblk_t gyda bloc data o'r maint penodedig maint, ail ddadl - pri nas defnyddir yn y fersiwn hwn o'r llyfrgell. Dylai aros yn sero. Yn ystod gweithrediad y swyddogaeth, bydd cof yn cael ei ddyrannu ar gyfer strwythur y neges newydd a bydd y swyddogaeth yn cael ei alw mblk_init(), a fydd yn ailosod pob maes o'r enghraifft a grëwyd o'r strwythur ac yna, gan ddefnyddio'r uchod datab_alloc(), yn creu byffer data. Ar ôl hynny bydd y meysydd yn y strwythur yn cael eu ffurfweddu:

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

Yn yr allbwn rydym yn derbyn neges newydd gyda meysydd cychwynnol a byffer data gwag. I ychwanegu data at neges, mae angen i chi ei gopïo i'r byffer bloc data:

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

lle data yn bwyntydd i'r ffynhonnell ddata, a maint - eu maint.
yna mae angen i chi ddiweddaru'r pwyntydd i'r pwynt ysgrifennu fel ei fod yn pwyntio eto at ddechrau'r ardal rydd yn y byffer:

msg->b_wptr = msg->b_wptr + size

Os oes angen i chi greu neges o glustog sy'n bodoli eisoes, heb gopïo, yna defnyddiwch y swyddogaeth:

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

Bydd y swyddogaeth, ar ôl creu'r neges a strwythur y bloc data, yn ffurfweddu ei awgrymiadau i'r data yn y cyfeiriad bwff. Y rhai. yn yr achos hwn, nid yw'r byffer data wedi'i leoli ar ôl meysydd pennawd y bloc data, fel oedd yn wir wrth greu bloc data gyda'r swyddogaeth datab_alloc(). Bydd y byffer gyda data a drosglwyddir i'r swyddogaeth yn aros lle'r oedd, ond gyda chymorth awgrymiadau bydd yn cael ei gysylltu â phennawd y bloc data sydd newydd ei greu, a hynny, yn unol â hynny, i'r neges.

I un neges mblk_t Gellir cydgatenu sawl bloc data yn olynol. Gwneir hyn gan y swyddogaeth:

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

mp — neges y bydd bloc data arall yn cael ei ychwanegu ati;
data - pwyntydd i'r bloc, y bydd copi ohono'n cael ei ychwanegu at y neges;
maint — maint data;
pad — baner bod yn rhaid alinio maint y cof a neilltuwyd ar hyd ffin 4-beit (bydd padin yn cael ei wneud â sero).

Os oes digon o le yn y byffer data neges presennol, yna bydd y data newydd yn cael ei gludo y tu ôl i'r data sydd yno eisoes. Os oes llai o le rhydd yn y byffer data neges na maint, yna mae neges newydd yn cael ei chreu gyda maint byffer digonol ac mae'r data'n cael ei gopïo i'w byffer. Mae hon yn neges newydd, wedi'i chysylltu â'r un wreiddiol gan ddefnyddio pwyntydd b_cont. Yn yr achos hwn, mae'r neges yn troi'n tuple.

Os oes angen i chi ychwanegu bloc arall o ddata at y tuple, yna mae angen i chi ddefnyddio'r swyddogaeth:

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

bydd hi'n dod o hyd i'r neges olaf yn y tuple (mae ganddo b_cont yn null) a bydd yn galw'r swyddogaeth ar gyfer y neges hon atodiad().

Gallwch ddarganfod maint y data mewn neges neu tuple gan ddefnyddio'r swyddogaeth:

int msgdsize(const mblk_t *mp);

bydd yn dolennu drwy'r holl negeseuon yn y tuple ac yn dychwelyd cyfanswm y data yn y byfferau data o'r negeseuon hynny. Ar gyfer pob neges, cyfrifir swm y data fel a ganlyn:

 mp->b_wptr - mp->b_rptr

I gyfuno dau duple, defnyddiwch y swyddogaeth:

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

mae hi'n atodi'r tuple newm i gynffon y tuple mp ac yn dychwelyd pwyntydd i neges olaf y tuple canlyniadol.

Os oes angen, gellir troi tuple yn un neges gydag un bloc o ddata; gwneir hyn gan y swyddogaeth:

void msgpullup(mblk_t *mp,int len);

os dadl len yw -1, yna penderfynir maint y byffer a ddyrennir yn awtomatig. Os len yn rhif positif, bydd byffer o'r maint hwn yn cael ei greu a bydd y data neges tuple yn cael ei gopïo i mewn iddo. Os bydd y byffer yn dod i ben, bydd copïo yn dod i ben yno. Bydd neges gyntaf y tuple yn derbyn byffer maint newydd gyda'r data wedi'i gopïo. Bydd y negeseuon sy'n weddill yn cael eu dileu a bydd y cof yn dychwelyd i'r domen.

Wrth ddileu strwythur mblk_t cymerir cyfrif cyfeirnod y bloc data i ystyriaeth os, wrth ffonio freeb() mae'n troi allan i fod yn sero, yna caiff y byffer data ei ddileu ynghyd â'r enghraifft mblk_t, sy'n pwyntio ato.

Cychwyn meysydd neges newydd:

void mblk_init(mblk_t *mp);

Ychwanegu darn arall o ddata i'r neges:

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

Os nad yw'r data newydd yn ffitio i le rhydd y byffer data neges, yna mae neges wedi'i chreu ar wahân gyda byffer o'r maint gofynnol ynghlwm wrth y neges (mae pwyntydd i'r neges ychwanegol wedi'i osod yn y neges gyntaf) a'r neges yn troi'n tuple.

Ychwanegu darn o ddata at tuple:

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

Mae'r ffwythiant yn galw appendb() mewn dolen.

Cyfuno dau duple yn un:

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

Neges newm bydd ynghlwm wrth mp.

Gwneud copi o un neges:

mblk_t *copyb(const mblk_t *mp);

Copïo cyflawn o tuple gyda'r holl flociau data:

mblk_t *copymsg(const mblk_t *mp);

Mae elfennau'r tuple yn cael eu copïo gan y swyddogaeth copib().

Creu copi hawdd o neges mblk_t. Yn yr achos hwn, nid yw'r bloc data yn cael ei gopïo, ond mae ei gownter cyfeirio yn cynyddu db_ref:

mblk_t *dupb(mblk_t *mp);

Gwneud copi ysgafn o tuple. Ni chaiff blociau data eu copïo, dim ond eu rhifyddion cyfeirio sy'n cael eu cynyddu db_ref:

mblk_t *dupmsg(mblk_t* m);

Gludo holl negeseuon tuple i mewn i un neges:

void msgpullup(mblk_t *mp,size_t len);

Os bydd y ddadl len yw -1, yna penderfynir maint y byffer a ddyrennir yn awtomatig.

Wrthi'n dileu neges, tuple:

void freemsg(mblk_t *mp);

Mae cyfrif cyfeirnod y bloc data yn cael ei ostwng o un. Os yw'n cyrraedd sero, caiff y bloc data ei ddileu hefyd.

Cyfrifo cyfanswm y data mewn neges neu tuple.

size_t msgdsize(const mblk_t *mp);

Nôl neges o gynffon y ciw:

mblk_t *ms_queue_peek_last (q);

Copïo cynnwys meysydd neilltuedig un neges i neges arall (mewn gwirionedd, mae'r meysydd hyn yn cynnwys baneri a ddefnyddir gan y ffrwdiwr cyfryngau):

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

Ciw ciw_t

Mae'r ciw neges yn y ffrwd cyfryngau yn cael ei weithredu fel rhestr gylchol sydd â chysylltiadau dwbl. Mae pob elfen rhestr yn cynnwys pwyntydd i floc data gyda samplau signal. Mae'n ymddangos mai dim ond awgrymiadau i'r bloc data sy'n symud yn eu tro, tra bod y data ei hun yn parhau i fod yn llonydd. Y rhai. dim ond dolenni iddynt sy'n cael eu symud.
Strwythur sy'n disgrifio'r ciw ciw_t, a ddangosir isod:

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

Mae'r strwythur yn cynnwys cae - pwyntydd _q_stopiwr teipiwch *mblk_t, mae'n pwyntio at yr elfen gyntaf (neges) yn y ciw. Ail faes y strwythur yw rhifydd negeseuon yn y ciw.
Mae'r ffigwr isod yn dangos ciw o'r enw q1 sy'n cynnwys 4 neges m1, m2, m3, m4.
Archwilio peiriant VoIP Mediastreamer2. Rhan 11
Mae'r ffigwr canlynol yn dangos ciw o'r enw q1 sy'n cynnwys 4 neges m1,m2,m3,m4. Neges m2 yw pen tuple sy'n cynnwys dwy neges arall m2_1 a m2_2.

Archwilio peiriant VoIP Mediastreamer2. Rhan 11

Swyddogaethau ar gyfer gweithio gyda ciw queue_t

Cychwyn ciw:

void qinit(queue_t *q);

Maes _q_stopiwr (o hyn ymlaen byddwn yn ei alw'n “stopiwr”) yn cael ei gychwyn gan y swyddogaeth mblk_init(), mae ei elfen flaenorol a'r pwyntydd elfen nesaf yn cael eu haddasu i bwyntio ato'i hun. Mae rhifydd yr elfen ciw yn cael ei ailosod i sero.

Ychwanegu elfen newydd (negeseuon):

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

Elfen newydd m yn cael ei ychwanegu at ddiwedd y rhestr, mae'r awgrymiadau elfen yn cael eu haddasu fel bod y stopiwr yn dod yn elfen nesaf ar ei gyfer, ac mae'n dod yn elfen flaenorol ar gyfer y stopiwr. Cynyddir y cownter elfen ciw.

Adalw elfen o'r ciw:

mblk_t * getq(queue_t *q); 

Mae'r neges sy'n dod ar ôl y stopiwr yn cael ei adfer, ac mae'r rhifydd elfen yn cael ei ostwng. Os nad oes unrhyw elfennau yn y ciw ac eithrio'r stopiwr, yna dychwelir 0.

Mewnosod neges mewn ciw:

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

Elfen mp wedi'i fewnosod cyn yr elfen emp. Os emp=0, yna mae'r neges yn cael ei ychwanegu at gynffon y ciw.

Nôl neges o ben y ciw:

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

Mae'r rhifydd elfen yn cael ei ostwng.

Darllen pwyntydd i'r elfen gyntaf yn y ciw:

mblk_t * peekq(queue_t *q); 

Tynnu pob elfen o'r ciw tra'n dileu'r elfennau eu hunain:

void flushq(queue_t *q, int how);

ddadl sut na chaiff ei ddefnyddio. Mae rhifydd yr elfen ciw wedi'i osod i sero.

Macro ar gyfer darllen pwyntydd i elfen olaf y ciw:

mblk_t * qlast(queue_t *q);

Wrth weithio gyda chiwiau neges, byddwch yn ymwybodol pan fyddwch yn ffonio ms_ciw_put(q, m) gyda phwyntydd null i'r neges, mae'r ffwythiant yn dolennu. Bydd eich rhaglen yn rhewi. yn ymddwyn yn debyg ms_ciw_nesaf(q, m).

Cysylltu hidlwyr

Defnyddir y ciw a ddisgrifir uchod i drosglwyddo negeseuon o un hidlydd i'r llall neu o un i sawl hidlydd. Mae hidlwyr a'u cysylltiadau yn ffurfio graff cyfeiriedig. Gelwir mewnbwn neu allbwn yr hidlydd y gair cyffredinol “pin”. I ddisgrifio'r drefn y mae hidlwyr wedi'u cysylltu â'i gilydd, mae'r ffrwdiwr cyfryngau yn defnyddio'r cysyniad o "bwynt signal". Pwynt signal yw strwythur _MSCPoint, sy'n cynnwys pwyntydd i'r hidlydd a rhif un o'i binnau; yn unol â hynny, mae'n disgrifio cysylltiad un o fewnbynnau neu allbynnau'r hidlydd.

Pwynt signal graff prosesu data

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

Mae pinnau hidlo wedi'u rhifo gan ddechrau o sero.

Disgrifir cysylltiad dau bin gan giw neges gan y strwythur _MSCiw, sy'n cynnwys ciw neges ac awgrymiadau i'r ddau bwynt signal y mae'n eu cysylltu:

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

Byddwn yn galw'r strwythur hwn yn gyswllt signal. Mae pob hidlydd ffrydio cyfryngau yn cynnwys tabl o ddolenni mewnbwn a thabl o ddolenni allbwn (MSQueue). Mae maint y tablau yn cael ei osod wrth greu hidlydd; rydym eisoes wedi gwneud hyn gan ddefnyddio newidyn o fath wedi'i allforio MSFilterDesc, pan wnaethom ddatblygu ein hidlydd ein hunain. Isod mae strwythur sy'n disgrifio unrhyw hidlydd mewn ffrwd cyfryngau, 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;

Ar ôl i ni gysylltu'r hidlwyr yn y rhaglen C yn unol â'n cynllun (ond heb gysylltu'r ticiwr), fe wnaethom felly greu graff cyfeiriedig, y mae ei nodau yn enghreifftiau o'r strwythur MSFilter, ac ymylon yn enghreifftiau o gysylltiadau MSQueue.

Gweithgareddau tu ôl i'r llenni y ticiwr

Pan ddywedais wrthych fod y ticiwr yn ffilter ar gyfer ffynhonnell y trogod, nid dyna'r gwir i gyd amdano. Mae ticiwr yn wrthrych sy'n rhedeg swyddogaethau ar y cloc proses () holl hidlyddion y gylched (graff) y mae wedi'i gysylltu â hi. Pan fyddwn yn cysylltu ticiwr i hidlydd graff mewn rhaglen C, rydyn ni'n dangos i'r ticiwr y graff y bydd yn ei reoli o hyn ymlaen nes i ni ei ddiffodd. Ar ôl cysylltu, mae'r ticiwr yn dechrau archwilio'r graff a ymddiriedwyd i'w ofal, gan lunio rhestr o hidlwyr sy'n ei gynnwys. Er mwyn peidio â “chyfrif” yr un hidlydd ddwywaith, mae'n nodi'r hidlwyr a ganfuwyd trwy osod blwch ticio ynddynt gweld. Gwneir y chwiliad gan ddefnyddio'r tablau cyswllt sydd gan bob hidlydd.

Yn ystod ei daith ragarweiniol o amgylch y graff, mae'r ticiwr yn gwirio a oes o leiaf un sy'n gweithredu fel ffynhonnell blociau data ymhlith yr hidlwyr. Os nad oes rhai, yna ystyrir bod y graff yn anghywir ac mae'r ticiwr yn chwalu.

Os yw'r graff yn troi allan i fod yn “gywir”, ar gyfer pob hidlydd a ganfyddir, gelwir y ffwythiant i'w gychwyn rhagbrosesu (). Cyn gynted ag y bydd y foment yn cyrraedd ar gyfer y cylch prosesu nesaf (pob 10 milieiliad yn ddiofyn), mae'r ticiwr yn galw'r swyddogaeth proses () ar gyfer pob hidlydd ffynhonnell a ddarganfuwyd yn flaenorol, ac yna ar gyfer yr hidlwyr sy'n weddill yn y rhestr. Os oes gan yr hidlydd gysylltiadau mewnbwn, yna rhedeg y swyddogaeth proses () yn ailadrodd nes bod y ciwiau cyswllt mewnbwn yn wag. Ar ôl hyn, mae'n symud ymlaen i'r hidlydd nesaf yn y rhestr ac yn ei “sgrolio” nes bod y dolenni mewnbwn yn rhydd o negeseuon. Mae'r ticiwr yn symud o hidlydd i hidlydd nes i'r rhestr ddod i ben. Mae hyn yn cwblhau prosesu'r cylch.

Nawr byddwn yn dychwelyd at tuples ac yn siarad am pam yr ychwanegwyd endid o'r fath at y streamer cyfryngau. Yn gyffredinol, nid yw faint o ddata sy'n ofynnol gan yr algorithm sy'n gweithredu y tu mewn i'r hidlydd yn cyd-daro ac nid yw'n lluosrif maint y byfferau data a dderbynnir yn y mewnbwn. Er enghraifft, rydym yn ysgrifennu hidlydd sy'n perfformio trawsnewidiad Fourier cyflym, sydd yn ôl diffiniad ond yn gallu prosesu blociau data y mae eu maint yn bŵer o ddau. Gadewch iddo fod yn 512 cyfrif. Os yw'r data'n cael ei gynhyrchu gan sianel ffôn, yna bydd byffer data pob neges yn y mewnbwn yn dod â 160 o samplau signal i ni. Mae'n demtasiwn peidio â chasglu data o'r mewnbwn nes bod y swm gofynnol o ddata yno. Ond yn yr achos hwn, bydd gwrthdrawiad yn digwydd gyda'r ticiwr, a fydd yn ceisio sgrolio'r hidlydd yn aflwyddiannus nes bod y ddolen fewnbwn yn wag. Yn flaenorol, dynodwyd y rheol hon fel trydydd egwyddor yr hidlydd. Yn ôl yr egwyddor hon, rhaid i swyddogaeth proses() yr hidlydd gymryd yr holl ddata o'r ciwiau mewnbwn.

Yn ogystal, ni fydd yn bosibl cymryd dim ond 512 sampl o'r mewnbwn, gan mai dim ond blociau cyfan y gallwch eu cymryd, h.y. bydd yn rhaid i'r hidlydd gymryd 640 o samplau a defnyddio 512 ohonynt, a'r gweddill cyn cronni cyfran newydd o ddata. Felly, mae'n rhaid i'n hidlydd, yn ychwanegol at ei brif waith, ddarparu camau gweithredu ategol ar gyfer storio data mewnbwn yn y canol. Mae datblygwyr y streamer cyfryngau a datrysiad i'r broblem gyffredinol hon wedi datblygu gwrthrych arbennig - MSBufferizer (byfferer), sy'n datrys y broblem hon gan ddefnyddio tuples.

Clustogydd (MSBufferizer)

Mae hwn yn wrthrych a fydd yn cronni data mewnbwn y tu mewn i'r hidlydd ac yn dechrau ei gyflwyno i'w brosesu cyn gynted ag y bydd swm y wybodaeth yn ddigonol i redeg yr algorithm hidlo. Tra bod y byffer yn cronni data, bydd yr hidlydd yn gweithredu yn y modd segur, heb ddefnyddio pŵer prosesu'r prosesydd. Ond cyn gynted ag y bydd y swyddogaeth darllen o'r byffer yn dychwelyd gwerth heblaw sero, mae swyddogaeth proses () yr hidlydd yn dechrau cymryd a phrosesu data o'r byffer mewn dognau o'r maint gofynnol, nes ei fod wedi dod i ben.
Mae data nad oes ei angen eto yn aros yn y byffer fel elfen gyntaf y tuple, y mae blociau dilynol o ddata mewnbwn ynghlwm wrtho.

Y strwythur sy'n disgrifio'r byffer:

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

Swyddogaethau ar gyfer gweithio gyda MSBufferizer

Creu enghraifft byffer newydd:

MSBufferizer * ms_bufferizer_new(void);

Cof yn cael ei ddyrannu, cychwyn i mewn ms_bufferizer_init() a dychwelir pwyntydd.

Swyddogaeth cychwyn:

void ms_bufferizer_init(MSBufferizer *obj); 

Mae'r ciw yn cychwyn q, maes maint wedi'i osod i sero.

Wrthi'n ychwanegu neges:

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

Neges m yn cael ei ychwanegu at y ciw. Ychwanegir at faint cyfrifedig y blociau data maint.

Trosglwyddo pob neges o'r ciw data cyswllt i'r byffer q:

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

Trosglwyddo negeseuon o ddolen q yn y byffer yn cael ei berfformio gan ddefnyddio'r swyddogaeth ms_bufferizer_put().

Darllen o'r byffer:

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

Os yw maint y data a gronnwyd yn y byffer yn llai na'r un y gofynnwyd amdano (datalen), yna mae'r swyddogaeth yn dychwelyd sero, ni chaiff data ei gopïo i ddata. Fel arall, cyflawnir copïo dilyniannol o ddata o tuples sydd wedi'u lleoli yn y byffer. Ar ôl copïo, caiff y tuple ei ddileu a rhyddheir y cof. Daw'r copïo i ben ar hyn o bryd pan fydd datalen beit yn cael eu copïo. Os bydd gofod yn rhedeg allan yng nghanol bloc data, yna yn y neges hon, bydd y bloc data yn cael ei leihau i'r rhan sydd heb ei gopïo sy'n weddill. Y tro nesaf y byddwch yn ffonio, bydd copïo yn parhau o'r pwynt hwn.

Darllen faint o ddata sydd ar gael ar hyn o bryd yn y byffer:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Yn dychwelyd y cae maint byffer.

Gwaredu rhan o'r data yn y byffer:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Mae'r nifer penodedig o beit o ddata yn cael eu hadalw a'u taflu. Mae'r data hynaf yn cael ei ddileu.

Dileu pob neges yn y byffer:

void ms_bufferizer_flush(MSBufferizer *obj); 

Mae'r rhifydd data yn cael ei ailosod i sero.

Dileu pob neges yn y byffer:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Nid yw'r cownter yn cael ei ailosod.

Tynnu'r byffer a rhyddhau cof:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Mae enghreifftiau o ddefnyddio'r byffer i'w gweld yng nghod ffynhonnell sawl hidlydd ffrydio cyfryngau. Er enghraifft, yn yr hidlydd MS_L16_ENC, sy'n aildrefnu'r beit yn y samplau o'r gorchymyn rhwydwaith i'r gorchymyn gwesteiwr: l16.c

Yn yr erthygl nesaf, byddwn yn edrych ar y mater o amcangyfrif llwyth ticker a sut i ddelio â llwyth cyfrifiadura gormodol yn y streamer cyfryngau.

Ffynhonnell: hab.com

Ychwanegu sylw