1 /*
2 * MOC - music on console
3 * Copyright (C) 2004,2005 Damian Pietras <daper@daper.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 */
11
12 /*#define DEBUG*/
13
14 /* Defining OUT_TEST causes the raw audio samples to be written
15 * to the file 'out_test' in the current directory for debugging. */
16 /*#define OUT_TEST*/
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #include <assert.h>
23 #include <pthread.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #ifdef OUT_TEST
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #endif
33
34 #include "common.h"
35 #include "audio.h"
36 #include "log.h"
37 #include "fifo_buf.h"
38 #include "out_buf.h"
39 #include "options.h"
40
41 /* Don't play more than this value (in seconds) in one audio_play().
42 * This prevents locking. */
43 #define AUDIO_MAX_PLAY 0.1
44 #define AUDIO_MAX_PLAY_BYTES 32768
45
46 #ifdef OUT_TEST
47 static int fd;
48 #endif
49
set_realtime_prio()50 static void set_realtime_prio ()
51 {
52 #ifdef HAVE_SCHED_GET_PRIORITY_MAX
53 int rc;
54
55 if (options_get_int("UseRealtimePriority")) {
56 struct sched_param param;
57
58 param.sched_priority = sched_get_priority_max(SCHED_RR);
59 rc = pthread_setschedparam (pthread_self (), SCHED_RR, ¶m);
60 if (rc != 0)
61 logit ("Can't set realtime priority: %s", strerror (rc));
62 }
63 #else
64 logit ("No sched_get_priority_max() function: "
65 "realtime priority not used.");
66 #endif
67 }
68
69 /* Reading thread of the buffer. */
read_thread(void * arg)70 static void *read_thread (void *arg)
71 {
72 struct out_buf *buf = (struct out_buf *)arg;
73 int audio_dev_closed = 0;
74
75 logit ("entering output buffer thread");
76
77 set_realtime_prio ();
78
79 LOCK (buf->mutex);
80
81 while (1) {
82 int played = 0;
83 char play_buf[AUDIO_MAX_PLAY_BYTES];
84 int play_buf_fill;
85 int play_buf_pos = 0;
86
87 if (buf->reset_dev && !audio_dev_closed) {
88 audio_reset ();
89 buf->reset_dev = 0;
90 }
91
92 if (buf->stop)
93 fifo_buf_clear (&buf->buf);
94
95 if (buf->free_callback) {
96 /* unlock the mutex to make calls to out_buf functions
97 * possible in the callback */
98 UNLOCK (buf->mutex);
99 buf->free_callback ();
100 LOCK (buf->mutex);
101 }
102
103 debug ("sending the signal");
104 pthread_cond_broadcast (&buf->ready_cond);
105
106 if ((fifo_buf_get_fill(&buf->buf) == 0 || buf->pause || buf->stop)
107 && !buf->exit) {
108 if (buf->pause && !audio_dev_closed) {
109 logit ("Closing the device due to pause");
110 audio_close ();
111 audio_dev_closed = 1;
112 }
113
114 debug ("waiting for something in the buffer");
115 buf->read_thread_waiting = 1;
116 pthread_cond_wait (&buf->play_cond, &buf->mutex);
117 debug ("something appeared in the buffer");
118 }
119
120 buf->read_thread_waiting = 0;
121
122 if (audio_dev_closed && !buf->pause) {
123 logit ("Opening the device again after pause");
124 if (!audio_open(NULL)) {
125 logit ("Can't reopen the device! sleeping...");
126 sleep (1); /* there is no way to exit :( */
127 }
128 else
129 audio_dev_closed = 0;
130 }
131
132 if (fifo_buf_get_fill(&buf->buf) == 0) {
133 if (buf->exit) {
134 logit ("exit");
135 break;
136 }
137
138 logit ("buffer empty");
139 continue;
140 }
141
142 if (buf->pause) {
143 logit ("paused");
144 continue;
145 }
146
147 if (buf->stop) {
148 logit ("stopped");
149 continue;
150 }
151
152 if (!audio_dev_closed) {
153 int audio_bpf;
154 size_t play_buf_frames;
155
156 audio_bpf = audio_get_bpf();
157 play_buf_frames = MIN(audio_get_bps() * AUDIO_MAX_PLAY,
158 AUDIO_MAX_PLAY_BYTES) / audio_bpf;
159 play_buf_fill = fifo_buf_get(&buf->buf, play_buf,
160 play_buf_frames * audio_bpf);
161 UNLOCK (buf->mutex);
162
163 debug ("playing %d bytes", play_buf_fill);
164
165 while (play_buf_pos < play_buf_fill) {
166 played = audio_send_pcm (
167 play_buf + play_buf_pos,
168 play_buf_fill - play_buf_pos);
169
170 #ifdef OUT_TEST
171 write (fd, play_buf + play_buf_pos, played);
172 #endif
173
174 play_buf_pos += played;
175 }
176
177 /*logit ("done sending PCM");*/
178
179 LOCK (buf->mutex);
180
181 /* Update time */
182 if (play_buf_fill && audio_get_bps())
183 buf->time += play_buf_fill / (float)audio_get_bps();
184 buf->hardware_buf_fill = audio_get_buf_fill();
185 }
186 }
187
188 UNLOCK (buf->mutex);
189
190 logit ("exiting");
191
192 return NULL;
193 }
194
195 /* Initialize the buf structure, size is the buffer size. */
out_buf_init(struct out_buf * buf,int size)196 void out_buf_init (struct out_buf *buf, int size)
197 {
198 int rc;
199
200 assert (buf != NULL);
201 assert (size > 0);
202
203 fifo_buf_init (&buf->buf, size);
204 buf->exit = 0;
205 buf->pause = 0;
206 buf->stop = 0;
207 buf->time = 0.0;
208 buf->reset_dev = 0;
209 buf->hardware_buf_fill = 0;
210 buf->read_thread_waiting = 0;
211 buf->free_callback = NULL;
212
213 pthread_mutex_init (&buf->mutex, NULL);
214 pthread_cond_init (&buf->play_cond, NULL);
215 pthread_cond_init (&buf->ready_cond, NULL);
216
217 #ifdef OUT_TEST
218 fd = open ("out_test", O_CREAT | O_TRUNC | O_WRONLY, 0600);
219 #endif
220
221 rc = pthread_create (&buf->tid, NULL, read_thread, buf);
222 if (rc != 0)
223 fatal ("Can't create buffer thread: %s", strerror (rc));
224 }
225
226 /* Wait for empty buffer, end playing, free resources allocated for the buf
227 * structure. Can be used only if nothing is played. */
out_buf_destroy(struct out_buf * buf)228 void out_buf_destroy (struct out_buf *buf)
229 {
230 int rc;
231
232 assert (buf != NULL);
233
234 LOCK (buf->mutex);
235 buf->exit = 1;
236 pthread_cond_signal (&buf->play_cond);
237 UNLOCK (buf->mutex);
238
239 pthread_join (buf->tid, NULL);
240
241 /* Let other threads using this buffer know that the state of the
242 * buffer has changed. */
243 LOCK (buf->mutex);
244 fifo_buf_clear (&buf->buf);
245 pthread_cond_broadcast (&buf->ready_cond);
246 UNLOCK (buf->mutex);
247
248 fifo_buf_destroy (&buf->buf);
249 rc = pthread_mutex_destroy (&buf->mutex);
250 if (rc != 0)
251 logit ("Destroying buffer mutex failed: %s", strerror (rc));
252 rc = pthread_cond_destroy (&buf->play_cond);
253 if (rc != 0)
254 logit ("Destroying buffer play condition failed: %s", strerror (rc));
255 rc = pthread_cond_destroy (&buf->ready_cond);
256 if (rc != 0)
257 logit ("Destroying buffer ready condition failed: %s", strerror (rc));
258
259 logit ("buffer destroyed");
260
261 #ifdef OUT_TEST
262 close (fd);
263 #endif
264 }
265
266 /* Put data at the end of the buffer, return 0 if nothing was put. */
out_buf_put(struct out_buf * buf,const char * data,int size)267 int out_buf_put (struct out_buf *buf, const char *data, int size)
268 {
269 int pos = 0;
270
271 /*logit ("got %d bytes to play", size);*/
272
273 while (size) {
274 int written;
275
276 LOCK (buf->mutex);
277
278 if (fifo_buf_get_space(&buf->buf) == 0 && !buf->stop) {
279 /*logit ("buffer full, waiting for the signal");*/
280 pthread_cond_wait (&buf->ready_cond, &buf->mutex);
281 /*logit ("buffer ready");*/
282 }
283
284 if (buf->stop) {
285 logit ("the buffer is stopped, refusing to write to the buffer");
286 UNLOCK (buf->mutex);
287 return 0;
288 }
289
290 written = fifo_buf_put (&buf->buf, data + pos, size);
291
292 if (written) {
293 pthread_cond_signal (&buf->play_cond);
294 size -= written;
295 pos += written;
296 }
297
298 UNLOCK (buf->mutex);
299 }
300
301 return 1;
302 }
303
out_buf_pause(struct out_buf * buf)304 void out_buf_pause (struct out_buf *buf)
305 {
306 LOCK (buf->mutex);
307 buf->pause = 1;
308 buf->reset_dev = 1;
309 UNLOCK (buf->mutex);
310 }
311
out_buf_unpause(struct out_buf * buf)312 void out_buf_unpause (struct out_buf *buf)
313 {
314 LOCK (buf->mutex);
315 buf->pause = 0;
316 pthread_cond_signal (&buf->play_cond);
317 UNLOCK (buf->mutex);
318 }
319
320 /* Stop playing, after that buffer will refuse to play anything and ignore data
321 * sent by buf_put(). */
out_buf_stop(struct out_buf * buf)322 void out_buf_stop (struct out_buf *buf)
323 {
324 logit ("stopping the buffer");
325 LOCK (buf->mutex);
326 buf->stop = 1;
327 buf->pause = 0;
328 buf->reset_dev = 1;
329 logit ("sending signal");
330 pthread_cond_signal (&buf->play_cond);
331 logit ("waiting for signal");
332 pthread_cond_wait (&buf->ready_cond, &buf->mutex);
333 logit ("done");
334 UNLOCK (buf->mutex);
335 }
336
337 /* Reset the buffer state: this can by called ONLY when the buffer is stopped
338 * and buf_put is not used! */
out_buf_reset(struct out_buf * buf)339 void out_buf_reset (struct out_buf *buf)
340 {
341 logit ("resetting the buffer");
342
343 LOCK (buf->mutex);
344 fifo_buf_clear (&buf->buf);
345 buf->stop = 0;
346 buf->pause = 0;
347 buf->reset_dev = 0;
348 buf->hardware_buf_fill = 0;
349 UNLOCK (buf->mutex);
350 }
351
out_buf_time_set(struct out_buf * buf,const float time)352 void out_buf_time_set (struct out_buf *buf, const float time)
353 {
354 LOCK (buf->mutex);
355 buf->time = time;
356 UNLOCK (buf->mutex);
357 }
358
359 /* Return the time in the audio which the user is currently hearing.
360 * If unplayed samples still remain in the hardware buffer from the
361 * previous audio then the value returned may be negative and it is
362 * up to the caller to handle this appropriately in the context of
363 * its own processing. */
out_buf_time_get(struct out_buf * buf)364 int out_buf_time_get (struct out_buf *buf)
365 {
366 int time;
367 int bps = audio_get_bps ();
368
369 LOCK (buf->mutex);
370 time = buf->time - (bps ? buf->hardware_buf_fill / (float)bps : 0);
371 UNLOCK (buf->mutex);
372
373 return time;
374 }
375
out_buf_set_free_callback(struct out_buf * buf,out_buf_free_callback callback)376 void out_buf_set_free_callback (struct out_buf *buf,
377 out_buf_free_callback callback)
378 {
379 assert (buf != NULL);
380
381 LOCK (buf->mutex);
382 buf->free_callback = callback;
383 UNLOCK (buf->mutex);
384 }
385
out_buf_get_free(struct out_buf * buf)386 int out_buf_get_free (struct out_buf *buf)
387 {
388 int space;
389
390 assert (buf != NULL);
391
392 LOCK (buf->mutex);
393 space = fifo_buf_get_space (&buf->buf);
394 UNLOCK (buf->mutex);
395
396 return space;
397 }
398
out_buf_get_fill(struct out_buf * buf)399 int out_buf_get_fill (struct out_buf *buf)
400 {
401 int fill;
402
403 assert (buf != NULL);
404
405 LOCK (buf->mutex);
406 fill = fifo_buf_get_fill (&buf->buf);
407 UNLOCK (buf->mutex);
408
409 return fill;
410 }
411
412 /* Wait until the read thread will stop and wait for data to come.
413 * This makes sure that the audio device isn't used (of course only if you
414 * don't put anything in the buffer). */
out_buf_wait(struct out_buf * buf)415 void out_buf_wait (struct out_buf *buf)
416 {
417 assert (buf != NULL);
418
419 logit ("Waiting for read thread to suspend...");
420
421 LOCK (buf->mutex);
422 while (!buf->read_thread_waiting) {
423 debug ("waiting....");
424 pthread_cond_wait (&buf->ready_cond, &buf->mutex);
425 }
426 UNLOCK (buf->mutex);
427
428 logit ("done");
429 }
430