Materi artikel diambil dari saya
Mengirimkan sinyal audio melalui aliran RTP
Terakhir
Protokol RTP (Protokol Waktu Nyata) diterjemahkan berarti protokol waktu nyata, digunakan untuk mengirimkan audio, video, data, segala sesuatu yang memerlukan transmisi secara waktu nyata. Mari kita ambil sinyal audio sebagai contoh. Fleksibilitas protokol sedemikian rupa sehingga memungkinkan Anda mengirimkan sinyal audio dengan kualitas yang telah ditentukan.
Transmisi dilakukan dengan menggunakan paket UDP, yang berarti kehilangan paket cukup dapat diterima selama transmisi. Setiap paket berisi header RTP khusus dan blok data dari sinyal yang dikirimkan. Header berisi pengidentifikasi sumber sinyal yang dipilih secara acak, informasi tentang jenis sinyal yang ditransmisikan, dan nomor urut paket yang unik sehingga paket dapat disusun dalam urutan yang benar saat decoding, terlepas dari urutan pengirimannya oleh paket. jaringan. Header juga dapat berisi informasi tambahan, yang disebut ekstensi, yang memungkinkan header diadaptasi untuk digunakan dalam tugas aplikasi tertentu.
Blok data berisi payload paket. Organisasi internal konten bergantung pada jenis beban, dapat berupa sampel sinyal mono, sinyal stereo, saluran gambar video, dll.
Jenis beban ditunjukkan dengan angka tujuh bit. Rekomendasi RFC3551 (Profil RTP untuk Konferensi Audio dan Video dengan Kontrol Minimal) menetapkan beberapa jenis beban; tabel terkait memberikan deskripsi jenis beban dan arti kode yang digunakan untuk menentukannya. Beberapa kode tidak terikat secara ketat pada jenis beban apa pun; kode tersebut dapat digunakan untuk menunjukkan beban yang berubah-ubah.
Ukuran blok data dibatasi di atas oleh ukuran paket maksimum yang dapat ditransmisikan pada jaringan tertentu tanpa segmentasi (parameter MTU). Secara umum, ini tidak lebih dari 1500 byte. Jadi, untuk meningkatkan jumlah data yang dikirimkan per detik, Anda dapat meningkatkan ukuran paket hingga titik tertentu, dan kemudian Anda perlu meningkatkan frekuensi pengiriman paket. Di media streamer, ini adalah pengaturan yang dapat dikonfigurasi. Secara default adalah 50 Hz, mis. 50 paket per detik. Kami akan menyebut urutan paket RTP yang dikirimkan sebagai aliran RTP.
Untuk mulai mentransmisikan data antara sumber dan penerima, pemancar cukup mengetahui alamat IP penerima dan nomor port yang digunakan untuk menerima. Itu. tanpa prosedur awal apa pun, sumber mulai mengirimkan data, dan penerima, pada gilirannya, siap untuk segera menerima dan memprosesnya. Menurut standar, nomor port yang digunakan untuk mengirim atau menerima aliran RTP harus genap.
Dalam situasi di mana tidak mungkin mengetahui alamat penerima terlebih dahulu, server digunakan di mana penerima meninggalkan alamatnya, dan pemancar dapat memintanya dengan merujuk pada beberapa nama unik penerima.
Dalam kasus di mana kualitas saluran komunikasi atau kemampuan penerima tidak diketahui, saluran umpan balik diatur melalui mana penerima dapat memberi tahu pemancar tentang kemampuannya, jumlah paket yang terlewat, dll. Saluran ini menggunakan protokol RTCP. Format paket yang dikirimkan dalam saluran ini ditentukan dalam RFC 3605. Data yang dikirimkan melalui saluran ini relatif sedikit, 200..300 byte per detik, sehingga secara umum kehadirannya tidak memberatkan. Nomor port tujuan pengiriman paket RTCP harus ganjil dan satu lebih besar dari nomor port asal aliran RTP. Dalam contoh kami, kami tidak akan menggunakan saluran ini, karena kemampuan receiver dan saluran jelas melebihi kebutuhan kami yang sejauh ini sederhana.
Dalam program kita, rangkaian transmisi data, tidak seperti contoh sebelumnya, akan dibagi menjadi dua bagian: jalur transmisi dan jalur penerima. Untuk setiap bagian kita akan membuat sumber jamnya sendiri, seperti terlihat pada gambar judul.
Komunikasi satu arah di antara mereka akan dilakukan menggunakan protokol RTP. Dalam contoh ini, kita tidak memerlukan jaringan eksternal, karena pemancar dan penerima akan ditempatkan di komputer yang sama - paket akan berjalan di dalamnya.
Untuk membuat aliran RTP, streamer media menggunakan dua filter: MS_RTP_SEND dan MS_RTP_RECV. Yang pertama mengirimkan yang kedua dan menerima aliran RTP. Agar filter ini berfungsi, mereka perlu meneruskan pointer ke objek sesi RTP, yang dapat mengubah aliran blok data menjadi aliran paket RTP atau melakukan sebaliknya. Karena format data internal media streamer tidak cocok dengan format data paket RTP, sebelum mentransfer data ke MS_RTP_SEND, Anda perlu menggunakan filter encoder yang mengubah sampel sinyal audio 16-bit menjadi delapan-bit yang dikodekan sesuai dengan u-hukum (mu-hukum). Di sisi penerima, filter dekoder menjalankan fungsi sebaliknya.
Di bawah ini adalah teks program yang mengimplementasikan skema yang ditunjukkan pada gambar (simbol # sebelum arahan include dihilangkan, jangan lupa untuk menyertakannya):
/* Π€Π°ΠΉΠ» mstest6.c ΠΠΌΠΈΡΠ°ΡΠΎΡ ΠΏΡΠ»ΡΡΠ° ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΈ ΠΏΡΠΈΠ΅ΠΌΠ½ΠΈΠΊΠ°. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>
#include <mediastreamer2/mstonedetector.h>
#include <mediastreamer2/msrtp.h>
#include <ortp/rtpsession.h>
#include <ortp/payloadtype.h>
/* ΠΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡΠ½ΡΠΉ ΡΠ°ΠΉΠ» Ρ ΡΡΠ½ΠΊΡΠΈΡΠΌΠΈ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΡΠΎΠ±ΡΡΠΈΡΠΌΠΈ
* ΠΌΠ΅Π΄ΠΈΠ°ΡΡΡΠΈΠΌΠ΅ΡΠ°.*/
include <mediastreamer2/mseventqueue.h>
#define PCMU 0
/* Π€ΡΠ½ΠΊΡΠΈΡ ΠΎΠ±ΡΠ°ΡΠ½ΠΎΠ³ΠΎ Π²ΡΠ·ΠΎΠ²Π°, ΠΎΠ½Π° Π±ΡΠ΄Π΅Ρ Π²ΡΠ·Π²Π°Π½Π° ΡΠΈΠ»ΡΡΡΠΎΠΌ, ΠΊΠ°ΠΊ ΡΠΎΠ»ΡΠΊΠΎ ΠΎΠ½
ΠΎΠ±Π½Π°ΡΡΠΆΠΈΡ ΡΠΎΠ²ΠΏΠ°Π΄Π΅Π½ΠΈΠ΅ Ρ
Π°ΡΠ°ΠΊΡΠ΅ΡΠΈΡΡΠΈΠΊ Π²Ρ
ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡΠΈΠ³Π½Π°Π»Π° Ρ Π·Π°Π΄Π°Π½Π½ΡΠΌΠΈ. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,
MSToneDetectorEvent *ev)
{
printf("ΠΡΠΈΠ½ΡΡΠ° ΠΊΠΎΠΌΠ°Π½Π΄Π°: %sn", ev->tone_name);
}
/*----------------------------------------------------------------------------*/
/* Π€ΡΠ½ΠΊΡΠΈΡ ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΠΈ ΡΠΈΠΏΠΎΠ² ΠΏΠΎΠ»Π΅Π·Π½ΡΡ
Π½Π°Π³ΡΡΠ·ΠΎΠΊ. */
void register_payloads(void)
{
/*Π Π΅Π³ΠΈΡΡΡΠΈΡΡΠ΅ΠΌ ΡΠΈΠΏΡ Π½Π°Π³ΡΡΠ·ΠΎΠΊ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ ΠΏΡΠΎΡΠΈΠ»Π΅ΠΉ. ΠΠΎΠ·Π΄Π½Π΅Π΅, ΠΏΠΎ ΠΈΠ½Π΄Π΅ΠΊΡΡ
Π²Π·ΡΡΠΎΠΌΡ ΠΈΠ· Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° RTP-ΠΏΠ°ΠΊΠ΅ΡΠ° ΠΈΠ· ΡΡΠΎΠΉ ΡΠ°Π±Π»ΠΈΡΡ Π±ΡΠ΄ΡΡ ΠΈΠ·Π²Π»Π΅ΠΊΠ°ΡΡΡΡ
ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π½Π°Π³ΡΡΠ·ΠΊΠΈ, Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΡΠ΅ Π΄Π»Ρ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π΄Π°Π½Π½ΡΡ
ΠΏΠ°ΠΊΠ΅ΡΠ°. */
rtp_profile_set_payload (&av_profile, PCMU, &payload_type_pcm8000);
}
/*----------------------------------------------------------------------------*/
/* ΠΡΠ° ΡΡΠ½ΠΊΡΠΈΡ ΡΠΎΠ·Π΄Π°Π½Π° ΠΈΠ· ΡΡΠ½ΠΊΡΠΈΠΈ create_duplex_rtpsession() Π² audiostream.c
ΠΌΠ΅Π΄ΠΈΠ°ΡΡΡΠΈΠΌΠ΅ΡΠ°2. */
static RtpSession *
create_rtpsession (int loc_rtp_port, int loc_rtcp_port,
bool_t ipv6, RtpSessionMode mode)
{
RtpSession *rtpr;
rtpr = rtp_session_new ((int) mode);
rtp_session_set_scheduling_mode (rtpr, 0);
rtp_session_set_blocking_mode (rtpr, 0);
rtp_session_enable_adaptive_jitter_compensation (rtpr, TRUE);
rtp_session_set_symmetric_rtp (rtpr, TRUE);
rtp_session_set_local_addr (rtpr, ipv6 ? "::" : "0.0.0.0", loc_rtp_port,
loc_rtcp_port);
rtp_session_signal_connect (rtpr, "timestamp_jump",
(RtpCallback) rtp_session_resync, 0);
rtp_session_signal_connect (rtpr, "ssrc_changed",
(RtpCallback) rtp_session_resync, 0);
rtp_session_set_ssrc_changed_threshold (rtpr, 0);
rtp_session_set_send_payload_type(rtpr, PCMU);
/* ΠΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ Π²ΡΠΊΠ»ΡΡΠ°Π΅ΠΌ RTCP-ΡΠ΅ΡΡΠΈΡ, ΡΠ°ΠΊ ΠΊΠ°ΠΊ Π½Π°Ρ ΠΏΡΠ»ΡΡ Π½Π΅ Π±ΡΠ΄Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π΅Ρ. */
rtp_session_enable_rtcp (rtpr, FALSE);
return rtpr;
}
/*----------------------------------------------------------------------------*/
int main()
{
ms_init();
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡΡ ΡΠΈΠ»ΡΡΡΠΎΠ². */
MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
MSFilter *volume = ms_filter_new(MS_VOLUME_ID);
MSSndCard *card_playback =
ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
MSFilter *snd_card_write = ms_snd_card_create_writer(card_playback);
MSFilter *detector = ms_filter_new(MS_TONE_DETECTOR_ID);
/* ΠΡΠΈΡΠ°Π΅ΠΌ ΠΌΠ°ΡΡΠΈΠ² Π½Π°Ρ
ΠΎΠ΄ΡΡΠΈΠΉΡΡ Π²Π½ΡΡΡΠΈ Π΄Π΅ΡΠ΅ΠΊΡΠΎΡΠ° ΡΠΎΠ½ΠΎΠ², ΠΎΠ½ ΠΎΠΏΠΈΡΡΠ²Π°Π΅Ρ
* ΠΎΡΠΎΠ±ΡΠ΅ ΠΏΡΠΈΠΌΠ΅ΡΡ ΡΠ°Π·ΡΡΠΊΠΈΠ²Π°Π΅ΠΌΡΡ
ΡΠΈΠ³Π½Π°Π»ΠΎΠ².*/
ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);
/* ΠΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΠΌ ΠΊ ΡΠΈΠ»ΡΡΡΡ ΡΡΠ½ΠΊΡΠΈΡ ΠΎΠ±ΡΠ°ΡΠ½ΠΎΠ³ΠΎ Π²ΡΠ·ΠΎΠ²Π°. */
ms_filter_set_notify_callback(detector,
(MSFilterNotifyFunc)tone_detected_cb, NULL);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΌΠ°ΡΡΠΈΠ², ΠΊΠ°ΠΆΠ΄ΡΠΉ ΡΠ»Π΅ΠΌΠ΅Π½Ρ ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ ΠΎΠΏΠΈΡΡΠ²Π°Π΅Ρ Ρ
Π°ΡΠ°ΠΊΡΠ΅ΡΠΈΡΡΠΈΠΊΡ
* ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΈΠ· ΡΠΎΠ½ΠΎΠ², ΠΊΠΎΡΠΎΡΡΠΉ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ ΠΎΠ±Π½Π°ΡΡΠΆΠΈΠ²Π°ΡΡ: Π’Π΅ΠΊΡΡΠΎΠ²ΠΎΠ΅ ΠΈΠΌΡ
* Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ°, ΡΠ°ΡΡΠΎΡΠ° Π² Π³Π΅ΡΡΠ°Ρ
, Π΄Π»ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ Π² ΠΌΠΈΠ»Π»ΠΈΡΠ΅ΠΊΡΠ½Π΄Π°Ρ
,
* ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΡΠΉ ΡΡΠΎΠ²Π΅Π½Ρ ΠΎΡΠ½ΠΎΡΠΈΡΠ΅Π»ΡΠ½ΠΎ 0,775Π. */
MSToneDetectorDef scan[6]=
{
{"V+",440, 100, 0.1}, /* ΠΠΎΠΌΠ°Π½Π΄Π° "Π£Π²Π΅Π»ΠΈΡΠΈΡΡ Π³ΡΠΎΠΌΠΊΠΎΡΡΡ". */
{"V-",540, 100, 0.1}, /* ΠΠΎΠΌΠ°Π½Π΄Π° "Π£ΠΌΠ΅Π½ΡΡΠΈΡΡ Π³ΡΠΎΠΌΠΊΠΎΡΡΡ". */
{"C+",640, 100, 0.1}, /* ΠΠΎΠΌΠ°Π½Π΄Π° "Π£Π²Π΅Π»ΠΈΡΠΈΡΡ Π½ΠΎΠΌΠ΅Ρ ΠΊΠ°Π½Π°Π»Π°". */
{"C-",740, 100, 0.1}, /* ΠΠΎΠΌΠ°Π½Π΄Π° "Π£ΠΌΠ΅Π½ΡΡΠΈΡΡ Π½ΠΎΠΌΠ΅Ρ ΠΊΠ°Π½Π°Π»Π°". */
{"ON",840, 100, 0.1}, /* ΠΠΎΠΌΠ°Π½Π΄Π° "ΠΠΊΠ»ΡΡΠΈΡΡ ΡΠ΅Π»Π΅Π²ΠΈΠ·ΠΎΡ". */
{"OFF", 940, 100, 0.1}/* ΠΠΎΠΌΠ°Π½Π΄Π° "ΠΡΠΊΠ»ΡΡΠΈΡΡ ΡΠ΅Π»Π΅Π²ΠΈΠ·ΠΎΡ". */
};
/* ΠΠ΅ΡΠ΅Π΄Π°Π΅ΠΌ "ΠΏΡΠΈΠΌΠ΅ΡΡ" ΡΠΈΠ³Π½Π°Π»ΠΎΠ² Π΄Π΅ΡΠ΅ΠΊΡΠΎΡ ΡΠΎΠ½ΠΎΠ². */
int i;
for (i = 0; i < 6; i++)
{
ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,
&scan[i]);
}
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΡΠΈΠ»ΡΡΡΡ ΠΊΠΎΠ΄Π΅ΡΠ° ΠΈ Π΄Π΅ΠΊΠΎΠ΄Π΅ΡΠ° */
MSFilter *encoder = ms_filter_create_encoder("PCMU");
MSFilter *decoder=ms_filter_create_decoder("PCMU");
/* Π Π΅Π³ΠΈΡΡΡΠΈΡΡΠ΅ΠΌ ΡΠΈΠΏΡ Π½Π°Π³ΡΡΠ·ΠΊΠΈ. */
register_payloads();
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ RTP-ΡΠ΅ΡΡΠΈΡ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΠΈΠΊΠ°. */
RtpSession *tx_rtp_session = create_rtpsession (8010, 8011, FALSE, RTP_SESSION_SENDONLY);
rtp_session_set_remote_addr_and_port(tx_rtp_session,"127.0.0.1", 7010, 7011);
rtp_session_set_send_payload_type(tx_rtp_session, PCMU);
MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID);
ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, tx_rtp_session);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ RTP-ΡΠ΅ΡΡΠΈΡ ΠΏΡΠΈΠ΅ΠΌΠ½ΠΈΠΊΠ°. */
MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
RtpSession *rx_rtp_session = create_rtpsession (7010, 7011, FALSE, RTP_SESSION_RECVONLY);
ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rx_rtp_session);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠΈ ΡΠ°ΠΊΡΠΎΠ² - ΡΠΈΠΊΠ΅ΡΡ. */
MSTicker *ticker_tx = ms_ticker_new();
MSTicker *ticker_rx = ms_ticker_new();
/* Π‘ΠΎΠ΅Π΄ΠΈΠ½ΡΠ΅ΠΌ ΡΠΈΠ»ΡΡΡΡ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΠΈΠΊΠ°. */
ms_filter_link(voidsource, 0, dtmfgen, 0);
ms_filter_link(dtmfgen, 0, volume, 0);
ms_filter_link(volume, 0, encoder, 0);
ms_filter_link(encoder, 0, rtpsend, 0);
/* Π‘ΠΎΠ΅Π΄ΠΈΠ½ΡΠ΅ΠΌ ΡΠΈΠ»ΡΡΡΡ ΠΏΡΠΈΡΠΌΠ½ΠΈΠΊΠ°. */
ms_filter_link(rtprecv, 0, decoder, 0);
ms_filter_link(decoder, 0, detector, 0);
ms_filter_link(detector, 0, snd_card_write, 0);
/* ΠΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΠΌ ΠΈΡΡΠΎΡΠ½ΠΈΠΊ ΡΠ°ΠΊΡΠΎΠ². */
ms_ticker_attach(ticker_tx, voidsource);
ms_ticker_attach(ticker_rx, rtprecv);
/* ΠΠ°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌ ΡΡΡΡΠΊΡΡΡΡ, ΡΠΏΡΠ°Π²Π»ΡΡΡΡΡ Π²ΡΡ
ΠΎΠ΄Π½ΡΠΌ ΡΠΈΠ³Π½Π°Π»ΠΎΠΌ Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡΠ°. */
MSDtmfGenCustomTone dtmf_cfg;
dtmf_cfg.tone_name[0] = 0;
dtmf_cfg.duration = 1000;
dtmf_cfg.frequencies[0] = 440;
/* ΠΡΠ΄Π΅ΠΌ Π³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°ΡΡ ΠΎΠ΄ΠΈΠ½ ΡΠΎΠ½, ΡΠ°ΡΡΠΎΡΡ Π²ΡΠΎΡΠΎΠ³ΠΎ ΡΠΎΠ½Π° ΡΡΡΠ°Π½ΠΎΠ²ΠΈΠΌ Π² 0. */
dtmf_cfg.frequencies[1] = 0;
dtmf_cfg.amplitude = 1.0;
dtmf_cfg.interval = 0.;
dtmf_cfg.repeat_count = 0.;
/* ΠΡΠ³Π°Π½ΠΈΠ·ΡΠ΅ΠΌ ΡΠΈΠΊΠ» ΡΠΊΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π½Π°ΠΆΠ°ΡΡΡ
ΠΊΠ»Π°Π²ΠΈΡ. ΠΠ²ΠΎΠ΄ Π½ΡΠ»Ρ Π·Π°Π²Π΅ΡΡΠ°Π΅Ρ
* ΡΠΈΠΊΠ» ΠΈ ΡΠ°Π±ΠΎΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ. */
char key='9';
printf("ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ»Π°Π²ΠΈΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ, Π·Π°ΡΠ΅ΠΌ Π²Π²ΠΎΠ΄.n"
"ΠΠ»Ρ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ Π²Π²Π΅Π΄ΠΈΡΠ΅ 0.n");
while(key != '0')
{
key = getchar();
if ((key >= 49) && (key <= 54))
{
printf("ΠΡΠΏΡΠ°Π²Π»Π΅Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: %cn", key);
/* Π£ΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ ΡΠ°ΡΡΠΎΡΡ Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡΠ° Π² ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΠΈ Ρ
* ΠΊΠΎΠ΄ΠΎΠΌ Π½Π°ΠΆΠ°ΡΠΎΠΉ ΠΊΠ»Π°Π²ΠΈΡΠΈ. */
dtmf_cfg.frequencies[0] = 440 + 100*(key-49);
/* ΠΠΊΠ»ΡΡΠ°Π΅ΠΌ Π·Π²ΡΠΊΠΎΠ²ΠΎΠΉ Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡ c ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π½ΠΎΠΉ ΡΠ°ΡΡΠΎΡΠΎΠΉ. */
ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
(void*)&dtmf_cfg);
}
/* Π£ΠΊΠ»Π°Π΄ΡΠ²Π°Π΅ΠΌ ΡΡΠ΅Π΄ Π² ΡΠΏΡΡΠΊΡ Π½Π° 20ΠΌΡ, ΡΡΠΎΠ±Ρ Π΄ΡΡΠ³ΠΈΠ΅ ΡΡΠ΅Π΄Ρ
* ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΠΏΠΎΠ»ΡΡΠΈΠ»ΠΈ Π²ΡΠ΅ΠΌΡ Π½Π° ΡΠ°Π±ΠΎΡΡ. */
ms_usleep(20000);
}
}
Kami mengkompilasi dan menjalankan. Program ini akan bekerja seperti pada contoh sebelumnya, tetapi data akan dikirimkan melalui aliran RTP.
Pada artikel berikutnya kami akan membagi program ini menjadi dua aplikasi independen - penerima dan pemancar dan meluncurkannya di terminal berbeda. Pada saat yang sama, kita akan mempelajari cara menganalisis paket RTP menggunakan program TShark.
Sumber: www.habr.com