XMMS2
src/xmms/ringbuf_xform.c
Go to the documentation of this file.
00001 
00002 #include "xmms/xmms_log.h"
00003 #include "xmms/xmms_medialib.h"
00004 #include "xmmspriv/xmms_ringbuf.h"
00005 #include "xmmspriv/xmms_xform.h"
00006 
00007 /*
00008    - producer:
00009      want_buffer -> buffering
00010      want_seek -> seeked
00011      want_stop -> stopped
00012 
00013    - consumer:
00014      * -> want_seek
00015           wait until state == seek_done
00016       seek_done -> want_buffer
00017 
00018      * -> want_stop
00019           wait until state == is_stopped
00020 
00021 */
00022 typedef enum xmms_buffer_state_E {
00023     STATE_WANT_BUFFER,
00024     STATE_BUFFERING,
00025     STATE_WANT_SEEK,
00026     STATE_SEEK_DONE,
00027     STATE_WANT_STOP,
00028     STATE_IS_STOPPED
00029 } xmms_buffer_state_t;
00030 
00031 typedef struct xmms_ringbuf_priv_St {
00032     GThread *thread;
00033 
00034     xmms_ringbuf_t *buffer;
00035     GMutex *buffer_lock;
00036 
00037     xmms_buffer_state_t state;
00038     GCond *state_cond;
00039     GMutex *state_lock;
00040 } xmms_ringbuf_priv_t;
00041 
00042 static xmms_xform_plugin_t *ringbuf_plugin;
00043 
00044 static gpointer xmms_ringbuf_xform_thread (gpointer data);
00045 
00046 static gboolean
00047 xmms_ringbuf_plugin_init (xmms_xform_t *xform)
00048 {
00049     xmms_ringbuf_priv_t *priv;
00050 
00051     priv = g_new0 (xmms_ringbuf_priv_t, 1);
00052 
00053     xmms_xform_private_data_set (xform, priv);
00054 
00055     priv->buffer = xmms_ringbuf_new (4096*8);
00056     priv->buffer_lock = g_mutex_new ();
00057     priv->state = STATE_WANT_BUFFER;
00058     priv->state_cond = g_cond_new ();
00059     priv->state_lock = g_mutex_new ();
00060     priv->thread = g_thread_create (xmms_ringbuf_xform_thread, xform, TRUE, NULL);
00061 
00062     xmms_xform_outdata_type_copy (xform);
00063 
00064     return TRUE;
00065 }
00066 
00067 static void
00068 xmms_ringbuf_plugin_destroy (xmms_xform_t *xform)
00069 {
00070     xmms_ringbuf_priv_t *priv;
00071     priv = xmms_xform_private_data_get (xform);
00072 
00073     g_mutex_lock (priv->state_lock);
00074     xmms_ringbuf_clear (priv->buffer);
00075     while (priv->state != STATE_IS_STOPPED) {
00076         priv->state = STATE_WANT_STOP;
00077         g_cond_wait (priv->state_cond, priv->state_lock);
00078     }
00079     g_mutex_unlock (priv->state_lock);
00080 
00081     g_thread_join (priv->thread);
00082 
00083     XMMS_DBG ("Ringbuf destroyed!");
00084 }
00085 
00086 static gint
00087 xmms_ringbuf_plugin_read (xmms_xform_t *xform, void *buffer, gint len, xmms_error_t *error)
00088 {
00089     xmms_ringbuf_priv_t *priv;
00090     priv = xmms_xform_private_data_get (xform);
00091 
00092     return xmms_ringbuf_read_wait (priv->buffer, buffer, len, priv->buffer_lock);
00093 }
00094 
00095 
00096 static gboolean
00097 xmms_ringbuf_plugin_setup (xmms_xform_plugin_t *xform_plugin)
00098 {
00099     xmms_xform_methods_t methods;
00100 
00101     XMMS_XFORM_METHODS_INIT (methods);
00102     methods.init = xmms_ringbuf_plugin_init;
00103     methods.destroy = xmms_ringbuf_plugin_destroy;
00104     methods.read = xmms_ringbuf_plugin_read;
00105     /*
00106       methods.seek
00107     */
00108 
00109     xmms_xform_plugin_methods_set (xform_plugin, &methods);
00110 
00111     ringbuf_plugin = xform_plugin;
00112 
00113     return TRUE;
00114 }
00115 
00116 static xmms_xform_t *
00117 xmms_ringbuf_xform_new (xmms_xform_t *prev, xmms_medialib_entry_t entry, GList *gt)
00118 {
00119     xmms_xform_t *xform;
00120 
00121     xform = xmms_xform_new (ringbuf_plugin, prev, entry, gt);
00122 
00123     return xform;
00124 }
00125 
00126 static void
00127 fill (xmms_xform_t *xform, xmms_ringbuf_priv_t *priv)
00128 {
00129     xmms_error_t err;
00130     char buf[4096];
00131     int res;
00132 
00133     res = xmms_xform_read (xform, buf, sizeof (buf), &err);
00134     if (res > 0) {
00135         xmms_ringbuf_write_wait (priv->buffer, buf, res, priv->buffer_lock);
00136     } else if (res == -1) {
00137         /* XXX copy error */
00138         g_mutex_lock (priv->state_lock);
00139         priv->state = STATE_WANT_STOP;
00140     } else {
00141         xmms_ringbuf_set_eos (priv->buffer, TRUE);
00142         priv->state = STATE_WANT_STOP;
00143     }
00144 }
00145 
00146 static gpointer
00147 xmms_ringbuf_xform_thread (gpointer data)
00148 {
00149     xmms_xform_t *xform = (xmms_xform_t *)data;
00150     xmms_ringbuf_priv_t *priv;
00151 
00152     priv = xmms_xform_private_data_get (xform);
00153 
00154     g_mutex_lock (priv->state_lock);
00155     while (priv->state != STATE_WANT_STOP) {
00156         if (priv->state == STATE_WANT_BUFFER) {
00157             priv->state = STATE_BUFFERING;
00158             g_cond_signal (priv->state_cond);
00159             while (priv->state == STATE_BUFFERING) {
00160                 g_mutex_unlock (priv->state_lock);
00161                 fill (xform, priv);
00162                 g_mutex_lock (priv->state_lock);
00163             }
00164         } else if (priv->state == STATE_WANT_SEEK) {
00165             /** **/
00166             priv->state = STATE_SEEK_DONE;
00167             g_cond_signal (priv->state_cond);
00168             while (priv->state == STATE_SEEK_DONE) {
00169                 g_cond_wait (priv->state_cond, priv->state_lock);
00170             }
00171         }
00172         XMMS_DBG ("thread: state: %d", priv->state);
00173     }
00174     priv->state = STATE_IS_STOPPED;
00175     g_cond_signal (priv->state_cond);
00176     g_mutex_unlock (priv->state_lock);
00177 
00178     return NULL;
00179 }
00180 
00181 XMMS_XFORM_BUILTIN (ringbuf,
00182                     "Ringbuffer",
00183                     XMMS_VERSION,
00184                     "Buffer",
00185                     xmms_ringbuf_plugin_setup);