XMMS2
ringbuf_xform.c
Go to the documentation of this file.
1 
2 #include "xmms/xmms_log.h"
3 #include "xmms/xmms_medialib.h"
5 #include "xmmspriv/xmms_xform.h"
6 
7 /*
8  - producer:
9  want_buffer -> buffering
10  want_seek -> seeked
11  want_stop -> stopped
12 
13  - consumer:
14  * -> want_seek
15  wait until state == seek_done
16  seek_done -> want_buffer
17 
18  * -> want_stop
19  wait until state == is_stopped
20 
21 */
22 typedef enum xmms_buffer_state_E {
30 
31 typedef struct xmms_ringbuf_priv_St {
32  GThread *thread;
33 
34  xmms_ringbuf_t *buffer;
35  GMutex *buffer_lock;
36 
37  xmms_buffer_state_t state;
38  GCond *state_cond;
39  GMutex *state_lock;
41 
42 static xmms_xform_plugin_t *ringbuf_plugin;
43 
44 static gpointer xmms_ringbuf_xform_thread (gpointer data);
45 
46 static gboolean
47 xmms_ringbuf_plugin_init (xmms_xform_t *xform)
48 {
49  xmms_ringbuf_priv_t *priv;
50 
51  priv = g_new0 (xmms_ringbuf_priv_t, 1);
52 
53  xmms_xform_private_data_set (xform, priv);
54 
55  priv->buffer = xmms_ringbuf_new (4096*8);
56  priv->buffer_lock = g_mutex_new ();
57  priv->state = STATE_WANT_BUFFER;
58  priv->state_cond = g_cond_new ();
59  priv->state_lock = g_mutex_new ();
60  priv->thread = g_thread_create (xmms_ringbuf_xform_thread, xform, TRUE, NULL);
61 
63 
64  return TRUE;
65 }
66 
67 static void
68 xmms_ringbuf_plugin_destroy (xmms_xform_t *xform)
69 {
70  xmms_ringbuf_priv_t *priv;
71  priv = xmms_xform_private_data_get (xform);
72 
73  g_mutex_lock (priv->state_lock);
74  xmms_ringbuf_clear (priv->buffer);
75  while (priv->state != STATE_IS_STOPPED) {
76  priv->state = STATE_WANT_STOP;
77  g_cond_wait (priv->state_cond, priv->state_lock);
78  }
79  g_mutex_unlock (priv->state_lock);
80 
81  g_thread_join (priv->thread);
82 
83  XMMS_DBG ("Ringbuf destroyed!");
84 }
85 
86 static gint
87 xmms_ringbuf_plugin_read (xmms_xform_t *xform, void *buffer, gint len, xmms_error_t *error)
88 {
89  xmms_ringbuf_priv_t *priv;
90  priv = xmms_xform_private_data_get (xform);
91 
92  return xmms_ringbuf_read_wait (priv->buffer, buffer, len, priv->buffer_lock);
93 }
94 
95 
96 static gboolean
97 xmms_ringbuf_plugin_setup (xmms_xform_plugin_t *xform_plugin)
98 {
99  xmms_xform_methods_t methods;
100 
101  XMMS_XFORM_METHODS_INIT (methods);
102  methods.init = xmms_ringbuf_plugin_init;
103  methods.destroy = xmms_ringbuf_plugin_destroy;
104  methods.read = xmms_ringbuf_plugin_read;
105  /*
106  methods.seek
107  */
108 
109  xmms_xform_plugin_methods_set (xform_plugin, &methods);
110 
111  ringbuf_plugin = xform_plugin;
112 
113  return TRUE;
114 }
115 
116 static xmms_xform_t *
117 xmms_ringbuf_xform_new (xmms_xform_t *prev, xmms_medialib_entry_t entry, GList *gt)
118 {
119  xmms_xform_t *xform;
120 
121  xform = xmms_xform_new (ringbuf_plugin, prev, entry, gt);
122 
123  return xform;
124 }
125 
126 static void
127 fill (xmms_xform_t *xform, xmms_ringbuf_priv_t *priv)
128 {
129  xmms_error_t err;
130  char buf[4096];
131  int res;
132 
133  res = xmms_xform_read (xform, buf, sizeof (buf), &err);
134  if (res > 0) {
135  xmms_ringbuf_write_wait (priv->buffer, buf, res, priv->buffer_lock);
136  } else if (res == -1) {
137  /* XXX copy error */
138  g_mutex_lock (priv->state_lock);
139  priv->state = STATE_WANT_STOP;
140  } else {
141  xmms_ringbuf_set_eos (priv->buffer, TRUE);
142  priv->state = STATE_WANT_STOP;
143  }
144 }
145 
146 static gpointer
147 xmms_ringbuf_xform_thread (gpointer data)
148 {
149  xmms_xform_t *xform = (xmms_xform_t *)data;
150  xmms_ringbuf_priv_t *priv;
151 
152  priv = xmms_xform_private_data_get (xform);
153 
154  g_mutex_lock (priv->state_lock);
155  while (priv->state != STATE_WANT_STOP) {
156  if (priv->state == STATE_WANT_BUFFER) {
157  priv->state = STATE_BUFFERING;
158  g_cond_signal (priv->state_cond);
159  while (priv->state == STATE_BUFFERING) {
160  g_mutex_unlock (priv->state_lock);
161  fill (xform, priv);
162  g_mutex_lock (priv->state_lock);
163  }
164  } else if (priv->state == STATE_WANT_SEEK) {
165  /** **/
166  priv->state = STATE_SEEK_DONE;
167  g_cond_signal (priv->state_cond);
168  while (priv->state == STATE_SEEK_DONE) {
169  g_cond_wait (priv->state_cond, priv->state_lock);
170  }
171  }
172  XMMS_DBG ("thread: state: %d", priv->state);
173  }
174  priv->state = STATE_IS_STOPPED;
175  g_cond_signal (priv->state_cond);
176  g_mutex_unlock (priv->state_lock);
177 
178  return NULL;
179 }
180 
181 XMMS_XFORM_BUILTIN (ringbuf,
182  "Ringbuffer",
183  XMMS_VERSION,
184  "Buffer",
185  xmms_ringbuf_plugin_setup);
struct xmms_ringbuf_St xmms_ringbuf_t
Definition: xmms_ringbuf.h:25
G_BEGIN_DECLS typedef gint32 xmms_medialib_entry_t
Definition: xmms_medialib.h:86
struct xmms_xform_plugin_St xmms_xform_plugin_t
Xform plugin.
guint xmms_ringbuf_read_wait(xmms_ringbuf_t *ringbuf, gpointer data, guint len, GMutex *mtx)
Same as xmms_ringbuf_read but blocks until you have all the data you want.
Definition: ringbuf.c:265
struct xmms_xform_St xmms_xform_t
gboolean(* init)(xmms_xform_t *)
Initialisation method.
xmms_buffer_state_E
Definition: ringbuf_xform.c:22
gpointer xmms_xform_private_data_get(xmms_xform_t *xform)
Get private data for this xform.
Definition: xform.c:424
enum xmms_buffer_state_E xmms_buffer_state_t
struct xmms_ringbuf_priv_St xmms_ringbuf_priv_t
xmms_ringbuf_t * xmms_ringbuf_new(guint size)
Allocate a new ringbuffer.
Definition: ringbuf.c:74
Methods provided by an xform plugin.
void xmms_xform_plugin_methods_set(xmms_xform_plugin_t *plugin, xmms_xform_methods_t *methods)
Should be called once from the plugin's setupfunc.
Definition: xform_plugin.c:53
void(* destroy)(xmms_xform_t *)
Destruction method.
guint xmms_ringbuf_write_wait(xmms_ringbuf_t *ringbuf, gconstpointer data, guint len, GMutex *mtx)
Same as xmms_ringbuf_write but blocks until there is enough free space.
Definition: ringbuf.c:353
void xmms_xform_outdata_type_copy(xmms_xform_t *xform)
Definition: xform.c:452
void xmms_ringbuf_clear(xmms_ringbuf_t *ringbuf)
Clear the ringbuffers data.
Definition: ringbuf.c:121
xmms_xform_t * xmms_xform_new(xmms_xform_plugin_t *plugin, xmms_xform_t *prev, xmms_medialib_entry_t entry, GList *goal_hints)
Definition: xform.c:375
gint xmms_xform_read(xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
Read data from previous xform.
Definition: xform.c:1113
void xmms_ringbuf_set_eos(xmms_ringbuf_t *ringbuf, gboolean eos)
Set EOS flag on ringbuffer.
Definition: ringbuf.c:427
gint(* read)(xmms_xform_t *, gpointer, gint, xmms_error_t *)
Read method.
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
#define XMMS_XFORM_METHODS_INIT(m)
void xmms_xform_private_data_set(xmms_xform_t *xform, gpointer data)
Set private data for this xform.
Definition: xform.c:430
XMMS_XFORM_BUILTIN(ringbuf, "Ringbuffer", XMMS_VERSION, "Buffer", xmms_ringbuf_plugin_setup)