Initial code for the event system.
[platform/upstream/gstreamer.git] / gst / gstinfo.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstinfo.c: INFO, ERROR, and DEBUG systems
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <dlfcn.h>
24 #include "gst_private.h"
25 #include "gstelement.h"
26 #include "gstpad.h"
27
28 extern gchar *_gst_progname;
29
30
31 /***** Categories and colorization *****/
32 static gchar *_gst_info_category_strings[] = {
33   "GST_INIT",
34   "COTHREADS",
35   "COTHREAD_SWITCH",
36   "AUTOPLUG",
37   "AUTOPLUG_ATTEMPT",
38   "PARENTAGE",
39   "STATES",
40   "PLANNING",
41   "SCHEDULING",
42   "DATAFLOW",
43   "BUFFER",
44   "CAPS",
45   "CLOCK",
46   "ELEMENT_PADS",
47   "ELEMENTFACTORY",
48   "PADS",
49   "PIPELINE",
50   "PLUGIN_LOADING",
51   "PLUGIN_ERRORS",
52   "PLUGIN_INFO",
53   "PROPERTIES",
54   "THREAD",
55   "TYPES",
56   "XML",
57   "NEGOTIATION",
58   "REFCOUNTING",
59   "EVENT",
60 };
61
62 /**
63  * gst_get_category_name:
64  * @category: the category to return the name of
65  *
66  * Returns: string containing the name of the category
67  */
68 const gchar *
69 gst_get_category_name (gint category) {
70   if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
71     return _gst_info_category_strings[category];
72   else
73     return NULL;
74 }
75
76
77 /*
78  * Attribute codes:
79  * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
80  * Text color codes:
81  * 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
82  * Background color codes:
83  * 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
84  */
85 const gchar *_gst_category_colors[32] = {
86   [GST_CAT_GST_INIT]            = "07;37",
87   [GST_CAT_COTHREADS]           = "00;32",
88   [GST_CAT_COTHREAD_SWITCH]     = "00;37;42",
89   [GST_CAT_AUTOPLUG]            = "00;34",
90   [GST_CAT_AUTOPLUG_ATTEMPT]    = "00;36;44",
91   [GST_CAT_PARENTAGE]           = "01;37;41",           // !!
92   [GST_CAT_STATES]              = "00;31",
93   [GST_CAT_PLANNING]            = "07;35",
94   [GST_CAT_SCHEDULING]          = "00;35",
95   [GST_CAT_DATAFLOW]            = "00;32",
96   [GST_CAT_BUFFER]              = "00;32",
97   [GST_CAT_CAPS]                = "04;34",
98   [GST_CAT_CLOCK]               = "00;33",              // !!
99   [GST_CAT_ELEMENT_PADS]        = "01;37;41",           // !!
100   [GST_CAT_ELEMENTFACTORY]      = "01;37;41",           // !!
101   [GST_CAT_PADS]                = "01;37;41",           // !!
102   [GST_CAT_PIPELINE]            = "01;37;41",           // !!
103   [GST_CAT_PLUGIN_LOADING]      = "00;36",
104   [GST_CAT_PLUGIN_ERRORS]       = "05;31",
105   [GST_CAT_PLUGIN_INFO]         = "00;36",
106   [GST_CAT_PROPERTIES]          = "00;37;44",           // !!
107   [GST_CAT_THREAD]              = "00;31",
108   [GST_CAT_TYPES]               = "01;37;41",           // !!
109   [GST_CAT_XML]                 = "01;37;41",           // !!
110   [GST_CAT_NEGOTIATION]         = "07;34",
111   [GST_CAT_REFCOUNTING]         = "00;34:42",
112   [GST_CAT_EVENT]               = "01;37;41",           // !!
113
114   [31]                          = "",
115 };
116
117 /* colorization hash - DEPRACATED in favor of above */
118 inline gint _gst_debug_stringhash_color(gchar *file) {
119   int filecolor = 0;
120   while (file[0]) filecolor += *(char *)(file++);
121   filecolor = (filecolor % 6) + 31;
122   return filecolor;
123 }
124
125
126
127 /***** DEBUG system *****/
128 GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
129 guint32 _gst_debug_categories = 0x00000000;
130
131 /**
132  * gst_default_debug_handler:
133  * @category: category of the DEBUG message
134  * @incore: if the debug handler is for core code.
135  * @file: the file the DEBUG occurs in
136  * @function: the function the DEBUG occurs in
137  * @line: the line number in the file
138  * @debug_string: the current debug_string in the function, if any
139  * @element: pointer to the #GstElement in question
140  * @string: the actual DEBUG string
141  *
142  * Prints out the DEBUG mesage in a variant of the following form:
143  *
144  *   DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
145  */
146 void
147 gst_default_debug_handler (gint category, gboolean incore,
148                            const gchar *file, const gchar *function,
149                            gint line, const gchar *debug_string,
150                            void *element, gchar *string)
151 {
152   gchar *empty = "";
153   gchar *elementname = empty,*location = empty;
154   int pthread_id = getpid();
155   int cothread_id = cothread_getcurrent();
156 #ifdef GST_DEBUG_COLOR
157   int pthread_color = pthread_id%6 + 31;
158   int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
159 #endif
160
161   if (debug_string == NULL) debug_string = "";
162 //  if (category != GST_CAT_GST_INIT)
163     location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
164   if (element && GST_IS_ELEMENT (element))
165 #ifdef GST_DEBUG_COLOR
166     elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
167 #else
168     elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
169 #endif
170
171 #ifdef GST_DEBUG_COLOR
172   fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
173           "%s;%sm%s%s\033[00m %s",
174           pthread_color,pthread_id,cothread_color,cothread_id,incore?"00":"01",
175           _gst_category_colors[category],location,elementname,string);
176 #else
177   fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s",
178           pthread_id,cothread_id,location,elementname,string);
179 #endif /* GST_DEBUG_COLOR */
180
181   if (location != empty) g_free(location);
182   if (elementname != empty) g_free(elementname);
183
184   g_free(string);
185 }
186
187
188 /**
189  * gst_debug_set_categories:
190  * @categories: bitmask of DEBUG categories to enable
191  *
192  * Enable the output of DEBUG categories based on the given bitmask.
193  * The bit for any given category is (1 << GST_CAT_...).
194  */
195 void
196 gst_debug_set_categories (guint32 categories) {
197   _gst_debug_categories = categories;
198   if (categories)
199     GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
200 }
201
202 /**
203  * gst_debug_get_categories:
204  *
205  * Returns: the current bitmask of enabled DEBUG categories
206  * The bit for any given category is (1 << GST_CAT_...).
207  */
208 guint32
209 gst_debug_get_categories () {
210   return _gst_debug_categories;
211 }
212
213 /**
214  * gst_debug_enable_category:
215  * @category: the category to enable
216  *
217  * Enables the given GST_CAT_... DEBUG category.
218  */
219 void
220 gst_debug_enable_category (gint category) {
221   _gst_debug_categories |= (1 << category);
222   if (_gst_debug_categories)
223     GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
224 }
225
226 /**
227  * gst_debug_disable_category:
228  * @category: the category to disable
229  *
230  * Disables the given GST_CAT_... DEBUG category.
231  */
232 void
233 gst_debug_disable_category (gint category) {
234   _gst_debug_categories &= ~ (1 << category);
235   if (_gst_debug_categories)
236     GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
237 }
238
239
240
241
242 /***** INFO system *****/
243 GstInfoHandler _gst_info_handler = gst_default_info_handler;
244 guint32 _gst_info_categories = 0x00000001;
245
246
247 /**
248  * gst_default_info_handler:
249  * @category: category of the INFO message
250  * @incore: if the info handler is for core code.
251  * @file: the file the INFO occurs in
252  * @function: the function the INFO occurs in
253  * @line: the line number in the file
254  * @debug_string: the current debug_string in the function, if any
255  * @element: pointer to the #GstElement in question
256  * @string: the actual INFO string
257  *
258  * Prints out the INFO mesage in a variant of the following form:
259  *
260  *   INFO:gst_function:542(args): [elementname] something neat happened
261  */
262 void
263 gst_default_info_handler (gint category, gboolean incore,
264                           const gchar *file, const gchar *function,
265                           gint line, const gchar *debug_string,
266                           void *element, gchar *string)
267 {
268   gchar *empty = "";
269   gchar *elementname = empty,*location = empty;
270   int pthread_id = getpid();
271   int cothread_id = cothread_getcurrent();
272 #ifdef GST_DEBUG_COLOR
273   int pthread_color = pthread_id%6 + 31;
274   int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
275 #endif
276
277   if (debug_string == NULL) debug_string = "";
278   if (category != GST_CAT_GST_INIT)
279     location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
280   if (element && GST_IS_ELEMENT (element))
281     elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
282
283 /*
284 #ifdef GST_DEBUG_ENABLED
285 */
286   #ifdef GST_DEBUG_COLOR
287     fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
288             GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
289             pthread_color,pthread_id,cothread_color,cothread_id,
290             _gst_category_colors[category],location,elementname,string);
291   #else
292     fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
293             pthread_id,cothread_id,location,elementname,string);
294   #endif // GST_DEBUG_COLOR
295 /*
296 #else
297   #ifdef GST_DEBUG_COLOR
298     fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
299             location,elementname,_gst_category_colors[category],string);
300   #else
301     fprintf(stderr,"INFO:%s%s %s\n",
302             location,elementname,string);
303   #endif // GST_DEBUG_COLOR
304 #endif
305 */
306
307   if (location != empty) g_free(location);
308   if (elementname != empty) g_free(elementname);
309
310   g_free(string);
311 }
312
313 /**
314  * gst_info_set_categories:
315  * @categories: bitmask of INFO categories to enable
316  *
317  * Enable the output of INFO categories based on the given bitmask.
318  * The bit for any given category is (1 << GST_CAT_...).
319  */
320 void
321 gst_info_set_categories (guint32 categories) {
322   _gst_info_categories = categories;
323   if (categories)
324     GST_INFO (0, "setting INFO categories to 0x%08X",categories);
325 }
326
327 /**
328  * gst_info_get_categories:
329  *
330  * Returns: the current bitmask of enabled INFO categories
331  * The bit for any given category is (1 << GST_CAT_...).
332  */
333 guint32
334 gst_info_get_categories () {
335   return _gst_info_categories;
336 }
337
338 /**
339  * gst_info_enable_category:
340  * @category: the category to enable
341  *
342  * Enables the given GST_CAT_... INFO category.
343  */
344 void
345 gst_info_enable_category (gint category) {
346   _gst_info_categories |= (1 << category);
347   if (_gst_info_categories)
348     GST_INFO (0, "setting INFO categories to 0x%08X",_gst_info_categories);
349 }
350
351 /**
352  * gst_info_disable_category:
353  * @category: the category to disable
354  *
355  * Disables the given GST_CAT_... INFO category.
356  */
357 void
358 gst_info_disable_category (gint category) {
359   _gst_info_categories &= ~ (1 << category);
360   if (_gst_info_categories)
361     GST_INFO (0, "setting INFO categories to 0x%08X",_gst_info_categories);
362 }
363
364
365
366 /***** ERROR system *****/
367 GstErrorHandler _gst_error_handler = gst_default_error_handler;
368
369 /**
370  * gst_default_error_handler:
371  * @file: the file the ERROR occurs in
372  * @function: the function the INFO occurs in
373  * @line: the line number in the file
374  * @debug_string: the current debug_string in the function, if any
375  * @element: pointer to the #GstElement in question
376  * @object: pointer to a related object
377  * @string: the actual ERROR string
378  *
379  * Prints out the given ERROR string in a variant of the following format:
380  *
381  * ***** GStreamer ERROR ***** in file gstsomething.c at gst_function:399(arg)
382  * Element: /pipeline/thread/element.src
383  * Error: peer is null!
384  * ***** attempting to stack trace.... *****
385  *
386  * At the end, it attempts to print the stack trace via GDB.
387  */
388 void
389 gst_default_error_handler (gchar *file, gchar *function,
390                            gint line, gchar *debug_string,
391                            void *element, void *object, gchar *string)
392 {
393   int chars = 0;
394   gchar *path;
395   int i;
396
397   // if there are NULL pointers, point them to null strings to clean up output
398   if (!debug_string) debug_string = "";
399   if (!string) string = "";
400
401   // print out a preamble
402   fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
403           file,function,line,debug_string);
404
405   // if there's an element, print out the pertinent information
406   if (element) {
407     if (GST_IS_OBJECT(element)) {
408       path = gst_object_get_path_string(element);
409       fprintf(stderr,"Element: %s",path);
410       chars = 9 + strlen(path);
411       g_free(path);
412     } else {
413       fprintf(stderr,"Element ptr: %p",element);
414       chars = 15 + sizeof(void*)*2;
415     }
416   }
417
418   // if there's an object, print it out as well
419   if (object) {
420     // attempt to pad the line, or create a new one
421     if (chars < 40)
422       for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
423     else
424       fprintf(stderr,"\n");
425
426     if (GST_IS_OBJECT(object)) {
427       path = gst_object_get_path_string(object);
428       fprintf(stderr,"Object: %s",path);
429       g_free(path);
430     } else {
431       fprintf(stderr,"Object ptr: %p",object);
432     }
433   }
434
435   fprintf(stderr,"\n");
436   fprintf(stderr,"Error: %s\n",string);
437
438   g_free(string);
439
440   fprintf(stderr,"***** attempting to stack trace.... *****\n");
441
442   g_on_error_stack_trace (_gst_progname);
443
444   exit(1);
445 }
446
447
448
449 /***** DEBUG system *****/
450 GHashTable *__gst_function_pointers = NULL;
451
452 gchar *
453 _gst_debug_nameof_funcptr (void *ptr)
454 {
455   gchar *ptrname;
456   Dl_info dlinfo;
457   if (__gst_function_pointers) {
458     if ((ptrname = g_hash_table_lookup(__gst_function_pointers,ptr)))
459       return g_strdup(ptrname);
460   } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
461     return g_strdup(dlinfo.dli_sname);
462   } else {
463     return g_strdup_printf("%p",ptr);
464   }
465   return NULL;
466 }