diff --git a/chan_capi.c b/chan_capi.c index daac9da..2399fbb 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -7230,59 +7230,61 @@ static struct capicommands_s { pbx_capi_command_proc_t cmd; int capionly; int resourceplcisupported; + int notchannelrelated; } capicommands[] = { - { "getid", pbx_capi_get_id, 0, 0 }, - { "peerlink", pbx_capi_peer_link, 0, 0 }, - { "progress", pbx_capi_signal_progress, 1, 0 }, - { "deflect", pbx_capi_call_deflect, 1, 0 }, - { "receivefax", pbx_capi_receive_fax, 1, 1 }, - { "sendfax", pbx_capi_send_fax, 1, 1 }, - { "echosquelch", pbx_capi_echosquelch, 1, 0 }, - { "echocancel", pbx_capi_echocancel, 1, 1 }, + { "getid", pbx_capi_get_id, 0, 0, 0 }, + { "peerlink", pbx_capi_peer_link, 0, 0, 0 }, + { "progress", pbx_capi_signal_progress, 1, 0, 0 }, + { "deflect", pbx_capi_call_deflect, 1, 0, 0 }, + { "receivefax", pbx_capi_receive_fax, 1, 1, 0 }, + { "sendfax", pbx_capi_send_fax, 1, 1, 0 }, + { "echosquelch", pbx_capi_echosquelch, 1, 0, 0 }, + { "echocancel", pbx_capi_echocancel, 1, 1, 0 }, - { "noisesuppressor", pbx_capi_noisesuppressor, 1, 1 }, - { "rxagc", pbx_capi_rxagc, 1, 1 }, - { "txagc", pbx_capi_txagc, 1, 1 }, - { "rxdgain", pbx_capi_rxdgain, 1, 1 }, - { "incrxdgain", pbx_capi_incrxdgain, 1, 1 }, - { "txdgain", pbx_capi_txdgain, 1, 1 }, - { "inctxdgain", pbx_capi_inctxdgain, 1, 1 }, - { "clamping", pbx_capi_clamping, 1, 1 }, - { "mftonedetection", pbx_capi_mftonedetection, 1, 1 }, - { "pulsedetection", pbx_capi_pulsedetection, 1, 1 }, - { "sendtone", pbx_capi_sendtone, 1, 1 }, - { "stoptone", pbx_capi_stoptone, 1, 1 }, - { "starttonedetection", pbx_capi_starttonedetection, 1, 1 }, - { "stoptonedetection", pbx_capi_stoptonedetection, 1, 1 }, - { "pitchcontrol", pbx_capi_pitchcontrol, 1, 1 }, - { "incpitchcontrol", pbx_capi_incpitchcontrol, 1, 1 }, + { "noisesuppressor", pbx_capi_noisesuppressor, 1, 1, 0 }, + { "rxagc", pbx_capi_rxagc, 1, 1, 0 }, + { "txagc", pbx_capi_txagc, 1, 1, 0 }, + { "rxdgain", pbx_capi_rxdgain, 1, 1, 0 }, + { "incrxdgain", pbx_capi_incrxdgain, 1, 1, 0 }, + { "txdgain", pbx_capi_txdgain, 1, 1, 0 }, + { "inctxdgain", pbx_capi_inctxdgain, 1, 1, 0 }, + { "clamping", pbx_capi_clamping, 1, 1, 0 }, + { "mftonedetection", pbx_capi_mftonedetection, 1, 1, 0 }, + { "pulsedetection", pbx_capi_pulsedetection, 1, 1, 0 }, + { "sendtone", pbx_capi_sendtone, 1, 1, 0 }, + { "stoptone", pbx_capi_stoptone, 1, 1, 0 }, + { "starttonedetection", pbx_capi_starttonedetection, 1, 1, 0 }, + { "stoptonedetection", pbx_capi_stoptonedetection, 1, 1, 0 }, + { "pitchcontrol", pbx_capi_pitchcontrol, 1, 1, 0 }, + { "incpitchcontrol", pbx_capi_incpitchcontrol, 1, 1, 0 }, - { "vc", pbx_capi_voicecommand, 1, 1 }, - { "vctransparency", pbx_capi_voicecommand_transparency, 1, 1 }, + { "vc", pbx_capi_voicecommand, 1, 1, 0 }, + { "vctransparency", pbx_capi_voicecommand_transparency, 1, 1, 0 }, - { "getplci", pbx_capi_getplci, 1, 0 }, + { "getplci", pbx_capi_getplci, 1, 0, 0 }, - { "malicious", pbx_capi_malicious, 1, 0 }, - { "keypad", pbx_capi_keypad, 1, 0 }, - { "hold", pbx_capi_hold, 1, 0 }, - { "holdtype", pbx_capi_holdtype, 1, 0 }, - { "retrieve", pbx_capi_retrieve, 0, 0 }, - { "ect", pbx_capi_ect, 1, 0 }, - { "3pty_begin", pbx_capi_3pty_begin, 1, 0 }, - { "ccbs", pbx_capi_ccbs, 0, 0 }, - { "ccbsstop", pbx_capi_ccbsstop, 0, 0 }, - { "ccpartybusy", pbx_capi_ccpartybusy, 0, 0 }, - { "chat", pbx_capi_chat, 0, 0 }, - { "chat_command", pbx_capi_chat_command, 0, 0 }, - { "chat_mute", pbx_capi_chat_mute, 0, 0 }, - { "chat_play", pbx_capi_chat_play, 0, 0 }, - { "resource", pbx_capi_chat_associate_resource_plci, 0, 0 }, - { "mwi", pbx_capi_mwi, 1, 0 }, - { "hangup", pbx_capi_realhangup, 0, 0 }, - { "qsig_ssct", pbx_capi_qsig_ssct, 1, 0 }, - { "qsig_ct", pbx_capi_qsig_ct, 1, 0 }, - { "qsig_callmark",pbx_capi_qsig_callmark, 1, 0 }, - { "qsig_getplci", pbx_capi_qsig_getplci, 1, 0 }, + { "malicious", pbx_capi_malicious, 1, 0, 0 }, + { "keypad", pbx_capi_keypad, 1, 0, 0 }, + { "hold", pbx_capi_hold, 1, 0, 0 }, + { "holdtype", pbx_capi_holdtype, 1, 0, 0 }, + { "retrieve", pbx_capi_retrieve, 0, 0, 0 }, + { "ect", pbx_capi_ect, 1, 0, 0 }, + { "3pty_begin", pbx_capi_3pty_begin, 1, 0, 0 }, + { "ccbs", pbx_capi_ccbs, 0, 0, 0 }, + { "ccbsstop", pbx_capi_ccbsstop, 0, 0, 0 }, + { "ccpartybusy", pbx_capi_ccpartybusy, 0, 0, 0 }, + { "chat", pbx_capi_chat, 0, 0, 0 }, + { "chat_command", pbx_capi_chat_command, 0, 0, 0 }, + { "chat_mute", pbx_capi_chat_mute, 0, 0, 0 }, + { "chat_play", pbx_capi_chat_play, 0, 0, 0 }, + { "chat_connect", pbx_capi_chat_connect, 0, 0, 1 }, + { "resource", pbx_capi_chat_associate_resource_plci, 0, 0, 0 }, + { "mwi", pbx_capi_mwi, 1, 0, 0 }, + { "hangup", pbx_capi_realhangup, 0, 0, 0 }, + { "qsig_ssct", pbx_capi_qsig_ssct, 1, 0, 0 }, + { "qsig_ct", pbx_capi_qsig_ct, 1, 0, 0 }, + { "qsig_callmark",pbx_capi_qsig_callmark, 1, 0, 0 }, + { "qsig_getplci", pbx_capi_qsig_getplci, 1, 0, 0 }, { NULL, NULL, 0 } }; @@ -7324,11 +7326,15 @@ static int pbx_capicommand_exec(struct ast_channel *chan, void *data) return -1; } + if (chan != NULL) { #ifdef CC_AST_HAS_VERSION_1_4 - u = ast_module_user_add(chan); + u = ast_module_user_add(chan); #else - LOCAL_USER_ADD(u); + LOCAL_USER_ADD(u); #endif + } else { + u = NULL; + } s = ast_strdupa(data); stringp = s; @@ -7342,18 +7348,21 @@ static int pbx_capicommand_exec(struct ast_channel *chan, void *data) break; capicmd++; } - if (!capicmd->cmd) { + if ((capicmd->cmd == NULL) || + ((chan == NULL) && (capicmd->notchannelrelated == 0))) { + if (chan != NULL) { #ifdef CC_AST_HAS_VERSION_1_4 - ast_module_user_remove(u); + ast_module_user_remove(u); #else - LOCAL_USER_REMOVE(u); + LOCAL_USER_REMOVE(u); #endif - cc_log(LOG_WARNING, "Unknown command '%s' for capicommand\n", - command); + } + cc_log(LOG_WARNING, "%s command '%s' for capicommand\n", + (capicmd->cmd == NULL) ? "Unknown" : "Channel required for", command); return -1; } - if (chan->tech != &capi_tech) { + if ((chan != NULL) && (chan->tech != &capi_tech)) { if (capicmd->capionly != 0) { struct capi_pvt* resource_plci = pbx_check_resource_plci (chan); @@ -7373,12 +7382,15 @@ static int pbx_capicommand_exec(struct ast_channel *chan, void *data) } res = (capicmd->cmd)(chan, params); - + + if (chan != NULL) { #ifdef CC_AST_HAS_VERSION_1_4 - ast_module_user_remove(u); + ast_module_user_remove(u); #else - LOCAL_USER_REMOVE(u); + LOCAL_USER_REMOVE(u); #endif + } + return res; } diff --git a/chan_capi.h b/chan_capi.h index ea06c36..1e15ce1 100644 --- a/chan_capi.h +++ b/chan_capi.h @@ -52,6 +52,7 @@ #ifdef DIVA_STREAMING struct _diva_stream_scheduling_entry; #endif +struct _pbx_capi_conference_bridge; #define CAPI_MAX_CONTROLLERS 64 #define CAPI_MAX_B3_BLOCKS 7 @@ -561,6 +562,8 @@ struct capi_pvt { #ifdef DIVA_STREAMING struct _diva_stream_scheduling_entry* diva_stream_entry; #endif + /* Connection between two conference rooms. NULL PLCI */ + struct capi_pvt *bridgePeer; /*! Next channel in list */ struct capi_pvt *next; diff --git a/chan_capi_chat.c b/chan_capi_chat.c index 24e3201..1ba8eef 100644 --- a/chan_capi_chat.c +++ b/chan_capi_chat.c @@ -364,7 +364,7 @@ static void del_chat_member(struct capichat_s *room) /* * add a new chat member */ -static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i, room_member_type_t room_member_type) +static struct capichat_s *add_chat_member(const char *roomname, struct capi_pvt *i, room_member_type_t room_member_type) { struct capichat_s *room = NULL; struct capichat_s *tmproom; @@ -1318,3 +1318,81 @@ void pbx_capi_unlock_chat_rooms(void) cc_mutex_unlock(&chat_lock); } +/*! + \brief Connect two conference rooms. + */ +static struct capi_pvt* +pbx_capi_create_conference_bridge(const char* mainName, + unsigned long long mainController, + const char* additionalName, + unsigned long long additionalController) +{ + struct capi_pvt *capi_ifc[2] = { 0, 0 }; + struct capichat_s *room[sizeof(capi_ifc)/sizeof(capi_ifc[0])] = { 0, 0 }; + const char* name[sizeof(capi_ifc)/sizeof(capi_ifc[0])] = { mainName, additionalName }; + unsigned long long controller[sizeof(capi_ifc)/sizeof(capi_ifc[0])] = { mainController, additionalController }; + int error, i; + + if ((mainName == 0) || (additionalName == 0) || + (mainController == 0) || (additionalController == 0)) + return NULL; + + pbx_capi_nulliflist_lock(); + for (i = 0, error = 0; (error == 0) && (i < sizeof(name)/sizeof(name[0])); i++) { + capi_ifc[i] = capi_mknullif(NULL, controller[i]); + error |= (capi_ifc[i] == NULL); + } + if (error == 0) { + capi_ifc[0]->bridgePeer = capi_ifc[1]; + capi_ifc[1]->bridgePeer = capi_ifc[0]; + } + pbx_capi_nulliflist_unlock(); + + for (i = 0; (error == 0) && (i < sizeof(name)/sizeof(name[0])); i++) { + room[i] = add_chat_member(name[i], capi_ifc[i], RoomMemberOperator); + error |= (room[i] == NULL); + } + + if (error != 0) { + for (i = 0; i < sizeof(name)/sizeof(name[0]); i++) { + if (room[i] != 0) { + del_chat_member(room[i]); + } + if (capi_ifc[i] != 0) { + capi_remove_nullif(capi_ifc[i]); + capi_ifc[i] = 0; + } + } + } + + return capi_ifc[0]; +} + +/*! + \brief Connect two conference rooms. "room,controller,room,controller"; + */ +int pbx_capi_chat_connect(struct ast_channel *c, char *param) { + char* rooms[2]; + unsigned long long controllers[sizeof(rooms)/sizeof(rooms[0])] = { 0UL, 0UL }; + struct capi_pvt *capi_ifc; + int i; + + for (i = 0; i < sizeof(rooms)/sizeof(rooms[0]); i++) { + char* v; + rooms[i] = strsep(¶m, COMMANDSEPARATOR); + v = pbx_capi_strsep_controller_list (¶m); + controllers[i] = ast_get_group(v); + } + + capi_ifc = pbx_capi_create_conference_bridge(rooms[0], controllers[0], rooms[1], controllers[1]); + + if (capi_ifc != NULL) { + cc_verbose(3, 0, VERBOSE_PREFIX_3 CC_MESSAGE_NAME + "Chat connect '%s' <-> '%s'\n", rooms[0], rooms[1]); + } else { + cc_log(LOG_WARNING, "Chat failed to connect '%s' <-> '%s'\n", rooms[0], rooms[1]); + } + + return ((capi_ifc != NULL) ? 0 : -1); +} + diff --git a/chan_capi_chat.h b/chan_capi_chat.h index b131af2..45324e0 100644 --- a/chan_capi_chat.h +++ b/chan_capi_chat.h @@ -26,6 +26,7 @@ extern int pbxcli_capi_chatinfo(int fd, int argc, char *argv[]); extern int pbx_capi_chat_command (struct ast_channel *c, char *param); extern int pbx_capi_chat_mute(struct ast_channel *c, char *param); extern int pbx_capi_chat_play(struct ast_channel *c, char *param); +extern int pbx_capi_chat_connect(struct ast_channel *c, char *param); int pbx_capi_chat_remove_user(const char* room, const char* name); struct capichat_s; diff --git a/chan_capi_management_common.c b/chan_capi_management_common.c index a1154ad..fdc6c20 100644 --- a/chan_capi_management_common.c +++ b/chan_capi_management_common.c @@ -63,6 +63,11 @@ int pbx_capi_management_capicommand(const char *requiredChannelName, const char return -3; } + if (strcmp(requiredChannelName, "none") == 0) { + int ret = (pbx_capi_cli_exec_capicommand(NULL, chancapiCommand) == 0) ? 0 : -1; + return (ret); + } + for (ifc_type = 0; ifc_type < sizeof(data)/sizeof(data[0]); ifc_type++) { search_loops = 10; do { diff --git a/chan_capi_utils.c b/chan_capi_utils.c index cf7ccd7..82460e3 100644 --- a/chan_capi_utils.c +++ b/chan_capi_utils.c @@ -191,7 +191,7 @@ struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long control cc_mutex_init(&tmp->lock); ast_cond_init(&tmp->event_trigger, NULL); - snprintf(tmp->name, sizeof(tmp->name) - 1, "%s-NULLPLCI", c->name); + snprintf(tmp->name, sizeof(tmp->name) - 1, "%s-NULLPLCI", (c != 0) ? c->name : "BRIDGE"); snprintf(tmp->vname, sizeof(tmp->vname) - 1, "%s", tmp->name); tmp->channeltype = CAPI_CHANNELTYPE_NULL; @@ -214,9 +214,11 @@ struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long control tmp->txgain = 1.0; capi_gains(&tmp->g, 1.0, 1.0); - if (!(capi_create_reader_writer_pipe(tmp))) { - ast_free(tmp); - return NULL; + if (c != 0) { + if (!(capi_create_reader_writer_pipe(tmp))) { + ast_free(tmp); + return NULL; + } } tmp->bproto = CC_BPROTO_TRANSPARENT; @@ -1646,3 +1648,31 @@ void pbx_capi_nulliflist_unlock(void) cc_mutex_unlock(&nullif_lock); } +/*! + \brief get list of controllers. Stop parsing + after non digit detected after separator + character or end of string is reached + */ +char* pbx_capi_strsep_controller_list (char** param) +{ + char *src, *p; + + if ((param == NULL) || (*param == NULL) || (**param == 0)) + return NULL; + + if (strchr(*param, '|') != NULL) + return (strsep(param, "|")); + + src = *param; + p = src - 1; + do { + p = strchr(p+1, ','); + } while ((p != NULL) && (isdigit(p[1]) != 0)); + + if (p != NULL) + *p++ = 0; + + *param = p; + + return src; +} diff --git a/chan_capi_utils.h b/chan_capi_utils.h index fc0fa62..a179535 100644 --- a/chan_capi_utils.h +++ b/chan_capi_utils.h @@ -62,6 +62,7 @@ extern int capi_verify_resource_plci(const struct capi_pvt *i); extern const char* pbx_capi_get_cid (const struct ast_channel* c, const char *notAvailableVisual); extern const char* pbx_capi_get_callername (const struct ast_channel* c, const char *notAvailableVisual); const char* pbx_capi_get_connectedname (const struct ast_channel* c, const char *notAvailableVisual); +char* pbx_capi_strsep_controller_list (char** param); #define capi_number(data, strip) \ capi_number_func(data, strip, alloca(AST_MAX_EXTENSION)) diff --git a/divastreaming/chan_capi_divastreaming_utils.c b/divastreaming/chan_capi_divastreaming_utils.c index 6fe15a9..d55252c 100644 --- a/divastreaming/chan_capi_divastreaming_utils.c +++ b/divastreaming/chan_capi_divastreaming_utils.c @@ -78,8 +78,24 @@ static int divaStreamingMessageRx (void* user_context, dword message, dword leng if (likely(process_indication != 0)) { if (likely(Ind == 8)) { - if (likely(pE->i != 0 && pE->i->NCCI != 0)) - capidev_handle_data_b3_indication_vector (pE->i, vind, vind_nr); + if (likely(pE->i != 0 && pE->i->NCCI != 0)) { + if (pE->i->bridgePeer != 0) { + struct capi_pvt* bridgePeer = pE->i->bridgePeer; + if (bridgePeer->NCCI != 0 && bridgePeer->diva_stream_entry != 0 && + bridgePeer->diva_stream_entry->diva_stream_state == DivaStreamActive && + bridgePeer->diva_stream_entry->diva_stream->get_tx_free (bridgePeer->diva_stream_entry->diva_stream) > 2*CAPI_MAX_B3_BLOCK_SIZE+128) { + dword i = 0, k = 0, b3len; + byte b3buf[CAPI_MAX_B3_BLOCK_SIZE]; + b3len = diva_streaming_read_vector_data(vind, vind_nr, &i, &k, b3buf, CAPI_MAX_B3_BLOCK_SIZE); + bridgePeer->diva_stream_entry->diva_stream->write (bridgePeer->diva_stream_entry->diva_stream, + 8U << 8 | DIVA_STREAM_MESSAGE_TX_IDI_REQUEST, + b3buf, b3len); + bridgePeer->diva_stream_entry->diva_stream->flush_stream(bridgePeer->diva_stream_entry->diva_stream); + } + } else { + capidev_handle_data_b3_indication_vector (pE->i, vind, vind_nr); + } + } } else { dword i = 0, k = 0; word data_length;