new implementation for read the MPlayer's fifo out, a thread will look the stdout/stderr and gives a response when that is necessary
1 --- a/src/wrapper_mplayer.c Wed Aug 01 22:46:23 2007 +0200
2 +++ b/src/wrapper_mplayer.c Sat Aug 04 17:00:27 2007 +0200
3 @@ -30,6 +30,8 @@
4 #include <sys/types.h>
5 #include <sys/stat.h> /* stat */
6 #include <signal.h> /* sigaction */
7 +#include <pthread.h> /* pthread_... */
8 +#include <semaphore.h> /* sem_post sem_wait sem_init */
9
10 #include "player.h"
11 #include "player_internals.h"
12 @@ -54,6 +56,12 @@
13 MPLAYER_IS_DEAD
14 } mplayer_status_t;
15
16 +/* property and value for a search in the fifo_out */
17 +typedef struct mp_search_s {
18 + char *property;
19 + char *value;
20 +} mp_search_t;
21 +
22 /* player specific structure */
23 typedef struct mplayer_s {
24 mplayer_status_t status;
25 @@ -62,6 +70,11 @@
26 int pipe_out[2]; /* pipe for receive results */
27 FILE *fifo_in; /* fifo on the pipe_in (write only) */
28 FILE *fifo_out; /* fifo on the pipe_out (read only) */
29 + /* specific to thread */
30 + pthread_t th_fifo; /* thread for the fifo_out parser */
31 + pthread_mutex_t mutex;
32 + sem_t sem;
33 + mp_search_t *search; /* use when a property is searched */
34 } mplayer_t;
35
36 /* slave commands */
37 @@ -166,21 +179,109 @@
38 }
39
40 /**
41 + * Thread for parse the fifo_out of MPlayer. This thread must be used only
42 + * with slave_result() when a property is needed. The rest of the time,
43 + * this thread will just respond to some events.
44 + */
45 +static void *
46 +thread_fifo (void *arg)
47 +{
48 + char buffer[SLAVE_CMD_BUFFER];
49 + char *its, *ite;
50 + player_t *player;
51 + mplayer_t *mplayer;
52 +
53 + player = (player_t *) arg;
54 +
55 + if (player) {
56 + mplayer = (mplayer_t *) player->priv;
57 +
58 + if (mplayer && mplayer->fifo_out) {
59 + /* MPlayer's stdout parser */
60 + while (fgets (buffer, SLAVE_CMD_BUFFER, mplayer->fifo_out))
61 + {
62 + /* lock the mutex for protect mplayer->search */
63 + pthread_mutex_lock (&mplayer->mutex);
64 + /* search the result for a property */
65 + if (mplayer->search && mplayer->search->property &&
66 + (its = strstr(buffer, mplayer->search->property)))
67 + {
68 + /* value start */
69 + its += strlen (mplayer->search->property);
70 + ite = its;
71 + while (*ite != '\0' && *ite != '\n')
72 + ite++;
73 +
74 + /* value end */
75 + *ite = '\0';
76 +
77 + if ((mplayer->search->value = malloc (strlen (its) + 1))) {
78 + memcpy (mplayer->search->value, its, strlen (its));
79 + *(mplayer->search->value + strlen (its)) = '\0';
80 + }
81 + }
82 + /* If this error (from stderr) exists, then we can go out
83 + * because there is no result for the real command.
84 + */
85 + else if (strstr (buffer, "Command loadfile")) {
86 + if (mplayer->search) {
87 + free (mplayer->search->property);
88 + mplayer->search->property = NULL;
89 + /* search ended */
90 + sem_post (&mplayer->sem);
91 + }
92 + }
93 + pthread_mutex_unlock (&mplayer->mutex);
94 +
95 + if (strstr (buffer, "Exiting")) {
96 + mplayer->status = MPLAYER_IS_DEAD;
97 + break;
98 + }
99 + }
100 + }
101 + }
102 +
103 + pthread_exit (0);
104 +}
105 +
106 +/**
107 + * Send a command to slave for get a property. That will return nothing
108 + * because the response is grabbed with slave_result().
109 + */
110 +static void
111 +slave_get_property (player_t *player, slave_property_t property)
112 +{
113 + mplayer_t *mplayer = NULL;
114 + char *prop;
115 +
116 + if (!player)
117 + return;
118 +
119 + mplayer = (mplayer_t *) player->priv;
120 +
121 + if (!mplayer || !mplayer->fifo_in)
122 + return;
123 +
124 + /* get the right property in the global list */
125 + prop = get_prop (property);
126 + if (prop)
127 + send_to_slave (mplayer, "get_property %s", prop);
128 + else
129 + /* should never going here */
130 + return;
131 +}
132 +
133 +/**
134 * Get results of commands sent to MPlayer. The MPlayer's stdout and sterr
135 - * are connected to fifo_out. Because MPlayer doesn't confirm all commands
136 - * (for example, a get_property with no stream return nothing), that is
137 - * necessary for send an other command with an output in all cases.
138 - * Here, this command create an error captured in the stderr for confirm
139 - * the end of the fifo_out.
140 + * are connected to fifo_out. This function uses the thread_fifo for get
141 + * the result. That uses semaphore and mutex.
142 */
143 static char *
144 slave_result (slave_property_t property, player_t *player)
145 {
146 char str[SLAVE_CMD_BUFFER];
147 - char *buffer;
148 char *prop;
149 char *ret = NULL;
150 - char *its, *ite;
151 mplayer_t *mplayer = NULL;
152
153 if (!player)
154 @@ -199,50 +300,43 @@
155 /* should never going here */
156 return NULL;
157
158 - /* NOTE: /!\ That is ugly but it works pretty well :o)
159 - * Because MPlayer doesn't confirm commands, that is necessary for
160 - * have a text in the fifo_out for know if there is no new message.
161 - * Else, the fgets (read) will block on the pipe. NONBLOCK is not a
162 - * solution, better for have an information that will to confirm if
163 - * MPlayer has no result and then to stop the read.
164 - *
165 - * An error is created by the command 'loadfile' without arguments. This
166 - * error is got with fgets() and the while is break if there is no
167 - * result for the real command in var 'str'.
168 - */
169 - send_to_slave (mplayer, "loadfile");
170 + /* lock the mutex for protect mplayer->search */
171 + pthread_mutex_lock (&mplayer->mutex);
172 + mplayer->search = malloc (sizeof (mp_search_t));
173
174 - if ((buffer = malloc (SLAVE_CMD_BUFFER))) {
175 - /* MPlayer's stdout parser */
176 - while (fgets (buffer, SLAVE_CMD_BUFFER, mplayer->fifo_out))
177 - {
178 - /* search the result */
179 - if ((its = strstr(buffer, str))) {
180 - /* value start */
181 - its += strlen (str);
182 - ite = its;
183 - while (*ite != '\0' && *ite != '\n')
184 - ite++;
185 + if (mplayer->search) {
186 + mplayer->search->property = strdup (str);
187 + mplayer->search->value = NULL;
188 + pthread_mutex_unlock (&mplayer->mutex);
189
190 - /* value end */
191 - *ite = '\0';
192 + /* send the slave command for get a response from MPlayer */
193 + slave_get_property (player, property);
194
195 - if ((ret = malloc (strlen (its) + 1))) {
196 - memcpy (ret, its, strlen (its));
197 - *(ret + strlen (its)) = '\0';
198 - }
199 - }
200 - /* If this error (from stderr) exists, then we can go out
201 - * because there is no result for the real command.
202 - */
203 - else if (strstr (buffer, "Command loadfile"))
204 - break;
205 + /* NOTE: /!\ That is ugly but it works pretty well :o)
206 + * Because MPlayer doesn't confirm commands, that is necessary for
207 + * have a text in the fifo_out for know if there is no new message
208 + * because MPlayer will not response all the time to get_property.
209 + *
210 + * An error is created by the command 'loadfile' without argument. This
211 + * error is got with fgets() and the search is ended if there is no
212 + * result for the real command.
213 + */
214 + send_to_slave (mplayer, "loadfile");
215
216 - *buffer = '\0';
217 - }
218 + /* wait that the thread will found the value */
219 + sem_wait (&mplayer->sem);
220
221 - free (buffer);
222 + /* we take the result */
223 + ret = mplayer->search->value;
224 +
225 + /* the search is ended */
226 + pthread_mutex_lock (&mplayer->mutex);
227 + free (mplayer->search);
228 + mplayer->search = NULL;
229 + pthread_mutex_unlock (&mplayer->mutex);
230 }
231 + else
232 + pthread_mutex_unlock (&mplayer->mutex);
233
234 return ret;
235 }
236 @@ -313,45 +407,22 @@
237 }
238 }
239
240 -/**
241 - * Send a command to slave for get a property. That will return nothing
242 - * because the response is grabbed with slave_result().
243 - */
244 -static void
245 -slave_get_property (player_t *player, slave_property_t property)
246 -{
247 - mplayer_t *mplayer = NULL;
248 - char *prop;
249 -
250 - if (!player)
251 - return;
252 -
253 - mplayer = (mplayer_t *) player->priv;
254 -
255 - if (!mplayer || !mplayer->fifo_in)
256 - return;
257 -
258 - /* get the right property in the global list */
259 - prop = get_prop (property);
260 - if (prop)
261 - send_to_slave (mplayer, "get_property %s", prop);
262 - else
263 - /* should never going here */
264 - return;
265 -}
266 -
267 static inline int
268 slave_get_property_int (player_t *player, slave_property_t property)
269 {
270 - slave_get_property (player, property);
271 - return slave_result_int (player, property);
272 + int res;
273 +
274 + res = slave_result_int (player, property);
275 + return res;
276 }
277
278 static inline char *
279 slave_get_property_str (player_t *player, slave_property_t property)
280 {
281 - slave_get_property (player, property);
282 - return slave_result_str (player, property);
283 + char *res;
284 +
285 + res = slave_result_str (player, property);
286 + return res;
287 }
288
289 static void
290 @@ -673,7 +744,14 @@
291
292 mplayer->status = MPLAYER_IS_IDLE;
293
294 - return PLAYER_INIT_OK;
295 + /* init semaphore and mutex */
296 + sem_init (&mplayer->sem, 0, 0);
297 + pthread_mutex_init (&mplayer->mutex, NULL);
298 +
299 + /* create the thread */
300 + if (pthread_create (&mplayer->th_fifo, NULL,
301 + thread_fifo, (void *) player) >= 0)
302 + return PLAYER_INIT_OK;
303 }
304 }
305 }
306 @@ -685,6 +763,7 @@
307 mplayer_uninit (player_t *player)
308 {
309 mplayer_t *mplayer = NULL;
310 + void *ret;
311
312 plog (MODULE_NAME, "uninit");
313
314 @@ -699,6 +778,9 @@
315 if (mplayer && mplayer->fifo_in) {
316 /* suicide of MPlayer */
317 slave_cmd (player, SLAVE_QUIT);
318 +
319 + /* wait the death of the thread fifo_out */
320 + (void) pthread_join (mplayer->th_fifo, &ret);
321
322 /* wait the death of MPlayer */
323 waitpid (mplayer->pid, NULL, 0);
324 @@ -1123,6 +1205,7 @@
325 mplayer->status = MPLAYER_IS_DEAD;
326 mplayer->fifo_in = NULL;
327 mplayer->fifo_out = NULL;
328 + mplayer->search = NULL;
329
330 return mplayer;
331 }