Menjelajahi mesin VoIP Mediastreamer2. Bagian 11

Materi artikel diambil dari saya saluran Zen.

Menjelajahi mesin VoIP Mediastreamer2. Bagian 11

Mekanisme perpindahan data

  • Blok data dblk_t
  • Pesan mblk_t
  • Fungsi untuk bekerja dengan pesan mblk_t
  • Antrian antrian_t
  • Fungsi untuk bekerja dengan antrian queue_t
  • Menghubungkan filter
  • Titik sinyal grafik pemrosesan data
  • Aktivitas di balik layar ticker
  • Penyangga (MSBufferizer)
  • Fungsi untuk bekerja dengan MSBufferizer

Terakhir Artikel kami telah mengembangkan filter kami sendiri. Artikel ini akan fokus pada mekanisme internal untuk memindahkan data antar filter media streamer. Ini akan memungkinkan Anda menulis filter canggih dengan sedikit usaha di masa depan.

Mekanisme perpindahan data

Pergerakan data di media streamer dilakukan menggunakan antrian yang dijelaskan oleh struktur antrian_t. Rangkaian pesan seperti mblk_t, yang tidak berisi data sinyal, tetapi hanya link ke pesan sebelumnya, pesan berikutnya, dan ke blok data. Selain itu, saya ingin menekankan secara khusus bahwa ada juga bidang untuk tautan ke pesan dengan jenis yang sama, yang memungkinkan Anda mengatur daftar pesan tertaut tunggal. Kami akan menyebut sekelompok pesan yang disatukan oleh daftar seperti itu sebagai tuple. Dengan demikian, setiap elemen antrian dapat menjadi satu pesan mblk_t, dan mungkin kepala tupel pesan mblk_t. Setiap pesan tupel dapat memiliki blok data lingkungannya sendiri. Kita akan membahas mengapa tupel diperlukan nanti.

Seperti disebutkan di atas, pesan itu sendiri tidak berisi blok data; melainkan hanya berisi penunjuk ke area memori tempat blok tersebut disimpan. Pada bagian ini, gambaran keseluruhan pekerjaan media streamer mengingatkan pada pintu gudang dalam kartun “Monsters, Inc.,” di mana pintu (tautan ke ruang data) bergerak dengan kecepatan gila di sepanjang konveyor di atas, sedangkan ruangan itu sendiri tetap tidak bergerak.

Sekarang, menelusuri hierarki dari bawah ke atas, mari kita pertimbangkan secara rinci entitas yang terdaftar dari mekanisme transmisi data di media streamer.

Blok data dblk_t

Blok data terdiri dari header dan buffer data. Header dijelaskan oleh struktur berikut,

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

Bidang struktur berisi penunjuk ke awal buffer, akhir buffer, dan fungsi untuk menghapus buffer data. Elemen terakhir di header db_ref — penghitung referensi, jika mencapai nol, ini berfungsi sebagai sinyal untuk menghapus blok ini dari memori. Jika blok data dibuat oleh fungsi datab_alloc() , maka buffer data akan ditempatkan di memori segera setelah header. Dalam kasus lainnya, buffer dapat ditempatkan di suatu tempat secara terpisah. Buffer data akan berisi sampel sinyal atau data lain yang ingin kita proses dengan filter.

Sebuah contoh baru dari blok data dibuat menggunakan fungsi:

dblk_t *datab_alloc(int size);

Sebagai parameter masukan, diberikan ukuran data yang akan disimpan oleh blok. Lebih banyak memori dialokasikan untuk menempatkan header - struktur - di awal memori yang dialokasikan datab. Namun saat menggunakan fungsi lain, hal ini tidak selalu terjadi, dalam beberapa kasus, buffer data mungkin ditempatkan terpisah dari header blok data. Saat membuat struktur, bidang dikonfigurasikan sehingga bidangnya db_base menunjuk ke awal area data, dan db_lim sampai akhir. Jumlah tautan db_ref diatur ke satu. Penunjuk fungsi penghapusan data diatur ke nol.

Pesan mblk_t

Seperti yang dinyatakan, elemen antrian bertipe mblk_t, itu didefinisikan sebagai berikut:

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;

Struktur mblk_t berisi petunjuk di awal b_sebelumnya, b_selanjutnya, yang diperlukan untuk mengatur daftar tertaut ganda (yang merupakan antrian antrian_t).

Lalu muncul penunjuknya b_lanjutan, yang hanya digunakan jika pesan merupakan bagian dari tupel. Untuk pesan terakhir dalam tupel, penunjuk ini tetap nol.

Selanjutnya kita melihat penunjuk ke blok data b_datap, yang pesannya ada. Hal ini diikuti oleh pointer ke area di dalam buffer data blok. Bidang b_rptr menentukan lokasi dari mana data dari buffer akan dibaca. Bidang b_wptr menunjukkan lokasi dari mana penulisan ke buffer akan dilakukan.

Bidang lainnya bersifat layanan dan tidak berhubungan dengan pengoperasian mekanisme transfer data.

Di bawah ini adalah satu pesan dengan nama m1 dan blok data d1.
Menjelajahi mesin VoIP Mediastreamer2. Bagian 11
Gambar berikut menunjukkan rangkaian tiga pesan m1, m1_1, m1_2.
Menjelajahi mesin VoIP Mediastreamer2. Bagian 11

Fungsi perpesanan mblk_t

Sebuah pesan baru mblk_t dibuat oleh fungsi:

mblk_t *allocb(int size, int pri); 

dia menempatkan pesan baru di memori mblk_t dengan blok data dengan ukuran tertentu ukuran, argumen kedua - pri tidak digunakan dalam versi perpustakaan ini. Ini harus tetap nol. Selama pengoperasian fungsi, memori akan dialokasikan untuk struktur pesan baru dan fungsi tersebut akan dipanggil mblk_init(), yang akan mengatur ulang semua bidang dari contoh struktur yang dibuat dan kemudian, menggunakan yang disebutkan di atas datab_alloc(), akan membuat buffer data. Setelah itu bidang dalam struktur akan dikonfigurasi:

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

Pada output kami menerima pesan baru dengan bidang yang diinisialisasi dan buffer data kosong. Untuk menambahkan data ke pesan, Anda perlu menyalinnya ke buffer blok data:

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

dimana data adalah penunjuk ke sumber data, dan ukuran - ukurannya.
maka Anda perlu memperbarui penunjuk ke titik tulis agar menunjuk lagi ke awal area bebas di buffer:

msg->b_wptr = msg->b_wptr + size

Jika Anda perlu membuat pesan dari buffer yang ada, tanpa menyalin, gunakan fungsi:

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

Fungsi tersebut, setelah membuat pesan dan struktur blok data, akan mengonfigurasi penunjuknya ke data di alamat tersebut buf. Itu. dalam hal ini, buffer data tidak terletak setelah bidang header blok data, seperti halnya saat membuat blok data dengan fungsi datab_alloc(). Buffer dengan data yang diteruskan ke fungsi akan tetap di tempatnya, tetapi dengan bantuan pointer, buffer tersebut akan dilampirkan ke header blok data yang baru dibuat, dan karenanya, ke pesan.

Untuk satu pesan mblk_t Beberapa blok data dapat digabungkan secara berurutan. Hal ini dilakukan oleh fungsi:

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

mp — pesan yang akan ditambahkan blok data lain;
data — penunjuk ke blok, salinannya akan ditambahkan ke pesan;
ukuran — ukuran data;
bantalan — sebuah tanda bahwa ukuran memori yang dialokasikan harus disejajarkan sepanjang batas 4-byte (padding akan dilakukan dengan nol).

Jika terdapat cukup ruang pada buffer data pesan yang ada, maka data baru akan ditempelkan di belakang data yang sudah ada. Jika ada lebih sedikit ruang kosong di buffer data pesan daripada ukuran, kemudian pesan baru dibuat dengan ukuran buffer yang memadai dan data disalin ke buffernya. Ini adalah pesan baru, ditautkan ke pesan asli menggunakan penunjuk b_lanjutan. Dalam hal ini, pesan berubah menjadi tupel.

Jika Anda perlu menambahkan blok data lain ke tupel, Anda perlu menggunakan fungsi:

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

dia akan menemukan pesan terakhir di tuple (dia punya b_lanjutan akan menjadi nol) dan akan memanggil fungsi untuk pesan ini lampiran().

Anda dapat mengetahui ukuran data dalam pesan atau tupel menggunakan fungsi:

int msgdsize(const mblk_t *mp);

itu akan mengulang semua pesan di tuple dan mengembalikan jumlah total data di buffer data pesan tersebut. Untuk setiap pesan, jumlah data dihitung sebagai berikut:

 mp->b_wptr - mp->b_rptr

Untuk menggabungkan dua tupel, gunakan fungsi:

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

dia menambahkan Tuple baru ke ekor tupel mp dan mengembalikan pointer ke pesan terakhir dari tupel yang dihasilkan.

Jika perlu, sebuah tupel dapat diubah menjadi satu pesan dengan satu blok data; hal ini dilakukan dengan fungsi:

void msgpullup(mblk_t *mp,int len);

jika argumen len adalah -1, maka ukuran buffer yang dialokasikan ditentukan secara otomatis. Jika len adalah bilangan positif, buffer sebesar ini akan dibuat dan data pesan tuple akan disalin ke dalamnya. Jika buffer habis, penyalinan akan berhenti di situ. Pesan pertama dari Tuple akan menerima buffer ukuran baru dengan data yang disalin. Pesan yang tersisa akan dihapus dan memori dikembalikan ke heap.

Saat menghapus struktur mblk_t jumlah referensi blok data diperhitungkan jika, saat menelepon gratis() ternyata nol, maka buffer data dihapus bersama dengan instance mblk_t, yang menunjuk ke sana.

Menginisialisasi bidang pesan baru:

void mblk_init(mblk_t *mp);

Menambahkan bagian data lain ke pesan:

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

Jika data baru tidak sesuai dengan ruang kosong buffer data pesan, maka pesan yang dibuat secara terpisah dengan buffer dengan ukuran yang diperlukan dilampirkan ke pesan (penunjuk ke pesan yang ditambahkan diatur di pesan pertama) dan pesan berubah menjadi Tuple.

Menambahkan sepotong data ke Tuple:

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

Fungsi ini memanggil appendb() dalam satu lingkaran.

Menggabungkan dua tupel menjadi satu:

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

Pesan baru akan dilampirkan mp.

Membuat salinan satu pesan:

mblk_t *copyb(const mblk_t *mp);

Selesaikan penyalinan Tuple dengan semua blok data:

mblk_t *copymsg(const mblk_t *mp);

Elemen tuple disalin oleh fungsinya salinanb().

Buat salinan pesan dengan mudah mblk_t. Dalam hal ini, blok data tidak disalin, tetapi penghitung referensinya diperbesar db_ref:

mblk_t *dupb(mblk_t *mp);

Membuat salinan tupel yang ringan. Blok data tidak disalin, hanya penghitung referensinya yang bertambah db_ref:

mblk_t *dupmsg(mblk_t* m);

Merekatkan semua pesan Tuple menjadi satu pesan:

void msgpullup(mblk_t *mp,size_t len);

Jika argumen len adalah -1, maka ukuran buffer yang dialokasikan ditentukan secara otomatis.

Menghapus pesan, tuple:

void freemsg(mblk_t *mp);

Jumlah referensi blok data dikurangi satu. Jika mencapai nol, blok data juga terhapus.

Perhitungan jumlah total data dalam pesan atau tuple.

size_t msgdsize(const mblk_t *mp);

Mengambil pesan dari bagian ekor antrian:

mblk_t *ms_queue_peek_last (q);

Menyalin konten bidang yang dicadangkan dari satu pesan ke pesan lain (sebenarnya, bidang ini berisi tanda yang digunakan oleh media streamer):

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

Antrian antrian_t

Antrean pesan di media streamer diimplementasikan sebagai daftar tertaut ganda melingkar. Setiap elemen daftar berisi penunjuk ke blok data dengan sampel sinyal. Ternyata hanya penunjuk ke blok data yang bergerak secara bergantian, sedangkan datanya sendiri tetap tidak bergerak. Itu. hanya tautan ke sana yang dipindahkan.
Struktur yang menggambarkan antrian antrian_t, ditunjukkan di bawah ini:

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

Strukturnya berisi bidang - penunjuk _q_penghenti ketik *mblk_t, ini menunjuk ke elemen pertama (pesan) dalam antrian. Bidang kedua dari struktur ini adalah penghitung pesan dalam antrian.
Gambar di bawah menunjukkan antrian bernama q1 yang berisi 4 pesan m1, m2, m3, m4.
Menjelajahi mesin VoIP Mediastreamer2. Bagian 11
Gambar berikut menunjukkan antrian bernama q1 yang berisi 4 pesan m1,m2,m3,m4. Pesan m2 adalah kepala tupel yang berisi dua pesan lagi m2_1 dan m2_2.

Menjelajahi mesin VoIP Mediastreamer2. Bagian 11

Fungsi untuk bekerja dengan antrian queue_t

Inisialisasi antrian:

void qinit(queue_t *q);

Lapangan _q_penghenti (selanjutnya kita akan menyebutnya “stopper”) diinisialisasi oleh fungsinya mblk_init(), elemen sebelumnya dan penunjuk elemen berikutnya disesuaikan agar menunjuk ke dirinya sendiri. Penghitung elemen antrian direset ke nol.

Menambahkan elemen baru (pesan):

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

Elemen baru m ditambahkan ke akhir daftar, penunjuk elemen disesuaikan sehingga penghenti menjadi elemen berikutnya, dan menjadi elemen sebelumnya untuk penghenti. Penghitung elemen antrian bertambah.

Mengambil elemen dari antrian:

mblk_t * getq(queue_t *q); 

Pesan yang muncul setelah stopper diambil, dan penghitung elemen dikurangi. Jika tidak ada elemen dalam antrian kecuali stopper, maka 0 dikembalikan.

Memasukkan pesan ke dalam antrian:

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

Elemen mp disisipkan sebelum elemen emp. Jika emp=0, maka pesan ditambahkan ke bagian ekor antrian.

Mengambil pesan dari kepala antrian:

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

Penghitung elemen dikurangi.

Membaca pointer ke elemen pertama dalam antrian:

mblk_t * peekq(queue_t *q); 

Menghapus semua elemen dari antrian sambil menghapus elemen itu sendiri:

void flushq(queue_t *q, int how);

Argumen bagaimana tidak digunakan. Penghitung elemen antrian diatur ke nol.

Makro untuk membaca pointer ke elemen terakhir antrian:

mblk_t * qlast(queue_t *q);

Saat bekerja dengan antrian pesan, berhati-hatilah saat Anda menelepon ms_queue_put(q,m) dengan penunjuk nol ke pesan, fungsi tersebut berulang. Program Anda akan terhenti. berperilaku serupa ms_queue_next(q,m).

Menghubungkan filter

Antrian yang dijelaskan di atas digunakan untuk meneruskan pesan dari satu filter ke filter lainnya atau dari satu filter ke beberapa filter. Filter dan hubungannya membentuk grafik berarah. Input atau output dari filter akan disebut dengan kata umum “pin”. Untuk menggambarkan urutan filter yang terhubung satu sama lain, media streamer menggunakan konsep “titik sinyal”. Titik sinyal adalah struktur _MSCPoint, yang berisi penunjuk ke filter dan nomor salah satu pinnya; oleh karena itu, ini menjelaskan koneksi salah satu input atau output filter.

Titik sinyal grafik pemrosesan data

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

Pin filter diberi nomor mulai dari nol.

Koneksi dua pin dengan antrian pesan dijelaskan oleh struktur _MSAntrian, yang berisi antrian pesan dan penunjuk ke dua titik sinyal yang dihubungkannya:

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

Kami akan menyebut struktur ini sebagai tautan sinyal. Setiap filter media streamer berisi tabel tautan masukan dan tabel tautan keluaran (MSQueue). Ukuran tabel diatur saat membuat filter; kita telah melakukan ini menggunakan tipe variabel yang diekspor MSFilterDesc, saat kami mengembangkan filter kami sendiri. Di bawah ini adalah struktur yang menjelaskan filter apa pun di media streamer, 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;

Setelah kami menghubungkan filter dalam program C sesuai dengan rencana kami (tetapi tidak menghubungkan ticker), kami membuat grafik berarah, yang nodenya merupakan instance dari struktur MSFilter, dan edge adalah contoh tautan MSQueue.

Aktivitas di balik layar ticker

Ketika saya memberi tahu Anda bahwa ticker adalah filter untuk sumber tick, itu tidak sepenuhnya benar. Ticker adalah objek yang menjalankan fungsi pada jam proses() semua filter dari rangkaian (grafik) yang terhubung. Saat kita menghubungkan ticker ke filter grafik di program C, kita menampilkan ticker grafik yang akan dikontrolnya mulai sekarang hingga kita mematikannya. Setelah terhubung, ticker mulai memeriksa grafik yang dipercayakan kepadanya, menyusun daftar filter yang menyertakannya. Agar tidak "menghitung" filter yang sama dua kali, ini menandai filter yang terdeteksi dengan memberi tanda centang di dalamnya terlihat. Pencarian dilakukan dengan menggunakan tabel link yang dimiliki setiap filter.

Selama tur pengenalan grafik, ticker memeriksa apakah di antara filter terdapat setidaknya satu yang bertindak sebagai sumber blok data. Jika tidak ada, maka grafik dianggap salah dan ticker crash.

Jika grafiknya ternyata “benar”, untuk setiap filter yang ditemukan, fungsinya dipanggil untuk inisialisasi proses awal(). Segera setelah saatnya tiba untuk siklus pemrosesan berikutnya (setiap 10 milidetik secara default), ticker memanggil fungsi tersebut proses() untuk semua filter sumber yang ditemukan sebelumnya, lalu untuk filter lainnya dalam daftar. Jika filter memiliki tautan masukan, maka jalankan fungsinya proses() ulangi sampai antrian tautan masukan kosong. Setelah ini, ia berpindah ke filter berikutnya dalam daftar dan “menggulirnya” hingga tautan masukan bebas dari pesan. Ticker berpindah dari filter ke filter hingga daftar berakhir. Ini menyelesaikan pemrosesan siklus.

Sekarang kita akan kembali ke tuple dan membicarakan mengapa entitas seperti itu ditambahkan ke media streamer. Secara umum, jumlah data yang dibutuhkan oleh algoritma yang beroperasi di dalam filter tidak sama atau merupakan kelipatan dari ukuran buffer data yang diterima pada input. Misalnya, kami sedang menulis filter yang melakukan transformasi Fourier cepat, yang menurut definisi hanya dapat memproses blok data yang ukurannya adalah pangkat dua. Biarlah 512 hitungan. Jika data dihasilkan oleh saluran telepon, maka buffer data dari setiap pesan input akan memberikan kita 160 sampel sinyal. Sangat menggoda untuk tidak mengumpulkan data dari input sampai jumlah data yang dibutuhkan tersedia. Namun dalam kasus ini, tabrakan akan terjadi dengan ticker, yang gagal mencoba menggulir filter hingga link input kosong. Sebelumnya, kami menetapkan aturan ini sebagai prinsip ketiga dari filter. Menurut prinsip ini, fungsi process() filter harus mengambil semua data dari antrian input.

Selain itu, tidak mungkin mengambil hanya 512 sampel dari masukan, karena Anda hanya dapat mengambil seluruh blok, yaitu. filter harus mengambil 640 sampel dan menggunakan 512 sampel, sisanya sebelum mengumpulkan sebagian data baru. Jadi, filter kami, selain pekerjaan utamanya, harus menyediakan tindakan tambahan untuk penyimpanan perantara data masukan. Pengembang media streamer dan solusi untuk masalah umum ini telah mengembangkan objek khusus - MSBufferizer (bufferer), yang memecahkan masalah ini menggunakan tupel.

Penyangga (MSBufferizer)

Ini adalah objek yang akan mengumpulkan data masukan di dalam filter dan mulai mengirimkannya untuk diproses segera setelah jumlah informasi mencukupi untuk menjalankan algoritma filter. Saat buffer mengumpulkan data, filter akan beroperasi dalam mode siaga, tanpa menggunakan daya pemrosesan prosesor. Namun segera setelah fungsi membaca dari bufferer mengembalikan nilai selain nol, fungsi process() dari filter mulai mengambil dan memproses data dari bufferer dalam porsi dengan ukuran yang diperlukan, hingga habis.
Data yang belum diperlukan tetap berada di buffer sebagai elemen pertama tupel, yang mana blok data masukan berikutnya dilampirkan.

Struktur yang menggambarkan buffer:

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

Fungsi untuk bekerja dengan MSBufferizer

Membuat instance buffer baru:

MSBufferizer * ms_bufferizer_new(void);

Memori dialokasikan, diinisialisasi ms_bufferizer_init() dan sebuah pointer dikembalikan.

Fungsi inisialisasi:

void ms_bufferizer_init(MSBufferizer *obj); 

Antrian sedang diinisialisasi q, bidang ukuran diatur ke nol.

Menambahkan pesan:

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

Pesan m ditambahkan ke antrian. Ukuran blok data yang dihitung ditambahkan ke ukuran.

Mentransfer semua pesan dari antrian data tautan ke buffer q:

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

Mentransfer pesan dari tautan q di buffer dilakukan menggunakan fungsi ms_bufferizer_put().

Membaca dari buffer:

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

Jika ukuran data yang terakumulasi di buffer lebih kecil dari yang diminta (datalen), maka fungsi mengembalikan nol, data tidak disalin ke data. Jika tidak, penyalinan data secara berurutan dari tupel yang terletak di buffer akan dilakukan. Setelah menyalin, tupel dihapus dan memori dibebaskan. Penyalinan berakhir pada saat byte datalen disalin. Jika ruang habis di tengah-tengah blok data, maka dalam pesan ini, blok data akan dikurangi menjadi sisa bagian yang belum disalin. Saat Anda menelepon lagi, penyalinan akan dilanjutkan mulai saat ini.

Membaca jumlah data yang saat ini tersedia di buffer:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Mengembalikan bidang ukuran penyangga.

Membuang sebagian data di buffer:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Jumlah byte data yang ditentukan diambil dan dibuang. Data terlama akan dibuang.

Menghapus semua pesan di buffer:

void ms_bufferizer_flush(MSBufferizer *obj); 

Penghitung data diatur ulang ke nol.

Menghapus semua pesan di buffer:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Penghitung tidak disetel ulang.

Menghapus buffer dan mengosongkan memori:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Contoh penggunaan bufferer dapat ditemukan di kode sumber beberapa filter media streamer. Misalnya, dalam filter MS_L16_ENC, yang mengatur ulang byte dalam sampel dari urutan jaringan ke urutan host: l16.c

Pada artikel selanjutnya, kita akan melihat masalah estimasi beban ticker dan cara mengatasi beban komputasi yang berlebihan di media streamer.

Sumber: www.habr.com

Tambah komentar