Merge "BuildSystem: Really do not pass unknown-warning options to the compiler."
[asterisk/asterisk.git] / funcs / func_frame_trace.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * David Vossel <dvossel@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Trace internal ast_frames on a channel.
22  *
23  * \author David Vossel <dvossel@digium.com>
24  *
25  * \ingroup functions
26  */
27
28 /*** MODULEINFO
29         <support_level>extended</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include "asterisk/module.h"
35 #include "asterisk/channel.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/framehook.h"
38
39 /*** DOCUMENTATION
40         <function name="FRAME_TRACE" language="en_US">
41                 <synopsis>
42                         View internal ast_frames as they are read and written on a channel.
43                 </synopsis>
44                 <syntax>
45                         <parameter name="filter list type" required="true">
46                                 <para>A filter can be applied to the trace to limit what frames are viewed.  This
47                                 filter can either be a <literal>white</literal> or <literal>black</literal> list
48                                 of frame types.  When no filter type is present, <literal>white</literal> is
49                                 used.  If no arguments are provided at all, all frames will be output.
50                                 </para>
51
52                                 <para>Below are the different types of frames that can be filtered.</para>
53                                 <enumlist>
54                                         <enum name = "DTMF_BEGIN" />
55                                         <enum name = "DTMF_END" />
56                                         <enum name = "VOICE" />
57                                         <enum name = "VIDEO" />
58                                         <enum name = "CONTROL" />
59                                         <enum name = "NULL" />
60                                         <enum name = "IAX" />
61                                         <enum name = "TEXT" />
62                                         <enum name = "IMAGE" />
63                                         <enum name = "HTML" />
64                                         <enum name = "CNG" />
65                                         <enum name = "MODEM" />
66                                 </enumlist>
67                         </parameter>
68                 </syntax>
69                 <description>
70                         <para>Examples:</para>
71                         <para>exten => 1,1,Set(FRAME_TRACE(white)=DTMF_BEGIN,DTMF_END); view only DTMF frames. </para>
72                         <para>exten => 1,1,Set(FRAME_TRACE()=DTMF_BEGIN,DTMF_END); view only DTMF frames. </para>
73                         <para>exten => 1,1,Set(FRAME_TRACE(black)=DTMF_BEGIN,DTMF_END); view everything except DTMF frames. </para>
74                 </description>
75         </function>
76  ***/
77
78 static void print_frame(struct ast_frame *frame);
79 static struct {
80         enum ast_frame_type type;
81         const char *str;
82 } frametype2str[] = {
83         { AST_FRAME_DTMF_BEGIN,   "DTMF_BEGIN" },
84         { AST_FRAME_DTMF_END,   "DTMF_END" },
85         { AST_FRAME_VOICE,   "VOICE" },
86         { AST_FRAME_VIDEO,   "VIDEO" },
87         { AST_FRAME_CONTROL,   "CONTROL" },
88         { AST_FRAME_NULL,   "NULL" },
89         { AST_FRAME_IAX,   "IAX" },
90         { AST_FRAME_TEXT,   "TEXT" },
91         { AST_FRAME_IMAGE,   "IMAGE" },
92         { AST_FRAME_HTML,   "HTML" },
93         { AST_FRAME_CNG,   "CNG" },
94         { AST_FRAME_MODEM,   "MODEM" },
95 };
96
97 struct frame_trace_data {
98         int list_type; /* 0 = white, 1 = black */
99         int values[ARRAY_LEN(frametype2str)];
100 };
101
102 static void datastore_destroy_cb(void *data) {
103         ast_free(data);
104 }
105
106 static const struct ast_datastore_info frame_trace_datastore = {
107         .type = "frametrace",
108         .destroy = datastore_destroy_cb
109 };
110
111 static void hook_destroy_cb(void *framedata)
112 {
113         ast_free(framedata);
114 }
115
116 static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
117 {
118         int i;
119         int show_frame = 0;
120         struct frame_trace_data *framedata = data;
121         if (!frame) {
122                 return frame;
123         }
124
125         if ((event != AST_FRAMEHOOK_EVENT_WRITE) && (event != AST_FRAMEHOOK_EVENT_READ)) {
126                 return frame;
127         }
128
129         for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
130                 if (frame->frametype == frametype2str[i].type) {
131                         if ((framedata->list_type == 0) && (framedata->values[i])) { /* white list */
132                                 show_frame = 1;
133                         } else if ((framedata->list_type == 1) && (!framedata->values[i])){ /* black list */
134                                 show_frame = 1;
135                         }
136                         break;
137                 }
138         }
139
140         if (show_frame) {
141                 ast_verbose("%s on Channel %s\n", event == AST_FRAMEHOOK_EVENT_READ ? "<--Read" : "--> Write", ast_channel_name(chan));
142                 print_frame(frame);
143         }
144         return frame;
145 }
146
147 static int frame_trace_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
148 {
149         struct frame_trace_data *framedata;
150         struct ast_datastore *datastore = NULL;
151         struct ast_framehook_interface interface = {
152                 .version = AST_FRAMEHOOK_INTERFACE_VERSION,
153                 .event_cb = hook_event_cb,
154                 .destroy_cb = hook_destroy_cb,
155         };
156         int i = 0;
157
158         if (!chan) {
159                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
160                 return -1;
161         }
162
163         if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
164                 return 0;
165         }
166
167         interface.data = framedata;
168
169         if (!strcasecmp(data, "black")) {
170                 framedata->list_type = 1;
171         }
172         for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
173                 if (strcasestr(value, frametype2str[i].str)) {
174                         framedata->values[i] = 1;
175                 }
176         }
177
178         ast_channel_lock(chan);
179         i = ast_framehook_attach(chan, &interface);
180         if (i >= 0) {
181                 int *id;
182                 if ((datastore = ast_channel_datastore_find(chan, &frame_trace_datastore, NULL))) {
183                         id = datastore->data;
184                         ast_framehook_detach(chan, *id);
185                         ast_channel_datastore_remove(chan, datastore);
186                         ast_datastore_free(datastore);
187                 }
188
189                 if (!(datastore = ast_datastore_alloc(&frame_trace_datastore, NULL))) {
190                         ast_framehook_detach(chan, i);
191                         ast_channel_unlock(chan);
192                         return 0;
193                 }
194
195                 if (!(id = ast_calloc(1, sizeof(int)))) {
196                         ast_datastore_free(datastore);
197                         ast_framehook_detach(chan, i);
198                         ast_channel_unlock(chan);
199                         return 0;
200                 }
201
202                 *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
203                 datastore->data = id;
204                 ast_channel_datastore_add(chan, datastore);
205         }
206         ast_channel_unlock(chan);
207
208         return 0;
209 }
210
211 static void print_frame(struct ast_frame *frame)
212 {
213         switch (frame->frametype) {
214         case AST_FRAME_DTMF_END:
215                 ast_verbose("FrameType: DTMF END\n");
216                 ast_verbose("Digit: 0x%02X '%c'\n", (unsigned)frame->subclass.integer,
217                         frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer);
218                 break;
219         case AST_FRAME_VOICE:
220                 ast_verbose("FrameType: VOICE\n");
221                 ast_verbose("Codec: %s\n", ast_format_get_name(frame->subclass.format));
222                 ast_verbose("MS: %ld\n", frame->len);
223                 ast_verbose("Samples: %d\n", frame->samples);
224                 ast_verbose("Bytes: %d\n", frame->datalen);
225                 break;
226         case AST_FRAME_VIDEO:
227                 ast_verbose("FrameType: VIDEO\n");
228                 ast_verbose("Codec: %s\n", ast_format_get_name(frame->subclass.format));
229                 ast_verbose("MS: %ld\n", frame->len);
230                 ast_verbose("Samples: %d\n", frame->samples);
231                 ast_verbose("Bytes: %d\n", frame->datalen);
232                 break;
233         case AST_FRAME_CONTROL:
234                 ast_verbose("FrameType: CONTROL\n");
235                 switch ((enum ast_control_frame_type) frame->subclass.integer) {
236                 case AST_CONTROL_HANGUP:
237                         ast_verbose("SubClass: HANGUP\n");
238                         break;
239                 case AST_CONTROL_RING:
240                         ast_verbose("SubClass: RING\n");
241                         break;
242                 case AST_CONTROL_RINGING:
243                         ast_verbose("SubClass: RINGING\n");
244                         break;
245                 case AST_CONTROL_ANSWER:
246                         ast_verbose("SubClass: ANSWER\n");
247                         break;
248                 case AST_CONTROL_BUSY:
249                         ast_verbose("SubClass: BUSY\n");
250                         break;
251                 case AST_CONTROL_TAKEOFFHOOK:
252                         ast_verbose("SubClass: TAKEOFFHOOK\n");
253                         break;
254                 case AST_CONTROL_OFFHOOK:
255                         ast_verbose("SubClass: OFFHOOK\n");
256                         break;
257                 case AST_CONTROL_CONGESTION:
258                         ast_verbose("SubClass: CONGESTION\n");
259                         break;
260                 case AST_CONTROL_FLASH:
261                         ast_verbose("SubClass: FLASH\n");
262                         break;
263                 case AST_CONTROL_WINK:
264                         ast_verbose("SubClass: WINK\n");
265                         break;
266                 case AST_CONTROL_OPTION:
267                         ast_verbose("SubClass: OPTION\n");
268                         break;
269                 case AST_CONTROL_RADIO_KEY:
270                         ast_verbose("SubClass: RADIO KEY\n");
271                         break;
272                 case AST_CONTROL_RADIO_UNKEY:
273                         ast_verbose("SubClass: RADIO UNKEY\n");
274                         break;
275                 case AST_CONTROL_PROGRESS:
276                         ast_verbose("SubClass: PROGRESS\n");
277                         break;
278                 case AST_CONTROL_PROCEEDING:
279                         ast_verbose("SubClass: PROCEEDING\n");
280                         break;
281                 case AST_CONTROL_HOLD:
282                         ast_verbose("SubClass: HOLD\n");
283                         break;
284                 case AST_CONTROL_UNHOLD:
285                         ast_verbose("SubClass: UNHOLD\n");
286                         break;
287                 case AST_CONTROL_VIDUPDATE:
288                         ast_verbose("SubClass: VIDUPDATE\n");
289                         break;
290                 case _XXX_AST_CONTROL_T38:
291                         ast_verbose("SubClass: XXX T38\n");
292                         break;
293                 case AST_CONTROL_SRCUPDATE:
294                         ast_verbose("SubClass: SRCUPDATE\n");
295                         break;
296                 case AST_CONTROL_TRANSFER:
297                         ast_verbose("SubClass: TRANSFER\n");
298                         break;
299                 case AST_CONTROL_CONNECTED_LINE:
300                         ast_verbose("SubClass: CONNECTED LINE\n");
301                         break;
302                 case AST_CONTROL_REDIRECTING:
303                         ast_verbose("SubClass: REDIRECTING\n");
304                         break;
305                 case AST_CONTROL_T38_PARAMETERS:
306                         ast_verbose("SubClass: T38 PARAMETERS\n");
307                         break;
308                 case AST_CONTROL_CC:
309                         ast_verbose("SubClass: CC\n");
310                         break;
311                 case AST_CONTROL_SRCCHANGE:
312                         ast_verbose("SubClass: SRCCHANGE\n");
313                         break;
314                 case AST_CONTROL_READ_ACTION:
315                         ast_verbose("SubClass: READ ACTION\n");
316                         break;
317                 case AST_CONTROL_AOC:
318                         ast_verbose("SubClass: AOC\n");
319                         break;
320                 case AST_CONTROL_MCID:
321                         ast_verbose("SubClass: MCID\n");
322                         break;
323                 case AST_CONTROL_INCOMPLETE:
324                         ast_verbose("SubClass: INCOMPLETE\n");
325                         break;
326                 case AST_CONTROL_END_OF_Q:
327                         ast_verbose("SubClass: END_OF_Q\n");
328                         break;
329                 case AST_CONTROL_UPDATE_RTP_PEER:
330                         ast_verbose("SubClass: UPDATE_RTP_PEER\n");
331                         break;
332                 case AST_CONTROL_PVT_CAUSE_CODE:
333                         ast_verbose("SubClass: PVT_CAUSE_CODE\n");
334                         break;
335                 case AST_CONTROL_MASQUERADE_NOTIFY:
336                         /* Should never happen. */
337                         ast_assert(0);
338                         break;
339                 case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE:
340                         ast_verbose("SubClass: STREAM_TOPOLOGY_REQUEST_CHANGE\n");
341                         break;
342                 case AST_CONTROL_STREAM_TOPOLOGY_CHANGED:
343                         ast_verbose("SubClass: STREAM_TOPOLOGY_CHANGED\n");
344                         break;
345                 case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED:
346                         ast_verbose("SubClass: STREAM_TOPOLOGY_SOURCE_CHANGED\n");
347                         break;
348                 case AST_CONTROL_STREAM_STOP:
349                         ast_verbose("SubClass: STREAM_STOP\n");
350                         break;
351                 case AST_CONTROL_STREAM_SUSPEND:
352                         ast_verbose("SubClass: STREAM_SUSPEND\n");
353                         break;
354                 case AST_CONTROL_STREAM_RESTART:
355                         ast_verbose("SubClass: STREAM_RESTART\n");
356                         break;
357                 case AST_CONTROL_STREAM_REVERSE:
358                         ast_verbose("SubClass: STREAM_REVERSE\n");
359                         break;
360                 case AST_CONTROL_STREAM_FORWARD:
361                         ast_verbose("SubClass: STREAM_FORWARD\n");
362                         break;
363                 case AST_CONTROL_RECORD_CANCEL:
364                         ast_verbose("SubClass: RECORD_CANCEL\n");
365                         break;
366                 case AST_CONTROL_RECORD_STOP:
367                         ast_verbose("SubClass: RECORD_STOP\n");
368                         break;
369                 case AST_CONTROL_RECORD_SUSPEND:
370                         ast_verbose("SubClass: RECORD_SUSPEND\n");
371                         break;
372                 case AST_CONTROL_RECORD_MUTE:
373                         ast_verbose("SubClass: RECORD_MUTE\n");
374                         break;
375                 }
376
377                 if (frame->subclass.integer == -1) {
378                         ast_verbose("SubClass: %d\n", frame->subclass.integer);
379                 }
380                 ast_verbose("Bytes: %d\n", frame->datalen);
381                 break;
382         case AST_FRAME_RTCP:
383                 ast_verbose("FrameType: RTCP\n");
384                 break;
385         case AST_FRAME_NULL:
386                 ast_verbose("FrameType: NULL\n");
387                 break;
388         case AST_FRAME_IAX:
389                 ast_verbose("FrameType: IAX\n");
390                 break;
391         case AST_FRAME_TEXT:
392                 ast_verbose("FrameType: TXT\n");
393                 break;
394         case AST_FRAME_IMAGE:
395                 ast_verbose("FrameType: IMAGE\n");
396                 break;
397         case AST_FRAME_HTML:
398                 ast_verbose("FrameType: HTML\n");
399                 break;
400         case AST_FRAME_CNG:
401                 ast_verbose("FrameType: CNG\n");
402                 break;
403         case AST_FRAME_MODEM:
404                 ast_verbose("FrameType: MODEM\n");
405                 break;
406         case AST_FRAME_DTMF_BEGIN:
407                 ast_verbose("FrameType: DTMF BEGIN\n");
408                 ast_verbose("Digit: 0x%02X '%c'\n", (unsigned)frame->subclass.integer,
409                         frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer);
410                 break;
411         case AST_FRAME_BRIDGE_ACTION:
412                 ast_verbose("FrameType: Bridge\n");
413                 ast_verbose("SubClass: %d\n", frame->subclass.integer);
414                 break;
415         case AST_FRAME_BRIDGE_ACTION_SYNC:
416                 ast_verbose("Frametype: Synchronous Bridge\n");
417                 ast_verbose("Subclass: %d\n", frame->subclass.integer);
418                 break;
419         }
420
421         ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src);
422         ast_verbose("\n");
423 }
424
425 static struct ast_custom_function frame_trace_function = {
426         .name = "FRAME_TRACE",
427         .write = frame_trace_helper,
428 };
429
430 static int unload_module(void)
431 {
432         return ast_custom_function_unregister(&frame_trace_function);
433 }
434
435 static int load_module(void)
436 {
437         int res = ast_custom_function_register(&frame_trace_function);
438         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
439 }
440
441 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Frame Trace for internal ast_frame debugging.");