We study the Mediastreamer2 VoIP engine. Part 13, the final

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 .
/*  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
/*  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. , . .




All Articles