diff --git a/libs/freetdm/mod_openzap/mod_openzap.c b/libs/freetdm/mod_openzap/mod_openzap.c index ee8234c99f..3042d8e817 100644 --- a/libs/freetdm/mod_openzap/mod_openzap.c +++ b/libs/freetdm/mod_openzap/mod_openzap.c @@ -2665,7 +2665,7 @@ void dump_chan_xml(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *s ); } -#define OZ_SYNTAX "list || dump [] || q931_pcap on|off [pcapfilename without suffix]" +#define OZ_SYNTAX "list || dump [] || q931_pcap on|off [pcapfilename without suffix] || gains " SWITCH_STANDARD_API(oz_function) { char *mycmd = NULL, *argv[10] = { 0 }; @@ -2750,7 +2750,7 @@ SWITCH_STANDARD_API(oz_function) for (j = 0 ; j < ZAP_MAX_SPANS_INTERFACE; j++) { if (SPAN_CONFIG[j].span) { const char *flags = "none"; - zap_channel_sig_status_t chanstatus; + zap_signaling_status_t sigstatus; if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_3WAY) { flags = "3way"; @@ -2758,8 +2758,7 @@ SWITCH_STANDARD_API(oz_function) flags = "call swap"; } - /* check signaling status just in the first span channel */ - if ((ZAP_SUCCESS == zap_channel_get_sig_status(SPAN_CONFIG[j].span->channels[1], &chanstatus))) { + if ((ZAP_SUCCESS == zap_span_get_sig_status(SPAN_CONFIG[j].span, &sigstatus))) { stream->write_function(stream, "+OK\n" "span: %u (%s)\n" @@ -2775,7 +2774,7 @@ SWITCH_STANDARD_API(oz_function) j, SPAN_CONFIG[j].span->name, SPAN_CONFIG[j].type, - zap_sig_status2str(chanstatus), + zap_signaling_status2str(sigstatus), SPAN_CONFIG[j].span->chan_count, SPAN_CONFIG[j].dialplan, SPAN_CONFIG[j].context, @@ -2883,6 +2882,44 @@ SWITCH_STANDARD_API(oz_function) goto end; } + } else if (!strcasecmp(argv[0], "gains")) { + int i = 0; + float txgain = 0.0; + float rxgain = 0.0; + uint32_t chan_id = 0; + zap_span_t *span = NULL; + if (argc < 4) { + stream->write_function(stream, "-ERR Usage: oz gains []\n"); + goto end; + } + zap_span_find_by_name(argv[3], &span); + if (!span) { + stream->write_function(stream, "-ERR invalid span\n"); + goto end; + } + if (argc > 4) { + chan_id = atoi(argv[4]); + if (chan_id > span->chan_count) { + stream->write_function(stream, "-ERR invalid chan\n"); + goto end; + } + } + i = sscanf(argv[1], "%f", &rxgain); + i += sscanf(argv[2], "%f", &txgain); + if (i != 2) { + stream->write_function(stream, "-ERR invalid gains\n"); + goto end; + } + if (chan_id) { + zap_channel_command(span->channels[chan_id], ZAP_COMMAND_SET_RX_GAIN, &rxgain); + zap_channel_command(span->channels[chan_id], ZAP_COMMAND_SET_TX_GAIN, &txgain); + } else { + for (i = 1; i < span->chan_count; i++) { + zap_channel_command(span->channels[i], ZAP_COMMAND_SET_RX_GAIN, &rxgain); + zap_channel_command(span->channels[i], ZAP_COMMAND_SET_TX_GAIN, &txgain); + } + } + stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain); } else { char *rply = zap_api_execute(cmd, NULL); diff --git a/libs/freetdm/src/include/openzap.h b/libs/freetdm/src/include/openzap.h index 5a311e6c6f..15996fd64c 100644 --- a/libs/freetdm/src/include/openzap.h +++ b/libs/freetdm/src/include/openzap.h @@ -473,7 +473,8 @@ typedef enum { ZAP_TYPE_CHANNEL } zap_data_type_t; - +/* 2^8 table size, one for each byte value */ +#define ZAP_GAINS_TABLE_SIZE 256 struct zap_channel { zap_data_type_t data_type; uint32_t span_id; @@ -535,6 +536,10 @@ struct zap_channel { zap_hash_t *variable_hash; unsigned char rx_cas_bits; uint32_t pre_buffer_size; + unsigned char rxgain_table[ZAP_GAINS_TABLE_SIZE]; + unsigned char txgain_table[ZAP_GAINS_TABLE_SIZE]; + float rxgain; + float txgain; }; diff --git a/libs/freetdm/src/include/zap_types.h b/libs/freetdm/src/include/zap_types.h index eb5c698f5e..e4f6811b57 100644 --- a/libs/freetdm/src/include/zap_types.h +++ b/libs/freetdm/src/include/zap_types.h @@ -73,6 +73,7 @@ struct zap_io_interface; #define ZAP_COMMAND_OBJ_INT *((int *)obj) #define ZAP_COMMAND_OBJ_CHAR_P (char *)obj +#define ZAP_COMMAND_OBJ_FLOAT *(float *)obj #define ZAP_FSK_MOD_FACTOR 0x10000 #define ZAP_DEFAULT_DTMF_ON 250 #define ZAP_DEFAULT_DTMF_OFF 50 @@ -403,7 +404,9 @@ typedef enum { ZAP_CHANNEL_PROGRESS = (1 << 21), ZAP_CHANNEL_MEDIA = (1 << 22), ZAP_CHANNEL_ANSWERED = (1 << 23), - ZAP_CHANNEL_MUTE = (1 << 24) + ZAP_CHANNEL_MUTE = (1 << 24), + ZAP_CHANNEL_USE_RX_GAIN = (1 << 25), + ZAP_CHANNEL_USE_TX_GAIN = (1 << 26), } zap_channel_flag_t; #if defined(__cplusplus) && defined(WIN32) // fix C2676 diff --git a/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c b/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c index a6f436ffc5..027bdabcea 100644 --- a/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c +++ b/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c @@ -33,7 +33,7 @@ * Contributors: * * Moises Silva - * David Yatzin + * David Yat Sin * Nenad Corbic * */ diff --git a/libs/freetdm/src/zap_io.c b/libs/freetdm/src/zap_io.c index 5aec3021fb..09814a522d 100644 --- a/libs/freetdm/src/zap_io.c +++ b/libs/freetdm/src/zap_io.c @@ -587,17 +587,65 @@ OZ_DECLARE(zap_status_t) zap_span_load_tones(zap_span_t *span, const char *mapna } +#define ZAP_SLINEAR_MAX_VALUE 32767 +#define ZAP_SLINEAR_MIN_VALUE -32767 +static void reset_gain_table(unsigned char *gain_table, float new_gain, zap_codec_t codec_gain) +{ + /* sample value */ + unsigned sv = 0; + /* linear gain factor */ + float lingain = 0; + /* linear value for each table sample */ + float linvalue = 0; + /* amplified (or attenuated in case of negative amplification) sample value */ + int ampvalue = 0; + + /* gain tables are only for alaw and ulaw */ + if (codec_gain != ZAP_CODEC_ALAW && codec_gain != ZAP_CODEC_ULAW) { + zap_log(ZAP_LOG_WARNING, "Not resetting gain table because codec is not ALAW or ULAW but %d\n", codec_gain); + return; + } + + if (!new_gain) { + /* for a 0.0db gain table, each alaw/ulaw sample value is left untouched (0 ==0, 1 == 1, 2 == 2 etc)*/ + for (sv = 0; sv < ZAP_GAINS_TABLE_SIZE; sv++) { + gain_table[sv] = sv; + } + return; + } + + /* use the 20log rule to increase the gain: http://en.wikipedia.org/wiki/Gain, http:/en.wipedia.org/wiki/20_log_rule#Definitions */ + lingain = pow(10.0, new_gain/ 20.0); + for (sv = 0; sv < ZAP_GAINS_TABLE_SIZE; sv++) { + /* get the linear value for this alaw/ulaw sample value */ + linvalue = codec_gain == ZAP_CODEC_ALAW ? alaw_to_linear(sv) : ulaw_to_linear(sv); + + /* multiply the linear value and the previously calculated linear gain */ + ampvalue = (int)(linvalue * lingain); + + /* chop it if goes beyond the limits */ + if (ampvalue > ZAP_SLINEAR_MAX_VALUE) { + ampvalue = ZAP_SLINEAR_MAX_VALUE; + } + + if (ampvalue < ZAP_SLINEAR_MIN_VALUE) { + ampvalue = ZAP_SLINEAR_MIN_VALUE; + } + gain_table[sv] = codec_gain == ZAP_CODEC_ALAW ? linear_to_alaw(ampvalue) : linear_to_ulaw(ampvalue); + } +} + OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan) { + unsigned i = 0; if (span->chan_count < ZAP_MAX_CHANNELS_SPAN) { zap_channel_t *new_chan = span->channels[++span->chan_count]; if (!new_chan) { - if (!(new_chan = zap_malloc(sizeof(*new_chan)))) { + if (!(new_chan = zap_calloc(1, sizeof(*new_chan)))) { return ZAP_FAIL; } span->channels[span->chan_count] = new_chan; - memset(new_chan, 0, sizeof(*new_chan)); } new_chan->type = type; @@ -626,6 +674,12 @@ OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t soc new_chan->dtmf_hangup_buf = zap_calloc (span->dtmf_hangup_len + 1, sizeof (char)); + /* set 0.0db gain table */ + for (i = 0; i < sizeof(new_chan->txgain_table); i++) { + new_chan->txgain_table[i] = i; + new_chan->rxgain_table[i] = i; + } + zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY); *chan = new_chan; return ZAP_SUCCESS; @@ -1833,6 +1887,40 @@ OZ_DECLARE(zap_status_t) zap_channel_command(zap_channel_t *zchan, zap_command_t zap_mutex_unlock(zchan->pre_buffer_mutex); } break; + + /* FIXME: validate user gain values */ + case ZAP_COMMAND_SET_RX_GAIN: + { + zchan->rxgain = ZAP_COMMAND_OBJ_FLOAT; + reset_gain_table(zchan->rxgain_table, zchan->rxgain, zchan->native_codec); + if (zchan->rxgain == 0.0) { + zap_clear_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN); + } else { + zap_set_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN); + } + } + break; + case ZAP_COMMAND_GET_RX_GAIN: + { + ZAP_COMMAND_OBJ_FLOAT = zchan->rxgain; + } + break; + case ZAP_COMMAND_SET_TX_GAIN: + { + zchan->txgain = ZAP_COMMAND_OBJ_FLOAT; + reset_gain_table(zchan->txgain_table, zchan->txgain, zchan->native_codec); + if (zchan->txgain == 0.0) { + zap_clear_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN); + } else { + zap_set_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN); + } + } + break; + case ZAP_COMMAND_GET_TX_GAIN: + { + ZAP_COMMAND_OBJ_FLOAT = zchan->txgain; + } + break; default: break; } @@ -2212,10 +2300,10 @@ OZ_DECLARE(zap_status_t) zap_channel_read(zap_channel_t *zchan, void *data, zap_ zap_status_t status = ZAP_FAIL; zio_codec_t codec_func = NULL; zap_size_t max = *datalen; + unsigned i = 0; assert(zchan != NULL); assert(zchan->zio != NULL); - assert(zchan->zio != NULL); if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) { snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open"); @@ -2237,6 +2325,13 @@ OZ_DECLARE(zap_status_t) zap_channel_read(zap_channel_t *zchan, void *data, zap_ } if (status == ZAP_SUCCESS) { + if (zap_test_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN) + && (zchan->native_codec == ZAP_CODEC_ALAW || zchan->native_codec == ZAP_CODEC_ULAW)) { + unsigned char *rdata = data; + for (i = 0; i < *datalen; i++) { + rdata[i] = zchan->rxgain_table[rdata[i]]; + } + } handle_dtmf(zchan, *datalen); } @@ -2435,6 +2530,7 @@ OZ_DECLARE(zap_status_t) zap_channel_write(zap_channel_t *zchan, void *data, zap zap_status_t status = ZAP_FAIL; zio_codec_t codec_func = NULL; zap_size_t max = datasize; + unsigned int i = 0; assert(zchan != NULL); assert(zchan->zio != NULL); @@ -2484,6 +2580,13 @@ OZ_DECLARE(zap_status_t) zap_channel_write(zap_channel_t *zchan, void *data, zap } } + if (zap_test_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN) + && (zchan->native_codec == ZAP_CODEC_ALAW || zchan->native_codec == ZAP_CODEC_ULAW)) { + unsigned char *wdata = data; + for (i = 0; i < *datalen; i++) { + wdata[i] = zchan->txgain_table[wdata[i]]; + } + } status = zchan->zio->write(zchan, data, datalen); return status;