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: 419684 $")
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 (!chan) {
00161 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00162 return -1;
00163 }
00164
00165 if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
00166 return 0;
00167 }
00168
00169 interface.data = framedata;
00170
00171 if (!strcasecmp(data, "black")) {
00172 framedata->list_type = 1;
00173 }
00174 for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
00175 if (strcasestr(value, frametype2str[i].str)) {
00176 framedata->values[i] = 1;
00177 }
00178 }
00179
00180 ast_channel_lock(chan);
00181 i = ast_framehook_attach(chan, &interface);
00182 if (i >= 0) {
00183 int *id;
00184 if ((datastore = ast_channel_datastore_find(chan, &frame_trace_datastore, NULL))) {
00185 id = datastore->data;
00186 ast_framehook_detach(chan, *id);
00187 ast_channel_datastore_remove(chan, datastore);
00188 ast_datastore_free(datastore);
00189 }
00190
00191 if (!(datastore = ast_datastore_alloc(&frame_trace_datastore, NULL))) {
00192 ast_framehook_detach(chan, i);
00193 ast_channel_unlock(chan);
00194 return 0;
00195 }
00196
00197 if (!(id = ast_calloc(1, sizeof(int)))) {
00198 ast_datastore_free(datastore);
00199 ast_framehook_detach(chan, i);
00200 ast_channel_unlock(chan);
00201 return 0;
00202 }
00203
00204 *id = i;
00205 datastore->data = id;
00206 ast_channel_datastore_add(chan, datastore);
00207 }
00208 ast_channel_unlock(chan);
00209
00210 return 0;
00211 }
00212
00213 static void print_frame(struct ast_frame *frame)
00214 {
00215 switch (frame->frametype) {
00216 case AST_FRAME_DTMF_END:
00217 ast_verbose("FrameType: DTMF END\n");
00218 ast_verbose("Digit: %d\n", frame->subclass.integer);
00219 break;
00220 case AST_FRAME_VOICE:
00221 ast_verbose("FrameType: VOICE\n");
00222 ast_verbose("Codec: %s\n", ast_getformatname(frame->subclass.codec));
00223 ast_verbose("MS: %ld\n", frame->len);
00224 ast_verbose("Samples: %d\n", frame->samples);
00225 ast_verbose("Bytes: %d\n", frame->datalen);
00226 break;
00227 case AST_FRAME_VIDEO:
00228 ast_verbose("FrameType: VIDEO\n");
00229 ast_verbose("Codec: %s\n", ast_getformatname(frame->subclass.codec));
00230 ast_verbose("MS: %ld\n", frame->len);
00231 ast_verbose("Samples: %d\n", frame->samples);
00232 ast_verbose("Bytes: %d\n", frame->datalen);
00233 break;
00234 case AST_FRAME_CONTROL:
00235 ast_verbose("FrameType: CONTROL\n");
00236 switch ((enum ast_control_frame_type) frame->subclass.integer) {
00237 case AST_CONTROL_HANGUP:
00238 ast_verbose("SubClass: HANGUP\n");
00239 break;
00240 case AST_CONTROL_RING:
00241 ast_verbose("SubClass: RING\n");
00242 break;
00243 case AST_CONTROL_RINGING:
00244 ast_verbose("SubClass: RINGING\n");
00245 break;
00246 case AST_CONTROL_ANSWER:
00247 ast_verbose("SubClass: ANSWER\n");
00248 break;
00249 case AST_CONTROL_BUSY:
00250 ast_verbose("SubClass: BUSY\n");
00251 break;
00252 case AST_CONTROL_TAKEOFFHOOK:
00253 ast_verbose("SubClass: TAKEOFFHOOK\n");
00254 break;
00255 case AST_CONTROL_OFFHOOK:
00256 ast_verbose("SubClass: OFFHOOK\n");
00257 break;
00258 case AST_CONTROL_CONGESTION:
00259 ast_verbose("SubClass: CONGESTION\n");
00260 break;
00261 case AST_CONTROL_FLASH:
00262 ast_verbose("SubClass: FLASH\n");
00263 break;
00264 case AST_CONTROL_WINK:
00265 ast_verbose("SubClass: WINK\n");
00266 break;
00267 case AST_CONTROL_OPTION:
00268 ast_verbose("SubClass: OPTION\n");
00269 break;
00270 case AST_CONTROL_RADIO_KEY:
00271 ast_verbose("SubClass: RADIO KEY\n");
00272 break;
00273 case AST_CONTROL_RADIO_UNKEY:
00274 ast_verbose("SubClass: RADIO UNKEY\n");
00275 break;
00276 case AST_CONTROL_PROGRESS:
00277 ast_verbose("SubClass: PROGRESS\n");
00278 break;
00279 case AST_CONTROL_PROCEEDING:
00280 ast_verbose("SubClass: PROCEEDING\n");
00281 break;
00282 case AST_CONTROL_HOLD:
00283 ast_verbose("SubClass: HOLD\n");
00284 break;
00285 case AST_CONTROL_UNHOLD:
00286 ast_verbose("SubClass: UNHOLD\n");
00287 break;
00288 case AST_CONTROL_VIDUPDATE:
00289 ast_verbose("SubClass: VIDUPDATE\n");
00290 break;
00291 case _XXX_AST_CONTROL_T38:
00292 ast_verbose("SubClass: XXX T38\n");
00293 break;
00294 case AST_CONTROL_SRCUPDATE:
00295 ast_verbose("SubClass: SRCUPDATE\n");
00296 break;
00297 case AST_CONTROL_TRANSFER:
00298 ast_verbose("SubClass: TRANSFER\n");
00299 break;
00300 case AST_CONTROL_CONNECTED_LINE:
00301 ast_verbose("SubClass: CONNECTED LINE\n");
00302 break;
00303 case AST_CONTROL_REDIRECTING:
00304 ast_verbose("SubClass: REDIRECTING\n");
00305 break;
00306 case AST_CONTROL_T38_PARAMETERS:
00307 ast_verbose("SubClass: T38 PARAMETERS\n");
00308 break;
00309 case AST_CONTROL_CC:
00310 ast_verbose("SubClass: CC\n");
00311 break;
00312 case AST_CONTROL_SRCCHANGE:
00313 ast_verbose("SubClass: SRCCHANGE\n");
00314 break;
00315 case AST_CONTROL_READ_ACTION:
00316 ast_verbose("SubClass: READ ACTION\n");
00317 break;
00318 case AST_CONTROL_AOC:
00319 ast_verbose("SubClass: AOC\n");
00320 break;
00321 case AST_CONTROL_INCOMPLETE:
00322 ast_verbose("SubClass: INCOMPLETE\n");
00323 break;
00324 case AST_CONTROL_END_OF_Q:
00325 ast_verbose("SubClass: END_OF_Q\n");
00326 break;
00327 case AST_CONTROL_UPDATE_RTP_PEER:
00328 ast_verbose("SubClass: UPDATE_RTP_PEER\n");
00329 break;
00330 }
00331
00332 if (frame->subclass.integer == -1) {
00333 ast_verbose("SubClass: %d\n", frame->subclass.integer);
00334 }
00335 ast_verbose("Bytes: %d\n", frame->datalen);
00336 break;
00337 case AST_FRAME_NULL:
00338 ast_verbose("FrameType: NULL\n");
00339 break;
00340 case AST_FRAME_IAX:
00341 ast_verbose("FrameType: IAX\n");
00342 break;
00343 case AST_FRAME_TEXT:
00344 ast_verbose("FrameType: TXT\n");
00345 break;
00346 case AST_FRAME_IMAGE:
00347 ast_verbose("FrameType: IMAGE\n");
00348 break;
00349 case AST_FRAME_HTML:
00350 ast_verbose("FrameType: HTML\n");
00351 break;
00352 case AST_FRAME_CNG:
00353 ast_verbose("FrameType: CNG\n");
00354 break;
00355 case AST_FRAME_MODEM:
00356 ast_verbose("FrameType: MODEM\n");
00357 break;
00358 case AST_FRAME_DTMF_BEGIN:
00359 ast_verbose("FrameType: DTMF BEGIN\n");
00360 ast_verbose("Digit: %d\n", frame->subclass.integer);
00361 break;
00362 }
00363
00364 ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src);
00365 ast_verbose("\n");
00366 }
00367
00368 static struct ast_custom_function frame_trace_function = {
00369 .name = "FRAME_TRACE",
00370 .write = frame_trace_helper,
00371 };
00372
00373 static int unload_module(void)
00374 {
00375 return ast_custom_function_unregister(&frame_trace_function);
00376 }
00377
00378 static int load_module(void)
00379 {
00380 int res = ast_custom_function_register(&frame_trace_function);
00381 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00382 }
00383
00384 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Frame Trace for internal ast_frame debugging.");
00385