{"id":79540,"date":"2020-04-28T07:42:01","date_gmt":"2020-04-28T05:42:01","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11"},"modified":"2020-04-28T07:42:01","modified_gmt":"2020-04-28T05:42:01","slug":"izuchaem-voip-dvizhok-mediastreamer2-chast-11","status":"publish","type":"post","link":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","title":{"rendered":"Explorons le moteur VoIP Mediastreamer2. Partie 11","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Le contenu de cet article est tir\u00e9 de ma <noindex><a rel=\"nofollow\" href=\"https:\/\/zen.yandex.ru\/profile\/editor\/id\/5e3f8e0751f5346faab4fc7a\">cha\u00eene Zen<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Explorons le moteur VoIP Mediastreamer2. Partie 11\" src=\"\/wp-content\/uploads\/2020\/04\/b66fab43eb45c626c50f0383dcfa7cca.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>M\u00e9canisme de transfert de donn\u00e9es<\/p>\n<p><\/p>\n<ul>\n<li>Bloc de donn\u00e9es dblk_t<\/li>\n<li>Message mblk_t<\/li>\n<li>Fonctions de traitement des messages mblk_t<\/li>\n<li>File d'attente queue_t<\/li>\n<li>Fonctions de gestion des files d'attente queue_t<\/li>\n<li>Connexion de filtres<\/li>\n<li>Point de signalisation du graphe de traitement de donn\u00e9es<\/li>\n<li>Activit\u00e9 en coulisse du ticker<\/li>\n<li>Mise en m\u00e9moire tampon (MSBufferizer)<\/li>\n<li>Fonctions de gestion du MSBufferizer<\/li>\n<\/ul>\n<p><\/p>\n<p>Dans le pass\u00e9, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/497932\/\">article<\/a><\/noindex> Nous avons d\u00e9velopp\u00e9 notre propre filtre. Cet article sera consacr\u00e9 aux m\u00e9canismes internes de transfert de donn\u00e9es entre les filtres du mediastreamer. Cela permettra d'\u00e9crire des filtres complexes avec moins d'efforts.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"mehanizm-peremescheniya-dannyh\">M\u00e9canisme de transfert de donn\u00e9es<\/h2>\n<p><\/p>\n<p>Le transfert de donn\u00e9es dans le mediastreamer se fait \u00e0 l'aide de files d'attente d\u00e9crites par la structure <em>queue_t<\/em>. Les files d'attente transf\u00e8rent des cha\u00eenes de messages de type <em>mblk_t<\/em>, qui ne contiennent pas de donn\u00e9es de signal en elles-m\u00eames, mais uniquement des r\u00e9f\u00e9rences au message pr\u00e9c\u00e9dent, au message suivant et au bloc de donn\u00e9es. De plus, il est crucial de souligner qu'il existe \u00e9galement un champ pour r\u00e9f\u00e9rencer un message du m\u00eame type, ce qui permet d'organiser une liste cha\u00een\u00e9e de messages. Le groupe de messages ainsi r\u00e9unis sera appel\u00e9 un tuple. Ainsi, tout \u00e9l\u00e9ment de la file d'attente peut \u00eatre un message unique <em>mblk_t<\/em>, ou bien la t\u00eate d'un tuple de messages <em>mblk_t<\/em>. Chaque message dans le tuple peut avoir son propre bloc de donn\u00e9es associ\u00e9. Nous discuterons davantage de l'utilit\u00e9 des tuples un peu plus tard.<\/p>\n<p><\/p>\n<p>Comme mentionn\u00e9 ci-dessus, le message lui-m\u00eame ne contient pas de bloc de donn\u00e9es, mais seulement un pointeur vers la zone m\u00e9moire o\u00f9 le bloc est stock\u00e9. \u00c0 ce stade, l'image g\u00e9n\u00e9rale du fonctionnement du m\u00e9diastreamer \u00e9voque un entrep\u00f4t de portes dans le dessin anim\u00e9 \"Monstres et Cie\", o\u00f9 les portes (liens vers des donn\u00e9es \u2014 chambres) se d\u00e9placent \u00e0 une vitesse folle sur des tapis roulants suspendus, tandis que les chambres elles-m\u00eames restent immobiles. <\/p>\n<p><\/p>\n<p>Maintenant, en progressant dans la hi\u00e9rarchie de bas en haut, examinons plus en d\u00e9tail les entit\u00e9s du m\u00e9canisme de transfert de donn\u00e9es dans le mediastreamer.<\/p>\n<p><\/p>\n<h3 id=\"blok--dannyh-dblk_t\">Bloc de donn\u00e9es <em>dblk_t<\/em><\/h3>\n<p><\/p>\n<p>Un bloc de donn\u00e9es se compose d'un en-t\u00eate et d'un tampon de donn\u00e9es. L'en-t\u00eate est d\u00e9crit par la structure suivante,<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct datab\n{\nunsigned char *db_base; \/\/ Pointeur vers le d\u00e9but du tampon de donn\u00e9es.\nunsigned char *db_lim;  \/\/ Pointeur vers la fin du tampon de donn\u00e9es.\nvoid (*db_freefn)(void*); \/\/ Fonction de lib\u00e9ration de m\u00e9moire lors de la suppression du bloc.\nint db_ref; \/\/ Compteur de r\u00e9f\u00e9rences.\n} dblk_t;<\/code><\/pre>\n<p><\/p>\n<p>Les champs de la structure contiennent des pointeurs vers le d\u00e9but du tampon, la fin du tampon, et une fonction pour supprimer le tampon de donn\u00e9es. Le dernier \u00e9l\u00e9ment dans l'en-t\u00eate <em>db_ref<\/em> \u2014 est un compteur de r\u00e9f\u00e9rences ; s'il atteint z\u00e9ro, cela signale la suppression de ce bloc de la m\u00e9moire. Si le bloc de donn\u00e9es a \u00e9t\u00e9 cr\u00e9\u00e9 par la fonction <em>datab_alloc() <\/em>, alors le tampon de donn\u00e9es sera situ\u00e9 en m\u00e9moire imm\u00e9diatement apr\u00e8s l'en-t\u00eate. Dans tous les autres cas, le tampon peut \u00eatre situ\u00e9 quelque part ailleurs. Dans le tampon de donn\u00e9es se trouveront les \u00e9chantillons de signal ou d'autres donn\u00e9es que nous souhaitons traiter avec des filtres.<\/p>\n<p><\/p>\n<p>Une nouvelle instance du bloc de donn\u00e9es est cr\u00e9\u00e9e \u00e0 l'aide de la fonction :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">dblk_t *datab_alloc(int size);<\/code><\/pre>\n<p><\/p>\n<p>Le param\u00e8tre d'entr\u00e9e est la taille des donn\u00e9es que le bloc va stocker. Plus de m\u00e9moire est allou\u00e9e afin que, au d\u00e9but de la m\u00e9moire allou\u00e9e, l'en-t\u00eate \u2014 la structure <em>datab<\/em>. Cependant, lorsque d'autres fonctions sont utilis\u00e9es, cela ne se produit pas toujours ; dans certains cas, le tampon de donn\u00e9es peut \u00eatre situ\u00e9 s\u00e9par\u00e9ment de l'en-t\u00eate du bloc de donn\u00e9es. Les champs de la structure sont configur\u00e9s lors de la cr\u00e9ation afin que son champ <em>db_base<\/em> pointe vers le d\u00e9but de la zone de donn\u00e9es, et <em>db_lim<\/em> vers sa fin. Le compteur de r\u00e9f\u00e9rences <em>db_ref<\/em> est initialis\u00e9 \u00e0 un. Le pointeur de fonction pour nettoyer les donn\u00e9es est initialis\u00e9 \u00e0 z\u00e9ro.<\/p>\n<p><\/p>\n<h3 id=\"soobschenie-mblk_t\">Message <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Comme indiqu\u00e9, les \u00e9l\u00e9ments de la queue ont le type <em>mblk_t,<\/em> il est d\u00e9fini comme suit :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct msgb\n{\n  struct msgb *b_prev;   \/\/ Pointeur vers l'\u00e9l\u00e9ment pr\u00e9c\u00e9dent de la liste.\n  struct msgb *b_next;   \/\/ Pointeur vers l'\u00e9l\u00e9ment suivant de la liste.\n  struct msgb *b_cont;   \/\/ Pointeur pour relier d'autres messages au message, afin de cr\u00e9er un tuple de messages.\n  struct datab *b_datap; \/\/ Pointeur vers la structure du bloc de donn\u00e9es.\n  unsigned char *b_rptr; \/\/ Pointeur vers le d\u00e9but de la zone de donn\u00e9es pour lire les donn\u00e9es du tampon b_datap.\n  unsigned char *b_wptr; \/\/ Pointeur vers le d\u00e9but de la zone de donn\u00e9es pour \u00e9crire des donn\u00e9es dans le tampon b_datap.\n  uint32_t reserved1;    \/\/ Champ r\u00e9serv\u00e91, le flux multim\u00e9dia y place des informations de service.\n  uint32_t reserved2;    \/\/ Champ r\u00e9serv\u00e92, le flux multim\u00e9dia y place des informations de service.\n  #if defined(ORTP_TIMESTAMP)\n  struct timeval timestamp;\n  #endif\n  ortp_recv_addr_t recv_addr;\n} mblk_t;<\/code><\/pre>\n<p><\/p>\n<p>Structure <em>mblk_t<\/em> commence par des pointeurs <em>b_prev<\/em>, <em>b_next<\/em>, n\u00e9cessaires pour organiser une liste doublement cha\u00een\u00e9e (qui est la queue <em>queue_t<\/em>). <\/p>\n<p><\/p>\n<p>Ensuite vient le pointeur <em>b_cont<\/em>, qui est utilis\u00e9 uniquement lorsque le message entre dans le tuple. Pour le dernier message du tuple, ce pointeur reste nul. <\/p>\n<p><\/p>\n<p>Ensuite, nous voyons un pointeur vers un bloc de donn\u00e9es <em>b_datap<\/em>, pour lequel le message existe. Il est suivi de pointeurs, vers la zone \u00e0 l'int\u00e9rieur du tampon de donn\u00e9es du bloc. Le champ <em>b_rptr<\/em> indique le lieu \u00e0 partir duquel les donn\u00e9es seront lues \u00e0 partir du tampon. Le champ <em>b_wptr<\/em> indique le lieu \u00e0 partir duquel l'\u00e9criture dans le tampon sera effectu\u00e9e. <\/p>\n<p><\/p>\n<p>Les champs restants sont d'ordre fonctionnel et ne sont pas li\u00e9s au m\u00e9canisme de transmission des donn\u00e9es.<\/p>\n<p><\/p>\n<p>Ci-dessous, un message unique nomm\u00e9 <em>m1<\/em> et un bloc de donn\u00e9es <em>d1<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Explorons le moteur VoIP Mediastreamer2. Partie 11\" src=\"\/wp-content\/uploads\/2020\/04\/e6a726b13491832258c1228f03bde802.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00c0 la figure suivante, un tuple de trois messages est montr\u00e9 <em>m1<\/em>, <em>m1_1<\/em>, <em>m1_2<\/em>.<br \/>\n<img decoding=\"async\" alt=\"Explorons le moteur VoIP Mediastreamer2. Partie 11\" src=\"\/wp-content\/uploads\/2020\/04\/9613feefe9684b9551cd98115faa9a08.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-soobscheniyami--mblk_t\">Les fonctions de gestion des messages <em>mblk_t<\/em><\/h3>\n<p><\/p>\n<p>Un nouveau message <em>mblk_t<\/em> est cr\u00e9\u00e9 par la fonction :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *allocb(int size, int pri); <\/code><\/pre>\n<p><\/p>\n<p>elle alloue en m\u00e9moire un nouveau message <em>mblk_t<\/em> avec un bloc de donn\u00e9es de taille sp\u00e9cifi\u00e9e <em>taille<\/em>, le deuxi\u00e8me argument \u2014 <em>pri<\/em> n'est pas utilis\u00e9 dans la version de la biblioth\u00e8que consid\u00e9r\u00e9e. Il doit rester nul. Pendant l'ex\u00e9cution de la fonction, de la m\u00e9moire sera allou\u00e9e pour la structure du nouveau message et la fonction <em>mblk_init()<\/em>, qui remettra \u00e0 z\u00e9ro tous les champs de l'instance cr\u00e9\u00e9e de la structure et ensuite, \u00e0 l'aide de ce qui a \u00e9t\u00e9 mentionn\u00e9 ci-dessus, <em>datab_alloc()<\/em>, un tampon de donn\u00e9es sera cr\u00e9\u00e9. Apr\u00e8s cela, les champs de la structure seront configur\u00e9s : <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mp-&gt;b_datap=datab;\nmp-&gt;b_rptr=mp-&gt;b_wptr=datab-&gt;db_base;\nmp-&gt;b_next=mp-&gt;b_prev=mp-&gt;b_cont=NULL;<\/code><\/pre>\n<p><\/p>\n<p>\u00c0 la sortie, nous obtenons un nouveau message avec des champs initialis\u00e9s et un tampon de donn\u00e9es vide. Pour ajouter des donn\u00e9es au message, il faut les copier dans le tampon du bloc de donn\u00e9es :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">memcpy(msg-&gt;b_rptr, data, size);<\/code><\/pre>\n<p><\/p>\n<p>o\u00f9 <em>data<\/em> \u2014 pointeur vers la source des donn\u00e9es, et <em>taille<\/em> \u2014 leur taille.<br \/>\nEnsuite, il faut mettre \u00e0 jour le pointeur vers le point d'\u00e9criture, pour qu'il pointe \u00e0 nouveau vers le d\u00e9but de la zone libre dans le tampon :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">msg-&gt;b_wptr = msg-&gt;b_wptr + size<\/code><\/pre>\n<p><\/p>\n<p>S'il est n\u00e9cessaire de cr\u00e9er un message \u00e0 partir d'un tampon d\u00e9j\u00e0 existant, sans copier, alors pour cela, on utilise la fonction :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*)); <\/code><\/pre>\n<p><\/p>\n<p>La fonction apr\u00e8s la cr\u00e9ation du message et de la structure du bloc de donn\u00e9es, configurera ses pointeurs vers les donn\u00e9es \u00e0 l'adresse <em>buf<\/em>. C'est-\u00e0-dire que, dans ce cas, le tampon de donn\u00e9es ne se trouve pas juste apr\u00e8s les champs de l'en-t\u00eate du bloc de donn\u00e9es, comme cela a \u00e9t\u00e9 fait lors de la cr\u00e9ation du bloc de donn\u00e9es par la fonction. <em>datab_alloc()<\/em>Le tampon de donn\u00e9es pass\u00e9 \u00e0 la fonction restera \u00e0 l'endroit o\u00f9 il \u00e9tait, mais gr\u00e2ce aux pointeurs, il sera dirig\u00e9 vers l'en-t\u00eate du bloc de donn\u00e9es nouvellement cr\u00e9\u00e9, ce dernier \u00e9tant associ\u00e9 au message.<\/p>\n<p><\/p>\n<p>\u00c0 un message <em>mblk_t<\/em> peuvent \u00eatre successivement attach\u00e9s plusieurs blocs de donn\u00e9es. Cela se fait par la fonction :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad); <\/code><\/pre>\n<p><\/p>\n<p><em>mp<\/em> \u2014 le message auquel un autre bloc de donn\u00e9es sera ajout\u00e9 ;<br \/>\n<em>data<\/em> \u2014 un pointeur vers le bloc, une copie de celui-ci sera ajout\u00e9e au message ;<br \/>\n<em>taille<\/em> \u2014 la taille des donn\u00e9es ;<br \/>\n<em>pad<\/em> \u2014 un drapeau indiquant que la taille de la m\u00e9moire allou\u00e9e doit \u00eatre arrondie \u00e0 la fronti\u00e8re de 4 octets (le remplissage sera effectu\u00e9 avec des z\u00e9ros). <\/p>\n<p><\/p>\n<p>Si le tampon de donn\u00e9es du message existe a suffisamment d'espace, alors les nouvelles donn\u00e9es seront coll\u00e9es apr\u00e8s les donn\u00e9es d\u00e9j\u00e0 pr\u00e9sentes. Si l'espace libre dans le tampon de donn\u00e9es du message est inf\u00e9rieur \u00e0 <em>taille<\/em>, un nouveau message est cr\u00e9\u00e9 avec une taille de tampon ad\u00e9quate, et les donn\u00e9es sont copi\u00e9es dans son tampon. Ce nouveau message est attach\u00e9 \u00e0 l'original \u00e0 l'aide d'un pointeur <em>b_cont<\/em>. Dans ce cas, le message se transforme en un tuple. <\/p>\n<p><\/p>\n<p>Si un autre bloc de donn\u00e9es doit \u00eatre ajout\u00e9 au tuple, il faut utiliser la fonction :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgappend(mblk_t *mp, const char *data, int size, bool_t pad);<\/code><\/pre>\n<p><\/p>\n<p>elle recherchera le dernier message dans le tuple (il aura une valeur nulle) et appellera la fonction <em>b_cont<\/em> appendb() <em>Pour conna\u00eetre la taille des donn\u00e9es dans un message ou un tuple, on peut utiliser la fonction :<\/em>.<\/p>\n<p><\/p>\n<p>int msgdsize(const mblk_t *mp);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">elle parcourra tous les messages du tuple et renverra la quantit\u00e9 totale de donn\u00e9es dans les tampons de donn\u00e9es de ces messages. Pour chaque message, la quantit\u00e9 de donn\u00e9es est calcul\u00e9e ainsi :<\/code><\/pre>\n<p><\/p>\n<p>mp-&gt;b_wptr - mp-&gt;b_rptr<\/p>\n<p><\/p>\n<pre><code class=\"cpp\"> Pour fusionner deux tuples, on utilise la fonction :<\/code><\/pre>\n<p><\/p>\n<p>mblk_t *concatb(mblk_t *mp, mblk_t *newm);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">elle attachera le tuple<\/code><\/pre>\n<p><\/p>\n<p>newm <em>\u00e0 la fin du tuple<\/em> et renverra un pointeur vers le dernier message du tuple r\u00e9sultant. <em>mp<\/em> Si n\u00e9cessaire, un tuple peut \u00eatre transform\u00e9 en un seul message avec un bloc de donn\u00e9es unifi\u00e9, cela se fait par la fonction :<\/p>\n<p><\/p>\n<p>void msgpullup(mblk_t *mp,int len);<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">si l'argument<\/code><\/pre>\n<p><\/p>\n<p>est \u00e9gal \u00e0 -1, la taille du tampon allou\u00e9 est d\u00e9termin\u00e9e automatiquement. Si <em>len<\/em> si \u00e9gal \u00e0 -1, alors la taille du tampon de sortie est d\u00e9termin\u00e9e automatiquement. Si <em>len<\/em> S'il s'agit d'un nombre positif, un tampon de cette taille sera cr\u00e9\u00e9 et les donn\u00e9es des messages de tuple y seront copi\u00e9es. Si le tampon est plein, la copie sera interrompue. Le premier message du tuple obtiendra un tampon de nouvelle taille avec les donn\u00e9es copi\u00e9es. Les autres messages seront supprim\u00e9s et la m\u00e9moire sera restitu\u00e9e au tas.<\/p>\n<p><\/p>\n<p>Lors de la suppression de la structure <em>mblk_t<\/em> le compteur de r\u00e9f\u00e9rences du bloc de donn\u00e9es est pris en compte, si lors de l'appel <em>freeb()<\/em> il est \u00e9gal \u00e0 z\u00e9ro, alors le tampon de donn\u00e9es est supprim\u00e9 avec l'instance <em>mblk_t<\/em>, qui pointe vers lui.<\/p>\n<p><\/p>\n<p>Initialisation des champs d'un nouveau message :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void mblk_init(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Ajout d'une autre portion de donn\u00e9es au message : <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * appendb(mblk_t *mp, const char *data, size_t size, bool_t pad);<\/code><\/pre>\n<p><\/p>\n<p>Si les nouvelles donn\u00e9es ne tiennent pas dans l'espace libre du tampon de donn\u00e9es du message, un message s\u00e9par\u00e9 est attach\u00e9 avec un tampon de la taille n\u00e9cessaire (dans le premier message, un pointeur vers le message ajout\u00e9 est \u00e9tabli) et le message se transforme en tuple.<\/p>\n<p><\/p>\n<p>Ajout d'une portion de donn\u00e9es au tuple :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgappend(mblk_t *mp, const char *data, size_t size, bool_t pad); <\/code><\/pre>\n<p><\/p>\n<p>La fonction appelle appendb() dans une boucle.<\/p>\n<p><\/p>\n<p>Fusion de deux tuples en un :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">elle attachera le tuple<\/code><\/pre>\n<p><\/p>\n<p>Message <em>\u00e0 la fin du tuple<\/em> sera attach\u00e9 \u00e0 <em>mp<\/em>.<\/p>\n<p><\/p>\n<p>Cr\u00e9ation d'une copie d'un message unique :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copyb(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Copie compl\u00e8te d'un tuple avec tous les blocs de donn\u00e9es :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *copymsg(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Les \u00e9l\u00e9ments du tuple sont alors copi\u00e9s par la fonction <em>copyb()<\/em>.<\/p>\n<p><\/p>\n<p>Cr\u00e9ation d'une copie l\u00e9g\u00e8re d'un message. <em>mblk_t<\/em>Dans ce cas, le bloc de donn\u00e9es n'est pas copi\u00e9, mais son compteur de r\u00e9f\u00e9rences est augment\u00e9. <em>db_ref<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *dupb(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Cr\u00e9ation d'une copie l\u00e9g\u00e8re d'un tuple. Les blocs de donn\u00e9es ne sont pas copi\u00e9s, seuls leurs compteurs de r\u00e9f\u00e9rences sont augment\u00e9s. <em>db_ref<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *dupmsg(mblk_t* m);<\/code><\/pre>\n<p><\/p>\n<p>Collage de tous les messages du tuple en un seul message :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void msgpullup(mblk_t *mp,size_t len);<\/code><\/pre>\n<p><\/p>\n<p>Si l'argument <em>len<\/em> est \u00e9gal \u00e0 -1, la taille du tampon allou\u00e9 est d\u00e9termin\u00e9e automatiquement.<\/p>\n<p><\/p>\n<p>Suppression d'un message, d'un tuple :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void freemsg(mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Le compteur de r\u00e9f\u00e9rences du bloc de donn\u00e9es est diminu\u00e9 d'une unit\u00e9. S'il atteint z\u00e9ro, le bloc de donn\u00e9es est \u00e9galement supprim\u00e9.<\/p>\n<p><\/p>\n<p>Calcul du volume total de donn\u00e9es dans un message ou un tuple.<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">size_t msgdsize(const mblk_t *mp);<\/code><\/pre>\n<p><\/p>\n<p>Extraction d'un message de la fin de la file d'attente :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t *ms_queue_peek_last (q);<\/code><\/pre>\n<p><\/p>\n<p>Copie du contenu des champs r\u00e9serv\u00e9s d'un message dans un autre message (dans ces champs se trouvent en r\u00e9alit\u00e9 des drapeaux utilis\u00e9s par le lecteur multim\u00e9dia) :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_meta_copy(const mblk_t *source, mblk *dest);<\/code><\/pre>\n<p><\/p>\n<h3 id=\"ochered-queue_t\">File d'attente <em>queue_t<\/em><\/h3>\n<p><\/p>\n<p>La file de messages dans le m\u00e9diastreamer est r\u00e9alis\u00e9e sous la forme d'une liste doublement cha\u00een\u00e9e circulaire. Chaque \u00e9l\u00e9ment de la liste contient un pointeur vers un bloc de donn\u00e9es avec des \u00e9chantillons de signal. Cela signifie que seuls les pointeurs vers le bloc de donn\u00e9es sont d\u00e9plac\u00e9s s\u00e9quentiellement, tandis que les donn\u00e9es elles-m\u00eames restent immobiles. Autrement dit, seules les r\u00e9f\u00e9rences \u00e0 ces donn\u00e9es se d\u00e9placent.<br \/>\nStructure d\u00e9crivant la file <em>queue_t<\/em>, illustr\u00e9e ci-dessous :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _queue\n{\n   mblk_t _q_stopper; \/* \"\u00c9l\u00e9ment \"vide\" de la file d'attente, ne pointe pas vers des donn\u00e9es, utilis\u00e9 uniquement pour g\u00e9rer la file d'attente. Lors de l'initialisation de la file (qinit()), ses pointeurs sont r\u00e9gl\u00e9s pour pointer vers lui-m\u00eame. *\/\n   int q_mcount;        \/\/ Nombre d'\u00e9l\u00e9ments dans la file d'attente.\n} queue_t;<\/code><\/pre>\n<p><\/p>\n<p>La structure contient un champ \u2014 un pointeur <em>_q_stopper<\/em> de type *mblk_t, il pointe vers le premier \u00e9l\u00e9ment (message) de la file. Le deuxi\u00e8me champ de la structure est un compteur des messages pr\u00e9sents dans la file.<br \/>\nLa figure ci-dessous montre la file nomm\u00e9e q1, contenant 4 messages m1, m2, m3, m4.<br \/>\n<img decoding=\"async\" alt=\"Explorons le moteur VoIP Mediastreamer2. Partie 11\" src=\"\/wp-content\/uploads\/2020\/04\/07fc043861edf15e5eb40e49c8ec5e3e.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLa figure suivante montre la file nomm\u00e9e q1, contenant 4 messages m1, m2, m3, m4. Le message m2 est la t\u00eate du tuple, dans lequel sont int\u00e9gr\u00e9s deux autres messages m2_1 et m2_2.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Explorons le moteur VoIP Mediastreamer2. Partie 11\" src=\"\/wp-content\/uploads\/2020\/04\/8fa7667f3690674a2ee321b4a6c39e1d.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-ocheredyami-queue_t\">Fonctions de gestion des files d'attente queue_t<\/h3>\n<p><\/p>\n<p>L'initialisation de la file :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void qinit(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>Champ <em>_q_stopper<\/em> (appel\u00e9 ci-dessous \"stopper\") est initialis\u00e9 par la fonction <em>mblk_init()<\/em>, son pointeur d'\u00e9l\u00e9ment pr\u00e9c\u00e9dent et de l'\u00e9l\u00e9ment suivant est configur\u00e9 pour pointer vers lui-m\u00eame. Le compteur des \u00e9l\u00e9ments de la file est mis \u00e0 z\u00e9ro.<\/p>\n<p><\/p>\n<p>Ajout d'un nouvel \u00e9l\u00e9ment (message) :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void putq(queue_t *q, mblk_t *m);<\/code><\/pre>\n<p><\/p>\n<p>Un nouvel \u00e9l\u00e9ment <em>m<\/em> est ajout\u00e9 \u00e0 la fin de la liste, les pointeurs de l'\u00e9l\u00e9ment sont configur\u00e9s de sorte que le stopper devienne le suivant pour lui, et lui le pr\u00e9c\u00e9dent pour le stopper. Le compteur des \u00e9l\u00e9ments de la file est incr\u00e9ment\u00e9.<\/p>\n<p><\/p>\n<p>Extraction d'un \u00e9l\u00e9ment de la file :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * getq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>le message qui se trouve apr\u00e8s le stopper est extrait, le compteur des \u00e9l\u00e9ments est d\u00e9cr\u00e9ment\u00e9. Si la file ne contient pas d'\u00e9l\u00e9ments \u00e0 part le stopper, elle retourne 0.<\/p>\n<p><\/p>\n<p>Insertion d'un message dans la file :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void insq(queue_t *q, mblk_t *emp, mblk_t *mp); <\/code><\/pre>\n<p><\/p>\n<p>L'\u00e9l\u00e9ment <em>mp<\/em> est ins\u00e9r\u00e9 avant l'\u00e9l\u00e9ment <em>emp<\/em>. Si <em>emp<\/em>=0, alors le message est ajout\u00e9 \u00e0 la fin de la file.<\/p>\n<p><\/p>\n<p>Extraction du message de la t\u00eate de la file :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void remq(queue_t *q, mblk_t *mp); <\/code><\/pre>\n<p><\/p>\n<p>Le compteur des \u00e9l\u00e9ments est d\u00e9cr\u00e9ment\u00e9.<\/p>\n<p><\/p>\n<p>Lecture du pointeur vers le premier \u00e9l\u00e9ment de la file :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * peekq(queue_t *q); <\/code><\/pre>\n<p><\/p>\n<p>Suppression de tous les \u00e9l\u00e9ments de la file avec suppression des \u00e9l\u00e9ments eux-m\u00eames :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void flushq(queue_t *q, int how);<\/code><\/pre>\n<p><\/p>\n<p>Argument <em>how<\/em> n'est pas utilis\u00e9. Le compteur d'\u00e9l\u00e9ments de la file d'attente est r\u00e9gl\u00e9 \u00e0 z\u00e9ro.<\/p>\n<p><\/p>\n<p>Macro de lecture du pointeur vers le dernier \u00e9l\u00e9ment de la file d'attente :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">mblk_t * qlast(queue_t *q);<\/code><\/pre>\n<p><\/p>\n<p>Lors de l'utilisation des files d'attente de messages, il faut garder \u00e0 l'esprit que lors de l'appel de <em>ms_queue_put(q, m)<\/em> avec un pointeur nul pour le message, la fonction entre dans une boucle infinie. Votre programme sera bloqu\u00e9. De m\u00eame se comporte <em>ms_queue_next(q, m)<\/em>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-filtrov\">Connexion de filtres<\/h3>\n<p><\/p>\n<p>La file d'attente d\u00e9crite ci-dessus est utilis\u00e9e pour transmettre des messages d'un filtre \u00e0 un autre ou d'un \u00e0 plusieurs filtres. Les filtres et leurs connexions forment un graphique orient\u00e9. L'entr\u00e9e ou la sortie d'un filtre sera appel\u00e9e par le terme g\u00e9n\u00e9ral \"broche\". Pour d\u00e9crire l'ordre de connexion des filtres entre eux, le m\u00e9diastreamer utilise le concept de \"point de signal\". Un point de signal est une structure <em>_MSCPoint<\/em>, qui contient un pointeur vers le filtre et le num\u00e9ro de l'un de ses passes, d\u00e9crivant ainsi la connexion de l'une des entr\u00e9es ou sorties du filtre. <\/p>\n<p><\/p>\n<h4 id=\"signalnaya-tochka-grafa-obrabotki-dannyh\">Point de signalisation du graphe de traitement de donn\u00e9es<\/h4>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _MSCPoint{\nstruct _MSFilter *filter; \/\/ Pointeur vers le filtre du m\u00e9diastreamer.\nint pin;                        \/\/ Num\u00e9ro de l'une des entr\u00e9es ou sorties du filtre, c'est-\u00e0-dire passe.\n} MSCPoint;\n<\/code><\/pre>\n<p><\/p>\n<p>Les passes des filtres sont num\u00e9rot\u00e9es \u00e0 partir de z\u00e9ro. <\/p>\n<p><\/p>\n<p>La connexion de deux passes par une file d'attente de messages est d\u00e9crite par la structure <em>_MSQueue<\/em>, qui contient la file d'attente de messages et des pointeurs vers deux points de signal qu'elle connecte :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">typedef struct _MSQueue\n{\nqueue_t q;\nMSCPoint prev;\nMSCPoint next;\n}MSQueue;\n<\/code><\/pre>\n<p><\/p>\n<p>Appelons cette structure un lien de signal. Chaque filtre du m\u00e9diastreamer contient une table de liens d'entr\u00e9e et une table de liens de sortie (<em>MSQueue<\/em>). La taille des tables est d\u00e9finie lors de la cr\u00e9ation du filtre, ce que nous avons d\u00e9j\u00e0 fait \u00e0 l'aide de la variable export\u00e9e de type <em>MSFilterDesc<\/em>, lors de la cr\u00e9ation de notre propre filtre. Ci-dessous est montr\u00e9e la structure d\u00e9crivant n'importe quel filtre dans le m\u00e9diastreamer, <em>MSFilter<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">\nstruct _MSFilter{\n    MSFilterDesc *desc;    \n    \/* Pointeur vers le descripteur du filtre. *\/\n    \/* Attributs prot\u00e9g\u00e9s, ils ne peuvent pas \u00eatre d\u00e9plac\u00e9s ou supprim\u00e9s sans perturber le fonctionnement des plugins. *\/\n    ms_mutex_t lock;      \/* S\u00e9maphore. *\/\n    MSQueue **inputs;     \/* Table des liens d'entr\u00e9e. *\/\n    MSQueue **outputs;    \/* Table des liens de sortie. *\/\n    struct _MSFactory *factory; \/* Pointeur vers la fabrique qui a cr\u00e9\u00e9 cette instance du filtre. *\/\n    void *padding;              \/* Non utilis\u00e9, sera activ\u00e9 si des champs prot\u00e9g\u00e9s sont ajout\u00e9s. *\/\n    void *data;                 \/* Pointeur vers une structure arbitraire pour stocker les donn\u00e9es d'\u00e9tat interne du filtre et les calculs interm\u00e9diaires. *\/\n    struct _MSTicker *ticker;   \/* Pointeur vers l'objet ticker, qui ne doit pas \u00eatre nul lors de l'appel de la fonction process(). *\/\n    \/* Attributs priv\u00e9s, ils peuvent \u00eatre d\u00e9plac\u00e9s et modifi\u00e9s \u00e0 tout moment *\/\n    MSList *notify_callbacks; \/* Liste des rappels utilis\u00e9s pour traiter les \u00e9v\u00e9nements du filtre. *\/\n    uint32_t last_tick;       \/* Num\u00e9ro du dernier tick, lorsque l'appel process() a \u00e9t\u00e9 ex\u00e9cut\u00e9. *\/\n    MSFilterStats *stats;     \/* Statistiques de l'ex\u00e9cution du filtre. *\/\n    int postponed_task; \/* Nombre de t\u00e2ches report\u00e9es. Certains filtres peuvent reporter le traitement des donn\u00e9es (appel process()) pendant plusieurs ticks. *\/\n    bool_t seen;  \/* Drapeau que le ticker utilise pour marquer que cette instance du filtre a d\u00e9j\u00e0 \u00e9t\u00e9 trait\u00e9e lors de ce tick. *\/\n};\ntypedef struct _MSFilter MSFilter;\n<\/code><\/pre>\n<p><\/p>\n<p>Apr\u00e8s avoir connect\u00e9 les filtres dans notre programme C selon notre conception (mais sans connecter le ticker), nous avons ainsi cr\u00e9\u00e9 un graphe dirig\u00e9, dont les n\u0153uds sont des instances de la structure <em>MSFilter<\/em>, et les ar\u00eates sont des instances de liens <em>MSQueue<\/em>. <\/p>\n<p><\/p>\n<h3 id=\"zakulisnaya-deyatelnost-tikera\">Activit\u00e9 en coulisse du ticker<\/h3>\n<p><\/p>\n<p>Quand je vous ai dit que le ticker est un filtre source de ticks, ce n'\u00e9tait pas toute la v\u00e9rit\u00e9 \u00e0 son sujet. Le ticker est un objet qui ex\u00e9cute des fonctions selon une horloge <em>process()<\/em> de tous les filtres du sch\u00e9ma (graphique) auquel il est connect\u00e9. Lorsque nous connectons un ticker \u00e0 un filtre du graphique dans un programme C, nous montrons au ticker le graphique qu'il va g\u00e9rer \u00e0 partir de ce moment jusqu'\u00e0 ce que nous le d\u00e9connectons. Une fois connect\u00e9, le ticker commence \u00e0 examiner le graphique qui lui est confi\u00e9, en dressant une liste des filtres qui en font partie. Pour ne pas \"compter\" le m\u00eame filtre deux fois, il marque les filtres d\u00e9couverts en y d\u00e9finissant un drapeau. <em>seen<\/em>. La recherche se fait \u00e0 travers les tables de liens, qui existent pour chaque filtre. <\/p>\n<p><\/p>\n<p>Lors de sa visite d'introduction au graphique, le ticker v\u00e9rifie s'il existe parmi les filtres, au moins un qui joue le r\u00f4le de source de blocs de donn\u00e9es. Si aucun n'est trouv\u00e9, le graphique est consid\u00e9r\u00e9 comme incorrect et le ticker s'arr\u00eate d'urgence.<\/p>\n<p><\/p>\n<p>Si le graphique est \"correct\", pour chaque filtre trouv\u00e9, la fonction d'initialisation est appel\u00e9e <em>preprocess()<\/em>. D\u00e8s qu'il est temps pour le prochain cycle de traitement (par d\u00e9faut toutes les 10 millisecondes), le ticker appelle la fonction. <em>process()<\/em> pour tous les filtres sources pr\u00e9c\u00e9demment trouv\u00e9s, puis pour les autres filtres de la liste. Si un filtre a des liens d'entr\u00e9e, le lancement de la fonction. <em>process()<\/em> jusqu'\u00e0 ce que les files d'attente des liens d'entr\u00e9e soient vides. Apr\u00e8s cela, il passe au filtre suivant de la liste et \"fait d\u00e9filer\" jusqu'\u00e0 ce que les liens d'entr\u00e9e soient lib\u00e9r\u00e9s des messages. Le ticker passe d'un filtre \u00e0 l'autre jusqu'\u00e0 ce que la liste soit termin\u00e9e. C'est ainsi que le traitement de l'\u00e9tape se termine. <\/p>\n<p><\/p>\n<p>Revenons maintenant aux tuples et parlons de l'ajout d'une telle entit\u00e9 dans le m\u00e9diastreamer. De mani\u00e8re g\u00e9n\u00e9rale, le volume de donn\u00e9es n\u00e9cessaire \u00e0 l'algorithme fonctionnant \u00e0 l'int\u00e9rieur du filtre ne correspond pas et n'est pas un multiple \u00e0 la taille des buffers de donn\u00e9es entrant. Par exemple, nous \u00e9crivons un filtre qui effectue une transformation de Fourier rapide, qui par d\u00e9finition ne peut traiter que des blocs de donn\u00e9es dont la taille est \u00e9gale \u00e0 une puissance de deux. Supposons qu'il s'agisse de 512 \u00e9chantillons. Si les donn\u00e9es sont g\u00e9n\u00e9r\u00e9es par un canal t\u00e9l\u00e9phonique, alors le buffer de donn\u00e9es de chaque message \u00e0 l'entr\u00e9e fournira 160 \u00e9chantillons du signal. Il est tentant de ne pas retirer les donn\u00e9es de l'entr\u00e9e tant qu'il n'y a pas un nombre suffisant de donn\u00e9es. Mais dans ce cas, il y aura un conflit avec le ticker, qui tentera sans succ\u00e8s de faire d\u00e9filer le filtre jusqu'\u00e0 ce que le lien d'entr\u00e9e soit vid\u00e9. Nous avons d\u00e9j\u00e0 d\u00e9sign\u00e9 cette r\u00e8gle comme le troisi\u00e8me principe de fonctionnement du filtre. Conform\u00e9ment \u00e0 ce principe, la fonction process() du filtre doit retirer toutes les donn\u00e9es des files d'attente d'entr\u00e9e.<\/p>\n<p><\/p>\n<p>De plus, il ne sera pas possible de r\u00e9cup\u00e9rer seulement 512 \u00e9chantillons \u00e0 partir de l'entr\u00e9e, car il faut r\u00e9cup\u00e9rer des blocs complets, c'est-\u00e0-dire que le filtre devra r\u00e9cup\u00e9rer 640 \u00e9chantillons et en utiliser 512, laissant le reste pour accumuler de nouvelles donn\u00e9es. Ainsi, notre filtre, en plus de son fonctionnement principal, doit assurer des actions auxiliaires pour le stockage temporaire des donn\u00e9es d'entr\u00e9e. Les d\u00e9veloppeurs du m\u00e9diastreamer ont con\u00e7u un objet sp\u00e9cial pour r\u00e9soudre cette t\u00e2che commune : le MSBufferizer, qui s'occupe de cette t\u00e2che \u00e0 l'aide de tuples. <\/p>\n<p><\/p>\n<h3 id=\"buferizator-msbufferizer\">Mise en m\u00e9moire tampon (MSBufferizer)<\/h3>\n<p><\/p>\n<p>C'est un objet qui va accumuler les donn\u00e9es d'entr\u00e9e \u00e0 l'int\u00e9rieur du filtre et commencera \u00e0 les traiter d\u00e8s que la quantit\u00e9 d'informations sera suffisante pour ex\u00e9cuter l'algorithme du filtre. Tant que le buffer accumule les donn\u00e9es, le filtre fonctionnera en mode idling, sans utiliser la puissance de calcul du processeur. Mais d\u00e8s que la fonction de lecture du buffer renvoie une valeur diff\u00e9rente de z\u00e9ro, la fonction process() du filtre commence \u00e0 r\u00e9cup\u00e9rer et traiter les donn\u00e9es du buffer par portions de la taille n\u00e9cessaire, jusqu'\u00e0 \u00e9puisement.<br \/>\nLes donn\u00e9es non encore utilis\u00e9es restent dans le buffer comme le premier \u00e9l\u00e9ment du tuple, auquel s'accrochent les blocs suivants de donn\u00e9es d'entr\u00e9e. <\/p>\n<p><\/p>\n<p>La structure qui d\u00e9crit le buffer : <\/p>\n<p><\/p>\n<pre><code class=\"cpp\">struct _MSBufferizer{\nqueue_t q; \/* File de messages. *\/\nint size; \/* Taille totale des donn\u00e9es actuellement dans le buffer. *\/\n};\ntypedef struct _MSBufferizer MSBufferizer;<\/code><\/pre>\n<p><\/p>\n<h3 id=\"funkcii-raboty-s-msbufferizer\">Fonctions de gestion du MSBufferizer<\/h3>\n<p><\/p>\n<p>Cr\u00e9ation d'une nouvelle instance du buffer :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">MSBufferizer * ms_bufferizer_new(void);<\/code><\/pre>\n<p><\/p>\n<p>La m\u00e9moire est allou\u00e9e, initialis\u00e9e dans <em>ms_bufferizer_init()<\/em> et un pointeur est retourn\u00e9.<\/p>\n<p><\/p>\n<p>Fonction d'initialisation :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_init(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>La file <em>q<\/em>, champ <em>taille<\/em> est initialis\u00e9e \u00e0 z\u00e9ro.<\/p>\n<p><\/p>\n<p>Ajout d'un message :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m); <\/code><\/pre>\n<p><\/p>\n<p>Le message m est ajout\u00e9 \u00e0 la file. La taille calcul\u00e9e des blocs de donn\u00e9es est ajout\u00e9e \u00e0 <em>taille<\/em>.<\/p>\n<p><\/p>\n<p>Translation of all messages from the data link queue to the buffer <em>q<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q);   <\/code><\/pre>\n<p><\/p>\n<p>Le transfert des messages du lien <em>q<\/em> au buffer se fait \u00e0 l'aide de la fonction <em>ms_bufferizer_put()<\/em>.<\/p>\n<p><\/p>\n<p>Lecture \u00e0 partir du buffer :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen); <\/code><\/pre>\n<p><\/p>\n<p>Si la taille des donn\u00e9es accumul\u00e9es dans le buffer est inf\u00e9rieure \u00e0 celle demand\u00e9e (<em>datalen<\/em>), la fonction renvoie z\u00e9ro, la copie des donn\u00e9es dans data n'est pas effectu\u00e9e. Sinon, une copie s\u00e9quentielle des donn\u00e9es \u00e0 partir des tuples dans le tampon s'effectue. Apr\u00e8s la copie, le tuple est supprim\u00e9 et la m\u00e9moire est lib\u00e9r\u00e9e. La copie s'ach\u00e8ve d\u00e8s que datalen octets ont \u00e9t\u00e9 copi\u00e9s. Si l'espace se termine au milieu d'un bloc de donn\u00e9es, alors dans ce message, le bloc de donn\u00e9es sera raccourci \u00e0 la partie restante non copi\u00e9e. Lors du prochain appel, la copie se poursuivra \u00e0 partir de cet endroit.<\/p>\n<p><\/p>\n<p>Lecture de la quantit\u00e9 de donn\u00e9es actuellement disponibles dans le tampon :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">int ms_bufferizer_get_avail(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Renvoie le champ <em>taille<\/em> du tampon.<\/p>\n<p><\/p>\n<p>\u00c9limination d'une partie des donn\u00e9es pr\u00e9sentes dans le tampon :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);<\/code><\/pre>\n<p><\/p>\n<p>Le nombre d'octets de donn\u00e9es sp\u00e9cifi\u00e9 est extrait et \u00e9limin\u00e9. Les donn\u00e9es les plus anciennes sont \u00e9limin\u00e9es.<\/p>\n<p><\/p>\n<p>Suppression de tous les messages pr\u00e9sents dans le tampon :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_flush(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>Le compteur de donn\u00e9es est r\u00e9initialis\u00e9 \u00e0 z\u00e9ro.<\/p>\n<p><\/p>\n<p>Suppression de tous les messages pr\u00e9sents dans le tampon :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_uninit(MSBufferizer *obj); <\/code><\/pre>\n<p><\/p>\n<p>La r\u00e9initialisation du compteur n'est pas effectu\u00e9e.<\/p>\n<p><\/p>\n<p>Suppression du tampon et lib\u00e9ration de la m\u00e9moire :<\/p>\n<p><\/p>\n<pre><code class=\"cpp\">void ms_bufferizer_destroy(MSBufferizer *obj);  <\/code><\/pre>\n<p><\/p>\n<p>Des exemples d'utilisation du tampon peuvent \u00eatre trouv\u00e9s dans le code source de plusieurs filtres du m\u00e9diastreamer. Par exemple, dans le filtre MS_L16_ENC, qui effectue une permutation des octets dans les \u00e9chantillons de l'ordre r\u00e9seau vers l'ordre h\u00f4te :<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/BelledonneCommunications\/mediastreamer2\/blob\/1a9e8dec369a65ed10db975f5b77b92dc999b096\/src\/audiofilters\/l16.c\"> l16.c<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Dans le prochain article, nous traiterons de l'\u00e9valuation de la charge sur le tickeur et des moyens de lutter contre une charge de calcul excessive dans le mediastreamer.<\/p>\n<p>Source : <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/499010\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430. \u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0411\u043b\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 dblk_t \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 mblk_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 mblk_t \u041e\u0447\u0435\u0440\u0435\u0434\u044c queue_t \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u044f\u043c\u0438 queue_t \u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0421\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0433\u0440\u0430\u0444\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0417\u0430\u043a\u0443\u043b\u0438\u0441\u043d\u0430\u044f \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0438\u043a\u0435\u0440\u0430 \u0411\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0442\u043e\u0440 (MSBufferizer) \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 MSBufferizer \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440. \u042d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u044b \u043f\u043e\u0441\u0432\u0435\u0442\u0438\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79541,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79540","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0418\u0437\u0443\u0447\u0430\u0435\u043c VoIP-\u0434\u0432\u0438\u0436\u043e\u043a Mediastreamer2. \u0427\u0430\u0441\u0442\u044c 11 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-04-28T05:42:01+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-04-28T05:42:01+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47D\u00e9couvrez le moteur VoIP Mediastreamer2. Partie 11 | ProHoster","description":"Le contenu de cet article est tir\u00e9 de mon canal Zen.","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0418\u0437\u0443\u0447\u0430\u0435\u043c VoIP-\u0434\u0432\u0438\u0436\u043e\u043a Mediastreamer2. \u0427\u0430\u0441\u0442\u044c 11 | ProHoster","og:description":"\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0437\u044f\u0442 \u0441 \u043c\u043e\u0435\u0433\u043e \u0434\u0437\u0435\u043d-\u043a\u0430\u043d\u0430\u043b\u0430.","og:url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/izuchaem-voip-dvizhok-mediastreamer2-chast-11","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-04-28T05:42:01+00:00","article:modified_time":"2020-04-28T05:42:01+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79540","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 12:40:33","updated":"2022-10-06 16:26:59","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/79540","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=79540"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/79540\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/79541"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=79540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=79540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=79540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}