/** * \brief Opens Wanpipe channel * \param ftdmchan Channel to open * \return Success or failure */ static FIO_OPEN_FUNCTION(wanpipe_open) { wanpipe_tdm_api_t tdm_api; memset(&tdm_api,0,sizeof(tdm_api)); sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api); #ifdef LIBSANGOMA_VERSION sangoma_flush_event_bufs(ftdmchan->sockfd, &tdm_api); #endif if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) { ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE; } else { ftdmchan->effective_codec = ftdmchan->native_codec; sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, wp_globals.codec_ms); ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL); ftdmchan->effective_interval = ftdmchan->native_interval = wp_globals.codec_ms; ftdmchan->packet_len = ftdmchan->native_interval * 8; } return FTDM_SUCCESS; }
/** * \brief Executes an FreeTDM command on a Wanpipe channel * \param ftdmchan Channel to execute command on * \param command FreeTDM command to execute * \param obj Object (unused) * \return Success or failure */ static FIO_COMMAND_FUNCTION(wanpipe_command) { wanpipe_tdm_api_t tdm_api; int err = 0; memset(&tdm_api, 0, sizeof(tdm_api)); switch(command) { case FTDM_COMMAND_OFFHOOK: { err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed"); return FTDM_FAIL; } ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); } break; case FTDM_COMMAND_ONHOOK: { err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed"); return FTDM_FAIL; } ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); } break; case FTDM_COMMAND_GENERATE_RING_ON: { err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed"); return FTDM_FAIL; } ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING); ftdm_set_pflag_locked(ftdmchan, WP_RINGING); ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms; } break; case FTDM_COMMAND_GENERATE_RING_OFF: { err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed"); return FTDM_FAIL; } ftdm_clear_pflag_locked(ftdmchan, WP_RINGING); ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING); } break; case FTDM_COMMAND_GET_INTERVAL: { err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api); if (err > 0 ) { FTDM_COMMAND_OBJ_INT = err; err=0; } } break; case FTDM_COMMAND_ENABLE_ECHOCANCEL: { err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed"); return FTDM_FAIL; } } break; case FTDM_COMMAND_DISABLE_ECHOCANCEL: { err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed"); return FTDM_FAIL; } } break; case FTDM_COMMAND_ENABLE_DTMF_DETECT: { #ifdef WP_API_FEATURE_DTMF_EVENTS err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api); if (err) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Enabling of Sangoma HW DTMF failed\n"); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Enable Failed"); return FTDM_FAIL; } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled DTMF events\n"); #else return FTDM_NOTIMPL; #endif } break; case FTDM_COMMAND_DISABLE_DTMF_DETECT: { #ifdef WP_API_FEATURE_DTMF_EVENTS err = sangoma_tdm_disable_dtmf_events(ftdmchan->sockfd, &tdm_api); if (err) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Disabling of Sangoma HW DTMF failed\n"); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Disable Failed"); return FTDM_FAIL; } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n"); #else return FTDM_NOTIMPL; #endif } break; case FTDM_COMMAND_ENABLE_LOOP: { #ifdef WP_API_FEATURE_LOOP err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed"); return FTDM_FAIL; } #endif } break; case FTDM_COMMAND_DISABLE_LOOP: { #ifdef WP_API_FEATURE_LOOP err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed"); return FTDM_FAIL; } #endif } break; case FTDM_COMMAND_SET_INTERVAL: { err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT); ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8); } break; case FTDM_COMMAND_SET_CAS_BITS: { #ifdef LIBSANGOMA_VERSION err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT)); #else err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT)); #endif } break; case FTDM_COMMAND_GET_CAS_BITS: { #ifdef LIBSANGOMA_VERSION unsigned char rbsbits; err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits); if (!err) { FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits); } #else // does sangoma_tdm_read_rbs is available here? FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits; #endif } break; case FTDM_COMMAND_SET_LINK_STATUS: { ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT; char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED; err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status); } break; case FTDM_COMMAND_GET_LINK_STATUS: { unsigned char sangoma_status = 0; err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status); if (!err) { FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED; } } break; default: break; }; if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno)); return FTDM_FAIL; } return FTDM_SUCCESS; }
static void *bridge_channel_media(void *channel_data) { unsigned char readframe[MEDIA_BUFFER_SIZE]; unsigned char writeframe[MEDIA_BUFFER_SIZE]; char trace_file_name[255]; char *trace_prefix = NULL; wanpipe_tdm_api_t tdm_api; sbridge_chan_t *chan = channel_data; sangoma_pri_t *spri = &chan->span->spri; int32_t channo = chan->channo; memset(readframe, 0, sizeof(readframe)); memset(writeframe, 0, sizeof(writeframe)); /* need to disable cancellation while registering the cleanup handler * if we get cancelled before registering, no harm done * once the cleanup handler gets registered, it does not matter * at which point of this thread we get cancelled, the cleanup routine * will take care of closing sockets or any other resource we eventually allocate * */ if (!sbridge_thread_setcancelstate(SBRIDGE_THREAD_CANCEL_DISABLE, NULL)) { sbridge_log(SBRIDGE_LOG_ERROR, "Failed to disable thread cancellation in chanel %d\n", channo); sbridge_thread_exit(NULL); } if (!sbridge_thread_setcanceltype(SBRIDGE_THREAD_CANCEL_DEFERRED, NULL)) { sbridge_log(SBRIDGE_LOG_ERROR, "Failed to set deferred cancel type in chanel %d\n", channo); sbridge_thread_exit(NULL); } /* just grab the lock to start once the thread that launched us is done using the channel * channel manipulations in this routine do not require the channel lock because the signaling * thread does not access the channel once the media thread is launched * */ sbridge_mutex_lock(&chan->lock); chan->running = SBRIDGE_TRUE; sbridge_mutex_unlock(&chan->lock); /* register the cleanup handler */ sbridge_thread_cleanup_push(clean_thread_data, chan); /* restore the cancellation state */ sbridge_thread_setcancelstate(SBRIDGE_THREAD_CANCEL_ENABLE, NULL); /* open sangoma media channel */ if ((chan->sangoma_sock = sangoma_open_tdmapi_span_chan(spri->span, channo)) < 0) { sbridge_log(SBRIDGE_LOG_ERROR, "Failed to open TDM API descriptor for sangoma channel %d\n", channo); sbridge_thread_exit(NULL); } if (!get_tcp_sock(chan)) { sbridge_log(SBRIDGE_LOG_ERROR, "Failed to get TCP socket for channel %d\n", channo); sbridge_thread_exit(NULL); } /* open the traces */ trace_prefix = chan->span->config->trace_prefix; if (strlen(trace_prefix)) { CHAN_MEDIA_TRACE_OPEN(trace_raw_in); CHAN_MEDIA_TRACE_OPEN(trace_raw_out); } /* set the channel read period */ if (sangoma_tdm_set_usr_period(chan->sangoma_sock, &tdm_api, SBRIDGE_MEDIA_PERIOD) < 0) { sbridge_log(SBRIDGE_LOG_ERROR, "Failed to set sangoma channel read period to %d\n", SBRIDGE_MEDIA_PERIOD); sbridge_thread_exit(NULL); } /* everything will be passed thru as received, WP_NONE */ if ((sangoma_tdm_set_codec(chan->sangoma_sock, &tdm_api, WP_NONE)) < 0) { sbridge_log(SBRIDGE_LOG_ERROR, "Failed to set native driver codec for sangoma channel %d\n", channo); sbridge_thread_exit(NULL); } chan->mtu = sangoma_tdm_get_usr_mtu_mru(chan->sangoma_sock, &tdm_api); if (chan->mtu != SBRIDGE_ALAW_MTU) { sbridge_log(SBRIDGE_LOG_ERROR, "Unexpected MTU of size %d, cannot handle media\n", chan->mtu); sbridge_thread_exit(NULL); } sbridge_log(SBRIDGE_LOG_NOTICE, "Sangoma socket MTU is %d\n", chan->mtu); /* run the proper application depending on the chan mode */ chan->app_func(chan); /* done, let's clean up our mess and notify the signaling thread */ sbridge_log(SBRIDGE_LOG_NOTICE, "Media thread for channel %d completed application execution\n", channo); if (!sbridge_thread_setcancelstate(SBRIDGE_THREAD_CANCEL_DISABLE, NULL)) { sbridge_log(SBRIDGE_LOG_ERROR, "Failed to disable thread cancellation when terminating media thread for channel %d\n", channo); sbridge_thread_exit(NULL); } /* this calls the cleanup handler to free resources */ sbridge_thread_cleanup_pop(SBRIDGE_THREAD_CLEANUP_EXECUTE); sbridge_thread_exit(NULL); return NULL; }
/** * \brief Executes an Openzap command on a Wanpipe channel * \param zchan Channel to execute command on * \param command Openzap command to execute * \param obj Object (unused) * \return Success or failure */ static ZIO_COMMAND_FUNCTION(wanpipe_command) { wanpipe_tdm_api_t tdm_api; int err = 0; memset(&tdm_api, 0, sizeof(tdm_api)); switch(command) { case ZAP_COMMAND_OFFHOOK: { err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed"); return ZAP_FAIL; } zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK); } break; case ZAP_COMMAND_ONHOOK: { err=sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed"); return ZAP_FAIL; } zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK); } break; case ZAP_COMMAND_GENERATE_RING_ON: { err=sangoma_tdm_txsig_start(zchan->sockfd,&tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed"); return ZAP_FAIL; } zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING); zap_set_pflag_locked(zchan, WP_RINGING); zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_on_ms; } break; case ZAP_COMMAND_GENERATE_RING_OFF: { err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed"); return ZAP_FAIL; } zap_clear_pflag_locked(zchan, WP_RINGING); zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING); } break; case ZAP_COMMAND_GET_INTERVAL: { err=sangoma_tdm_get_usr_period(zchan->sockfd, &tdm_api); if (err > 0 ) { ZAP_COMMAND_OBJ_INT = err; err=0; } } break; case ZAP_COMMAND_ENABLE_ECHOCANCEL: { err=sangoma_tdm_enable_hwec(zchan->sockfd, &tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Enable Failed"); return ZAP_FAIL; } } break; case ZAP_COMMAND_DISABLE_ECHOCANCEL: { err=sangoma_tdm_disable_hwec(zchan->sockfd, &tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Disable Failed"); return ZAP_FAIL; } } break; case ZAP_COMMAND_ENABLE_DTMF_DETECT: { #ifdef WP_API_FEATURE_DTMF_EVENTS err = sangoma_tdm_enable_dtmf_events(zchan->sockfd, &tdm_api); if (err) { zap_log(ZAP_LOG_WARNING, "Enabling of Sangoma HW DTMF failed\n"); snprintf(zchan->last_error, sizeof(zchan->last_error), "HW DTMF Enable Failed"); return ZAP_FAIL; } zap_log(ZAP_LOG_DEBUG, "Enabled DTMF events on chan %d:%d\n", zchan->span_id, zchan->chan_id); #else return ZAP_NOTIMPL; #endif } break; case ZAP_COMMAND_DISABLE_DTMF_DETECT: { #ifdef WP_API_FEATURE_DTMF_EVENTS err = sangoma_tdm_disable_dtmf_events(zchan->sockfd, &tdm_api); if (err) { zap_log(ZAP_LOG_WARNING, "Disabling of Sangoma HW DTMF failed\n"); snprintf(zchan->last_error, sizeof(zchan->last_error), "HW DTMF Disable Failed"); return ZAP_FAIL; } zap_log(ZAP_LOG_DEBUG, "Disabled DTMF events on chan %d:%d\n", zchan->span_id, zchan->chan_id); #else return ZAP_NOTIMPL; #endif } break; case ZAP_COMMAND_ENABLE_LOOP: { #ifdef WP_API_FEATURE_LOOP err=sangoma_tdm_enable_loop(zchan->sockfd, &tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "Loop Enable Failed"); return ZAP_FAIL; } #endif } break; case ZAP_COMMAND_DISABLE_LOOP: { #ifdef WP_API_FEATURE_LOOP err=sangoma_tdm_disable_loop(zchan->sockfd, &tdm_api); if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "Loop Disable Failed"); return ZAP_FAIL; } #endif } break; case ZAP_COMMAND_SET_INTERVAL: { err=sangoma_tdm_set_usr_period(zchan->sockfd, &tdm_api, ZAP_COMMAND_OBJ_INT); zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8); } break; case ZAP_COMMAND_SET_CAS_BITS: { #ifdef LIBSANGOMA_VERSION err = sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api, zchan->physical_chan_id, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT)); #else err = sangoma_tdm_write_rbs(zchan->sockfd, &tdm_api, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT)); #endif } break; case ZAP_COMMAND_GET_CAS_BITS: { #ifdef LIBSANGOMA_VERSION unsigned char rbsbits; err = sangoma_tdm_read_rbs(zchan->sockfd, &tdm_api, zchan->physical_chan_id, &rbsbits); if (!err) { ZAP_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits); } #else // does sangoma_tdm_read_rbs is available here? ZAP_COMMAND_OBJ_INT = zchan->rx_cas_bits; #endif } break; default: break; }; if (err) { snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno)); return ZAP_FAIL; } return ZAP_SUCCESS; }