]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
added the ability to set the audio gain in openzap channels via software
authorMoises Silva <moy@sangoma.com>
Fri, 12 Mar 2010 21:52:41 +0000 (21:52 +0000)
committerMoises Silva <moy@sangoma.com>
Fri, 12 Mar 2010 21:52:41 +0000 (21:52 +0000)
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@1061 a93c3328-9c30-0410-af19-c9cd2b2d52af

libs/openzap/mod_openzap/mod_openzap.c
libs/openzap/src/include/openzap.h
libs/openzap/src/include/zap_types.h
libs/openzap/src/zap_io.c

index c9159f3cb71c4c723f7af009031f4a78812c9354..5cad5abb798630e63ede694f8a7289b6d6cb2776 100644 (file)
@@ -2878,7 +2878,7 @@ void dump_chan_xml(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *s
                                                   );
 }
 
-#define OZ_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix]" 
+#define OZ_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <span> <txgain> <rxgain>
 SWITCH_STANDARD_API(oz_function)
 {
        char *mycmd = NULL, *argv[10] = { 0 };
@@ -3067,6 +3067,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 <txgain> <rxgain> <span_id> [<chan_id>]\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);
                
index 18275c43bf64ff87489d8db1d9f8732444fc0a35..8fde5795d54b7757859ad9741c79154ccc8a10f4 100644 (file)
@@ -494,7 +494,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;
@@ -556,6 +557,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;
 };
 
 
index 1ac2e86ba4dd1d1faa95cad3157d54d42bef2ae8..3bb726148e143cb296745dcef1eb86355045f708 100644 (file)
@@ -69,6 +69,7 @@ typedef struct zap_interrupt zap_interrupt_t;
 
 #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
@@ -380,7 +381,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;
 
 typedef enum {
index f0acf1ba2777aef0d3e667e642d84222c8396e28..8ca5e71b560aaa1d3051a3edae9768ac6085904c 100644 (file)
@@ -35,8 +35,6 @@
 #ifndef WIN32
 #endif
 #include "openzap.h"
-//#include "zap_isdn.h"
-//#include "zap_ss7_boost.h"
 #include <stdarg.h>
 #ifdef WIN32
 #include <io.h>
@@ -569,8 +567,67 @@ 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)*/
+               sv = 0;
+               while (1) {
+                       gain_table[sv] = sv;
+                       if (sv == (ZAP_GAINS_TABLE_SIZE - 1)) {
+                               break;
+                       }
+                       sv++;
+               }
+               return;
+       }
+
+       /* use the 20log rule to increase the gain: http://en.wikipedia.org/wiki/Gain, http:/en.wikipedia.org/wiki/20_log_rule#Definitions */
+       lingain = pow(10.0, new_gain/ 20.0);
+       sv = 0;
+       while (1) {
+               /* 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);
+               if (sv == (ZAP_GAINS_TABLE_SIZE-1)) {
+                       break;
+               }
+               sv++;
+       }
+}
+
 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];
 
@@ -608,6 +665,17 @@ OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t soc
 
                new_chan->dtmf_hangup_buf = calloc (span->dtmf_hangup_len + 1, sizeof (char));
 
+               /* set 0.0db gain table */
+               i = 0;
+               while (1) {
+                       new_chan->txgain_table[i] = i;
+                       new_chan->rxgain_table[i] = i;
+                       if (i == (sizeof(new_chan->txgain_table)-1)) {
+                               break;
+                       }
+                       i++;
+               }
+
                zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY);
                *chan = new_chan;
                return ZAP_SUCCESS;
@@ -1663,6 +1731,39 @@ OZ_DECLARE(zap_status_t) zap_channel_command(zap_channel_t *zchan, zap_command_t
                        zap_mutex_unlock(zchan->pre_buffer_mutex);
                }
                break;
+
+       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;
        }
@@ -2042,10 +2143,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");
@@ -2067,6 +2168,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);
        }
 
@@ -2265,6 +2373,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 i = 0;
 
        assert(zchan != NULL);
        assert(zchan->zio != NULL);
@@ -2314,6 +2423,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;