Go to the documentation of this file.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: 310585 $")
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 #include "asterisk/app.h"
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 struct volume_information {
00070 struct ast_audiohook audiohook;
00071 int tx_gain;
00072 int rx_gain;
00073 unsigned int flags;
00074 };
00075
00076 enum volume_flags {
00077 VOLUMEFLAG_CHANGE = (1 << 1),
00078 };
00079
00080 AST_APP_OPTIONS(volume_opts, {
00081 AST_APP_OPTION('p', VOLUMEFLAG_CHANGE),
00082 });
00083
00084 static void destroy_callback(void *data)
00085 {
00086 struct volume_information *vi = data;
00087
00088
00089 ast_audiohook_destroy(&vi->audiohook);
00090 free(vi);
00091
00092 return;
00093 }
00094
00095
00096 static const struct ast_datastore_info volume_datastore = {
00097 .type = "volume",
00098 .destroy = destroy_callback
00099 };
00100
00101 static int volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00102 {
00103 struct ast_datastore *datastore = NULL;
00104 struct volume_information *vi = NULL;
00105 int *gain = NULL;
00106
00107
00108 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00109 return 0;
00110
00111
00112 if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL)))
00113 return 0;
00114
00115 vi = datastore->data;
00116
00117
00118
00119 if (ast_test_flag(vi, VOLUMEFLAG_CHANGE)) {
00120 if (frame->frametype == AST_FRAME_DTMF) {
00121
00122 if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00123 return 0;
00124 if (frame->subclass == '*') {
00125 vi->tx_gain += 1;
00126 vi->rx_gain += 1;
00127 } else if (frame->subclass == '#') {
00128 vi->tx_gain -= 1;
00129 vi->rx_gain -= 1;
00130 }
00131 }
00132 }
00133
00134
00135 if (frame->frametype == AST_FRAME_VOICE) {
00136
00137 if (!(gain = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? &vi->rx_gain : &vi->tx_gain) || !*gain)
00138 return 0;
00139
00140 ast_frame_adjust_volume(frame, *gain);
00141 }
00142
00143 return 0;
00144 }
00145
00146 static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00147 {
00148 struct ast_datastore *datastore = NULL;
00149 struct volume_information *vi = NULL;
00150 int is_new = 0;
00151
00152
00153
00154 AST_DECLARE_APP_ARGS(args,
00155 AST_APP_ARG(direction);
00156 AST_APP_ARG(options);
00157 );
00158
00159 AST_STANDARD_APP_ARGS(args, data);
00160
00161 ast_channel_lock(chan);
00162 if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) {
00163 ast_channel_unlock(chan);
00164
00165 if (!(datastore = ast_datastore_alloc(&volume_datastore, NULL)))
00166 return 0;
00167 if (!(vi = ast_calloc(1, sizeof(*vi)))) {
00168 ast_datastore_free(datastore);
00169 return 0;
00170 }
00171 ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00172 vi->audiohook.manipulate_callback = volume_callback;
00173 ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
00174 is_new = 1;
00175 } else {
00176 ast_channel_unlock(chan);
00177 vi = datastore->data;
00178 }
00179
00180
00181 if (ast_strlen_zero(args.direction)) {
00182 ast_log(LOG_ERROR, "Direction must be specified for VOLUME function\n");
00183 return -1;
00184 }
00185
00186 if (!strcasecmp(args.direction, "tx")) {
00187 vi->tx_gain = atoi(value);
00188 } else if (!strcasecmp(args.direction, "rx")) {
00189 vi->rx_gain = atoi(value);
00190 } else {
00191 ast_log(LOG_ERROR, "Direction must be either RX or TX\n");
00192 }
00193
00194 if (is_new) {
00195 datastore->data = vi;
00196 ast_channel_lock(chan);
00197 ast_channel_datastore_add(chan, datastore);
00198 ast_channel_unlock(chan);
00199 ast_audiohook_attach(chan, &vi->audiohook);
00200 }
00201
00202
00203
00204 if (!ast_strlen_zero(args.options)) {
00205 struct ast_flags flags = { 0 };
00206 ast_app_parse_options(volume_opts, &flags, &data, args.options);
00207 vi->flags = flags.flags;
00208 } else {
00209 vi->flags = 0;
00210 }
00211
00212 return 0;
00213 }
00214
00215 static struct ast_custom_function volume_function = {
00216 .name = "VOLUME",
00217 .write = volume_write,
00218 };
00219
00220 static int unload_module(void)
00221 {
00222 return ast_custom_function_unregister(&volume_function);
00223 }
00224
00225 static int load_module(void)
00226 {
00227 return ast_custom_function_register(&volume_function);
00228 }
00229
00230 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Technology independent volume control");