Mediastreamer2 VoIP එන්ජිම ගවේෂණය කිරීම. 11 කොටස

ලිපියේ ද්‍රව්‍ය මගේ වෙතින් ලබාගෙන ඇත සෙන් නාලිකාව.

Mediastreamer2 VoIP එන්ජිම ගවේෂණය කිරීම. 11 කොටස

දත්ත චලනය යාන්ත්රණය

  • දත්ත අවහිර dblk_t
  • පණිවිඩය mblk_t
  • mblk_t පණිවිඩ සමඟ වැඩ කිරීම සඳහා වන කාර්යයන්
  • පෝලිම් පෝලිම_t
  • පෝලිම් queue_t සමඟ වැඩ කිරීම සඳහා කාර්යයන්
  • පෙරහන් සම්බන්ධ කිරීම
  • දත්ත සැකසුම් ප්රස්ථාරයේ සංඥා ලක්ෂ්යය
  • ටික්කරුගේ තිරය පිටුපස ක්‍රියාකාරකම්
  • බෆරයිසර් (MSBufferizer)
  • MSBufferizer සමඟ වැඩ කිරීම සඳහා වන කාර්යයන්

අන්තිමට ලිපියයි අපි අපේම පෙරහන සකස් කර ඇත. මෙම ලිපිය මාධ්‍ය ප්‍රවාහ පෙරහන් අතර දත්ත චලනය කිරීමේ අභ්‍යන්තර යාන්ත්‍රණය කෙරෙහි අවධානය යොමු කරනු ඇත. අනාගතයේදී අඩු උත්සාහයකින් නවීන පෙරහන් ලිවීමට මෙය ඔබට ඉඩ සලසයි.

දත්ත චලනය යාන්ත්රණය

මාධ්‍ය ප්‍රවාහයේ දත්ත චලනය ව්‍යුහය මගින් විස්තර කරන ලද පෝලිම් භාවිතයෙන් සිදු කෙරේ පෝලිම්_t. වැනි පණිවිඩ වැල mblk_t, තමන් විසින්ම සංඥා දත්ත අඩංගු නොවන නමුත් පෙර, ඊළඟ පණිවිඩයට සහ දත්ත අවහිර කිරීමට සබැඳි පමණි. ඊට අමතරව, එකම ආකාරයේ පණිවිඩයකට සබැඳියක් සඳහා ක්ෂේත්‍රයක් ද ඇති බව මට විශේෂයෙන් අවධාරණය කිරීමට අවශ්‍යය, එමඟින් ඔබට තනි සම්බන්ධිත පණිවිඩ ලැයිස්තුවක් සංවිධානය කිරීමට ඉඩ සලසයි. එවැනි ලැයිස්තුවක් මගින් එක්සත් කරන ලද පණිවිඩ සමූහයක් අපි ටුපල් ලෙස හඳුන්වමු. මේ අනුව, පෝලිමේ ඕනෑම අංගයක් තනි පණිවිඩයක් විය හැකිය mblk_t, සහ සමහර විට පණිවිඩ ටියුපල් ප්‍රධානියා mblk_t. සෑම ටුපල් පණිවිඩයකටම තමන්ගේම වාට්ටු දත්ත වාරණ තිබිය හැක. ටියුපල් අවශ්ය වන්නේ මන්දැයි අපි ටිකක් පසුව සාකච්ඡා කරමු.

ඉහත සඳහන් කළ පරිදි, පණිවිඩයේම දත්ත බ්ලොක් එකක් අඩංගු නොවේ; ඒ වෙනුවට, එහි අඩංගු වන්නේ බ්ලොක් එක ගබඩා කර ඇති මතක ප්‍රදේශයට දර්ශකයක් පමණි. මෙම කොටසේ, මාධ්‍ය ප්‍රවාහකයාගේ කාර්යයේ සමස්ත චිත්‍රය “Monsters, Inc.” නම් කාටූනයේ දොර ගබඩාව සිහිගන්වයි, එහිදී දොරවල් (දත්ත - කාමර වෙත සබැඳි) උඩිස් වාහක ඔස්සේ උමතු වේගයකින් ගමන් කරන අතරම කාමර ද වේ. චලනය නොවී සිටින්න.

දැන්, ධූරාවලිය දිගේ පහළ සිට ඉහළට ගමන් කරමින්, මාධ්‍ය ප්‍රවාහයේ දත්ත සම්ප්‍රේෂණ යාන්ත්‍රණයේ ලැයිස්තුගත කර ඇති ආයතන විස්තරාත්මකව සලකා බලමු.

දත්ත අවහිර කිරීම dblk_t

දත්ත වාරණය ශීර්ෂයක් සහ දත්ත බෆරයකින් සමන්විත වේ. ශීර්ෂය පහත ව්‍යුහය මගින් විස්තර කෙරේ,

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

ව්‍යුහයේ ක්ෂේත්‍ර වල බෆරයේ ආරම්භය, බෆරයේ අවසානය සහ දත්ත බෆරය මකා දැමීමේ ක්‍රියාකාරිත්වය සඳහා වන දර්ශක අඩංගු වේ. ශීර්ෂයේ අවසාන අංගය db_ref - යොමු කවුන්ටරය, එය ශුන්‍යයට ළඟා වුවහොත්, මෙය මතකයෙන් මෙම අවහිර කිරීම මකා දැමීමට සංඥාවක් ලෙස සේවය කරයි. දත්ත වාරණය නිර්මාණය කළේ නම් ශ්‍රිතයෙන් datab_alloc() , එවිට දත්ත බෆරය ශීර්ෂයට පසු වහාම මතකයේ තබනු ඇත. අනෙක් සෑම අවස්ථාවකදීම, බෆරය වෙන වෙනම කොහේ හරි ස්ථානගත කළ හැකිය. දත්ත බෆරයේ අපට පෙරහන් සමඟ සැකසීමට අවශ්‍ය සංඥා සාම්පල හෝ වෙනත් දත්ත අඩංගු වේ.

ශ්‍රිතය භාවිතයෙන් දත්ත අවහිරයක නව අවස්ථාවක් සාදනු ලැබේ:

dblk_t *datab_alloc(int size);

ආදාන පරාමිතියක් ලෙස, එය බ්ලොක් එක ගබඩා කරන දත්ත ප්රමාණය ලබා දී ඇත. වෙන් කළ මතකයේ ආරම්භයේ ශීර්ෂයක් - ව්‍යුහයක් - තැබීම සඳහා වැඩි මතකයක් වෙන් කරනු ලැබේ datab. නමුත් වෙනත් කාර්යයන් භාවිතා කරන විට, මෙය සැමවිටම සිදු නොවේ; සමහර අවස්ථාවලදී, දත්ත බෆරය දත්ත වාරණ ශීර්ෂයෙන් වෙන වෙනම පිහිටා තිබිය හැක. ව්යුහයක් නිර්මාණය කරන විට, එහි ක්ෂේත්රයේ ක්ෂේත්රයන් වින්යාස කර ඇත db_base දත්ත ප්රදේශයේ ආරම්භය වෙත යොමු කර ඇත, සහ db_lim එහි අවසානය දක්වා. සබැඳි ගණන db_ref එකකට සකසා ඇත. දත්ත පැහැදිලි ක්‍රියාකාරී දර්ශකය බිංදුවට සකසා ඇත.

ඔබේ පණිවුඩය mblk_t

සඳහන් කර ඇති පරිදි, පෝලිම් මූලද්රව්ය වර්ග වේ mblk_t, එය පහත පරිදි අර්ථ දක්වා ඇත:

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;

ව්යුහය mblk_t ආරම්භයේ ඇති දර්ශක අඩංගු වේ b_පෙර, b_ඊළඟට, ද්විත්ව සම්බන්ධිත ලැයිස්තුවක් සංවිධානය කිරීමට අවශ්‍ය වන (එය පෝලිමකි පෝලිම්_t).

එතකොට පොයින්ටර් එක එනවා b_cont, පණිවිඩය ටුපල් එකක කොටසක් වූ විට පමණක් භාවිතා වේ. Tuple හි අවසාන පණිවිඩය සඳහා, මෙම දර්ශකය ශුන්‍යව පවතී.

මීළඟට අපි දත්ත බ්ලොක් එකකට දර්ශකයක් දකිමු b_datap, ඒ සඳහා පණිවිඩය පවතී. බ්ලොක් දත්ත බෆරය තුළ ඇති ප්‍රදේශයට පොයින්ටර් මඟින් එය අනුගමනය කරයි. ක්ෂේත්රය b_rptr බෆරයෙන් දත්ත කියවන ස්ථානය නියම කරයි. ක්ෂේත්රය b_wptr බෆරය වෙත ලිවීම සිදු කරනු ලබන ස්ථානය පෙන්නුම් කරයි.

ඉතිරි ක්ෂේත්‍ර සේවා ස්වභාවයක් ඇති අතර දත්ත හුවමාරු යාන්ත්‍රණයේ ක්‍රියාකාරිත්වයට සම්බන්ධ නොවේ.

පහත දැක්වෙන්නේ නම සහිත තනි පණිවිඩයකි m1 සහ දත්ත අවහිර කිරීම d1.
Mediastreamer2 VoIP එන්ජිම ගවේෂණය කිරීම. 11 කොටස
පහත රූපයේ දැක්වෙන්නේ පණිවිඩ තුනක ටියුපල් එකක් m1, m1_1, m1_2.
Mediastreamer2 VoIP එන්ජිම ගවේෂණය කිරීම. 11 කොටස

පණිවිඩ යැවීමේ කාර්යයන් mblk_t

අලුත් පණිවිඩයක් mblk_t කාර්යය මගින් නිර්මාණය කරන ලදී:

mblk_t *allocb(int size, int pri); 

ඇය මතකයේ නව පණිවිඩයක් තබයි mblk_t නිශ්චිත ප්‍රමාණයේ දත්ත බ්ලොක් එකක් සමඟ විශාලත්වය, දෙවන තර්කය - pri පුස්තකාලයේ මෙම අනුවාදයේ භාවිතා නොවේ. එය ශුන්‍යව පැවතිය යුතුය. ශ්‍රිතයේ ක්‍රියාකාරිත්වය අතරතුර, නව පණිවිඩයේ ව්‍යුහය සඳහා මතකය වෙන් කරනු ලබන අතර ශ්‍රිතය කැඳවනු ලැබේ mblk_init(), එය ව්‍යුහයේ සාදන ලද අවස්ථාවෙහි සියලුම ක්ෂේත්‍ර නැවත සකසනු ඇත, පසුව ඉහත සඳහන් කළ ඒවා භාවිතා කරයි datab_alloc(), දත්ත බෆරයක් සාදනු ඇත. ඉන් පසු ව්‍යුහයේ ක්ෂේත්‍ර වින්‍යාස කරනු ලැබේ:

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

ප්‍රතිදානයේදී අපට ආරම්භක ක්ෂේත්‍ර සහ හිස් දත්ත බෆරයක් සහිත නව පණිවිඩයක් ලැබේ. පණිවිඩයකට දත්ත එක් කිරීමට, ඔබ එය දත්ත වාරණ බෆරය වෙත පිටපත් කළ යුතුය:

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

එහිදී දත්ත යනු දත්ත මූලාශ්‍රය වෙත දර්ශකයකි, සහ විශාලත්වය - ඔවුන්ගේ ප්රමාණය.
එවිට ඔබට එය නැවත බෆරයේ නිදහස් ප්‍රදේශයේ ආරම්භයට යොමු වන පරිදි ලිවීමේ ලක්ෂ්‍යය වෙත දර්ශකය යාවත්කාලීන කළ යුතුය:

msg->b_wptr = msg->b_wptr + size

ඔබට පිටපත් කිරීමකින් තොරව පවතින බෆරයකින් පණිවිඩයක් සෑදීමට අවශ්‍ය නම්, ශ්‍රිතය භාවිතා කරන්න:

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

ශ්‍රිතය, පණිවිඩය සහ දත්ත වාරණයේ ව්‍යුහය නිර්මාණය කිරීමෙන් පසුව, ලිපිනයෙහි ඇති දත්ත වෙත එහි දර්ශකයන් වින්‍යාස කරනු ඇත. buf. එම. මෙම අවස්ථාවෙහිදී, ශ්‍රිතය සමඟ දත්ත වාරණයක් නිර්මාණය කිරීමේදී මෙන් දත්ත වාරණයේ ශීර්ෂ ක්ෂේත්‍රවලට පසුව දත්ත බෆරය පිහිටා නොමැත. datab_alloc(). ශ්‍රිතයට යවන ලද දත්ත සහිත බෆරය එය තිබූ තැනම පවතිනු ඇත, නමුත් පොයින්ටර් ආධාරයෙන් එය දත්ත වාරණයේ අලුතින් සාදන ලද ශීර්ෂයට අමුණනු ඇත, ඒ අනුව පණිවිඩයට.

එක පණිවිඩයකට mblk_t දත්ත කොටස් කිහිපයක් අනුපිළිවෙලින් ඒකාබද්ධ කළ හැක. මෙය කාර්යය මගින් සිදු කරනු ලැබේ:

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

mp - වෙනත් දත්ත වාරණයක් එකතු කරන පණිවිඩයක්;
දත්ත - බ්ලොක් වෙත දර්ශකය, එහි පිටපතක් පණිවිඩයට එකතු කරනු ලැබේ;
විශාලත්වය - දත්ත ප්රමාණය;
පෑඩ් - වෙන් කළ මතකයේ ප්‍රමාණය බයිට් 4 සීමාවක් ඔස්සේ පෙළගැස්විය යුතු ධජයක් (පෑඩිං කිරීම බිංදු සමඟ සිදු කෙරේ).

පවතින පණිවිඩ දත්ත බෆරයේ ප්‍රමාණවත් ඉඩක් තිබේ නම්, නව දත්ත දැනටමත් එහි ඇති දත්ත පිටුපස අලවනු ලැබේ. පණිවිඩ දත්ත බෆරයේ නිදහස් ඉඩ අඩු නම් විශාලත්වය, පසුව ප්‍රමාණවත් බෆර ප්‍රමාණයකින් නව පණිවිඩයක් සාදනු ලබන අතර දත්ත එහි බෆරයට පිටපත් කරනු ලැබේ. මෙය නව පණිවිඩයකි, දර්ශක භාවිතයෙන් මුල් එකට සම්බන්ධ කර ඇත b_cont. මෙම අවස්ථාවේදී, පණිවිඩය ටියුපල් බවට හැරේ.

ඔබට ටියුපල් වෙත තවත් දත්ත කොටසක් එක් කිරීමට අවශ්‍ය නම්, ඔබ ශ්‍රිතය භාවිතා කළ යුතුය:

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

ඇය ටුපල් හි අවසාන පණිවිඩය සොයා ගනු ඇත (ඔහු සතුව ඇත b_cont ශුන්‍ය වනු ඇත) සහ මෙම පණිවිඩය සඳහා කාර්යය අමතන්න appendb().

ඔබට ශ්‍රිතය භාවිතයෙන් පණිවිඩයක හෝ ටපල් එකක දත්ත ප්‍රමාණය සොයා ගත හැක:

int msgdsize(const mblk_t *mp);

එය tuple හි ඇති සියලුම පණිවිඩ හරහා ලූප් කර එම පණිවිඩවල දත්ත බෆරවල ඇති මුළු දත්ත ප්‍රමාණය ආපසු ලබා දෙනු ඇත. සෑම පණිවිඩයක් සඳහාම, දත්ත ප්‍රමාණය පහත පරිදි ගණනය කෙරේ:

 mp->b_wptr - mp->b_rptr

ටියුපල් දෙකක් ඒකාබද්ධ කිරීමට, ශ්‍රිතය භාවිතා කරන්න:

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

ඇය ටුපල් එක එකතු කරයි newm ටුපල් වලිගයට mp සහ ලැබෙන ටියුපල් හි අවසාන පණිවිඩයට දර්ශකයක් ආපසු ලබා දෙයි.

අවශ්‍ය නම්, ටියුපල් එක දත්ත බ්ලොක් එකක් සමඟ එක් පණිවිඩයක් බවට පත් කළ හැකිය; මෙය සිදු කරනු ලබන්නේ ශ්‍රිතය මගිනි:

void msgpullup(mblk_t *mp,int len);

තර්කයක් නම් ලෙන් -1 වේ, එවිට වෙන් කරන ලද බෆරයේ ප්‍රමාණය ස්වයංක්‍රීයව තීරණය වේ. නම් ලෙන් ධන අංකයක් වන අතර, මෙම ප්‍රමාණයේ බෆරයක් සාදනු ලබන අතර ටුපල් පණිවිඩ දත්ත එයට පිටපත් කරනු ලැබේ. බෆරය අවසන් වුවහොත්, පිටපත් කිරීම එතැනින් නතර වේ. ටුපල් හි පළමු පණිවිඩයට පිටපත් කළ දත්ත සමඟ නව ප්‍රමාණයේ බෆරයක් ලැබෙනු ඇත. ඉතිරි පණිවිඩ මකා දමනු ඇති අතර මතකය ගොඩට නැවත පැමිණේ.

ව්යුහයක් මකා දැමීමේදී mblk_t ඇමතීමේ දී දත්ත වාරණයේ යොමු ගණන සැලකිල්ලට ගනී freeb() එය ශුන්‍ය වේ, එවිට දත්ත බෆරය නිදසුන සමඟ මකා දමනු ලැබේ mblk_t, එය පෙන්වා දෙන.

නව පණිවිඩයක ක්ෂේත්‍ර ආරම්භ කිරීම:

void mblk_init(mblk_t *mp);

පණිවිඩයට තවත් දත්ත කොටසක් එකතු කිරීම:

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

නව දත්ත පණිවිඩ දත්ත බෆරයේ නිදහස් අවකාශයට නොගැලපේ නම්, අවශ්‍ය ප්‍රමාණයේ බෆරයක් සහිත වෙනම සාදන ලද පණිවිඩයක් පණිවිඩයට අමුණා ඇත (එකතු කළ පණිවිඩයට දර්ශකයක් පළමු පණිවිඩයේ සකසා ඇත) සහ පණිවිඩය ටියුපල් බවට හැරේ.

ටුපල් එකකට දත්ත කැබැල්ලක් එකතු කිරීම:

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

ශ්‍රිතය ලූපයකින් appendb() අමතයි.

ටියුපල් දෙකක් එකකට ඒකාබද්ධ කිරීම:

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

ඔබේ පණිවුඩය newm වෙත අනුයුක්ත කරනු ඇත mp.

තනි පණිවිඩයක පිටපතක් සෑදීම:

mblk_t *copyb(const mblk_t *mp);

සියලුම දත්ත කොටස් සහිත ටුපල් එකක් සම්පූර්ණයෙන් පිටපත් කිරීම:

mblk_t *copymsg(const mblk_t *mp);

Tuple හි මූලද්රව්ය ශ්රිතය මගින් පිටපත් කරනු ලැබේ copyb().

පණිවිඩයක පහසු පිටපතක් සාදන්න mblk_t. මෙම අවස්ථාවේදී, දත්ත අවහිර කිරීම පිටපත් නොකෙරේ, නමුත් එහි යොමු කවුන්ටරය වැඩි වේ db_ref:

mblk_t *dupb(mblk_t *mp);

ටුපල් එකක සැහැල්ලු පිටපතක් සෑදීම. දත්ත වාරණ පිටපත් නොකෙරේ, ඒවායේ විමර්ශන කවුන්ටර පමණක් වැඩි වේ db_ref:

mblk_t *dupmsg(mblk_t* m);

ටුපල් එකක සියලුම පණිවිඩ එක් පණිවිඩයකට ඇලවීම:

void msgpullup(mblk_t *mp,size_t len);

තර්කය නම් ලෙන් -1 වේ, එවිට වෙන් කරන ලද බෆරයේ ප්‍රමාණය ස්වයංක්‍රීයව තීරණය වේ.

පණිවිඩයක් මකා දැමීම, ටියුපල්:

void freemsg(mblk_t *mp);

දත්ත වාරණයේ යොමු ගණන එකකින් අඩු වේ. එය බිංදුවට ළඟා වුවහොත්, දත්ත අවහිර කිරීම ද මකා දමනු ලැබේ.

පණිවිඩයක හෝ ටුපල් එකක ඇති මුළු දත්ත ප්‍රමාණය ගණනය කිරීම.

size_t msgdsize(const mblk_t *mp);

පෝලිමේ වලිගයෙන් පණිවිඩයක් ලබා ගැනීම:

mblk_t *ms_queue_peek_last (q);

එක් පණිවිඩයක වෙන් කර ඇති ක්ෂේත්‍රවල අන්තර්ගතය තවත් පණිවිඩයකට පිටපත් කිරීම (ඇත්ත වශයෙන්ම, මෙම ක්ෂේත්‍රවල මාධ්‍ය ප්‍රවාහකයා විසින් භාවිතා කරන කොඩි අඩංගු වේ):

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

පෝලිම් පෝලිම්_t

මාධ්‍ය ප්‍රවාහයේ පණිවිඩ පෝලිම චක්‍රලේඛය ද්විත්ව සම්බන්ධිත ලැයිස්තුවක් ලෙස ක්‍රියාත්මක වේ. එක් එක් ලැයිස්තු මූලද්‍රව්‍ය සංඥා සාම්පල සහිත දත්ත බ්ලොක් එකකට දර්ශකයක් අඩංගු වේ. දත්ත නිශ්චලව පවතින අතර දත්ත වාරණ වෙත යොමු කිරීම් පමණක් අනෙක් අතට චලනය වන බව පෙනේ. එම. ඒවාට සබැඳි පමණක් ගෙන යනු ලැබේ.
පෝලිම විස්තර කරන ව්‍යුහය පෝලිම්_t, පහත පෙන්වා ඇත:

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

ව්යුහයේ ක්ෂේත්රයක් අඩංගු වේ - දර්ශකයක් _q_stopper *mblk_t ලෙස ටයිප් කරන්න, එය පෝලිමේ පළමු අංගය (පණිවිඩය) වෙත යොමු කරයි. ව්යුහයේ දෙවන ක්ෂේත්රය වන්නේ පෝලිමේ පණිවිඩ කවුන්ටරයයි.
පහත රූපයේ දැක්වෙන්නේ m1, m4, m1, m2 යන පණිවිඩ 3ක් අඩංගු q4 නම් පෝලිමකි.
Mediastreamer2 VoIP එන්ජිම ගවේෂණය කිරීම. 11 කොටස
පහත රූපයේ දැක්වෙන්නේ m1,m4,m1,m2 පණිවිඩ 3ක් අඩංගු q4 නම් පෝලිමකි. Message m2 යනු තවත් පණිවිඩ දෙකක් m2_1 සහ m2_2 අඩංගු tuple එකක හිසයි.

Mediastreamer2 VoIP එන්ජිම ගවේෂණය කිරීම. 11 කොටස

පෝලිම් queue_t සමඟ වැඩ කිරීම සඳහා කාර්යයන්

පෝලිම් ආරම්භ කිරීම:

void qinit(queue_t *q);

ක්ෂේත්රයේ _q_stopper (මෙතැන් සිට අපි එය "stopper" ලෙස හඳුන්වමු) ශ්‍රිතයෙන් ආරම්භ වේ mblk_init(), එහි පෙර මූලද්‍රව්‍යය සහ මීළඟ මූලද්‍රව්‍ය දර්ශකය තමා වෙතට යොමු කිරීමට සකසනු ලැබේ. පෝලිම් මූලද්‍රව්‍ය කවුන්ටරය බිංදුවට යළි පිහිටුවයි.

නව අංගයක් එකතු කිරීම (පණිවිඩ):

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

නව මූලද්රව්යය m ලැයිස්තුවේ අවසානයට එකතු කරනු ලැබේ, මූලද්‍රව්‍ය දර්ශක සකසනු ලබන අතර එමඟින් නැවතුම එය සඳහා ඊළඟ මූලද්‍රව්‍යය බවට පත් වන අතර එය නැවතුම සඳහා පෙර මූලද්‍රව්‍යය බවට පත්වේ. පෝලිම් මූලද්‍රව්‍ය කවුන්ටරය වැඩි කර ඇත.

පෝලිමේ සිට අංගයක් ලබා ගැනීම:

mblk_t * getq(queue_t *q); 

නැවතුමට පසුව එන පණිවිඩය නැවත ලබා ගන්නා අතර, මූලද්රව්ය කවුන්ටරය අඩු වේ. නැවතුම හැර පෝලිමේ මූලද්‍රව්‍ය නොමැති නම්, 0 ආපසු ලබා දෙනු ලැබේ.

පෝලිමකට පණිවිඩයක් ඇතුල් කිරීම:

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

මූලද්රව්යය mp මූලද්රව්යයට පෙර ඇතුල් කර ඇත EMP. එසේ නම් EMP=0, එවිට පණිවිඩය පෝලිමේ වලිගයට එකතු වේ.

පෝලිමේ ප්‍රධානියාගෙන් පණිවිඩයක් ලබා ගැනීම:

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

මූලද්රව්ය කවුන්ටරය අඩු වී ඇත.

පෝලිමේ පළමු අංගයට දර්ශකයක් කියවීම:

mblk_t * peekq(queue_t *q); 

මූලද්‍රව්‍ය මකමින් පෝලිමෙන් සියලුම මූලද්‍රව්‍ය ඉවත් කිරීම:

void flushq(queue_t *q, int how);

තර්කය ආකාරය භාවිතා නොකරනලද. පෝලිම් මූලද්‍රව්‍ය කවුන්ටරය ශුන්‍යයට සකසා ඇත.

පෝලිමේ අවසාන අංගයට දර්ශකයක් කියවීම සඳහා මැක්‍රෝ:

mblk_t * qlast(queue_t *q);

පණිවිඩ පෝලිම් සමඟ වැඩ කරන විට, ඔබ අමතන විට දැනුවත් වන්න ms_queue_put(q, m) පණිවිඩයට ශුන්‍ය දර්ශකයක් සමඟ, ශ්‍රිතය ලූප වේ. ඔබගේ වැඩසටහන කැටි වනු ඇත. සමාන ලෙස හැසිරේ ms_පෝලිම_ඊළඟ(q, m).

පෙරහන් සම්බන්ධ කිරීම

ඉහත විස්තර කර ඇති පෝලිම එක් ෆිල්ටරයකින් තවත් ෆිල්ටරයකට හෝ ෆිල්ටර් එකක සිට කිහිපයකට පණිවිඩ යැවීමට භාවිතා කරයි. පෙරහන් සහ ඒවායේ සම්බන්ධතා අධ්‍යක්ෂණය කරන ලද ප්‍රස්ථාරයක් සාදයි. ෆිල්ටරයේ ආදානය හෝ ප්‍රතිදානය සාමාන්‍ය වචනය "පින්" ලෙස හැඳින්වේ. පෙරහන් එකිනෙක සම්බන්ධ වන අනුපිළිවෙල විස්තර කිරීම සඳහා, මාධ්‍ය ප්‍රවාහකයා "සංඥා ලක්ෂ්‍යයක්" යන සංකල්පය භාවිතා කරයි. සංඥා ලක්ෂ්‍යය ව්‍යුහයයි _MSCPpoint, ෆිල්ටරයට පොයින්ටරයක් ​​සහ එහි එක් අල්ෙපෙනති අංකයක් අඩංගු වේ; ඒ අනුව, එය ෆිල්ටරයේ එක් ආදාන හෝ ප්‍රතිදානයක සම්බන්ධය විස්තර කරයි.

දත්ත සැකසුම් ප්රස්ථාරයේ සංඥා ලක්ෂ්යය

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

පෙරහන් පින් ශුන්‍යයේ සිට අංකනය කර ඇත.

පණිවුඩ පෝලිමක් මගින් පින් දෙකක් සම්බන්ධ කිරීම ව්යුහය මගින් විස්තර කෙරේ _MS පෝලිම, එය සම්බන්ධ කරන සංඥා ස්ථාන දෙකට පණිවිඩ පෝලිමක් සහ පොයින්ටර් අඩංගු වේ:

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

අපි මෙම ව්යුහය සංඥා සම්බන්ධකයක් ලෙස හඳුන්වමු. සෑම මාධ්‍ය ප්‍රවාහ පෙරහනකම ආදාන සබැඳි වගුවක් සහ ප්‍රතිදාන සබැඳි වගුවක් අඩංගු වේ (MSQueue) පෙරහනක් සෑදීමේදී වගු වල ප්‍රමාණය සකසා ඇත; අපි දැනටමත් අපනයනය කරන ලද ආකාරයේ විචල්‍යයක් භාවිතයෙන් මෙය කර ඇත MSFilterDesc, අපි අපේම පෙරහන දියුණු කළ විට. මාධ්‍ය ප්‍රවාහයක ඕනෑම පෙරහනක් විස්තර කරන ව්‍යුහයක් පහත දැක්වේ, 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;

අපගේ සැලැස්මට අනුකූලව අපි C වැඩසටහනේ පෙරහන් සම්බන්ධ කළ පසු (නමුත් ටික් එක සම්බන්ධ නොකළ), එමඟින් අපි අධ්‍යක්‍ෂිත ප්‍රස්ථාරයක් නිර්මාණය කළෙමු, එහි නෝඩ් ව්‍යුහයේ අවස්ථා වේ. MSFilter, සහ දාර යනු සබැඳි වල අවස්ථා වේ MSQueue.

ටික්කරුගේ තිරය පිටුපස ක්‍රියාකාරකම්

ටික් එක කිනිතුල්ලන්ගේ ප්‍රභවය සඳහා පෙරනයක් බව මම ඔබට පැවසූ විට, එය එහි සම්පූර්ණ සත්‍ය නොවේ. ටිකර් එකක් යනු ඔරලෝසුව මත ක්‍රියා කරන වස්තුවකි ක්රියාවලිය () එය සම්බන්ධ කර ඇති පරිපථයේ (ප්‍රස්ථාරයේ) සියලුම පෙරහන්. අපි C වැඩසටහනක ප්‍රස්ථාර ෆිල්ටරයකට ටිකර් එකක් සම්බන්ධ කරන විට, අපි එය ක්‍රියා විරහිත කරන තෙක් එය පාලනය කරන ප්‍රස්ථාරය ටිකර් එකට පෙන්වමු. සම්බන්ධ කිරීමෙන් පසු, ටිකර් එහි රැකවරණය සඳහා භාර දී ඇති ප්‍රස්ථාරය පරීක්ෂා කිරීමට පටන් ගනී, එය ඇතුළත් වන පෙරහන් ලැයිස්තුවක් සම්පාදනය කරයි. එකම පෙරණය දෙවරක් "ගණන්" නොකිරීමට, එය හඳුනාගත් පෙරහන් ඒවායේ පිරික්සුම් පෙට්ටියක් තැබීමෙන් සලකුණු කරයි. දැක. එක් එක් පෙරහන ඇති සබැඳි වගු භාවිතයෙන් සෙවීම සිදු කෙරේ.

එහි ප්‍රස්ථාරයේ හඳුන්වාදීමේ චාරිකාව අතරතුර, ටික්කරය පෙරහන් අතර අවම වශයෙන් දත්ත අවහිර කිරීමේ ප්‍රභවයක් ලෙස ක්‍රියා කරන එකක් තිබේදැයි පරීක්ෂා කරයි. කිසිවක් නොමැති නම්, ප්‍රස්ථාරය වැරදි ලෙස සලකනු ලබන අතර ටිකර් බිඳ වැටේ.

ප්‍රස්ථාරය “නිවැරදි” බවට පත් වුවහොත්, සොයාගත් එක් එක් පෙරහන සඳහා, ශ්‍රිතය ආරම්භ කිරීම සඳහා කැඳවනු ලැබේ පෙර සැකසුම් (). ඊළඟ සැකසුම් චක්‍රය සඳහා මොහොත පැමිණි විගස (පෙරනිමියෙන් සෑම මිලි තත්පර 10කටම), ටිකර් ශ්‍රිතය අමතයි ක්රියාවලිය () කලින් සොයාගත් සියලුම මූලාශ්‍ර පෙරහන් සඳහා, පසුව ලැයිස්තුවේ ඉතිරි පෙරහන් සඳහා. ෆිල්ටරයේ ආදාන සබැඳි තිබේ නම්, කාර්යය ධාවනය කරන්න ක්රියාවලිය () ආදාන සබැඳි පෝලිම් හිස් වන තුරු නැවත නැවත සිදු වේ. මෙයින් පසු, එය ලැයිස්තුවේ ඊළඟ පෙරහන වෙත ගොස් ආදාන සබැඳි පණිවිඩ වලින් නිදහස් වන තෙක් එය "අනුචලනය" කරයි. ලැයිස්තුව අවසන් වන තුරු ටිකර් පෙරහනෙන් පෙරහනට ගමන් කරයි. මෙය චක්රය සැකසීම සම්පූර්ණ කරයි.

දැන් අපි tuples වෙත ආපසු ගොස් එවැනි ආයතනයක් මාධ්‍ය ප්‍රවාහයට එක් කළේ ඇයිද යන්න ගැන කතා කරමු. සාමාන්‍යයෙන්, ෆිල්ටරය තුළ ක්‍රියාත්මක වන ඇල්ගොරිතමයට අවශ්‍ය දත්ත ප්‍රමාණය සමපාත නොවන අතර එය ආදානයේදී ලැබෙන දත්ත බෆරවල ප්‍රමාණයේ ගුණාකාරයක් නොවේ. උදාහරණයක් ලෙස, අපි වේගවත් ෆූරියර් පරිවර්තනයක් සිදු කරන පෙරහනක් ලියන්නෙමු, නිර්වචනය අනුව ප්‍රමාණයෙන් දෙකක බලයක් ඇති දත්ත කොටස් පමණක් සැකසිය හැක. එය ගණන් 512ක් වේවා. දත්ත දුරකථන නාලිකාවක් මගින් ජනනය කරන්නේ නම්, ආදානයේ ඇති එක් එක් පණිවිඩයේ දත්ත බෆරය අපට සංඥා සාම්පල 160 ක් ගෙන එයි. අවශ්‍ය දත්ත ප්‍රමාණය ලැබෙන තුරු ආදානයෙන් දත්ත රැස් නොකිරීමට පෙළඹේ. නමුත් මෙම අවස්ථාවේදී, ටිකර් සමඟ ගැටීමක් සිදුවනු ඇත, එය ආදාන සබැඳිය හිස් වන තුරු පෙරණය අනුචලනය කිරීමට අසාර්ථක උත්සාහයක් ගනු ඇත. මීට පෙර, අපි මෙම රීතිය පෙරහනෙහි තුන්වන මූලධර්මය ලෙස නම් කළෙමු. මෙම මූලධර්මය අනුව, ෆිල්ටරයේ ක්‍රියාවලිය() ශ්‍රිතය ආදාන පෝලිම් වලින් සියලුම දත්ත ලබා ගත යුතුය.

ඊට අමතරව, ආදානයෙන් සාම්පල 512 ක් පමණක් ගැනීමට නොහැකි වනු ඇත, මන්ද ඔබට ගත හැක්කේ සම්පූර්ණ කුට්ටි පමණි, i.e. ෆිල්ටරයට සාම්පල 640 ක් ගෙන ඒවායින් 512 ක් භාවිතා කිරීමට සිදුවනු ඇත, ඉතිරිය නව දත්ත කොටසක් රැස් කිරීමට පෙර. මේ අනුව, අපගේ පෙරහන, එහි ප්රධාන කාර්යයට අමතරව, ආදාන දත්ත අතරමැදි ගබඩා කිරීම සඳහා සහායක ක්රියාවන් සැපයිය යුතුය. මාධ්‍ය ප්‍රවාහයේ සංවර්ධකයින් සහ මෙම සාමාන්‍ය ගැටලුවට විසඳුම විශේෂ වස්තුවක් සංවර්ධනය කර ඇත - MSBufferizer (බෆරර්), එය ටියුපල් භාවිතයෙන් මෙම ගැටළුව විසඳයි.

බෆරයිසර් (MSBufferizer)

මෙය ෆිල්ටරය තුළ ආදාන දත්ත රැස් කරන වස්තුවක් වන අතර පෙරහන් ඇල්ගොරිතම ක්‍රියාත්මක කිරීමට තොරතුරු ප්‍රමාණය ප්‍රමාණවත් වූ වහාම එය සැකසීම සඳහා ඉදිරිපත් කිරීමට පටන් ගනී. බෆරය දත්ත රැස් කරන අතරතුර, ෆිල්ටරය ප්‍රොසෙසරයේ සැකසුම් බලය භාවිතා නොකර, අක්‍රිය ආකාරයෙන් ක්‍රියා කරයි. නමුත් බෆරර් වෙතින් කියවීමේ ශ්‍රිතය බිංදුව හැර වෙනත් අගයක් ලබා දුන් වහාම, ෆිල්ටරයේ ක්‍රියාවලිය() ශ්‍රිතය බෆරයෙන් අවශ්‍ය ප්‍රමාණයේ කොටස් වලින් දත්ත ලබාගෙන එය අවසන් වන තුරු සැකසීමට පටන් ගනී.
තවමත් අවශ්‍ය නොවන දත්ත ටියුපල් හි පළමු මූලද්‍රව්‍යය ලෙස බෆරයේ පවතින අතර, ඊට පසු ආදාන දත්ත කොටස් අමුණා ඇත.

බෆරය විස්තර කරන ව්‍යුහය:

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

MSBufferizer සමඟ වැඩ කිරීම සඳහා වන කාර්යයන්

නව බෆර අවස්ථාවක් නිර්මාණය කිරීම:

MSBufferizer * ms_bufferizer_new(void);

මතකය වෙන් කර ඇත, ආරම්භ කර ඇත ms_bufferizer_init() සහ දර්ශකයක් ආපසු ලබා දෙනු ලැබේ.

ආරම්භක කාර්යය:

void ms_bufferizer_init(MSBufferizer *obj); 

පෝලිම ආරම්භ වේ q, ක්ෂේත්රය විශාලත්වය බිංදුවට සකසා ඇත.

පණිවිඩයක් එකතු කිරීම:

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

m පණිවිඩය පෝලිමට එකතු වේ. දත්ත කොටස්වල ගණනය කළ ප්‍රමාණය එකතු කරනු ලැබේ විශාලත්වය.

සබැඳි දත්ත පෝලිමේ සිට බෆරය වෙත සියලුම පණිවිඩ මාරු කිරීම q:

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

සබැඳියකින් පණිවිඩ මාරු කිරීම q බෆරය තුළ ශ්‍රිතය භාවිතයෙන් සිදු කෙරේ ms_bufferizer_put().

බෆරයෙන් කියවීම:

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

බෆරයේ එකතු වී ඇති දත්තවල ප්‍රමාණය ඉල්ලූ ප්‍රමාණයට වඩා අඩු නම් (datalen), එවිට ශ්‍රිතය ශුන්‍යය ලබා දෙයි, දත්ත දත්ත වෙත පිටපත් නොකෙරේ. එසේ නොමැතිනම්, බෆරයේ පිහිටා ඇති ටියුපල් වලින් දත්ත අනුක්රමික පිටපත් කිරීම සිදු කරනු ලැබේ. පිටපත් කිරීමෙන් පසු, ටියුපල් මකා දමා මතකය නිදහස් වේ. දත්තලේන් බයිට් පිටපත් කරන මොහොතේ පිටපත් කිරීම අවසන් වේ. දත්ත බ්ලොක් එකක් මධ්‍යයේ ඉඩ අවසන් වුවහොත්, මෙම පණිවිඩයේ, දත්ත වාරණ ඉතිරි පිටපත් නොකළ කොටස දක්වා අඩු කරනු ලැබේ. මීළඟ වතාවේ ඔබ අමතන විට, පිටපත් කිරීම මෙතැන් සිට දිගටම කරගෙන යනු ඇත.

බෆරයේ දැනට පවතින දත්ත ප්‍රමාණය කියවීම:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

ක්ෂේත්‍රය ආපසු ලබා දෙයි විශාලත්වය බෆරර්.

බෆරයේ ඇති දත්තවලින් කොටසක් ඉවතලීම:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

නිශ්චිත බයිට් සංඛ්‍යාව දත්ත ලබාගෙන ඉවත දමනු ලැබේ. පැරණිතම දත්ත ඉවත දමනු ලැබේ.

බෆරයේ ඇති සියලුම පණිවිඩ මකා දැමීම:

void ms_bufferizer_flush(MSBufferizer *obj); 

දත්ත කවුන්ටරය ශුන්‍යයට යළි පිහිටුවයි.

බෆරයේ ඇති සියලුම පණිවිඩ මකා දැමීම:

void ms_bufferizer_uninit(MSBufferizer *obj); 

කවුන්ටරය නැවත සකස් කර නැත.

බෆරය ඉවත් කිරීම සහ මතකය නිදහස් කිරීම:

void ms_bufferizer_destroy(MSBufferizer *obj);  

මාධ්‍ය ප්‍රවාහ පෙරහන් කිහිපයක ප්‍රභව කේතයෙන් බෆරරය භාවිතා කිරීමේ උදාහරණ සොයා ගත හැක. උදාහරණයක් ලෙස, MS_L16_ENC ෆිල්ටරය තුළ, සාම්පලවල බයිට් ජාල අනුපිළිවෙලේ සිට ධාරක අනුපිළිවෙල දක්වා නැවත සකස් කරයි: l16.c

මීළඟ ලිපියෙන්, අපි ටිකර් එකක බර ඇස්තමේන්තු කිරීමේ ගැටලුව සහ මාධ්‍ය ප්‍රවාහයක අධික පරිගණක භාරයට එරෙහිව සටන් කිරීමේ ක්‍රම දෙස බලමු.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න