Commit f7260e64 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

libvlc: add functions to register logging callbacks

parent 88bc3a7e
......@@ -307,10 +307,84 @@ LIBVLC_API const char * libvlc_event_type_name( libvlc_event_type_t event_type )
/** \defgroup libvlc_log LibVLC logging
* libvlc_log_* functions provide access to the LibVLC messages log.
* This is used for debugging or by advanced users.
* This is used for logging and debugging.
* @{
*/
/**
* Logging messages level.
* \note Future LibVLC versions may define new levels.
*/
enum libvlc_log_level
{
LIBVLC_DEBUG=0 /**< Debug message */,
LIBVLC_NOTICE=2 /**< Important informational message */,
LIBVLC_WARNING=3 /**< Warning (potential error) message */,
LIBVLC_ERROR=4 /**< Error message */,
};
/**
* Callback prototype for LibVLC log message handler.
* \param data data pointer as given to libvlc_log_subscribe()
* \param level message level (@ref enum libvlc_log_level)
* \param fmt printf() format string (as defined by ISO C11)
* \param args variable argument list for the format
* \note Log message handlers <b>must</b> be thread-safe.
*/
typedef void (*libvlc_log_cb)(void *data, int level, const char *fmt,
va_list args);
/**
* Data structure for a LibVLC logging callbacks.
* \note This structure contains exactly 4 pointers and will never change.
* Nevertheless, it should not be accessed directly outside of LibVLC.
* (In fact, doing so would fail the thread memory model.)
*/
typedef struct libvlc_log_subscriber
{
struct libvlc_log_subscriber *prev, *next;
libvlc_log_cb func;
void *opaque;
} libvlc_log_subscriber_t;
/**
* Registers a logging callback to LibVLC.
* This function is thread-safe.
*
* \param sub uninitialized subscriber structure
* \param cb callback function pointer
* \param data opaque data pointer for the callback function
*
* \note Some log messages (especially debug) are emitted by LibVLC while
* initializing, before any LibVLC instance even exists.
* Thus this function does not require a LibVLC instance parameter.
*
* \warning As a consequence of not depending on a LibVLC instance,
* all logging callbacks are shared by all LibVLC instances within the
* process / address space. This also enables log messages to be emitted
* by LibVLC components that are not specific to any given LibVLC instance.
*
* \warning Do not call this function from within a logging callback.
* It would trigger a dead lock.
*/
LIBVLC_API void libvlc_log_subscribe( libvlc_log_subscriber_t *sub,
libvlc_log_cb cb, void *data );
/**
* Deregisters a logging callback from LibVLC.
* This function is thread-safe.
*
* \note After (and only after) libvlc_log_unsubscribe() has returned,
* LibVLC warrants that there are no more pending calls of the subscription
* callback function.
*
* \warning Do not call this function from within a logging callback.
* It would trigger a dead lock.
*
* \param sub initialized subscriber structure
*/
LIBVLC_API void libvlc_log_unsubscribe( libvlc_log_subscriber_t *sub );
/**
* Always returns minus one.
* This function is only provided for backward compatibility.
......
......@@ -37,7 +37,10 @@ void libvlc_threads_init (void)
{
vlc_mutex_lock (&lock);
if (refs++ == 0)
{
vlc_threadvar_create (&context, free);
libvlc_log_init ();
}
vlc_mutex_unlock (&lock);
}
......@@ -46,7 +49,10 @@ void libvlc_threads_deinit (void)
vlc_mutex_lock (&lock);
assert (refs > 0);
if (--refs == 0)
{
libvlc_log_deinit ();
vlc_threadvar_delete (&context);
}
vlc_mutex_unlock (&lock);
}
......
......@@ -43,6 +43,8 @@ libvlc_get_fullscreen
libvlc_get_input_thread
libvlc_get_log_verbosity
libvlc_get_version
libvlc_log_subscribe
libvlc_log_unsubscribe
libvlc_log_clear
libvlc_log_close
libvlc_log_count
......
......@@ -82,6 +82,8 @@ struct libvlc_instance_t
/* Thread context */
void libvlc_threads_init (void);
void libvlc_threads_deinit (void);
void libvlc_log_init (void);
void libvlc_log_deinit (void);
/* Events */
libvlc_event_manager_t * libvlc_event_manager_new(
......
......@@ -26,9 +26,92 @@
# include "config.h"
#endif
#include "libvlc_internal.h"
#include <vlc/libvlc.h>
#include <assert.h>
#include <vlc/libvlc.h>
#include "libvlc_internal.h"
#include <vlc_common.h>
#include <vlc_interface.h>
/*** Logging core dispatcher ***/
static vlc_rwlock_t log_lock = VLC_STATIC_RWLOCK;
static libvlc_log_subscriber_t *log_first = NULL;
static msg_subscription_t sub;
VLC_FORMAT(2,3)
static void libvlc_log (int level, const char *fmt, ...)
{
libvlc_log_subscriber_t *sub;
va_list ap;
switch (level)
{
case VLC_MSG_INFO: level = LIBVLC_NOTICE; break;
case VLC_MSG_ERR: level = LIBVLC_ERROR; break;
case VLC_MSG_WARN: level = LIBVLC_WARNING; break;
case VLC_MSG_DBG: level = LIBVLC_DEBUG; break;
}
va_start (ap, fmt);
vlc_rwlock_rdlock (&log_lock);
for (sub = log_first; sub != NULL; sub = sub->next)
sub->func (sub->opaque, level, fmt, ap);
vlc_rwlock_unlock (&log_lock);
va_end (ap);
}
static void libvlc_logf (void *dummy, int level, const msg_item_t *item,
const char *fmt, va_list ap)
{
char *msg;
if (unlikely(vasprintf (&msg, fmt, ap) == -1))
msg = NULL;
if (item->psz_header != NULL)
libvlc_log (level, "[%p] [%s]: %s %s %s", (void *)item->i_object_id,
item->psz_header, item->psz_module, item->psz_object_type,
msg ? msg : "Not enough memory");
else
libvlc_log (level, "[%p]: %s %s %s", (void *)item->i_object_id,
item->psz_module, item->psz_object_type,
msg ? msg : "Not enough memory");
free (msg);
(void) dummy;
}
void libvlc_log_init (void)
{
vlc_Subscribe (&sub, libvlc_logf, NULL);
}
void libvlc_log_deinit (void)
{
vlc_Unsubscribe (&sub);
}
void libvlc_log_subscribe (libvlc_log_subscriber_t *sub,
libvlc_log_cb cb, void *data)
{
sub->prev = NULL;
sub->func = cb;
sub->opaque = data;
vlc_rwlock_wrlock (&log_lock);
sub->next = log_first;
log_first = sub;
vlc_rwlock_unlock (&log_lock);
}
void libvlc_log_unsubscribe( libvlc_log_subscriber_t *sub )
{
vlc_rwlock_wrlock (&log_lock);
if (sub->next != NULL)
sub->next->prev = sub->prev;
if (sub->prev != NULL)
sub->prev->next = sub->next;
else
log_first = sub->next;
vlc_rwlock_unlock (&log_lock);
}
unsigned libvlc_get_log_verbosity( const libvlc_instance_t *p_instance )
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment