The material of the article is taken from my Zen channel .
All articles of the series
Article 1
Article 2
Article 3
Article 4
Article 5
Article 6
Article 7
Article 8
Article 9
Article 10
Article 11
Article 12
Article 13
, , .
, . 10, , . , . , , :
MS2_PUBLIC float ms_ticker_get_average_load(MSTicker *ticker);
100% , . , ( ), . - RTP-, . ( -). , , . .
, 80%. . , , .
:
struct _MSTickerLateEvent{
int lateMs; /**< , */
uint64_t time; /**< , */
int current_late_ms; /**< , */
};
typedef struct _MSTickerLateEvent MSTickerLateEvent;
, :
ortp-warning-MSTicker: We are late of 164 miliseconds
void ms_ticker_get_last_late_tick(MSTicker *ticker, MSTickerLateEvent *ev);
.
. , . .
, MSTickerPrio:
enum _MSTickerPrio{
MS_TICKER_PRIO_NORMAL, /* . */
MS_TICKER_PRIO_HIGH, /* linux/MacOS setpriority() sched_setschedparams() SCHED_RR. */
MS_TICKER_PRIO_REALTIME /* , Linux SCHED_FIFO. */
};
typedef enum _MSTickerPrio MSTickerPrio;
, , 99%. :
ticker -> voidsource -> dtmfgen -> voidsink
dtmfgen voidsink ( MS_VOLUME), , .
, , :
/* mstest13.c . */
#include <stdio.h>
#include <signal.h>
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>
/*----------------------------------------------------------*/
struct _app_vars
{
int step; /* . */
int limit; /* . */
int ticker_priority; /* . */
char* file_name; /* . */
FILE *file;
};
typedef struct _app_vars app_vars;
/*----------------------------------------------------------*/
/*
* . */
void scan_args(int argc, char *argv[], app_vars *v)
{
char i;
for (i=0; i<argc; i++)
{
if (!strcmp(argv[i], "--help"))
{
char *p=argv[0]; p=p + 2;
printf(" %s computational load\n\n", p);
printf("--help List of options.\n");
printf("--version Version of application.\n");
printf("--step Filters count per step.\n");
printf("--tprio Ticker priority:\n"
" MS_TICKER_PRIO_NORMAL 0\n"
" MS_TICKER_PRIO_HIGH 1\n"
" MS_TICKER_PRIO_REALTIME 2\n");
printf("--limit Filters count limit.\n");
printf("-o Output file name.\n");
exit(0);
}
if (!strcmp(argv[i], "--version"))
{
printf("0.1\n");
exit(0);
}
if (!strcmp(argv[i], "--step"))
{
v->step = atoi(argv[i+1]);
printf("step: %i\n", v->step);
}
if (!strcmp(argv[i], "--tprio"))
{
int prio = atoi(argv[i+1]);
if ((prio >=MS_TICKER_PRIO_NORMAL) && (prio <= MS_TICKER_PRIO_REALTIME))
{
v->ticker_priority = atoi(argv[i+1]);
printf("ticker priority: %i\n", v->ticker_priority);
}
else
{
printf(" Bad ticker priority: %i\n", prio);
exit(1);
}
}
if (!strcmp(argv[i], "--limit"))
{
v->limit = atoi(argv[i+1]);
printf("limit: %i\n", v->limit);
}
if (!strcmp(argv[i], "-o"))
{
v->file_name=argv[i+1];
printf("file namet: %s\n", v->file_name);
}
}
}
/*----------------------------------------------------------*/
/* . */
app_vars vars;
/*----------------------------------------------------------*/
void saveMyData()
{
// .
if (vars.file) fclose(vars.file);
exit(0);
}
void signalHandler( int signalNumber )
{
static pthread_once_t semaphore = PTHREAD_ONCE_INIT;
printf("\nsignal %i received.\n", signalNumber);
pthread_once( & semaphore, saveMyData );
}
/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
/* . */
app_vars vars={100, 100500, MS_TICKER_PRIO_NORMAL, 0};
// Ctrl-C.
signal( SIGTERM, signalHandler );
signal( SIGINT, signalHandler );
/*
* . */
scan_args(argc, argv, &vars);
if (vars.file_name)
{
vars.file = fopen(vars.file_name, "w");
}
ms_init();
/* . */
MSFilter *voidsource=ms_filter_new(MS_VOID_SOURCE_ID);
MSFilter *dtmfgen=ms_filter_new(MS_DTMF_GEN_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 *voidsink=ms_filter_new(MS_VOID_SINK_ID);
MSDtmfGenCustomTone dtmf_cfg;
/* , ,
* , . */
strncpy(dtmf_cfg.tone_name, "busy", sizeof(dtmf_cfg.tone_name));
dtmf_cfg.duration=1000;
dtmf_cfg.frequencies[0]=440; /* , 0.*/
dtmf_cfg.frequencies[1]=0;
dtmf_cfg.amplitude=1.0; /* 0.707.*/
dtmf_cfg.interval=0.;
dtmf_cfg.repeat_count=0.;
/* */
float load=0.;
float latency=0.;
int filter_count=0;
/* . */
MSTicker *ticker=ms_ticker_new();
ms_ticker_set_priority(ticker, vars.ticker_priority);
/* . */
ms_filter_link(voidsource, 0, dtmfgen, 0);
ms_filter_link(dtmfgen, 0, voidsink, 0);
MSFilter* previous_filter=dtmfgen;
int gain=1;
int i;
printf("# filters load\n");
if (vars.file)
{
fprintf(vars.file, "# filters load\n");
}
while ((load <= 99.) && (filter_count < vars.limit))
{
// "" .
ms_filter_unlink(previous_filter, 0, voidsink, 0);
MSFilter *volume;
for (i=0; i<vars.step; i++)
{
volume=ms_filter_new(MS_VOLUME_ID);
ms_filter_call_method(volume, MS_VOLUME_SET_DB_GAIN, &gain);
ms_filter_link(previous_filter, 0, volume, 0);
previous_filter = volume;
}
// "" .
ms_filter_link(volume, 0, voidsink, 0);
/* . */
ms_ticker_attach(ticker,voidsource);
/* . */
ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM, (void*)&dtmf_cfg);
/* , 100 , . */
ms_usleep(500000);
/* . */
load=ms_ticker_get_average_load(ticker);
filter_count=filter_count + vars.step;
/* . */
ms_ticker_detach(ticker,voidsource);
printf("%i %f\n", filter_count, load);
if (vars.file) fprintf(vars.file,"%i %f\n", filter_count, load);
}
if (vars.file) fclose(vars.file);
}
mstest13.c :
$ gcc mstest13.c -o mstest13 `pkg-config mediastreamer --libs --cflags`
, :
$ ./mstest13 --step 100 --limit 40000 --tprio 0 -o log0.txt
$ ./mstest13 --step 100 --limit 40000 --tprio 1 -o log1.txt
$ ./mstest13 --step 100 --limit 40000 --tprio 2 -o log2.txt
"" log0.txt, log1.txt, log2.txt gnuplot:
$ gnuplot -e "set terminal png; set output 'load.png'; plot 'log0.txt' using 1:2 with lines , 'log1.txt' using 1:2 with lines, 'log2.txt' using 1:2 with lines"
load.png, :
, .
, , 2 ( ), 6000 , 0 () 1() , 1000 3000 .
, , , .
, β . , "", , (.. ). "" , . MS_ITC_SINK MS_ITC_SOURCE, "".
MS_ITC_SINK , . MS_ITC_SOURCE , , . , .
, , , .. ms_filter_link(). , MS_ITC_SINK_CONNECT MS_ITC_SINK:
ms_filter_call_method (itc_sink, MS_ITC_SINK_CONNECT, itc_src)
. .
. .
, . , . .
.
/* mstest14.c c . */
#include <stdio.h>
#include <signal.h>
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>
#include <mediastreamer2/msitc.h>
/*----------------------------------------------------------*/
struct _app_vars
{
int step; /* . */
int limit; /* . */
int ticker_priority; /* . */
char* file_name; /* . */
FILE *file;
};
typedef struct _app_vars app_vars;
/*----------------------------------------------------------*/
/*
* . */
void scan_args(int argc, char *argv[], app_vars *v)
{
char i;
for (i=0; i<argc; i++)
{
if (!strcmp(argv[i], "--help"))
{
char *p=argv[0]; p=p + 2;
printf(" %s computational load diveded for two threads.\n\n", p);
printf("--help List of options.\n");
printf("--version Version of application.\n");
printf("--step Filters count per step.\n");
printf("--tprio Ticker priority:\n"
" MS_TICKER_PRIO_NORMAL 0\n"
" MS_TICKER_PRIO_HIGH 1\n"
" MS_TICKER_PRIO_REALTIME 2\n");
printf("--limit Filters count limit.\n");
printf("-o Output file name.\n");
exit(0);
}
if (!strcmp(argv[i], "--version"))
{
printf("0.1\n");
exit(0);
}
if (!strcmp(argv[i], "--step"))
{
v->step = atoi(argv[i+1]);
printf("step: %i\n", v->step);
}
if (!strcmp(argv[i], "--tprio"))
{
int prio = atoi(argv[i+1]);
if ((prio >=MS_TICKER_PRIO_NORMAL) && (prio <= MS_TICKER_PRIO_REALTIME))
{
v->ticker_priority = atoi(argv[i+1]);
printf("ticker priority: %i\n", v->ticker_priority);
}
else
{
printf(" Bad ticker priority: %i\n", prio);
exit(1);
}
}
if (!strcmp(argv[i], "--limit"))
{
v->limit = atoi(argv[i+1]);
printf("limit: %i\n", v->limit);
}
if (!strcmp(argv[i], "-o"))
{
v->file_name=argv[i+1];
printf("file namet: %s\n", v->file_name);
}
}
}
/*----------------------------------------------------------*/
/* . */
app_vars vars;
/*----------------------------------------------------------*/
void saveMyData()
{
// .
if (vars.file) fclose(vars.file);
exit(0);
}
void signalHandler( int signalNumber )
{
static pthread_once_t semaphore = PTHREAD_ONCE_INIT;
printf("\nsignal %i received.\n", signalNumber);
pthread_once( & semaphore, saveMyData );
}
/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
/* . */
app_vars vars={100, 100500, MS_TICKER_PRIO_NORMAL, 0};
// Ctrl-C.
signal( SIGTERM, signalHandler );
signal( SIGINT, signalHandler );
/*
* . */
scan_args(argc, argv, &vars);
if (vars.file_name)
{
vars.file = fopen(vars.file_name, "w");
}
ms_init();
/* . */
MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
MSFilter *itc_sink = ms_filter_new(MS_ITC_SINK_ID);
MSDtmfGenCustomTone dtmf_cfg;
/* , ,
* , . */
strncpy(dtmf_cfg.tone_name, "busy", sizeof(dtmf_cfg.tone_name));
dtmf_cfg.duration=1000;
dtmf_cfg.frequencies[0]=440; /* , 0.*/
dtmf_cfg.frequencies[1]=0;
dtmf_cfg.amplitude=1.0; /* 0.707.*/
dtmf_cfg.interval=0.;
dtmf_cfg.repeat_count=0.;
/* */
float load=0.;
float latency=0.;
int filter_count=0;
/* . */
MSTicker *ticker1=ms_ticker_new();
ms_ticker_set_priority(ticker1, vars.ticker_priority);
/* . */
ms_filter_link(voidsource, 0, dtmfgen, 0);
ms_filter_link(dtmfgen, 0, itc_sink , 0);
/* . */
MSTicker *ticker2=ms_ticker_new();
ms_ticker_set_priority(ticker2, vars.ticker_priority);
MSFilter *itc_src = ms_filter_new(MS_ITC_SOURCE_ID);
MSFilter *voidsink2 = ms_filter_new(MS_VOID_SINK_ID);
ms_filter_call_method (itc_sink, MS_ITC_SINK_CONNECT, itc_src);
ms_filter_link(itc_src, 0, voidsink2, 0);
MSFilter* previous_filter1=dtmfgen;
MSFilter* previous_filter2=itc_src;
int gain=1;
int i;
printf("# filters load\n");
if (vars.file)
{
fprintf(vars.file, "# filters load\n");
}
while ((load <= 99.) && (filter_count < vars.limit))
{
// "" .
ms_filter_unlink(previous_filter1, 0, itc_sink, 0);
ms_filter_unlink(previous_filter2, 0, voidsink2, 0);
MSFilter *volume1, *volume2;
// .
int new_filters = vars.step>>1;
for (i=0; i < new_filters; i++)
{
volume1=ms_filter_new(MS_VOLUME_ID);
ms_filter_call_method(volume1, MS_VOLUME_SET_DB_GAIN, &gain);
ms_filter_link(previous_filter1, 0, volume1, 0);
previous_filter1 = volume1;
}
new_filters = vars.step - new_filters;
for (i=0; i < new_filters; i++)
{
volume2=ms_filter_new(MS_VOLUME_ID);
ms_filter_call_method(volume2, MS_VOLUME_SET_DB_GAIN, &gain);
ms_filter_link(previous_filter2, 0, volume2, 0);
previous_filter2 = volume2;
}
// "" .
ms_filter_link(volume1, 0, itc_sink, 0);
ms_filter_link(volume2, 0, voidsink2, 0);
/* . */
ms_ticker_attach(ticker2, itc_src);
ms_ticker_attach(ticker1, voidsource);
/* . */
ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM, (void*)&dtmf_cfg);
/* , , . */
ms_usleep(500000);
/* . */
load=ms_ticker_get_average_load(ticker1);
filter_count=filter_count + vars.step;
/* . */
ms_ticker_detach(ticker1, voidsource);
printf("%i %f\n", filter_count, load);
if (vars.file) fprintf(vars.file,"%i %f\n", filter_count, load);
}
if (vars.file) fclose(vars.file);
}
, :
$ ./mstest14 --step 100 --limit 40000 --tprio 0 -o log4.txt
:
, . "" . , "" . .
, RTP- ( ), , RTP- MTU.
, , . . .
2. , . .