Kami mempelajari mesin VoIP Mediastreamer2. Bagian 10

Materi artikel diambil dari saluran zen saya .



Pada artikel terakhir , kami membuat interkom dupleks yang menukar sinyal audio melalui sesi RTP dupleks. Pada artikel ini, kita akan belajar cara menulis filter dan menambahkan filter do-it-yourself ke interkom do-it-yourself.


Kami sedang mengembangkan sebuah plugin



, , .


, include . , ms_filter_register() . , .


. , , . , , .


, _ (NASH_FILTR). — . , , .


. / .


. . msfilter.h, MS_FILTER_METHOD ( ), ( ) MSFilterDesc . :


struct _MSFilterDesc{
    MSFilterId id;    /*       allfilters.h   .  */
    const char *name; /*   ( ). */
    const char *text; /**  ,  . */
    MSFilterCategory category; /*  ,   . */
    const char *enc_fmt; /* sub-mime  ,        MS_FILTER_ENCODER  MS_FILTER_DECODER */
    int ninputs; /*  . */
    int noutputs; /* .  */
    MSFilterFunc init; /*    . */
    MSFilterFunc preprocess; /*        . */
    MSFilterFunc process; /**<     ,       MSTicker. */
    MSFilterFunc postprocess; /*    ,      process(),   . */
    MSFilterFunc uninit; /**<    ,   ,        . */
    MSFilterMethod *methods; /*   . */
    unsigned int flags; /*         MSFilterFlags. */
};

/*
    .
*/
typedef struct _MSFilterDesc MSFilterDesc;

, msfilter.h. :


/*  nash_filter.h,  -  . */

#ifndef myfilter_h
#define myfilter_h

/*       . */
#include <mediastreamer2/msticker.h>

/* 
        .     
         .       allfilters.h
      enum MSFilterId.  , 
       ,     
   .      id     
   : 4000.   ,     , 
       .  
   */
#define NASH_FILTER_ID 4000

/* 
      .    
     ,   0.      
   ,        .  
       ,   . 
   */
#define NASH_FILTER_SET_TRESHOLD MS_FILTER_METHOD(NASH_FILTER_ID , 0, float)
#define NASH_FILTER_TUNE_OFF     MS_FILTER_METHOD_NO_ARG(NASH_FILTER_ID ,1)
#define NASH_FILTER_TUNE_ON      MS_FILTER_METHOD_NO_ARG(NASH_FILTER_ID ,2)

/*   ,      . */
struct _NASHFilterEvent
{
    /*  ,     ,
       0 -  , 1 -  .*/
    char state; 
    /* ,   . */
    uint64_t time;
};
typedef struct _NASHFilterEvent NASHFilterEvent;

/*     . */
#define NASH_FILTER_EVENT MS_FILTER_EVENT(MS_RTP_RECV_ID, 0, NASHFilterEvent)

/*   ,  
        . */
extern MSFilterDesc nash_filter_desc;

#endif /* myfilter_h */

. . , . nash_filter_desc. " " .


/*  nash_filter.,  -  . */

#include "nash_filter.h"
#include <math.h>

#define NASH_FILTER_NOUTPUTS 5

/*  ,     . */
typedef struct _nash_filterData
{
    bool_t disable_out;  /*     . */
    int last_state;   /*   . */
    char zero_count;     /*   . */
    char lag;            /*      . */
    char n_count;        /*   . */
    float skz_level;     /*    
,      .   
,     .  */

} nash_filterData;

/*----------------------------------------------------------*/
/*   . */
static void nash_filter_init(MSFilter *f)
{
    nash_filterData *d=ms_new0(nash_filterData, 1);
    d->lag=5;
    f->data=d;
}

/*----------------------------------------------------------*/
/*     ,
    . */
static void nash_filter_uninit(MSFilter *f)
{
    ms_free(f->data);
}

/*----------------------------------------------------------*/
/*     , 
      . */
char zero_array[1024]={0};

/*   . */
NASHFilterEvent event;

/*----------------------------------------------------------*/
/*   . */
static void send_event(MSFilter *f, int state)
{
    nash_filterData *d =( nash_filterData* ) f->data;
     d->last_state = state;
    /*    ,
          .   . */
    event.time=f -> ticker -> time;
    event.state=state;  
    ms_filter_notify(f, NASH_FILTER_EVENT, &event);
}   

/*----------------------------------------------------------*/
/*    ()   
  . */
static float calc_skz(nash_filterData *d, int16_t *signal, int numsamples)
{
    int i;
    float acc = 0;
    for (i=0; i<numsamples; i++)
    {
        int s=signal[i];
        acc = acc + s * s;
    }
    float skz = (float)sqrt(acc / numsamples);
    return skz;
}

/*----------------------------------------------------------*/
/*     ,
      . */
static void nash_filter_process(MSFilter *f)
{
    nash_filterData *d=(nash_filterData*)f->data;

    /*       . */
    mblk_t *im;
    int i;
    int state;
    /*     
          . */
    while((im=ms_queue_get(f->inputs[0]))!=NULL)
    {
        /*   ,     . */
        if ( d -> disable_out)
        {
          freemsg(im);
          continue;
        }

        /*         . */
        float skz = calc_skz(d, (int16_t*)im->b_rptr, msgdsize(im));
        state = (skz > d->skz_level) ? 1 : 0; 
        if (state) 
        {
            d->n_count++;
            d->zero_count = 0;
        }
        else
        {
            d->n_count = 0;
            d->zero_count++;
        }
        if (((d->zero_count > d->lag) || (d->n_count > d->lag))
            &&  (d->last_state != state)) send_event(f, state);

        /*         . 
         *   ,    .  
         *      0,      
         * . */ 
        int output_count = 0;
        mblk_t *outm; /*       . */
        for(i=0; i < f->desc->noutputs; i++)
        {
            if (f->outputs[i]!=NULL)
            {
                if (output_count == 0)
                {
                    outm = im;
                }
                else
                {
                    /*    . */       
                    outm = dupmsg(im);
                }
                /*        
                 *  . */ 
                ms_queue_put(f->outputs[i], outm);
                output_count++;
            }
        }
    }
}

/*----------------------------------------------------------*/
/* -   NASH_FILTER_SET_LAG. */
static int nash_filter_set_treshold(MSFilter *f, void *arg)
{
    nash_filterData *d=(nash_filterData*)f->data;
    d->skz_level=*(float*)arg;
    return 0;
}

/*----------------------------------------------------------*/
/* -   NASH_FILTER_TUNE_OFF. */
static int nash_filter_tune_off(MSFilter *f, void *arg)
{
    nash_filterData *d=(nash_filterData*)f->data;
    d->disable_out=TRUE;
    return 0;
}

/*----------------------------------------------------------*/
/* -   NASH_FILTER_TUNE_ON. */
static int nash_filter_tune_on(MSFilter *f, void *arg)
{
    nash_filterData *d=(nash_filterData*)f->data;
    d->disable_out=FALSE;
    return 0;
}

/*----------------------------------------------------------*/
/*    ,  
         
   . */
static MSFilterMethod nash_filter_methods[]={
    { NASH_FILTER_SET_TRESHOLD, nash_filter_set_treshold },
    { NASH_FILTER_TUNE_OFF, nash_filter_tune_off },
    { NASH_FILTER_TUNE_ON, nash_filter_tune_on },
    { 0 , NULL } /*   . */
};

/*----------------------------------------------------------*/
/*    . */
MSFilterDesc nash_filter_desc=
{
    NASH_FILTER_ID,
    "NASH_FILTER",
    "A filter with noise gate that reads from input and copy to it's five outputs.",
    MS_FILTER_OTHER,
    NULL,
    1,
    NASH_FILTER_NOUTPUTS,
    nash_filter_init,
    NULL,
    nash_filter_process,
    NULL,
    nash_filter_uninit,
    nash_filter_methods,
    0
};

MS_FILTER_DESC_EXPORT(nash_filter_desc)

, , . .
- - . .


-, wav. , . .
. , . "0", . "1" .


: --ng, --rec, record.wav.


/*  mstest9.c    c  
 * . */

#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>
#include <mediastreamer2/msfilerec.h>

/*   . */
#include "nash_filter.h"

/*    . */
#include "mstest_common.c"

/*----------------------------------------------------------*/
struct _app_vars
{
    int  local_port;              /*  . */
    int  remote_port;             /*      . */
    char remote_addr[128];        /* IP-  . */
    MSDtmfGenCustomTone dtmf_cfg; /*    . */
    MSFilter* recorder;           /*    . */
    bool_t file_is_open;          /*  ,     . */
    /* ,        . */
    float treshold; 
    bool_t en_rec;                /*   .*/    
};

typedef struct _app_vars app_vars;

/*----------------------------------------------------------*/
/*   RTP-. */
RtpSession* create_duplex_rtp_session(app_vars v)
{
    RtpSession *session = create_rtpsession (v.local_port, v.local_port + 1,
            FALSE, RTP_SESSION_SENDRECV);
    rtp_session_set_remote_addr_and_port(session, v.remote_addr, v.remote_port,
            v.remote_port + 1);
    rtp_session_set_send_payload_type(session, PCMU);
    return session;
}

/*----------------------------------------------------------*/
/*       
 *  . */
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 walkie talkie\n\n", p);
            printf("--help      List of options.\n");
            printf("--version   Version of application.\n");
            printf("--addr      Remote abonent IP address string.\n");
            printf("--port      Remote abonent port number.\n");
            printf("--lport     Local port number.\n");
            printf("--gen       Generator frequency.\n");
            printf("--ng        Noise gate treshold level from 0. to 1.0\n");
            printf("--rec       record to file 'record.wav'.\n");
            exit(0);
        }

        if (!strcmp(argv[i], "--version"))
        {
            printf("0.1\n");
            exit(0);
        }

        if (!strcmp(argv[i], "--addr"))
        {
            strncpy(v->remote_addr, argv[i+1], 16);
            v->remote_addr[16]=0;
            printf("remote addr: %s\n", v->remote_addr);
        }

        if (!strcmp(argv[i], "--port"))
        {
            v->remote_port=atoi(argv[i+1]);
            printf("remote port: %i\n", v->remote_port);
        }

        if (!strcmp(argv[i], "--lport"))
        {
            v->local_port=atoi(argv[i+1]);
            printf("local port : %i\n", v->local_port);
        }

        if (!strcmp(argv[i], "--gen"))
        {
            v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
            printf("gen freq : %i\n", v -> dtmf_cfg.frequencies[0]);
        }

        if (!strcmp(argv[i], "--ng"))
        {
            v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
            printf("noise gate treshold: %f\n", v -> treshold);
        }
         if (!strcmp(argv[i], "--rec"))
        {
            v -> en_rec = TRUE;
            printf("enable recording: %i\n", v -> en_rec);
        }
    }
}

/*----------------------------------------------------------*/
/*   ,    ,   
 * ,        . */
static void change_detected_cb(void *data, MSFilter *f, unsigned int event_id,
        NASHFilterEvent *ev)
{
    app_vars *vars = (app_vars*) data;

    /*     ,  . */
    if (! vars -> en_rec) return; 

    if (ev -> state)
    {
        /*  . */
        if(!vars->file_is_open)
        {
            ms_filter_call_method(vars->recorder, MS_FILE_REC_OPEN, "record.wav");
            vars->file_is_open = 1;
        }
        ms_filter_call_method(vars->recorder, MS_FILE_REC_START, 0);
        printf("Recording...\n");
    }
    else
    {
        /*  . */
        ms_filter_call_method(vars->recorder, MS_FILE_REC_STOP, 0);
        printf("Pause...\n");
    }
}

/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
    /*    . */
    app_vars vars={5004, 7010, "127.0.0.1", {0}, 0, 0, 0.01, 0};

    /*      
     *     . */
    scan_args(argc, argv, &vars);

    ms_init();

    /*     . */
    MSSndCard *snd_card =
        ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
    MSFilter *snd_card_read = ms_snd_card_create_reader(snd_card);
    MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
    MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID);

    /*   . */
    MSFilter *encoder = ms_filter_create_encoder("PCMU");

    /*   . */
    register_payloads();

    /*   RTP-. */
    RtpSession* rtp_session = create_duplex_rtp_session(vars);
    ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, rtp_session);

    /*   . */
    ms_filter_link(snd_card_read, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, encoder, 0);
    ms_filter_link(encoder, 0, rtpsend, 0);

    /*    . */
    MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
    ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rtp_session);

    /*   . */
    MSFilter *decoder=ms_filter_create_decoder("PCMU");
    //MS_FILE_REC_ID

    /*   . */
    ms_filter_register(&nash_filter_desc);
    MSFilter *nash = ms_filter_new(NASH_FILTER_ID);

    /*    . */
    MSFilter *snd_card_write = ms_snd_card_create_writer(snd_card);

    /*   . */
    MSFilter *recorder=ms_filter_new(MS_FILE_REC_ID);
    vars.recorder = recorder; 

    /*    . */
    ms_filter_link(rtprecv, 0, decoder, 0);
    ms_filter_link(decoder, 0, nash, 0);
    ms_filter_link(nash, 0, snd_card_write, 0);
    ms_filter_link(nash, 1, recorder, 0);

    /*      ,    
     *        
     * ,        
     * . */
    ms_filter_set_notify_callback(nash,
            (MSFilterNotifyFunc)change_detected_cb, &vars);
    ms_filter_call_method(nash,NASH_FILTER_SET_TRESHOLD, &vars.treshold); 

    /*    - . */
    MSTicker *ticker = ms_ticker_new();

    /*   . */
    ms_ticker_attach(ticker, snd_card_read);
    ms_ticker_attach(ticker, rtprecv);

    /*       ,   . */   
    if (vars.dtmf_cfg.frequencies[0])
    {
        /*  ,    . */
        vars.dtmf_cfg.duration = 10000;
        vars.dtmf_cfg.amplitude = 1.0;
    }

    /*    . */
    printf("Press ENTER to exit.\n ");
    char c=getchar();
    while(c != '\n')
    {
        if(vars.dtmf_cfg.frequencies[0])
        {
            /*   . */
            ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
                    (void*)&vars.dtmf_cfg);
        }
        char c=getchar();
        printf("--\n");
    }
    if (vars.en_rec ) ms_filter_call_method(recorder, MS_FILE_REC_CLOSE, 0);
}

- , math, , , :


$ gcc mstest9.c nash_filter.c -o mstest9   `pkg-config mediastreamer   --libs --cflags`  -lm

, :


$ ./mstest9  --lport 7010  --port 8010 --addr <   > --rec

:


$ ./mstest9  --lport 8010  --port 7010 --addr <   >

, . "Recording...". "Pause...". .


Pada artikel ini, kami belajar cara menulis filter. Seperti yang mungkin Anda perhatikan, fungsi nash_filter_process () memanipulasi blok data. Karena contoh tersebut adalah contoh pelatihan, maka ada kemampuan media streamer minimum untuk memanipulasi blok data.


Pada artikel selanjutnya , kita akan melihat antrian pesan dan fitur manajemen pesan. Yang di masa depan akan membantu mengembangkan filter dengan pemrosesan informasi yang lebih kompleks.


All Articles