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