Inachunguza injini ya Mediastreamer2 VoIP. Sehemu ya 11

Nyenzo za kifungu zimechukuliwa kutoka kwangu chaneli ya zen.

Inachunguza injini ya Mediastreamer2 VoIP. Sehemu ya 11

Utaratibu wa kuhamisha data

  • Kizuizi cha data dblk_t
  • Ujumbe mblk_t
  • Kazi za kufanya kazi na ujumbe mblk_t
  • Foleni_t
  • Kazi za kufanya kazi na foleni foleni_t
  • Kuunganisha vichungi
  • Sehemu ya mawimbi ya grafu ya usindikaji wa data
  • Nyuma ya pazia shughuli za ticker
  • Bufferizer (MSBufferizer)
  • Kazi za kufanya kazi na MSBufferizer

Zamani Ibara ya tumetengeneza chujio chetu wenyewe. Makala haya yatazingatia utaratibu wa ndani wa kuhamisha data kati ya vichujio vya vipeperushi vya media. Hii itakuruhusu kuandika vichungi vya kisasa na juhudi kidogo katika siku zijazo.

Utaratibu wa kuhamisha data

Harakati ya data kwenye kipeperushi cha media inafanywa kwa kutumia foleni zilizoelezewa na muundo foleni_t. Misururu ya ujumbe kama mblk_t, ambayo wenyewe hawana data ya ishara, lakini inaunganisha tu ujumbe uliopita, unaofuata na kuzuia data. Kwa kuongezea, nataka kusisitiza haswa kuwa kuna uwanja wa kiunga cha ujumbe wa aina moja, ambayo hukuruhusu kupanga orodha iliyounganishwa ya ujumbe. Tutaita kikundi cha jumbe zilizounganishwa na orodha kama hiyo tuple. Kwa hivyo, kipengele chochote cha foleni kinaweza kuwa ujumbe mmoja mblk_t, na labda kichwa cha tuple ya ujumbe mblk_t. Kila ujumbe wa nakala unaweza kuwa na kizuizi chake cha data cha kata. Tutajadili kwa nini nakala zinahitajika baadaye kidogo.

Kama ilivyoelezwa hapo juu, ujumbe wenyewe hauna kizuizi cha data; badala yake, ina pointer tu kwa eneo la kumbukumbu ambalo kizuizi kinahifadhiwa. Katika sehemu hii, picha ya jumla ya kazi ya kipeperushi cha habari inafanana na ghala la mlango kwenye katuni "Monsters, Inc.," ambapo milango (viungo vya vyumba vya data) husogea kwa kasi ya kichaa kwenye vidhibiti vya juu, huku vyumba vyenyewe. kubaki bila mwendo.

Sasa, tukisonga kwenye uongozi kutoka chini kwenda juu, hebu tuchunguze kwa undani vyombo vilivyoorodheshwa vya utaratibu wa upitishaji data kwenye kipeperushi cha media.

Kizuizi cha data dblk_t

Kizuizi cha data kina kichwa na bafa ya data. Kichwa kinaelezewa na muundo ufuatao,

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

Sehemu za muundo zina viashiria vya mwanzo wa bafa, mwisho wa bafa, na kazi ya kufuta bafa ya data. Kipengele cha mwisho katika kichwa db_ref — counter ya kumbukumbu, ikiwa inafikia sifuri, hii hutumika kama ishara ya kufuta kizuizi hiki kutoka kwa kumbukumbu. Ikiwa kizuizi cha data kiliundwa na kazi datab_alloc() , basi bafa ya data itawekwa kwenye kumbukumbu mara tu baada ya kichwa. Katika visa vingine vyote, buffer inaweza kupatikana mahali fulani kando. Bafa ya data itakuwa na sampuli za mawimbi au data nyingine ambayo tunataka kuchakata kwa kutumia vichujio.

Mfano mpya wa kizuizi cha data huundwa kwa kutumia kazi:

dblk_t *datab_alloc(int size);

Kama kigezo cha pembejeo, inapewa saizi ya data ambayo kizuizi kitahifadhi. Kumbukumbu zaidi imetengwa ili kuweka kichwa - muundo - mwanzoni mwa kumbukumbu iliyotengwa datab. Lakini wakati wa kutumia vitendaji vingine, hii haifanyiki kila wakati; katika hali zingine, bafa ya data inaweza kupatikana kando na kichwa cha kuzuia data. Wakati wa kuunda muundo, mashamba yameundwa ili shamba lake db_msingi ilionyesha mwanzo wa eneo la data, na db_lim hadi mwisho wake. Idadi ya viungo db_ref imewekwa kwa moja. Kiashiria cha utendakazi wazi cha data kimewekwa kuwa sifuri.

Ujumbe mblk_t

Kama ilivyoelezwa, vipengele vya foleni ni vya aina mblk_t, inafafanuliwa kama ifuatavyo:

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;

Muundo mblk_t ina viashiria mwanzoni b_prev, b_ijayo, ambayo ni muhimu kupanga orodha iliyounganishwa mara mbili (ambayo ni foleni foleni_t).

Kisha inakuja pointer b_endelea, ambayo hutumiwa tu wakati ujumbe ni sehemu ya nakala. Kwa ujumbe wa mwisho kwenye nakala, kielekezi hiki kinasalia kuwa batili.

Ifuatayo tunaona kiashiria kwenye kizuizi cha data b_data, ambayo ujumbe upo. Inafuatwa na viashiria kwa eneo ndani ya bafa ya data ya kuzuia. Shamba b_rptr inabainisha eneo ambalo data kutoka kwa bafa itasomwa. Shamba b_wptr inaonyesha mahali ambapo uandishi wa bafa utatekelezwa.

Sehemu zilizobaki ni za asili ya huduma na hazihusiani na uendeshaji wa utaratibu wa kuhamisha data.

Hapa chini kuna ujumbe mmoja wenye jina m1 na kizuizi cha data d1.
Inachunguza injini ya Mediastreamer2 VoIP. Sehemu ya 11
Kielelezo kifuatacho kinaonyesha nakala ya jumbe tatu m1, m1_1, m1_2.
Inachunguza injini ya Mediastreamer2 VoIP. Sehemu ya 11

Vitendaji vya kutuma ujumbe mblk_t

Ujumbe mpya mblk_t iliyoundwa na kazi:

mblk_t *allocb(int size, int pri); 

anaweka ujumbe mpya kwenye kumbukumbu mblk_t na kizuizi cha data cha saizi maalum kawaida, hoja ya pili - pri haitumiki katika toleo hili la maktaba. Inapaswa kubaki sifuri. Wakati wa uendeshaji wa kazi, kumbukumbu itatengwa kwa muundo wa ujumbe mpya na kazi itaitwa mblk_init(), ambayo itaweka upya nyanja zote za mfano ulioundwa wa muundo na kisha, kwa kutumia zilizotajwa hapo juu datab_alloc(), itaunda bafa ya data. Baada ya hapo sehemu katika muundo zitasanidiwa:

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

Kwenye pato tunapokea ujumbe mpya wenye sehemu zilizoanzishwa na bafa tupu ya data. Ili kuongeza data kwenye ujumbe, unahitaji kuinakili kwenye bafa ya kuzuia data:

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

ambapo data ni kielekezi kwa chanzo cha data, na kawaida - ukubwa wao.
basi unahitaji kusasisha pointer kwa mahali pa kuandika ili ielekeze tena mwanzo wa eneo la bure kwenye buffer:

msg->b_wptr = msg->b_wptr + size

Ikiwa unahitaji kuunda ujumbe kutoka kwa buffer iliyopo, bila kunakili, basi tumia kazi:

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

Kazi, baada ya kuunda ujumbe na muundo wa kizuizi cha data, itasanidi viashiria vyake kwa data kwenye anwani. buff. Wale. katika kesi hii, buffer ya data haipo baada ya sehemu za kichwa cha kizuizi cha data, kama ilivyokuwa wakati wa kuunda kizuizi cha data na kazi. datab_alloc(). Bafa iliyo na data iliyopitishwa kwenye kazi itabaki pale ilipokuwa, lakini kwa usaidizi wa viashiria itaunganishwa kwenye kichwa kipya cha kizuizi cha data, na kwamba, ipasavyo, kwa ujumbe.

Kwa ujumbe mmoja mblk_t Vitalu kadhaa vya data vinaweza kuunganishwa kwa mfuatano. Hii inafanywa na kazi:

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

mp - ujumbe ambao kizuizi kingine cha data kitaongezwa;
data - pointer kwa block, nakala ambayo itaongezwa kwa ujumbe;
kawaida - ukubwa wa data;
pedi - bendera ambayo saizi ya kumbukumbu iliyotengwa lazima ilinganishwe kando ya mpaka wa 4-byte (padding itafanywa kwa sifuri).

Ikiwa kuna nafasi ya kutosha katika bafa iliyopo ya data ya ujumbe, basi data mpya itabandikwa nyuma ya data ambayo tayari ipo. Ikiwa kuna nafasi ndogo ya bure katika bafa ya data ya ujumbe kuliko kawaida, kisha ujumbe mpya unaundwa na saizi ya bafa ya kutosha na data inakiliwa kwa bafa yake. Huu ni ujumbe mpya, uliounganishwa na ule wa asili kwa kutumia kielekezi b_endelea. Katika kesi hii, ujumbe unageuka kuwa tuple.

Ikiwa unahitaji kuongeza kizuizi kingine cha data kwenye nakala, basi unahitaji kutumia kazi:

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

atapata ujumbe wa mwisho kwenye nakala (ana b_endelea itakuwa null) na itaita kitendakazi cha ujumbe huu appendb().

Unaweza kujua saizi ya data katika ujumbe au nakala kwa kutumia chaguo la kukokotoa:

int msgdsize(const mblk_t *mp);

itapitia ujumbe wote kwenye nakala na kurudisha jumla ya kiasi cha data katika vihifadhi data vya ujumbe huo. Kwa kila ujumbe, kiasi cha data kinahesabiwa kama ifuatavyo:

 mp->b_wptr - mp->b_rptr

Ili kuchanganya nakala mbili, tumia chaguo la kukokotoa:

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

yeye appnds tuple mpya kwa mkia wa tuple mp na hurejesha kielekezi kwa ujumbe wa mwisho wa nakala inayotokana.

Ikiwa ni lazima, nakala inaweza kubadilishwa kuwa ujumbe mmoja na kizuizi kimoja cha data; hii inafanywa na kazi:

void msgpullup(mblk_t *mp,int len);

kama hoja lensi ni -1, basi saizi ya bafa iliyotengwa huamuliwa kiotomatiki. Kama lensi ni nambari chanya, bafa ya ukubwa huu itaundwa na data ya ujumbe wa tuple itanakiliwa humo. Ikiwa bafa itaisha, kunakili kutakoma hapo. Ujumbe wa kwanza wa nakala utapokea bafa ya saizi mpya na data iliyonakiliwa. Ujumbe uliosalia utafutwa na kumbukumbu itarejeshwa kwenye lundo.

Wakati wa kufuta muundo mblk_t hesabu ya kumbukumbu ya kizuizi cha data inazingatiwa ikiwa, wakati wa kupiga simu bureb() inageuka kuwa sifuri, basi buffer ya data inafutwa pamoja na mfano mblk_t, ambayo inaashiria.

Kuanzisha sehemu za ujumbe mpya:

void mblk_init(mblk_t *mp);

Kuongeza kipande kingine cha data kwenye ujumbe:

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

Ikiwa data mpya hailingani na nafasi ya bure ya bafa ya data ya ujumbe, basi ujumbe ulioundwa kando na bafa ya saizi inayohitajika huambatishwa kwenye ujumbe (kielekezi cha ujumbe ulioongezwa kimewekwa kwenye ujumbe wa kwanza) na ujumbe unageuka kuwa nakala.

Kuongeza kipande cha data kwenye nakala:

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

Chaguo la kukokotoa huita appendb() kwa kitanzi.

Kuchanganya nakala mbili kuwa moja:

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

Ujumbe mpya itaambatanishwa na mp.

Kufanya nakala ya ujumbe mmoja:

mblk_t *copyb(const mblk_t *mp);

Kamilisha kunakili nakala na vizuizi vyote vya data:

mblk_t *copymsg(const mblk_t *mp);

Vipengele vya tuple vinakiliwa na kazi nakalab().

Unda nakala rahisi ya ujumbe mblk_t. Katika kesi hii, kizuizi cha data haijakiliwa, lakini kihesabu chake cha kumbukumbu kinaongezeka db_ref:

mblk_t *dupb(mblk_t *mp);

Kutengeneza nakala nyepesi ya nakala. Vitalu vya data havijanakiliwa, vihesabio vyao vya marejeleo pekee ndivyo vinavyoongezwa db_ref:

mblk_t *dupmsg(mblk_t* m);

Kuingiza ujumbe wote wa nakala kwenye ujumbe mmoja:

void msgpullup(mblk_t *mp,size_t len);

Ikiwa hoja lensi ni -1, basi saizi ya bafa iliyotengwa huamuliwa kiotomatiki.

Inafuta ujumbe, tuple:

void freemsg(mblk_t *mp);

Hesabu ya marejeleo ya kizuizi cha data hupunguzwa kwa moja. Ikiwa inafikia sifuri, kizuizi cha data pia kinafutwa.

Kukokotoa jumla ya kiasi cha data katika ujumbe au nakala.

size_t msgdsize(const mblk_t *mp);

Kurejesha ujumbe kutoka kwa mkia wa foleni:

mblk_t *ms_queue_peek_last (q);

Kunakili yaliyomo katika sehemu zilizohifadhiwa za ujumbe mmoja hadi ujumbe mwingine (kwa kweli, sehemu hizi zina bendera zinazotumiwa na kipeperushi cha media):

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

Zamu foleni_t

Foleni ya ujumbe katika kipeperushi cha media inatekelezwa kama orodha iliyounganishwa maradufu. Kila kipengele cha orodha kina kielekezi kwa kizuizi cha data kilicho na sampuli za mawimbi. Inabadilika kuwa viashiria tu vya kuzuia data vinasonga kwa zamu, wakati data yenyewe inabaki bila kusonga. Wale. viungo kwao pekee ndivyo vinavyohamishwa.
Muundo unaoelezea foleni foleni_t, imeonyeshwa hapa chini:

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

Muundo una shamba - pointer _q_kizuizi chapa *mblk_t, inaelekeza kwenye kipengele cha kwanza (ujumbe) kwenye foleni. Sehemu ya pili ya muundo ni kihesabu cha ujumbe kwenye foleni.
Kielelezo hapa chini kinaonyesha foleni inayoitwa q1 iliyo na ujumbe 4 m1, m2, m3, m4.
Inachunguza injini ya Mediastreamer2 VoIP. Sehemu ya 11
Kielelezo kifuatacho kinaonyesha foleni inayoitwa q1 iliyo na ujumbe 4 m1,m2,m3,m4. Ujumbe m2 ndio kichwa cha nakala iliyo na jumbe mbili zaidi m2_1 na m2_2.

Inachunguza injini ya Mediastreamer2 VoIP. Sehemu ya 11

Kazi za kufanya kazi na foleni foleni_t

Uanzishaji wa foleni:

void qinit(queue_t *q);

Shamba _q_kizuizi (hapa tutaiita "kizuia") inaanzishwa na chaguo la kukokotoa mblk_init(), kipengele chake cha awali na pointer ya kipengele kinachofuata hurekebishwa ili kujielekeza. Kaunta ya kipengele cha foleni imewekwa upya hadi sifuri.

Kuongeza kipengele kipya (ujumbe):

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

Kipengele kipya m imeongezwa hadi mwisho wa orodha, viashiria vya kipengele vinarekebishwa ili kizuizi kiwe kipengele kinachofuata kwa ajili yake, na inakuwa kipengele cha awali cha kizuizi. Kaunta ya kipengele cha foleni imeongezwa.

Kurejesha kipengele kutoka kwa foleni:

mblk_t * getq(queue_t *q); 

Ujumbe unaokuja baada ya kizuia kurejeshwa, na kaunta ya kipengele imepunguzwa. Ikiwa hakuna vipengele kwenye foleni isipokuwa kizuizi, basi 0 inarudishwa.

Kuingiza ujumbe kwenye foleni:

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

Jambo mp kuingizwa kabla ya kipengele EMP. Ikiwa EMP=0, kisha ujumbe huongezwa kwenye mkia wa foleni.

Kurejesha ujumbe kutoka kwa mkuu wa foleni:

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

Kaunta ya kipengele imepunguzwa.

Kusoma kielekezi kwa kipengele cha kwanza kwenye foleni:

mblk_t * peekq(queue_t *q); 

Kuondoa vipengele vyote kutoka kwa foleni wakati wa kufuta vipengele vyenyewe:

void flushq(queue_t *q, int how);

hoja jinsi haijatumika. Kaunta ya kipengele cha foleni imewekwa kuwa sufuri.

Macro ya kusoma pointer kwa kipengele cha mwisho cha foleni:

mblk_t * qlast(queue_t *q);

Unapofanya kazi na foleni za ujumbe, fahamu kwamba unapopiga simu ms_queue_put(q, m) na kielekezi kisichofaa kwa ujumbe, kazi hujifunga. Programu yako itafungia. hutenda vivyo hivyo ms_foleni_ifuatayo(q, m).

Kuunganisha vichungi

Foleni iliyoelezwa hapo juu inatumika kupitisha ujumbe kutoka kwa kichujio kimoja hadi kingine au kutoka kwa kichujio kimoja hadi kadhaa. Vichungi na viunganisho vyao huunda grafu iliyoelekezwa. Ingizo au pato la chujio litaitwa neno la jumla "pini". Ili kuelezea utaratibu ambao vichujio vinaunganishwa kwa kila mmoja, kipeperushi cha media hutumia dhana ya "pointi ya ishara". Pointi ya ishara ni muundo _MSCPpoint, ambayo ina pointer kwa kichungi na nambari ya moja ya pini zake; ipasavyo, inaelezea unganisho la moja ya pembejeo au matokeo ya kichungi.

Sehemu ya mawimbi ya grafu ya usindikaji wa data

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

Pini za vichujio zimepewa nambari kuanzia sufuri.

Uunganisho wa pini mbili kwa foleni ya ujumbe unaelezewa na muundo _MSQueue, ambayo ina foleni ya ujumbe na viashiria kwa alama mbili zinazounganisha:

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

Tutaita muundo huu kiungo cha ishara. Kila kichujio cha kipeperushi cha media kina jedwali la viungo vya ingizo na jedwali la viungo vya kutoa (MSQueue) Saizi ya majedwali huwekwa wakati wa kuunda kichujio; tayari tumefanya hivi kwa kutumia aina tofauti iliyosafirishwa MSFilterDesc, tulipotengeneza chujio chetu wenyewe. Chini ni muundo unaoelezea kichujio chochote kwenye kipeperushi cha media, 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;

Baada ya kuunganisha vichungi kwenye programu ya C kulingana na mpango wetu (lakini hatukuunganisha ticker), kwa hivyo tuliunda grafu iliyoelekezwa, nodi ambazo ni mifano ya muundo. MSFilter, na kingo ni mifano ya viungo MSQueue.

Nyuma ya pazia shughuli za ticker

Nilipokuambia kuwa ticker ni chujio cha chanzo cha kupe, haikuwa ukweli wote kuhusu hilo. Ticker ni kitu kinachoendesha kazi kwenye saa mchakato() filters zote za mzunguko (grafu) ambayo imeunganishwa. Tunapounganisha ticker kwenye kichujio cha grafu katika programu ya C, tunaonyesha tiki chati ambayo itadhibiti kuanzia sasa hadi tukizima. Baada ya kuunganisha, ticker huanza kuchunguza grafu iliyokabidhiwa uangalizi wake, na kuandaa orodha ya vichungi vinavyojumuisha. Ili "usihesabu" kichungi sawa mara mbili, inaashiria vichungi vilivyotambuliwa kwa kuweka kisanduku cha kuteua ndani yao. kuonekana. Utafutaji unafanywa kwa kutumia majedwali ya viungo ambayo kila kichujio kina.

Wakati wa ziara yake ya utangulizi kwenye grafu, tiki hukagua ikiwa miongoni mwa vichujio kuna angalau moja ambayo hutumika kama chanzo cha vizuizi vya data. Ikiwa hakuna, basi grafu inachukuliwa kuwa sio sahihi na ticker inaanguka.

Ikiwa grafu itageuka kuwa "sahihi", kwa kila kichujio kilichopatikana, chaguo la kukokotoa linaitwa kuanzishwa mchakato wa awali (). Mara tu wakati unapofika wa mzunguko unaofuata wa uchakataji (kila milisekunde 10 kwa chaguo-msingi), kiweka alama huita kitendakazi. mchakato() kwa vichungi vyote vya chanzo vilivyopatikana hapo awali, na kisha kwa vichungi vilivyobaki kwenye orodha. Ikiwa kichujio kina viungo vya kuingiza, basi endesha chaguo la kukokotoa mchakato() hurudia hadi foleni za kiungo cha ingizo ziwe tupu. Baada ya hayo, inakwenda kwenye kichujio kinachofuata kwenye orodha na "kuisogeza" hadi viungo vya ingizo visiwe na ujumbe. Kibao husogea kutoka kichujio hadi kichujio hadi orodha iishe. Hii inakamilisha usindikaji wa mzunguko.

Sasa tutarudi kwenye nakala na tuzungumze juu ya kwa nini huluki kama hiyo iliongezwa kwa mtiririshaji wa media. Kwa ujumla, kiasi cha data kinachohitajika na algoriti inayofanya kazi ndani ya kichujio haiwiani na si kizidishio cha ukubwa wa vihifadhi data vilivyopokelewa kwenye ingizo. Kwa mfano, tunaandika kichujio ambacho hufanya mabadiliko ya haraka ya Fourier, ambayo kwa ufafanuzi yanaweza tu kuchakata vizuizi vya data ambavyo ukubwa wake ni nguvu ya mbili. Wacha iwe hesabu 512. Ikiwa data inatolewa na kituo cha simu, basi bafa ya data ya kila ujumbe kwenye pembejeo itatuletea sampuli 160 za ishara. Inajaribu kutokusanya data kutoka kwa ingizo hadi kiwango kinachohitajika cha data kiwepo. Lakini katika kesi hii, mgongano utatokea na ticker, ambayo itajaribu bila mafanikio kusonga chujio hadi kiungo cha pembejeo kiwe tupu. Hapo awali, tuliteua sheria hii kama kanuni ya tatu ya chujio. Kulingana na kanuni hii, utendakazi wa mchakato() wa kichujio lazima uchukue data zote kutoka kwa foleni za ingizo.

Kwa kuongeza, haitawezekana kuchukua sampuli 512 tu kutoka kwa pembejeo, kwa kuwa unaweza tu kuchukua vitalu vyote, i.e. kichujio kitalazimika kuchukua sampuli 640 na kutumia 512 kati yao, iliyobaki kabla ya kukusanya sehemu mpya ya data. Kwa hivyo, chujio chetu, pamoja na kazi yake kuu, lazima itoe vitendo vya msaidizi kwa uhifadhi wa kati wa data ya pembejeo. Watengenezaji wa mkondo wa media na suluhisho la shida hii ya jumla wameunda kitu maalum - MSBufferizer (bufferer), ambayo hutatua shida hii kwa kutumia tuples.

Bufferizer (MSBufferizer)

Hiki ni kitu ambacho kitakusanya data ya ingizo ndani ya kichujio na kuanza kuiwasilisha ili kuchakatwa mara tu kiasi cha maelezo kinapotosha kutekeleza kanuni ya kichujio. Wakati bafa inakusanya data, kichujio kitafanya kazi katika hali ya kutofanya kitu, bila kutumia nguvu ya kuchakata ya kichakataji. Lakini punde tu kitendakazi cha kusoma kutoka kwa kihifadhi kinarejesha thamani nyingine zaidi ya sifuri, mchakato () utendakazi wa kichujio huanza kuchukua na kuchakata data kutoka kwa kihifadhi katika sehemu za saizi inayohitajika, hadi itakapoisha.
Data ambayo bado haihitajiki inasalia katika bafa kama kipengele cha kwanza cha nakala, ambayo vizuizi vinavyofuata vya data ya ingizo vimeambatishwa.

Muundo unaoelezea bafa:

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

Kazi za kufanya kazi na MSBufferizer

Kuunda mfano mpya wa bafa:

MSBufferizer * ms_bufferizer_new(void);

Kumbukumbu imetengwa, imeanzishwa ndani ms_bufferizer_init() na pointer inarudishwa.

Kitendaji cha uanzishaji:

void ms_bufferizer_init(MSBufferizer *obj); 

Foleni inaanzishwa q, uwanja kawaida imewekwa kwa sifuri.

Kuongeza ujumbe:

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

Ujumbe m umeongezwa kwenye foleni. Saizi iliyohesabiwa ya vizuizi vya data huongezwa kwa kawaida.

Inahamisha ujumbe wote kutoka kwa foleni ya data ya kiungo hadi kwenye bafa q:

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

Inahamisha ujumbe kutoka kwa kiungo q katika buffer inafanywa kwa kutumia kazi ms_bufferizer_put().

Kusoma kutoka kwa bafa:

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

Ikiwa saizi ya data iliyokusanywa kwenye bafa ni chini ya ile iliyoombwa (datalen), kisha kazi inarudi sifuri, data haijakiliwa kwa data. Vinginevyo, kunakili kwa kufuatana kwa data kutoka kwa nakala zilizo kwenye bafa hufanywa. Baada ya kunakili, tuple inafutwa na kumbukumbu imeachiliwa. Kunakili huisha wakati baiti za datalen zinanakiliwa. Ikiwa nafasi itaisha katikati ya kizuizi cha data, basi katika ujumbe huu, kizuizi cha data kitapunguzwa hadi sehemu iliyobaki ambayo haijanakiliwa. Wakati mwingine utakapopiga simu, kunakili kutaendelea kutoka hatua hii.

Kusoma kiasi cha data ambacho kinapatikana kwa sasa kwenye bafa:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Hurejesha uga kawaida bafa.

Kutupa sehemu ya data kwenye bafa:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Idadi iliyobainishwa ya baiti za data hurejeshwa na kutupwa. Data ya zamani zaidi hutupwa.

Kufuta ujumbe wote katika bafa:

void ms_bufferizer_flush(MSBufferizer *obj); 

Kaunta ya data imewekwa upya hadi sifuri.

Kufuta ujumbe wote katika bafa:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Kaunta haijawekwa upya.

Kuondoa bafa na kuweka kumbukumbu huru:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Mifano ya kutumia bufferer inaweza kupatikana katika msimbo wa chanzo wa vichujio kadhaa vya utiririshaji wa media. Kwa mfano, katika kichujio cha MS_L16_ENC, ambacho hupanga upya baiti katika sampuli kutoka kwa mpangilio wa mtandao hadi kwa mpangilio wa mwenyeji: l16.c

Katika makala inayofuata, tutaangalia suala la makadirio ya mzigo wa ticker na jinsi ya kukabiliana na mzigo mkubwa wa kompyuta kwenye kipeperushi cha vyombo vya habari.

Chanzo: mapenzi.com

Kuongeza maoni