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 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 287647 $")
00031
00032 #include "asterisk/module.h"
00033 #include "asterisk/channel.h"
00034 #include "asterisk/pbx.h"
00035 #include "asterisk/framehook.h"
00036
00037
00038
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
00070
00071
00072
00073
00074
00075
00076 static void print_frame(struct ast_frame *frame);
00077 static struct {
00078 enum ast_frame_type type;
00079 const char *str;
00080 } frametype2str[] = {
00081 { AST_FRAME_DTMF_BEGIN, "DTMF_BEGIN" },
00082 { AST_FRAME_DTMF_END, "DTMF_END" },
00083 { AST_FRAME_VOICE, "VOICE" },
00084 { AST_FRAME_VIDEO, "VIDEO" },
00085 { AST_FRAME_CONTROL, "CONTROL" },
00086 { AST_FRAME_NULL, "NULL" },
00087 { AST_FRAME_IAX, "IAX" },
00088 { AST_FRAME_TEXT, "TEXT" },
00089 { AST_FRAME_IMAGE, "IMAGE" },
00090 { AST_FRAME_HTML, "HTML" },
00091 { AST_FRAME_CNG, "CNG" },
00092 { AST_FRAME_MODEM, "MODEM" },
00093 };
00094
00095 struct frame_trace_data {
00096 int list_type;
00097 int values[ARRAY_LEN(frametype2str)];
00098 };
00099
00100 static void datastore_destroy_cb(void *data) {
00101 ast_free(data);
00102 }
00103
00104 static const struct ast_datastore_info frame_trace_datastore = {
00105 .type = "frametrace",
00106 .destroy = datastore_destroy_cb
00107 };
00108
00109 static void hook_destroy_cb(void *framedata)
00110 {
00111 ast_free(framedata);
00112 }
00113
00114 static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
00115 {
00116 int i;
00117 int show_frame = 0;
00118 struct frame_trace_data *framedata = data;
00119 if (!frame) {
00120 return frame;
00121 }
00122
00123 if ((event != AST_FRAMEHOOK_EVENT_WRITE) && (event != AST_FRAMEHOOK_EVENT_READ)) {
00124 return frame;
00125 }
00126
00127 for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
00128 if (frame->frametype == frametype2str[i].type) {
00129 if ((framedata->list_type == 0) && (framedata->values[i])) {
00130 show_frame = 1;
00131 } else if ((framedata->list_type == 1) && (!framedata->values[i])){
00132 show_frame = 1;
00133 }
00134 break;
00135 }
00136 }
00137
00138 if (show_frame) {
00139 ast_verbose("%s on Channel %s\n", event == AST_FRAMEHOOK_EVENT_READ ? "<--Read" : "--> Write", chan->name);
00140 print_frame(frame);
00141 }
00142 return frame;
00143 }
00144
00145 static int frame_trace_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00146 {
00147 struct frame_trace_data *framedata;
00148 struct ast_datastore *datastore = NULL;
00149 struct ast_framehook_interface interface = {
00150 .version = AST_FRAMEHOOK_INTERFACE_VERSION,
00151 .event_cb = hook_event_cb,
00152 .destroy_cb = hook_destroy_cb,
00153 };
00154 int i = 0;
00155
00156 if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
00157 return 0;
00158 }
00159
00160 interface.data = framedata;
00161
00162 if (!strcasecmp(data, "black")) {
00163 framedata->list_type = 1;
00164 }
00165 for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
00166 if (strcasestr(value, frametype2str[i].str)) {
00167 framedata->values[i] = 1;
00168 }
00169 }
00170
00171 ast_channel_lock(chan);
00172 i = ast_framehook_attach(chan, &interface);
00173 if (i >= 0) {
00174 int *id;
00175 if ((datastore = ast_channel_datastore_find(chan, &frame_trace_datastore, NULL))) {
00176 id = datastore->data;
00177 ast_framehook_detach(chan, *id);
00178 ast_channel_datastore_remove(chan, datastore);
00179 }
00180
00181 if (!(datastore = ast_datastore_alloc(&frame_trace_datastore, NULL))) {
00182 ast_framehook_detach(chan, i);
00183 ast_channel_unlock(chan);
00184 return 0;
00185 }
00186
00187 if (!(id = ast_calloc(1, sizeof(int)))) {
00188 ast_datastore_free(datastore);
00189 ast_framehook_detach(chan, i);
00190 ast_channel_unlock(chan);
00191 return 0;
00192 }
00193
00194 *id = i;
00195 datastore->data = id;
00196 ast_channel_datastore_add(chan, datastore);
00197 }
00198 ast_channel_unlock(chan);
00199
00200 return 0;
00201 }
00202
00203 static void print_frame(struct ast_frame *frame)
00204 {
00205 switch (frame->frametype) {
00206 case AST_FRAME_DTMF_END:
00207 ast_verbose("FrameType: DTMF END\n");
00208 ast_verbose("Digit: %d\n", frame->subclass.integer);
00209 break;
00210 case AST_FRAME_VOICE:
00211 ast_verbose("FrameType: VOICE\n");
00212 ast_verbose("Codec: %s\n", ast_getformatname(frame->subclass.codec));
00213 ast_verbose("MS: %ld\n", frame->len);
00214 ast_verbose("Samples: %d\n", frame->samples);
00215 ast_verbose("Bytes: %d\n", frame->datalen);
00216 break;
00217 case AST_FRAME_VIDEO:
00218 ast_verbose("FrameType: VIDEO\n");
00219 ast_verbose("Codec: %s\n", ast_getformatname(frame->subclass.codec));
00220 ast_verbose("MS: %ld\n", frame->len);
00221 ast_verbose("Samples: %d\n", frame->samples);
00222 ast_verbose("Bytes: %d\n", frame->datalen);
00223 break;
00224 case AST_FRAME_CONTROL:
00225 ast_verbose("FrameType: CONTROL\n");
00226 switch (frame->subclass.integer) {
00227 case AST_CONTROL_HANGUP:
00228 ast_verbose("SubClass: HANGUP\n");
00229 break;
00230 case AST_CONTROL_RING:
00231 ast_verbose("SubClass: RING\n");
00232 break;
00233 case AST_CONTROL_RINGING:
00234 ast_verbose("SubClass: RINGING\n");
00235 break;
00236 case AST_CONTROL_ANSWER:
00237 ast_verbose("SubClass: ANSWER\n");
00238 break;
00239 case AST_CONTROL_BUSY:
00240 ast_verbose("SubClass: BUSY\n");
00241 break;
00242 case AST_CONTROL_TAKEOFFHOOK:
00243 ast_verbose("SubClass: TAKEOFFHOOK\n");
00244 break;
00245 case AST_CONTROL_OFFHOOK:
00246 ast_verbose("SubClass: OFFHOOK\n");
00247 break;
00248 case AST_CONTROL_CONGESTION:
00249 ast_verbose("SubClass: CONGESTION\n");
00250 break;
00251 case AST_CONTROL_FLASH:
00252 ast_verbose("SubClass: FLASH\n");
00253 break;
00254 case AST_CONTROL_WINK:
00255 ast_verbose("SubClass: WINK\n");
00256 break;
00257 case AST_CONTROL_OPTION:
00258 ast_verbose("SubClass: OPTION\n");
00259 break;
00260 case AST_CONTROL_RADIO_KEY:
00261 ast_verbose("SubClass: RADIO KEY\n");
00262 break;
00263 case AST_CONTROL_RADIO_UNKEY:
00264 ast_verbose("SubClass: RADIO UNKEY\n");
00265 break;
00266 case AST_CONTROL_PROGRESS:
00267 ast_verbose("SubClass: PROGRESS\n");
00268 break;
00269 case AST_CONTROL_PROCEEDING:
00270 ast_verbose("SubClass: PROCEEDING\n");
00271 break;
00272 case AST_CONTROL_HOLD:
00273 ast_verbose("SubClass: HOLD\n");
00274 break;
00275 case AST_CONTROL_UNHOLD:
00276 ast_verbose("SubClass: UNHOLD\n");
00277 break;
00278 case AST_CONTROL_VIDUPDATE:
00279 ast_verbose("SubClass: VIDUPDATE\n");
00280 break;
00281 case _XXX_AST_CONTROL_T38:
00282 ast_verbose("SubClass: XXX T38\n");
00283 break;
00284 case AST_CONTROL_SRCUPDATE:
00285 ast_verbose("SubClass: SRCUPDATE\n");
00286 break;
00287 case AST_CONTROL_TRANSFER:
00288 ast_verbose("SubClass: TRANSFER\n");
00289 break;
00290 case AST_CONTROL_CONNECTED_LINE:
00291 ast_verbose("SubClass: CONNECTED LINE\n");
00292 break;
00293 case AST_CONTROL_REDIRECTING:
00294 ast_verbose("SubClass: REDIRECTING\n");
00295 break;
00296 case AST_CONTROL_T38_PARAMETERS:
00297 ast_verbose("SubClass: T38 PARAMETERS\n");
00298 break;
00299 case AST_CONTROL_CC:
00300 ast_verbose("SubClass: CC\n");
00301 break;
00302 case AST_CONTROL_SRCCHANGE:
00303 ast_verbose("SubClass: SRCCHANGE\n");
00304 break;
00305 case AST_CONTROL_READ_ACTION:
00306 ast_verbose("SubClass: READ ACTION\n");
00307 break;
00308 case AST_CONTROL_AOC:
00309 ast_verbose("SubClass: AOC\n");
00310 break;
00311 }
00312 if (frame->subclass.integer == -1) {
00313 ast_verbose("SubClass: %d\n", frame->subclass.integer);
00314 }
00315 ast_verbose("Bytes: %d\n", frame->datalen);
00316 break;
00317 case AST_FRAME_NULL:
00318 ast_verbose("FrameType: NULL\n");
00319 break;
00320 case AST_FRAME_IAX:
00321 ast_verbose("FrameType: IAX\n");
00322 break;
00323 case AST_FRAME_TEXT:
00324 ast_verbose("FrameType: TXT\n");
00325 break;
00326 case AST_FRAME_IMAGE:
00327 ast_verbose("FrameType: IMAGE\n");
00328 break;
00329 case AST_FRAME_HTML:
00330 ast_verbose("FrameType: HTML\n");
00331 break;
00332 case AST_FRAME_CNG:
00333 ast_verbose("FrameType: CNG\n");
00334 break;
00335 case AST_FRAME_MODEM:
00336 ast_verbose("FrameType: MODEM\n");
00337 break;
00338 case AST_FRAME_DTMF_BEGIN:
00339 ast_verbose("FrameType: DTMF BEGIN\n");
00340 ast_verbose("Digit: %d\n", frame->subclass.integer);
00341 break;
00342 }
00343
00344 ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src);
00345 ast_verbose("\n");
00346 }
00347
00348 static struct ast_custom_function frame_trace_function = {
00349 .name = "FRAME_TRACE",
00350 .write = frame_trace_helper,
00351 };
00352
00353 static int unload_module(void)
00354 {
00355 return ast_custom_function_unregister(&frame_trace_function);
00356 }
00357
00358 static int load_module(void)
00359 {
00360 int res = ast_custom_function_register(&frame_trace_function);
00361 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00362 }
00363
00364 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Frame Trace for internal ast_frame debugging.");
00365