Freeswitch 停关空Mod 编写样例

最近在为公司的外呼系统做停关空识别,这里放一个asr mod模板

可以使用 originate sofia/gateway/xxx/13800000000 start_hd:'10',wait_for_answer,echo inline 来唤起识别,和自己的样本库比较(当然识别算法这里没有)

另外注意,由于需要录制回铃音,所以ignore_early_media一定要是false,否则录制不到回铃音,说啥都没用了。

#include <switch.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pthread.h>


static switch_status_t load_config(void);

SWITCH_MODULE_LOAD_FUNCTION(mod_asr_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_asr_shutdown);
SWITCH_MODULE_DEFINITION(mod_hangup_detect, mod_asr_load, mod_asr_shutdown, NULL);


static struct {
    switch_memory_pool_t *pool;
    int maxSampleSec = 10;
    char* pcmDir = "/data/freeswitch";
    
} globals;

typedef struct {

    switch_core_session_t   *session;
    switch_media_bug_t      *bug;
    
    FILE                    *stream;
    char                    *callUUID;
    char                    *filePath;

    int                     stop;
    int                     currentMaxSampleSec;

} switch_da_t;


static switch_bool_t asr_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
    switch_da_t *pvt = (switch_da_t *)user_data;

    if(pvt == NULL || pvt->stop == 1)
        return SWITCH_FALSE;

    switch_channel_t *channel = switch_core_session_get_channel(pvt->session);

    switch (type) {
        case SWITCH_ABC_TYPE_INIT:
            {
                pvt->filePath = (char*)malloc(strlen(globals.pcmDir) + strlen(pvt->callUUID) + 5 + 1);
                sprintf(pvt->filePath, "%s/%s.pcm", globals.pcmDir, pvt->callUUID);
                pvt->stream = fopen(pvt->filePath, "wb");
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s HD Start Succeed channel:%s, file:%s\n",pvt->callUUID, switch_channel_get_name(channel),pvt->filePath);
            }
            break;
        case SWITCH_ABC_TYPE_CLOSE:
            {
                if ( pvt->stream != NULL ) {
                    fclose(pvt->stream);
                }
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s HD Stop Succeed channel:%s\n",pvt->callUUID, switch_channel_get_name(channel));
            }
            break;

        case SWITCH_ABC_TYPE_READ_REPLACE:
            {
                switch_frame_t *frame;
                if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
                    char*frame_data = (char*)frame->data;
                    int frame_len = frame->datalen;
                    //默认的采样率  需要转换成8K采样率  每次samples个采样(每秒50次),   8000 / 50 / samples 就是倍率
                    switch_core_media_bug_set_read_replace_frame(bug, frame);

                    long sampleRate = frame->samples * 50;

                    if(pvt->sampleRate == 0) {
                        pvt->sampleRate = 8000;
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SWITCH_ABC_TYPE_READ_REPLACE sampleRate before Trans: %f\n",pvt->callUUID, sampleRate);
                    }


                    if(sampleRate > 8000) {
                        int beilv = sampleRate / 8000;
                        char newData[frame_len / beilv];
                        for(int i =0 ;i < frame_len / (beilv * 2);i++) {
                            newData[i * 2] = frame_data[i * beilv * 2];
                            newData[i * 2 + 1] = frame_data[i * beilv * 2 + 1];
                        }

                        if ( pvt->stream != NULL ) {
                            fwrite(newData, sizeof(char), frame_len / beilv , pvt->stream);
                        }
                    } else {
                        if ( pvt->stream != NULL ) {
                            fwrite(frame_data, sizeof(char), frame_len , pvt->stream);
                        }
                    }

                    

                    pvt->totalSample ++;
                    if(pvt->totalSample > pvt->currentMaxSampleSec * 50) {
                        fclose(pvt->stream);
                        pvt->stream = NULL;
                        pvt->stop = 1;
			//这里是采样完成之后的识别操作,自己发挥吧
                        			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s HD doCompare after %d sec, filePath:%s\n", pvt->callUUID, pvt->currentMaxSampleSec, pvt->filePath);

                    }
                }
    
            }
            break;
        default: break;
    }
    return SWITCH_TRUE;
}


SWITCH_STANDARD_APP(start_asr_session_function)
{
    switch_channel_t *channel = switch_core_session_get_channel(session);

    switch_status_t status;
    switch_da_t *pvt;
    switch_codec_implementation_t read_impl;
    memset(&read_impl, 0, sizeof(switch_codec_implementation_t));

    char *argv[2] = { 0 };
    int argc;
    char *lbuf = NULL;


    switch_core_session_get_read_impl(session, &read_impl);

    if (!(pvt = (switch_da_t*)switch_core_session_alloc(session, sizeof(switch_da_t)))) {
        return;
    }

    pvt->stop = 0;
    pvt->currentMaxSampleSec = globals.maxSampleSec;
    pvt->session = session;
    pvt->callUUID = switch_core_session_get_uuid(session);

    if (!zstr(data) && (lbuf = switch_core_session_strdup(session, data))) {
        pvt->currentMaxSampleSec = atoi(lbuf);
    }

    //添加media_bug 回调
    if ((status = switch_core_media_bug_add(session, "asr", NULL,
        asr_callback, pvt, 0, SMBF_READ_REPLACE | SMBF_NO_PAUSE | SMBF_ONE_ONLY, &(pvt->bug))) != SWITCH_STATUS_SUCCESS) {
        return;
    }

    switch_channel_set_private(channel, "asr", pvt);
    switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Start HD %s\n", switch_channel_get_name(channel), switch_core_session_get_uuid(session));
}





//mod 加载,做一些初始化操作
SWITCH_MODULE_LOAD_FUNCTION(mod_asr_load)
{
    switch_application_interface_t *app_interface;
    globals.pool = pool;

    *module_interface = switch_loadable_module_create_module_interface(globals.pool, modname);

    //注册app
    SWITCH_ADD_APP(app_interface, "start_hd", "start hd", "start hangup detect", start_asr_session_function, "", SAF_MEDIA_TAP);
   
    switch_status_t status = load_config();
    if(SWITCH_STATUS_SUCCESS == status) {

        pthread_t tid;
        int ret = pthread_create(&tid, NULL, initStandardAudioByDir, globals.sampleDir);
        if (ret != 0) {
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "HD load thread create faild, ret: %d\n", ret);
            return SWITCH_STATUS_FALSE;
        }

        //initStandardAudioByDir(globals.sampleDir);
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " hangup detect loaded ....\n");
        return SWITCH_STATUS_SUCCESS;
    }
    return status;
}


SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_asr_shutdown)
{
    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " hangup detect shutdown\n");
    return SWITCH_STATUS_SUCCESS;
}

//从配置文件加载配置
static switch_status_t load_config(void)
{
	char *cf = "hangup_detect.conf";
    size_t url_len = 0;
    char *api_base;
	switch_xml_t cfg, xml = NULL, param, settings;
	switch_status_t status = SWITCH_STATUS_SUCCESS;

    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "load config\n");
	if ( ! (xml = switch_xml_open_cfg(cf, &cfg, NULL)) ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
		status = SWITCH_STATUS_FALSE;
		goto done;
	}

	if ( (settings = switch_xml_child(cfg, "settings")) ) {
		for ( param = switch_xml_child(settings, "param"); param; param = param->next ) {
			char *var = (char *) switch_xml_attr_soft(param, "name");
			char *val = (char *) switch_xml_attr_soft(param, "value");
		    if ( strcasecmp(var, "pcmDir") == 0 ) {
				globals.pcmDir = switch_core_strdup(globals.pool, val);
			} else if ( strcasecmp(var, "sampleDir") == 0 ) {
				globals.sampleDir = switch_core_strdup(globals.pool, val);
			} else if ( strcasecmp(var, "deleteFileScore") == 0 ) {
				globals.deleteFileScore = atoi(val);
            } else if ( strcasecmp(var, "maxSampleSec") == 0 ) {
                globals.maxSampleSec = atoi(val);
            }
		}
	}
    done:
	    if (xml) {
		    switch_xml_free(xml);
	    }
	return status;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×