messages.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:17k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * messages.c: messages interface
  3.  * This library provides an interface to the message queue to be used by other
  4.  * modules, especially intf modules. See config.h for output configuration.
  5.  *****************************************************************************
  6.  * Copyright (C) 1998-2004 VideoLAN
  7.  * $Id: messages.c 8905 2004-10-04 13:34:42Z gbazin $
  8.  *
  9.  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  10.  *          Samuel Hocevar <sam@zoy.org>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <stdio.h>                                               /* required */
  30. #include <stdarg.h>                                       /* va_list for BSD */
  31. #include <stdlib.h>                                              /* malloc() */
  32. #include <string.h>                                            /* strerror() */
  33. #include <vlc/vlc.h>
  34. #ifdef HAVE_FCNTL_H
  35. #   include <fcntl.h>                  /* O_CREAT, O_TRUNC, O_WRONLY, O_SYNC */
  36. #endif
  37. #include <errno.h>                                                  /* errno */
  38. #ifdef HAVE_UNISTD_H
  39. #   include <unistd.h>                                   /* close(), write() */
  40. #endif
  41. #include "vlc_interface.h"
  42. /*****************************************************************************
  43.  * Local macros
  44.  *****************************************************************************/
  45. #if defined(HAVE_VA_COPY)
  46. #   define vlc_va_copy(dest,src) va_copy(dest,src)
  47. #elif defined(HAVE___VA_COPY)
  48. #   define vlc_va_copy(dest,src) __va_copy(dest,src)
  49. #else
  50. #   define vlc_va_copy(dest,src) (dest)=(src)
  51. #endif
  52. /*****************************************************************************
  53.  * Local prototypes
  54.  *****************************************************************************/
  55. static void QueueMsg ( vlc_object_t *, int , const char *,
  56.                        const char *, va_list );
  57. static void FlushMsg ( msg_bank_t * );
  58. static void PrintMsg ( vlc_object_t *, msg_item_t * );
  59. /**
  60.  * Initialize messages interface
  61.  *
  62.  * This functions has to be called before any call to other msg_* functions.
  63.  * It set up the locks and the message queue if it is used.
  64.  */
  65. void __msg_Create( vlc_object_t *p_this )
  66. {
  67.     /* Message queue initialization */
  68.     vlc_mutex_init( p_this, &p_this->p_libvlc->msg_bank.lock );
  69.     p_this->p_libvlc->msg_bank.b_configured = VLC_FALSE;
  70.     p_this->p_libvlc->msg_bank.b_overflow = VLC_FALSE;
  71.     p_this->p_libvlc->msg_bank.i_start = 0;
  72.     p_this->p_libvlc->msg_bank.i_stop = 0;
  73.     p_this->p_libvlc->msg_bank.i_sub = 0;
  74.     p_this->p_libvlc->msg_bank.pp_sub = NULL;
  75. #ifdef UNDER_CE
  76.     p_this->p_libvlc->msg_bank.logfile =
  77.         CreateFile( L"vlc-log.txt", GENERIC_WRITE,
  78.                     FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
  79.                     CREATE_ALWAYS, 0, NULL );
  80.     SetFilePointer( p_this->p_libvlc->msg_bank.logfile, 0, NULL, FILE_END );
  81. #endif
  82. }
  83. /**
  84.  * Flush the message queue
  85.  */
  86. void __msg_Flush( vlc_object_t *p_this )
  87. {
  88.     int i_index;
  89.     vlc_mutex_lock( &p_this->p_libvlc->msg_bank.lock );
  90.     p_this->p_libvlc->msg_bank.b_configured = VLC_TRUE;
  91.     for( i_index = p_this->p_libvlc->msg_bank.i_start;
  92.          i_index != p_this->p_libvlc->msg_bank.i_stop;
  93.          i_index = (i_index+1) % VLC_MSG_QSIZE )
  94.     {
  95.         PrintMsg( p_this, &p_this->p_libvlc->msg_bank.msg[i_index] );
  96.     }
  97.     FlushMsg( &p_this->p_libvlc->msg_bank );
  98.     vlc_mutex_unlock( &p_this->p_libvlc->msg_bank.lock );
  99. }
  100. /**
  101.  * Free resources allocated by msg_Create
  102.  *
  103.  * This functions prints all messages remaining in queue, then free all the
  104.  * resources allocated by msg_Create.
  105.  * No other messages interface functions should be called after this one.
  106.  */
  107. void __msg_Destroy( vlc_object_t *p_this )
  108. {
  109.     if( p_this->p_libvlc->msg_bank.i_sub )
  110.     {
  111.         msg_Err( p_this, "stale interface subscribers" );
  112.     }
  113.     /* Flush the queue */
  114.     if( !p_this->p_libvlc->msg_bank.b_configured )
  115.     {
  116.         msg_Flush( p_this );
  117.     }
  118.     else
  119.     {
  120.         FlushMsg( &p_this->p_libvlc->msg_bank );
  121.     }
  122. #ifdef UNDER_CE
  123.     CloseHandle( p_this->p_libvlc->msg_bank.logfile );
  124. #endif
  125.     /* Destroy lock */
  126.     vlc_mutex_destroy( &p_this->p_libvlc->msg_bank.lock );
  127. }
  128. /**
  129.  * Subscribe to the message queue.
  130.  */
  131. msg_subscription_t *__msg_Subscribe( vlc_object_t *p_this )
  132. {
  133.     msg_bank_t *p_bank = &p_this->p_libvlc->msg_bank;
  134.     msg_subscription_t *p_sub = malloc( sizeof( msg_subscription_t ) );
  135.     vlc_mutex_lock( &p_bank->lock );
  136.     /* Add subscription to the list */
  137.     INSERT_ELEM( p_bank->pp_sub, p_bank->i_sub, p_bank->i_sub, p_sub );
  138.     p_sub->i_start = p_bank->i_start;
  139.     p_sub->pi_stop = &p_bank->i_stop;
  140.     p_sub->p_msg   = p_bank->msg;
  141.     p_sub->p_lock  = &p_bank->lock;
  142.     vlc_mutex_unlock( &p_bank->lock );
  143.     return p_sub;
  144. }
  145. /**
  146.  * Unsubscribe from the message queue.
  147.  */
  148. void __msg_Unsubscribe( vlc_object_t *p_this, msg_subscription_t *p_sub )
  149. {
  150.     msg_bank_t *p_bank = &p_this->p_libvlc->msg_bank;
  151.     int i_index;
  152.     vlc_mutex_lock( &p_bank->lock );
  153.     /* Sanity check */
  154.     if( !p_bank->i_sub )
  155.     {
  156.         msg_Err( p_this, "no subscriber in the list" );
  157.         return;
  158.     }
  159.     /* Look for the appropriate subscription */
  160.     for( i_index = 0; i_index < p_bank->i_sub; i_index++ )
  161.     {
  162.         if( p_bank->pp_sub[ i_index ] == p_sub )
  163.         {
  164.             break;
  165.         }
  166.     }
  167.     if( p_bank->pp_sub[ i_index ] != p_sub )
  168.     {
  169.         msg_Err( p_this, "subscriber not found" );
  170.         vlc_mutex_unlock( &p_bank->lock );
  171.         return;
  172.     }
  173.     /* Remove this subscription */
  174.     REMOVE_ELEM( p_bank->pp_sub, p_bank->i_sub, i_index );
  175.     vlc_mutex_unlock( &p_bank->lock );
  176. }
  177. /*****************************************************************************
  178.  * __msg_*: print a message
  179.  *****************************************************************************
  180.  * These functions queue a message for later printing.
  181.  *****************************************************************************/
  182. void __msg_Generic( vlc_object_t *p_this, int i_type, const char *psz_module,
  183.                     const char *psz_format, ... )
  184. {
  185.     va_list args;
  186.     va_start( args, psz_format );
  187.     QueueMsg( p_this, i_type, psz_module, psz_format, args );
  188.     va_end( args );
  189. }
  190. void __msg_GenericVa( vlc_object_t *p_this, int i_type, const char *psz_module,
  191.                       const char *psz_format, va_list args )
  192. {
  193.     QueueMsg( p_this, i_type, psz_module, psz_format, args );
  194. }
  195. /* Generic functions used when variadic macros are not available. */
  196. #define DECLARE_MSG_FN( FN_NAME, FN_TYPE ) 
  197.     void FN_NAME( vlc_object_t *p_this, const char *psz_format, ... ) 
  198.     { 
  199.         va_list args; 
  200.         va_start( args, psz_format ); 
  201.         QueueMsg( (vlc_object_t *)p_this, FN_TYPE, "unknown", 
  202.                   psz_format, args ); 
  203.         va_end( args ); 
  204.     } 
  205.     struct _
  206. /**
  207.  * Output an informational message.
  208.  * note Do not use this for debug messages
  209.  * see input_AddInfo
  210.  */
  211. DECLARE_MSG_FN( __msg_Info, VLC_MSG_INFO );
  212. /**
  213.  * Output an error message.
  214.  */
  215. DECLARE_MSG_FN( __msg_Err,  VLC_MSG_ERR );
  216. /**
  217.  * Output a waring message
  218.  */
  219. DECLARE_MSG_FN( __msg_Warn, VLC_MSG_WARN );
  220. /**
  221.  * Output a debug message
  222.  */
  223. DECLARE_MSG_FN( __msg_Dbg,  VLC_MSG_DBG );
  224. /**
  225.  * Add a message to a queue
  226.  *
  227.  * This function provides basic functionnalities to other msg_* functions.
  228.  * It adds a message to a queue (after having printed all stored messages if it
  229.  * is full). If the message can't be converted to string in memory, it issues
  230.  * a warning.
  231.  */
  232. static void QueueMsg( vlc_object_t *p_this, int i_type, const char *psz_module,
  233.                       const char *psz_format, va_list _args )
  234. {
  235.     msg_bank_t * p_bank = &p_this->p_libvlc->msg_bank;       /* message bank */
  236.     char *       psz_str = NULL;                 /* formatted message string */
  237.     va_list      args;
  238.     msg_item_t * p_item = NULL;                        /* pointer to message */
  239.     msg_item_t   item;                    /* message in case of a full queue */
  240. #if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
  241.     int          i_size = strlen(psz_format) + INTF_MAX_MSG_SIZE;
  242. #endif
  243.     /*
  244.      * Convert message to string
  245.      */
  246. #if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN) && !defined( SYS_BEOS )
  247.     vlc_va_copy( args, _args );
  248.     vasprintf( &psz_str, psz_format, args );
  249.     va_end( args );
  250. #else
  251.     psz_str = (char*) malloc( i_size * sizeof(char) );
  252. #endif
  253.     if( psz_str == NULL )
  254.     {
  255.         fprintf( stderr, "main warning: can't store message (%s): ",
  256.                  strerror(errno) );
  257.         vlc_va_copy( args, _args );
  258.         vfprintf( stderr, psz_format, args );
  259.         va_end( args );
  260.         fprintf( stderr, "n" );
  261.         return;
  262.     }
  263. #if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
  264.     vlc_va_copy( args, _args );
  265.     vsnprintf( psz_str, i_size, psz_format, args );
  266.     va_end( args );
  267.     psz_str[ i_size - 1 ] = 0; /* Just in case */
  268. #endif
  269.     /* Put message in queue */
  270.     vlc_mutex_lock( &p_bank->lock );
  271.     /* Check there is room in the queue for our message */
  272.     if( p_bank->b_overflow )
  273.     {
  274.         FlushMsg( p_bank );
  275.         if( ((p_bank->i_stop - p_bank->i_start + 1) % VLC_MSG_QSIZE) == 0 )
  276.         {
  277.             /* Still in overflow mode, print from a dummy item */
  278.             p_item = &item;
  279.         }
  280.         else
  281.         {
  282.             /* Pheeew, at last, there is room in the queue! */
  283.             p_bank->b_overflow = VLC_FALSE;
  284.         }
  285.     }
  286.     else if( ((p_bank->i_stop - p_bank->i_start + 2) % VLC_MSG_QSIZE) == 0 )
  287.     {
  288.         FlushMsg( p_bank );
  289.         if( ((p_bank->i_stop - p_bank->i_start + 2) % VLC_MSG_QSIZE) == 0 )
  290.         {
  291.             p_bank->b_overflow = VLC_TRUE;
  292.             /* Put the overflow message in the queue */
  293.             p_item = p_bank->msg + p_bank->i_stop;
  294.             p_bank->i_stop = (p_bank->i_stop + 1) % VLC_MSG_QSIZE;
  295.             p_item->i_type =        VLC_MSG_WARN;
  296.             p_item->i_object_id =   p_this->i_object_id;
  297.             p_item->i_object_type = p_this->i_object_type;
  298.             p_item->psz_module =    strdup( "message" );
  299.             p_item->psz_msg =       strdup( "message queue overflowed" );
  300.             PrintMsg( p_this, p_item );
  301.             /* We print from a dummy item */
  302.             p_item = &item;
  303.         }
  304.     }
  305.     if( !p_bank->b_overflow )
  306.     {
  307.         /* Put the message in the queue */
  308.         p_item = p_bank->msg + p_bank->i_stop;
  309.         p_bank->i_stop = (p_bank->i_stop + 1) % VLC_MSG_QSIZE;
  310.     }
  311.     /* Fill message information fields */
  312.     p_item->i_type =        i_type;
  313.     p_item->i_object_id =   p_this->i_object_id;
  314.     p_item->i_object_type = p_this->i_object_type;
  315.     p_item->psz_module =    strdup( psz_module );
  316.     p_item->psz_msg =       psz_str;
  317.     PrintMsg( p_this, p_item );
  318.     if( p_bank->b_overflow )
  319.     {
  320.         free( p_item->psz_module );
  321.         free( p_item->psz_msg );
  322.     }
  323.     vlc_mutex_unlock( &p_bank->lock );
  324. }
  325. /* following functions are local */
  326. /*****************************************************************************
  327.  * FlushMsg
  328.  *****************************************************************************
  329.  * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
  330.  * this function does not check the lock.
  331.  *****************************************************************************/
  332. static void FlushMsg ( msg_bank_t *p_bank )
  333. {
  334.     int i_index, i_start, i_stop;
  335.     /* Only flush the queue if it has been properly configured */
  336.     if( !p_bank->b_configured )
  337.     {
  338.         return;
  339.     }
  340.     /* Get the maximum message index that can be freed */
  341.     i_stop = p_bank->i_stop;
  342.     /* Check until which value we can free messages */
  343.     for( i_index = 0; i_index < p_bank->i_sub; i_index++ )
  344.     {
  345.         i_start = p_bank->pp_sub[ i_index ]->i_start;
  346.         /* If this subscriber is late, we don't free messages before
  347.          * his i_start value, otherwise he'll miss messages */
  348.         if(   ( i_start < i_stop
  349.                && (p_bank->i_stop <= i_start || i_stop <= p_bank->i_stop) )
  350.            || ( i_stop < i_start
  351.                && (i_stop <= p_bank->i_stop && p_bank->i_stop <= i_start) ) )
  352.         {
  353.             i_stop = i_start;
  354.         }
  355.     }
  356.     /* Free message data */
  357.     for( i_index = p_bank->i_start;
  358.          i_index != i_stop;
  359.          i_index = (i_index+1) % VLC_MSG_QSIZE )
  360.     {
  361.         free( p_bank->msg[i_index].psz_msg );
  362.         free( p_bank->msg[i_index].psz_module );
  363.     }
  364.     /* Update the new start value */
  365.     p_bank->i_start = i_index;
  366. }
  367. /*****************************************************************************
  368.  * PrintMsg: output a message item to stderr
  369.  *****************************************************************************
  370.  * Print a message to stderr, with colour formatting if needed.
  371.  *****************************************************************************/
  372. static void PrintMsg ( vlc_object_t * p_this, msg_item_t * p_item )
  373. {
  374. #   define COL(x)  "33[" #x ";1m"
  375. #   define RED     COL(31)
  376. #   define GREEN   COL(32)
  377. #   define YELLOW  COL(33)
  378. #   define WHITE   COL(37)
  379. #   define GRAY    "33[0m"
  380. #ifdef UNDER_CE
  381.     int i_dummy;
  382. #endif
  383.     static const char * ppsz_type[4] = { "", " error", " warning", " debug" };
  384.     static const char *ppsz_color[4] = { WHITE, RED, YELLOW, GRAY };
  385.     char *psz_object = "private";
  386.     int i_type = p_item->i_type;
  387.     switch( i_type )
  388.     {
  389.         case VLC_MSG_ERR:
  390.             if( p_this->p_libvlc->i_verbose < 0 ) return;
  391.             break;
  392.         case VLC_MSG_INFO:
  393.             if( p_this->p_libvlc->i_verbose < 0 ) return;
  394.             break;
  395.         case VLC_MSG_WARN:
  396.             if( p_this->p_libvlc->i_verbose < 1 ) return;
  397.             break;
  398.         case VLC_MSG_DBG:
  399.             if( p_this->p_libvlc->i_verbose < 2 ) return;
  400.             break;
  401.     }
  402.     switch( p_item->i_object_type )
  403.     {
  404.         case VLC_OBJECT_ROOT: psz_object = "root"; break;
  405.         case VLC_OBJECT_VLC: psz_object = "vlc"; break;
  406.         case VLC_OBJECT_MODULE: psz_object = "module"; break;
  407.         case VLC_OBJECT_INTF: psz_object = "interface"; break;
  408.         case VLC_OBJECT_PLAYLIST: psz_object = "playlist"; break;
  409.         case VLC_OBJECT_ITEM: psz_object = "item"; break;
  410.         case VLC_OBJECT_INPUT: psz_object = "input"; break;
  411.         case VLC_OBJECT_DECODER: psz_object = "decoder"; break;
  412.         case VLC_OBJECT_PACKETIZER: psz_object = "packetizer"; break;
  413.         case VLC_OBJECT_ENCODER: psz_object = "encoder"; break;
  414.         case VLC_OBJECT_VOUT: psz_object = "video output"; break;
  415.         case VLC_OBJECT_AOUT: psz_object = "audio output"; break;
  416.         case VLC_OBJECT_SOUT: psz_object = "stream output"; break;
  417.         case VLC_OBJECT_HTTPD: psz_object = "http daemon"; break;
  418.         case VLC_OBJECT_DIALOGS: psz_object = "dialogs provider"; break;
  419.         case VLC_OBJECT_VLM: psz_object = "vlm"; break;
  420.         case VLC_OBJECT_ANNOUNCE: psz_object = "announce handler"; break;
  421.         case VLC_OBJECT_DEMUX: psz_object = "demuxer"; break;
  422.         case VLC_OBJECT_ACCESS: psz_object = "access"; break;
  423.     }
  424. #ifdef UNDER_CE
  425. #   define CE_WRITE(str) WriteFile( p_this->p_libvlc->msg_bank.logfile, 
  426.                                     str, strlen(str), &i_dummy, NULL );
  427.     CE_WRITE( p_item->psz_module );
  428.     CE_WRITE( " " );
  429.     CE_WRITE( psz_object );
  430.     CE_WRITE( ppsz_type[i_type] );
  431.     CE_WRITE( ": " );
  432.     CE_WRITE( p_item->psz_msg );
  433.     CE_WRITE( "rn" );
  434.     FlushFileBuffers( p_this->p_libvlc->msg_bank.logfile );
  435. #else
  436.     /* Send the message to stderr */
  437.     if( p_this->p_libvlc->b_color )
  438.     {
  439.         fprintf( stderr, "[" GREEN "%.8i" GRAY "] %s %s%s: %s%s" GRAY "n",
  440.                          p_item->i_object_id, p_item->psz_module, psz_object,
  441.                          ppsz_type[i_type], ppsz_color[i_type],
  442.                          p_item->psz_msg );
  443.     }
  444.     else
  445.     {
  446.         fprintf( stderr, "[%.8i] %s %s%s: %sn", p_item->i_object_id,
  447.                          p_item->psz_module, psz_object, ppsz_type[i_type],
  448.                          p_item->psz_msg );
  449.     }
  450. #   if defined(WIN32)
  451.     fflush( stderr );
  452. #   endif
  453. #endif
  454. }