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: 227580 $")
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
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 struct volume_information {
00060 struct ast_audiohook audiohook;
00061 int tx_gain;
00062 int rx_gain;
00063 };
00064
00065 static void destroy_callback(void *data)
00066 {
00067 struct volume_information *vi = data;
00068
00069
00070 ast_audiohook_destroy(&vi->audiohook);
00071 ast_free(vi);
00072
00073 return;
00074 }
00075
00076
00077 static const struct ast_datastore_info volume_datastore = {
00078 .type = "volume",
00079 .destroy = destroy_callback
00080 };
00081
00082 static int volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00083 {
00084 struct ast_datastore *datastore = NULL;
00085 struct volume_information *vi = NULL;
00086 int *gain = NULL;
00087
00088
00089 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00090 return 0;
00091
00092
00093 if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL)))
00094 return 0;
00095
00096 vi = datastore->data;
00097
00098
00099 if (frame->frametype == AST_FRAME_DTMF) {
00100
00101 if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00102 return 0;
00103 if (frame->subclass.integer == '*') {
00104 vi->tx_gain += 1;
00105 vi->rx_gain += 1;
00106 } else if (frame->subclass.integer == '#') {
00107 vi->tx_gain -= 1;
00108 vi->rx_gain -= 1;
00109 }
00110 } else if (frame->frametype == AST_FRAME_VOICE) {
00111
00112 if (!(gain = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? &vi->rx_gain : &vi->tx_gain) || !*gain)
00113 return 0;
00114
00115 ast_frame_adjust_volume(frame, *gain);
00116 }
00117
00118 return 0;
00119 }
00120
00121 static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00122 {
00123 struct ast_datastore *datastore = NULL;
00124 struct volume_information *vi = NULL;
00125 int is_new = 0;
00126
00127 if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) {
00128
00129 if (!(datastore = ast_datastore_alloc(&volume_datastore, NULL)))
00130 return 0;
00131 if (!(vi = ast_calloc(1, sizeof(*vi)))) {
00132 ast_datastore_free(datastore);
00133 return 0;
00134 }
00135 ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00136 vi->audiohook.manipulate_callback = volume_callback;
00137 ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
00138 is_new = 1;
00139 } else {
00140 vi = datastore->data;
00141 }
00142
00143
00144 if (!strcasecmp(data, "tx"))
00145 vi->tx_gain = atoi(value);
00146 else if (!strcasecmp(data, "rx"))
00147 vi->rx_gain = atoi(value);
00148
00149 if (is_new) {
00150 datastore->data = vi;
00151 ast_channel_datastore_add(chan, datastore);
00152 ast_audiohook_attach(chan, &vi->audiohook);
00153 }
00154
00155 return 0;
00156 }
00157
00158 static struct ast_custom_function volume_function = {
00159 .name = "VOLUME",
00160 .write = volume_write,
00161 };
00162
00163 static int unload_module(void)
00164 {
00165 return ast_custom_function_unregister(&volume_function);
00166 }
00167
00168 static int load_module(void)
00169 {
00170 return ast_custom_function_register(&volume_function);
00171 }
00172
00173 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Technology independent volume control");