00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "asterisk.h"
00030
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 89430 $")
00032
00033 #include "asterisk/module.h"
00034 #include "asterisk/channel.h"
00035 #include "asterisk/pbx.h"
00036 #include "asterisk/utils.h"
00037 #include "asterisk/audiohook.h"
00038
00039 struct volume_information {
00040 struct ast_audiohook audiohook;
00041 int tx_gain;
00042 int rx_gain;
00043 };
00044
00045 static void destroy_callback(void *data)
00046 {
00047 struct volume_information *vi = data;
00048
00049
00050 ast_audiohook_destroy(&vi->audiohook);
00051 free(vi);
00052
00053 return;
00054 }
00055
00056
00057 static const struct ast_datastore_info volume_datastore = {
00058 .type = "volume",
00059 .destroy = destroy_callback
00060 };
00061
00062 static int volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00063 {
00064 struct ast_datastore *datastore = NULL;
00065 struct volume_information *vi = NULL;
00066 int *gain = NULL;
00067
00068
00069 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00070 return 0;
00071
00072
00073 if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL)))
00074 return 0;
00075
00076 vi = datastore->data;
00077
00078
00079 if (frame->frametype == AST_FRAME_DTMF) {
00080
00081 if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00082 return 0;
00083 if (frame->subclass == '*') {
00084 vi->tx_gain += 1;
00085 vi->rx_gain += 1;
00086 } else if (frame->subclass == '#') {
00087 vi->tx_gain -= 1;
00088 vi->rx_gain -= 1;
00089 }
00090 } else if (frame->frametype == AST_FRAME_VOICE) {
00091
00092 if (!(gain = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? &vi->rx_gain : &vi->tx_gain) || !*gain)
00093 return 0;
00094
00095 ast_frame_adjust_volume(frame, *gain);
00096 }
00097
00098 return 0;
00099 }
00100
00101 static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00102 {
00103 struct ast_datastore *datastore = NULL;
00104 struct volume_information *vi = NULL;
00105 int is_new = 0;
00106
00107 if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) {
00108
00109 if (!(datastore = ast_channel_datastore_alloc(&volume_datastore, NULL)))
00110 return 0;
00111 if (!(vi = ast_calloc(1, sizeof(*vi)))) {
00112 ast_channel_datastore_free(datastore);
00113 return 0;
00114 }
00115 ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00116 vi->audiohook.manipulate_callback = volume_callback;
00117 ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
00118 is_new = 1;
00119 } else {
00120 vi = datastore->data;
00121 }
00122
00123
00124 if (!strcasecmp(data, "tx"))
00125 vi->tx_gain = atoi(value);
00126 else if (!strcasecmp(data, "rx"))
00127 vi->rx_gain = atoi(value);
00128
00129 if (is_new) {
00130 datastore->data = vi;
00131 ast_channel_datastore_add(chan, datastore);
00132 ast_audiohook_attach(chan, &vi->audiohook);
00133 }
00134
00135 return 0;
00136 }
00137
00138 static struct ast_custom_function volume_function = {
00139 .name = "VOLUME",
00140 .synopsis = "Set the TX or RX volume of a channel",
00141 .syntax = "VOLUME(TX|RX)",
00142 .desc =
00143 " The VOLUME function can be used to increase or decrease the tx or\n"
00144 "rx gain of any channel. For example:\n"
00145 " Set(VOLUME(TX)=3)\n"
00146 " Set(VOLUME(RX)=2)\n",
00147 .write = volume_write,
00148 };
00149
00150 static int unload_module(void)
00151 {
00152 return ast_custom_function_unregister(&volume_function);
00153 }
00154
00155 static int load_module(void)
00156 {
00157 return ast_custom_function_register(&volume_function);
00158 }
00159
00160 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Technology independent volume control");