Author: knhor Date: Thu Nov 23 20:01:35 2006 New Revision: 3450 Modified: freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c Log: add ability to pass caller control args from xml to callback handler. add dialout from caller control fn. Modified: freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c ============================================================================== --- freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c (original) +++ freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c Thu Nov 23 20:01:35 2006 @@ -82,6 +82,7 @@ CALLER_CONTROL_VOL_LISTEN_DN, CALLER_CONTROL_HANGUP, CALLER_CONTROL_MENU, + CALLER_CONTROL_DIAL, } caller_control_t; // forward declaration for conference_obj and caller_control @@ -948,6 +949,53 @@ } } +static void conference_loop_fn_dial(conference_member_t *member, void *data) +{ + if (member != NULL && data != NULL) { + char *lbuf = strdup(data); + char *argv[4]; + int argc = 0; + + if (lbuf != NULL) { + memset(argv,0,sizeof(argv)); + argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dial argc %u 1 '%s' 2 '%s' 3 '%s' 4 '%s'\n", + argc,argv[0],argv[1],argv[2],argv[3]); + if (argc >= 4) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "executing conference outcall\n"); + conference_outcall(member->conference, NULL, argv[0], atoi(argv[1]), NULL, argv[3], argv[2]); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "conference outcall not executed\n"); + } + + free(lbuf); + } + } +} + +static struct caller_control_fn_table { + char *key; + char *digits; + caller_control_t action; + void (*handler)(conference_member_t *, void *); +} ccfntbl[] = { + {"mute", "0", CALLER_CONTROL_MUTE, conference_loop_fn_mute_toggle}, + {"deaf mute", "*", CALLER_CONTROL_DEAF_MUTE, conference_loop_fn_deafmute_toggle}, + {"energy up", "9", CALLER_CONTROL_ENERGY_UP, conference_loop_fn_energy_up}, + {"energy equ", "8", CALLER_CONTROL_ENERGY_EQU_CONF, conference_loop_fn_energy_equ_conf}, + {"energy dn", "7", CALLER_CONTROL_ENERGEY_DN, conference_loop_fn_energy_dn}, + {"vol talk up", "3", CALLER_CONTROL_VOL_TALK_UP, conference_loop_fn_volume_talk_up}, + {"vol talk zero", "2", CALLER_CONTROL_VOL_TALK_ZERO, conference_loop_fn_volume_talk_zero}, + {"vol talk dn", "1", CALLER_CONTROL_VOL_TALK_DN, conference_loop_fn_volume_talk_dn}, + {"vol listen up", "6", CALLER_CONTROL_VOL_LISTEN_UP, conference_loop_fn_volume_listen_up}, + {"vol listen zero", "5", CALLER_CONTROL_VOL_LISTEN_ZERO, conference_loop_fn_volume_listen_zero}, + {"vol listen dn", "4", CALLER_CONTROL_VOL_LISTEN_DN, conference_loop_fn_volume_listen_dn}, + {"hangup", "#", CALLER_CONTROL_HANGUP, conference_loop_fn_hangup}, + {"menu", NULL, CALLER_CONTROL_MENU, conference_loop_fn_menu}, + {"dial", NULL, CALLER_CONTROL_DIAL, conference_loop_fn_dial}, +}; +#define CCFNTBL_QTY (sizeof(ccfntbl)/sizeof(ccfntbl[0])) + /* Create a thread for the conference and launch it */ static void launch_input_thread(conference_member_t *member, switch_memory_pool_t *pool) { @@ -1048,8 +1096,17 @@ for (digit = dtmf; *digit; digit++) { action = (caller_control_action_t *)switch_ivr_digit_stream_parser_feed(member->conference->dtmf_parser, *digit); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "digit_stream_parser_feed result != NULL %u\n",action != NULL); +// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "digit_stream_parser_feed result != NULL %u\n",action != NULL); if (action != NULL && action->handler != NULL) { + int i,found=0; + + for(i=0; i<CCFNTBL_QTY; i++) { + if (action->handler == ccfntbl[i].handler) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "excuting caller control '%s' param '%s'\n",ccfntbl[i].key,(ccfntbl[i].action != CALLER_CONTROL_MENU ? action->data : "")); + found = 1; + } + } + action->handler(member,action->data); } } @@ -2181,7 +2238,7 @@ int err = 0; if (argc > 2) { - conference_outcall(conference, NULL, argv[2], 60, argv[3], argv[4], argv[5]); + conference_outcall(conference, NULL, argv[2], 60, NULL, argv[4], argv[3]); stream->write_function(stream, "OK\n"); } else { err = 1; @@ -2331,7 +2388,7 @@ {"relate", &conf_api_sub_relate, 0, "<confname> relate <member_id> <other_member_id> [nospeak|nohear|clear]"}, {"lock", &conf_api_sub_lock, 0, "<confname> lock"}, {"unlock", &conf_api_sub_unlock, 0, "<confname> unlock"}, - {"dial", &conf_api_sub_dial, 0, "<confname> dial <endpoint_module_name>/<destination>"}, + {"dial", &conf_api_sub_dial, 0, "<confname> dial <endpoint_module_name>/<destination> <callerid number> <callerid name>"}, {"transfer", &conf_api_sub_transfer, 0, "<confname> transfer <member_id> <conference_name>"}, {"record", &conf_api_sub_record, 0, "<confname> record <filename>"}, {"norecord", &conf_api_sub_norecord, 0, "<confname> norecord <[filename|all]>"}, @@ -3222,28 +3279,6 @@ /*.chat_interface */ &conference_chat_interface }; -static struct caller_control_fn_table { - char *key; - char *digits; - caller_control_t action; - void (*handler)(conference_member_t *, void *); -} ccfntbl[] = { - {"mute", "0", CALLER_CONTROL_MUTE, conference_loop_fn_mute_toggle}, - {"deaf mute", "*", CALLER_CONTROL_DEAF_MUTE, conference_loop_fn_deafmute_toggle}, - {"energy up", "9", CALLER_CONTROL_ENERGY_UP, conference_loop_fn_energy_up}, - {"energy equ", "8", CALLER_CONTROL_ENERGY_EQU_CONF, conference_loop_fn_energy_equ_conf}, - {"energy dn", "7", CALLER_CONTROL_ENERGEY_DN, conference_loop_fn_energy_dn}, - {"vol talk up", "3", CALLER_CONTROL_VOL_TALK_UP, conference_loop_fn_volume_talk_up}, - {"vol talk zero", "2", CALLER_CONTROL_VOL_TALK_ZERO, conference_loop_fn_volume_talk_zero}, - {"vol talk dn", "1", CALLER_CONTROL_VOL_TALK_DN, conference_loop_fn_volume_talk_dn}, - {"vol listen up", "6", CALLER_CONTROL_VOL_LISTEN_UP, conference_loop_fn_volume_listen_up}, - {"vol listen zero", "5", CALLER_CONTROL_VOL_LISTEN_ZERO, conference_loop_fn_volume_listen_zero}, - {"vol listen dn", "4", CALLER_CONTROL_VOL_LISTEN_DN, conference_loop_fn_volume_listen_dn}, - {"hangup", "#", CALLER_CONTROL_HANGUP, conference_loop_fn_hangup}, - {"menu", NULL, CALLER_CONTROL_MENU, conference_loop_fn_menu}, -}; -#define CCFNTBL_QTY (sizeof(ccfntbl)/sizeof(ccfntbl[0])) - static switch_ivr_action_t conference_caller_control_menu_handler(switch_ivr_menu_t *menu, char *param, char *buf, size_t buflen, void *obj) { switch_ivr_action_t action = SWITCH_IVR_ACTION_NOOP; @@ -3251,16 +3286,33 @@ if (!switch_strlen_zero(param)) { if (obj != NULL) { int i,found; + char *action_name = strdup(param); - for(i=0,found=0; !found && i<CCFNTBL_QTY; i++) { - found = (ccfntbl[i].action != CALLER_CONTROL_MENU && strcasecmp(ccfntbl[i].key,param) == 0); - if (found) { - if (obj != NULL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "invoking caller control menu action '%s'\n",param); - ccfntbl[i].handler((conference_member_t *)obj,NULL); + if (action_name != NULL) { + char *sep = (action_name != NULL ? strchr(action_name,' ') : NULL); + + // split the action from any parameters + if (sep != NULL) { + *sep ='\0'; + } + + // find and execute the caller control handler + for(i=0,found=0; !found && i<CCFNTBL_QTY; i++) { + found = (ccfntbl[i].action != CALLER_CONTROL_MENU && strcasecmp(ccfntbl[i].key,action_name) == 0); + if (found) { + if (obj != NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "invoking caller control menu action '%s'\n",ccfntbl[i].key); + ccfntbl[i].handler((conference_member_t *)obj, (sep != NULL ? sep+1 : NULL)); + if (ccfntbl[i].action == CALLER_CONTROL_HANGUP) { + action = SWITCH_IVR_ACTION_DIE; + } + } } } + + free(action_name); } + if (!found) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unknown caller control menu action '%s'\n",param); } @@ -3554,25 +3606,19 @@ caller_control_action_t *action; for(i=0,status=SWITCH_STATUS_SUCCESS; status == SWITCH_STATUS_SUCCESS && i<CCFNTBL_QTY; i++) { - switch(ccfntbl[i].action) - { - case CALLER_CONTROL_MENU: - // default caller control, has no menu specification - break; - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing default caller control action '%s' bound to '%s'.\n", - ccfntbl[i].key, - ccfntbl[i].digits); - action = (caller_control_action_t *)switch_core_alloc(conference->pool,sizeof(caller_control_action_t)); - if (action != NULL) { - action->handler = ccfntbl[i].handler; - action->data = NULL; - status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser,ccfntbl[i].digits,action); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n",ccfntbl[i].key,ccfntbl[i].digits); - status = SWITCH_STATUS_MEMERR; - } - break; + if (!switch_strlen_zero(ccfntbl[i].digits)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing default caller control action '%s' bound to '%s'.\n", + ccfntbl[i].key, + ccfntbl[i].digits); + action = (caller_control_action_t *)switch_core_alloc(conference->pool,sizeof(caller_control_action_t)); + if (action != NULL) { + action->handler = ccfntbl[i].handler; + action->data = NULL; + status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser,ccfntbl[i].digits,action); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n",ccfntbl[i].key,ccfntbl[i].digits); + status = SWITCH_STATUS_MEMERR; + } } } } else if (strcasecmp(controls_set,"custom") == 0) { @@ -3580,43 +3626,43 @@ for (xml_kvp = switch_xml_child(xml_controls, "control"); xml_kvp; xml_kvp = xml_kvp->next) { char *key = (char *) switch_xml_attr(xml_kvp, "action"); char *val = (char *) switch_xml_attr(xml_kvp, "digits"); + char *data = (char *)switch_xml_attr_soft(xml_kvp, "data"); if(!switch_strlen_zero(key) && !switch_strlen_zero(val)) { int i; - caller_control_action_t *action; // scan through all of the valid actions, and if found, // set the new caller control action digit string, then // stop scanning the table, and go to the next xml kvp. for(i=0,status=SWITCH_STATUS_NOOP; i<CCFNTBL_QTY && status == SWITCH_STATUS_NOOP; i++) { - caller_control_menu_ctx_t *menu_ctx = NULL; if(strcasecmp(ccfntbl[i].key,key) == 0) { - switch(ccfntbl[i].action) - { - case CALLER_CONTROL_MENU: - { - char *menu_name = (char *)switch_xml_attr_soft(xml_kvp, "menu-name"); + status = SWITCH_STATUS_SUCCESS; - status = conference_caller_control_menu_build(&menu_ctx,conference,profile,menu_name); - if (status != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to build menu '%s' bound to '%s'\n", menu_name, val); - break; - } - } - // deliberate fall through to default case - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing caller control action '%s' bound to '%s'.\n",key,val); - action = (caller_control_action_t *)switch_core_alloc(conference->pool,sizeof(caller_control_action_t)); - if (action != NULL) { - action->handler = ccfntbl[i].handler; - action->data = (void *)menu_ctx; - status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser,val,action); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n",ccfntbl[i].key,ccfntbl[i].digits); - status = SWITCH_STATUS_MEMERR; - } - break; + if (ccfntbl[i].action == CALLER_CONTROL_MENU) { + caller_control_menu_ctx_t *menu_ctx = NULL; + + status = conference_caller_control_menu_build(&menu_ctx,conference,profile,data); + data = (char *)menu_ctx; + + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to build menu '%s' bound to '%s'\n",data,val); + } + } + + if (status == SWITCH_STATUS_SUCCESS) { + caller_control_action_t *action; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing caller control action '%s' bound to '%s'.\n",key,val); + action = (caller_control_action_t *)switch_core_alloc(conference->pool,sizeof(caller_control_action_t)); + if (action != NULL) { + action->handler = ccfntbl[i].handler; + action->data = (void *)data; + status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser,val,action); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n",ccfntbl[i].key,ccfntbl[i].digits); + status = SWITCH_STATUS_MEMERR; + } } } }