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