1 /**
2 * Originally digi.c from allegro wiki
3 * Original authors: KC/Milan
4 *
5 * Converted to allegro5 by Ryan Dickie
6 */
7
8 /* Title: Stream functions
9 */
10
11 #include <stdio.h>
12
13 #include "allegro5/allegro_audio.h"
14 #include "allegro5/internal/aintern_audio.h"
15 #include "allegro5/internal/aintern_audio_cfg.h"
16
17 ALLEGRO_DEBUG_CHANNEL("audio")
18
19 /*
20 * The highest quality interpolator is a cubic interpolator requiring
21 * four sample points. In the streaming case we lag the true sample
22 * position by three.
23 */
24 #define MAX_LAG (3)
25
26
27 /*
28 * To avoid deadlocks, unlock the mutex returned by this function, rather than
29 * whatever you passed as the argument.
30 */
maybe_lock_mutex(ALLEGRO_MUTEX * mutex)31 static ALLEGRO_MUTEX *maybe_lock_mutex(ALLEGRO_MUTEX *mutex)
32 {
33 if (mutex) {
34 al_lock_mutex(mutex);
35 }
36 return mutex;
37 }
38
39
maybe_unlock_mutex(ALLEGRO_MUTEX * mutex)40 static void maybe_unlock_mutex(ALLEGRO_MUTEX *mutex)
41 {
42 if (mutex) {
43 al_unlock_mutex(mutex);
44 }
45 }
46
47 /* Function: al_create_audio_stream
48 */
al_create_audio_stream(size_t fragment_count,unsigned int frag_samples,unsigned int freq,ALLEGRO_AUDIO_DEPTH depth,ALLEGRO_CHANNEL_CONF chan_conf)49 ALLEGRO_AUDIO_STREAM *al_create_audio_stream(size_t fragment_count,
50 unsigned int frag_samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth,
51 ALLEGRO_CHANNEL_CONF chan_conf)
52 {
53 ALLEGRO_AUDIO_STREAM *stream;
54 unsigned long bytes_per_sample;
55 unsigned long bytes_per_frag_buf;
56 size_t i;
57
58 if (!fragment_count) {
59 _al_set_error(ALLEGRO_INVALID_PARAM,
60 "Attempted to create stream with no buffers");
61 return NULL;
62 }
63 if (!frag_samples) {
64 _al_set_error(ALLEGRO_INVALID_PARAM,
65 "Attempted to create stream with no buffer size");
66 return NULL;
67 }
68 if (!freq) {
69 _al_set_error(ALLEGRO_INVALID_PARAM,
70 "Attempted to create stream with no frequency");
71 return NULL;
72 }
73
74 bytes_per_sample = al_get_channel_count(chan_conf) *
75 al_get_audio_depth_size(depth);
76 bytes_per_frag_buf = frag_samples * bytes_per_sample;
77
78 stream = al_calloc(1, sizeof(*stream));
79 if (!stream) {
80 _al_set_error(ALLEGRO_GENERIC_ERROR,
81 "Out of memory allocating stream object");
82 return NULL;
83 }
84
85 stream->spl.is_playing = true;
86 stream->is_draining = false;
87
88 stream->spl.loop = _ALLEGRO_PLAYMODE_STREAM_ONCE;
89 stream->spl.spl_data.depth = depth;
90 stream->spl.spl_data.chan_conf = chan_conf;
91 stream->spl.spl_data.frequency = freq;
92 stream->spl.speed = 1.0f;
93 stream->spl.gain = 1.0f;
94 stream->spl.pan = 0.0f;
95
96 stream->spl.step = 0;
97 stream->spl.pos = frag_samples;
98 stream->spl.spl_data.len = stream->spl.pos;
99
100 stream->buf_count = fragment_count;
101
102 stream->used_bufs = al_calloc(1, fragment_count * sizeof(void *) * 2);
103 if (!stream->used_bufs) {
104 al_free(stream->used_bufs);
105 al_free(stream);
106 _al_set_error(ALLEGRO_GENERIC_ERROR,
107 "Out of memory allocating stream buffer pointers");
108 return NULL;
109 }
110 stream->pending_bufs = stream->used_bufs + fragment_count;
111
112 /* The main_buffer holds all the buffer fragments in contiguous memory.
113 * To support interpolation across buffer fragments, we allocate extra
114 * MAX_LAG samples at the start of each buffer fragment, to hold the
115 * last few sample values which came before that fragment.
116 */
117 stream->main_buffer = al_calloc(1,
118 (MAX_LAG * bytes_per_sample + bytes_per_frag_buf) * fragment_count);
119 if (!stream->main_buffer) {
120 al_free(stream->used_bufs);
121 al_free(stream);
122 _al_set_error(ALLEGRO_GENERIC_ERROR,
123 "Out of memory allocating stream buffer");
124 return NULL;
125 }
126
127 for (i = 0; i < fragment_count; i++) {
128 char *buffer = (char *)stream->main_buffer
129 + i * (MAX_LAG * bytes_per_sample + bytes_per_frag_buf);
130 al_fill_silence(buffer, MAX_LAG, depth, chan_conf);
131 stream->used_bufs[i] = buffer + MAX_LAG * bytes_per_sample;
132 }
133
134 al_init_user_event_source(&stream->spl.es);
135
136 /* This can lead to deadlocks on shutdown, hence we don't do it. */
137 /* stream->dtor_item = _al_kcm_register_destructor(stream, (void (*)(void *)) al_destroy_audio_stream); */
138
139 return stream;
140 }
141
142
143 /* Function: al_destroy_audio_stream
144 */
al_destroy_audio_stream(ALLEGRO_AUDIO_STREAM * stream)145 void al_destroy_audio_stream(ALLEGRO_AUDIO_STREAM *stream)
146 {
147 if (stream) {
148 if (stream->feed_thread) {
149 stream->unload_feeder(stream);
150 }
151 /* See commented out call to _al_kcm_register_destructor. */
152 /* _al_kcm_unregister_destructor(stream->dtor_item); */
153 _al_kcm_detach_from_parent(&stream->spl);
154
155 al_destroy_user_event_source(&stream->spl.es);
156 al_free(stream->main_buffer);
157 al_free(stream->used_bufs);
158 al_free(stream);
159 }
160 }
161
162
163 /* Function: al_drain_audio_stream
164 */
al_drain_audio_stream(ALLEGRO_AUDIO_STREAM * stream)165 void al_drain_audio_stream(ALLEGRO_AUDIO_STREAM *stream)
166 {
167 bool playing;
168
169 if (!al_get_audio_stream_attached(stream)) {
170 al_set_audio_stream_playing(stream, false);
171 return;
172 }
173
174 stream->is_draining = true;
175 do {
176 al_rest(0.01);
177 playing = al_get_audio_stream_playing(stream);
178 } while (playing);
179 stream->is_draining = false;
180 }
181
182
183 /* Function: al_get_audio_stream_frequency
184 */
al_get_audio_stream_frequency(const ALLEGRO_AUDIO_STREAM * stream)185 unsigned int al_get_audio_stream_frequency(const ALLEGRO_AUDIO_STREAM *stream)
186 {
187 ASSERT(stream);
188
189 return stream->spl.spl_data.frequency;
190 }
191
192
193 /* Function: al_get_audio_stream_length
194 */
al_get_audio_stream_length(const ALLEGRO_AUDIO_STREAM * stream)195 unsigned int al_get_audio_stream_length(const ALLEGRO_AUDIO_STREAM *stream)
196 {
197 ASSERT(stream);
198
199 return stream->spl.spl_data.len;
200 }
201
202
203 /* Function: al_get_audio_stream_fragments
204 */
al_get_audio_stream_fragments(const ALLEGRO_AUDIO_STREAM * stream)205 unsigned int al_get_audio_stream_fragments(const ALLEGRO_AUDIO_STREAM *stream)
206 {
207 ASSERT(stream);
208
209 return stream->buf_count;
210 }
211
212
213 /* Function: al_get_available_audio_stream_fragments
214 */
al_get_available_audio_stream_fragments(const ALLEGRO_AUDIO_STREAM * stream)215 unsigned int al_get_available_audio_stream_fragments(
216 const ALLEGRO_AUDIO_STREAM *stream)
217 {
218 unsigned int i;
219 ASSERT(stream);
220
221 for (i = 0; i < stream->buf_count && stream->used_bufs[i]; i++)
222 ;
223 return i;
224 }
225
226
227 /* Function: al_get_audio_stream_speed
228 */
al_get_audio_stream_speed(const ALLEGRO_AUDIO_STREAM * stream)229 float al_get_audio_stream_speed(const ALLEGRO_AUDIO_STREAM *stream)
230 {
231 ASSERT(stream);
232
233 return stream->spl.speed;
234 }
235
236
237 /* Function: al_get_audio_stream_gain
238 */
al_get_audio_stream_gain(const ALLEGRO_AUDIO_STREAM * stream)239 float al_get_audio_stream_gain(const ALLEGRO_AUDIO_STREAM *stream)
240 {
241 ASSERT(stream);
242
243 return stream->spl.gain;
244 }
245
246
247 /* Function: al_get_audio_stream_pan
248 */
al_get_audio_stream_pan(const ALLEGRO_AUDIO_STREAM * stream)249 float al_get_audio_stream_pan(const ALLEGRO_AUDIO_STREAM *stream)
250 {
251 ASSERT(stream);
252
253 return stream->spl.pan;
254 }
255
256
257 /* Function: al_get_audio_stream_channels
258 */
al_get_audio_stream_channels(const ALLEGRO_AUDIO_STREAM * stream)259 ALLEGRO_CHANNEL_CONF al_get_audio_stream_channels(
260 const ALLEGRO_AUDIO_STREAM *stream)
261 {
262 ASSERT(stream);
263
264 return stream->spl.spl_data.chan_conf;
265 }
266
267
268 /* Function: al_get_audio_stream_depth
269 */
al_get_audio_stream_depth(const ALLEGRO_AUDIO_STREAM * stream)270 ALLEGRO_AUDIO_DEPTH al_get_audio_stream_depth(
271 const ALLEGRO_AUDIO_STREAM *stream)
272 {
273 ASSERT(stream);
274
275 return stream->spl.spl_data.depth;
276 }
277
278
279 /* Function: al_get_audio_stream_playmode
280 */
al_get_audio_stream_playmode(const ALLEGRO_AUDIO_STREAM * stream)281 ALLEGRO_PLAYMODE al_get_audio_stream_playmode(
282 const ALLEGRO_AUDIO_STREAM *stream)
283 {
284 ASSERT(stream);
285
286 return stream->spl.loop;
287 }
288
289
290 /* Function: al_get_audio_stream_playing
291 */
al_get_audio_stream_playing(const ALLEGRO_AUDIO_STREAM * stream)292 bool al_get_audio_stream_playing(const ALLEGRO_AUDIO_STREAM *stream)
293 {
294 ASSERT(stream);
295
296 return stream->spl.is_playing;
297 }
298
299
300 /* Function: al_get_audio_stream_attached
301 */
al_get_audio_stream_attached(const ALLEGRO_AUDIO_STREAM * stream)302 bool al_get_audio_stream_attached(const ALLEGRO_AUDIO_STREAM *stream)
303 {
304 ASSERT(stream);
305
306 return (stream->spl.parent.u.ptr != NULL);
307 }
308
309 /* Function: al_get_audio_stream_played_samples
310 */
al_get_audio_stream_played_samples(const ALLEGRO_AUDIO_STREAM * stream)311 uint64_t al_get_audio_stream_played_samples(const ALLEGRO_AUDIO_STREAM *stream)
312 {
313 uint64_t result;
314 ALLEGRO_MUTEX *stream_mutex;
315 ASSERT(stream);
316
317 stream_mutex = maybe_lock_mutex(stream->spl.mutex);
318 if (stream->spl.spl_data.buffer.ptr) {
319 result = stream->consumed_fragments * stream->spl.spl_data.len +
320 stream->spl.pos;
321 }
322 else {
323 result = 0;
324 }
325 maybe_unlock_mutex(stream_mutex);
326
327 return result;
328 }
329
330 /* Function: al_get_audio_stream_fragment
331 */
al_get_audio_stream_fragment(const ALLEGRO_AUDIO_STREAM * stream)332 void *al_get_audio_stream_fragment(const ALLEGRO_AUDIO_STREAM *stream)
333 {
334 size_t i;
335 void *fragment;
336 ALLEGRO_MUTEX *stream_mutex;
337 ASSERT(stream);
338
339 stream_mutex = maybe_lock_mutex(stream->spl.mutex);
340
341 if (!stream->used_bufs[0]) {
342 /* No free fragments are available. */
343 fragment = NULL;
344 }
345 else {
346 fragment = stream->used_bufs[0];
347 for (i = 0; i < stream->buf_count-1 && stream->used_bufs[i]; i++) {
348 stream->used_bufs[i] = stream->used_bufs[i+1];
349 }
350 stream->used_bufs[i] = NULL;
351 }
352
353 maybe_unlock_mutex(stream_mutex);
354
355 return fragment;
356 }
357
358
359 /* Function: al_set_audio_stream_speed
360 */
al_set_audio_stream_speed(ALLEGRO_AUDIO_STREAM * stream,float val)361 bool al_set_audio_stream_speed(ALLEGRO_AUDIO_STREAM *stream, float val)
362 {
363 ASSERT(stream);
364
365 if (val <= 0.0f) {
366 _al_set_error(ALLEGRO_INVALID_PARAM,
367 "Attempted to set stream speed to a zero or negative value");
368 return false;
369 }
370
371 if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) {
372 _al_set_error(ALLEGRO_GENERIC_ERROR,
373 "Could not set voice playback speed");
374 return false;
375 }
376
377 stream->spl.speed = val;
378 if (stream->spl.parent.u.mixer) {
379 ALLEGRO_MIXER *mixer = stream->spl.parent.u.mixer;
380 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
381
382 stream->spl.step = (stream->spl.spl_data.frequency) * stream->spl.speed;
383 stream->spl.step_denom = mixer->ss.spl_data.frequency;
384 /* Don't wanna be trapped with a step value of 0 */
385 if (stream->spl.step == 0) {
386 stream->spl.step = 1;
387 }
388
389 maybe_unlock_mutex(stream_mutex);
390 }
391
392 return true;
393 }
394
395
396 /* Function: al_set_audio_stream_gain
397 */
al_set_audio_stream_gain(ALLEGRO_AUDIO_STREAM * stream,float val)398 bool al_set_audio_stream_gain(ALLEGRO_AUDIO_STREAM *stream, float val)
399 {
400 ASSERT(stream);
401
402 if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) {
403 _al_set_error(ALLEGRO_GENERIC_ERROR,
404 "Could not set gain of stream attached to voice");
405 return false;
406 }
407
408 if (stream->spl.gain != val) {
409 stream->spl.gain = val;
410
411 /* If attached to a mixer already, need to recompute the sample
412 * matrix to take into account the gain.
413 */
414 if (stream->spl.parent.u.mixer) {
415 ALLEGRO_MIXER *mixer = stream->spl.parent.u.mixer;
416 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
417 _al_kcm_mixer_rejig_sample_matrix(mixer, &stream->spl);
418 maybe_unlock_mutex(stream_mutex);
419 }
420 }
421
422 return true;
423 }
424
425
426 /* Function: al_set_audio_stream_pan
427 */
al_set_audio_stream_pan(ALLEGRO_AUDIO_STREAM * stream,float val)428 bool al_set_audio_stream_pan(ALLEGRO_AUDIO_STREAM *stream, float val)
429 {
430 ASSERT(stream);
431
432 if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) {
433 _al_set_error(ALLEGRO_GENERIC_ERROR,
434 "Could not set gain of stream attached to voice");
435 return false;
436 }
437 if (val != ALLEGRO_AUDIO_PAN_NONE && (val < -1.0 || val > 1.0)) {
438 _al_set_error(ALLEGRO_GENERIC_ERROR, "Invalid pan value");
439 return false;
440 }
441
442 if (stream->spl.pan != val) {
443 stream->spl.pan = val;
444
445 /* If attached to a mixer already, need to recompute the sample
446 * matrix to take into account the panning.
447 */
448 if (stream->spl.parent.u.mixer) {
449 ALLEGRO_MIXER *mixer = stream->spl.parent.u.mixer;
450 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
451 _al_kcm_mixer_rejig_sample_matrix(mixer, &stream->spl);
452 maybe_unlock_mutex(stream_mutex);
453 }
454 }
455
456 return true;
457 }
458
459
460 /* Function: al_set_audio_stream_playmode
461 */
al_set_audio_stream_playmode(ALLEGRO_AUDIO_STREAM * stream,ALLEGRO_PLAYMODE val)462 bool al_set_audio_stream_playmode(ALLEGRO_AUDIO_STREAM *stream,
463 ALLEGRO_PLAYMODE val)
464 {
465 ASSERT(stream);
466
467 if (val == ALLEGRO_PLAYMODE_ONCE) {
468 stream->spl.loop = _ALLEGRO_PLAYMODE_STREAM_ONCE;
469 return true;
470 }
471 else if (val == ALLEGRO_PLAYMODE_LOOP) {
472 /* Only streams creating by al_load_audio_stream() support
473 * looping. */
474 if (!stream->feeder)
475 return false;
476
477 stream->spl.loop = _ALLEGRO_PLAYMODE_STREAM_ONEDIR;
478 return true;
479 }
480
481 // XXX _al_set_error
482 return false;
483 }
484
485
reset_stopped_stream(ALLEGRO_AUDIO_STREAM * stream)486 static void reset_stopped_stream(ALLEGRO_AUDIO_STREAM *stream)
487 {
488 const int bytes_per_sample =
489 al_get_channel_count(stream->spl.spl_data.chan_conf) *
490 al_get_audio_depth_size(stream->spl.spl_data.depth);
491 const int fragment_buffer_size =
492 bytes_per_sample * (stream->spl.spl_data.len + MAX_LAG);
493 size_t i, n;
494
495 /* Write silence to the "invisible" part in between fragment buffers to
496 * avoid interpolation artifacts. It's tempting to zero the complete
497 * memory block in one go but some of the buffers might be getting
498 * refilled. So they are currently "owned" by the library user and
499 * should not be overwritten. But zeroing the parts not visible to the
500 * user should be OK.
501 */
502 for (i = 0; i < stream->buf_count; ++i) {
503 al_fill_silence((char *)stream->main_buffer + i * fragment_buffer_size,
504 MAX_LAG, stream->spl.spl_data.depth, stream->spl.spl_data.chan_conf);
505 }
506
507 /* Get the current number of entries in the used_buf list. */
508 for (n = 0; n < stream->buf_count && stream->used_bufs[n]; n++)
509 ;
510
511 /* Move everything from pending_bufs to used_bufs. */
512 i = 0;
513 while (i < stream->buf_count &&
514 n < stream->buf_count &&
515 stream->pending_bufs[i])
516 {
517 stream->used_bufs[n] = stream->pending_bufs[i];
518 stream->pending_bufs[i] = NULL;
519 n++;
520 i++;
521 }
522
523 /* No fragment buffer is currently playing. */
524 stream->spl.spl_data.buffer.ptr = NULL;
525 stream->spl.pos = stream->spl.spl_data.len;
526 stream->spl.pos_bresenham_error = 0;
527 stream->consumed_fragments = 0;
528 }
529
530
531 /* Function: al_set_audio_stream_playing
532 */
al_set_audio_stream_playing(ALLEGRO_AUDIO_STREAM * stream,bool val)533 bool al_set_audio_stream_playing(ALLEGRO_AUDIO_STREAM *stream, bool val)
534 {
535 bool rc = true;
536 ALLEGRO_MUTEX *stream_mutex;
537 ASSERT(stream);
538
539 if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) {
540 ALLEGRO_VOICE *voice = stream->spl.parent.u.voice;
541 if (val != stream->spl.is_playing) {
542 rc = _al_kcm_set_voice_playing(voice, voice->mutex, val);
543 }
544 }
545
546 stream_mutex = maybe_lock_mutex(stream->spl.mutex);
547
548 stream->spl.is_playing = rc && val;
549
550 if (stream->spl.is_playing) {
551 /* We usually emit fragment events when a fragment is used up, but if the
552 * stream has zero pending fragments to begin with then no events would
553 * ever be emitted.
554 */
555 _al_kcm_emit_stream_events(stream);
556 }
557 else if (!val) {
558 reset_stopped_stream(stream);
559 }
560
561 maybe_unlock_mutex(stream_mutex);
562
563 return rc;
564 }
565
566
567 /* Function: al_detach_audio_stream
568 */
al_detach_audio_stream(ALLEGRO_AUDIO_STREAM * stream)569 bool al_detach_audio_stream(ALLEGRO_AUDIO_STREAM *stream)
570 {
571 ASSERT(stream);
572
573 _al_kcm_detach_from_parent(&stream->spl);
574 ASSERT(stream->spl.spl_read == NULL);
575 return !al_get_audio_stream_attached(stream);
576 }
577
578
579 /* Function: al_set_audio_stream_fragment
580 */
al_set_audio_stream_fragment(ALLEGRO_AUDIO_STREAM * stream,void * val)581 bool al_set_audio_stream_fragment(ALLEGRO_AUDIO_STREAM *stream, void *val)
582 {
583 size_t i;
584 bool ret;
585 ALLEGRO_MUTEX *stream_mutex;
586 ASSERT(stream);
587
588 stream_mutex = maybe_lock_mutex(stream->spl.mutex);
589
590 for (i = 0; i < stream->buf_count && stream->pending_bufs[i] ; i++)
591 ;
592 if (i < stream->buf_count) {
593 stream->pending_bufs[i] = val;
594 ret = true;
595 }
596 else {
597 _al_set_error(ALLEGRO_INVALID_OBJECT,
598 "Attempted to set a stream buffer with a full pending list");
599 ret = false;
600 }
601
602 maybe_unlock_mutex(stream_mutex);
603
604 return ret;
605 }
606
607
608 /* _al_kcm_refill_stream:
609 * Called by the mixer when the current buffer has been used up. It should
610 * point to the next pending buffer and adjust the sample position to reflect
611 * the buffer being updated. It may be necessary to call this function multiple
612 * times if the sample position is so far ahead that multiple buffers need to
613 * be consumed.
614 * Returns true if the next buffer is available and set up.
615 * Otherwise returns false.
616 */
_al_kcm_refill_stream(ALLEGRO_AUDIO_STREAM * stream)617 bool _al_kcm_refill_stream(ALLEGRO_AUDIO_STREAM *stream)
618 {
619 ALLEGRO_SAMPLE_INSTANCE *spl = &stream->spl;
620 void *old_buf = spl->spl_data.buffer.ptr;
621 void *new_buf;
622 size_t i;
623 int new_pos = spl->pos - spl->spl_data.len;
624
625 if (old_buf) {
626 /* Slide the buffers down one position and put the
627 * completed buffer into the used array to be refilled.
628 */
629 for (i = 0;
630 i < stream->buf_count-1 && stream->pending_bufs[i];
631 i++) {
632 stream->pending_bufs[i] = stream->pending_bufs[i+1];
633 }
634 stream->pending_bufs[i] = NULL;
635
636 for (i = 0; stream->used_bufs[i]; i++)
637 ;
638 stream->used_bufs[i] = old_buf;
639 }
640
641 new_buf = stream->pending_bufs[0];
642 stream->spl.spl_data.buffer.ptr = new_buf;
643 if (!new_buf) {
644 ALLEGRO_WARN("Out of buffers\n");
645 return false;
646 }
647
648 /* Copy the last MAX_LAG sample values to the front of the new buffer
649 * for interpolation.
650 */
651 if (old_buf) {
652 const int bytes_per_sample =
653 al_get_channel_count(spl->spl_data.chan_conf) *
654 al_get_audio_depth_size(spl->spl_data.depth);
655
656 memcpy(
657 (char *) new_buf - bytes_per_sample * MAX_LAG,
658 (char *) old_buf + bytes_per_sample * (spl->pos-MAX_LAG-new_pos),
659 bytes_per_sample * MAX_LAG);
660
661 stream->consumed_fragments++;
662 }
663
664 stream->spl.pos = new_pos;
665
666 return true;
667 }
668
669
670 /* _al_kcm_feed_stream:
671 * A routine running in another thread that feeds the stream buffers as
672 * necessary, usually getting data from some file reader backend.
673 */
_al_kcm_feed_stream(ALLEGRO_THREAD * self,void * vstream)674 void *_al_kcm_feed_stream(ALLEGRO_THREAD *self, void *vstream)
675 {
676 ALLEGRO_AUDIO_STREAM *stream = vstream;
677 ALLEGRO_EVENT_QUEUE *queue;
678 bool finished_event_sent = false;
679 (void)self;
680
681 ALLEGRO_DEBUG("Stream feeder thread started.\n");
682
683 queue = al_create_event_queue();
684 al_register_event_source(queue, &stream->spl.es);
685
686 al_lock_mutex(stream->feed_thread_started_mutex);
687 stream->feed_thread_started = true;
688 al_broadcast_cond(stream->feed_thread_started_cond);
689 al_unlock_mutex(stream->feed_thread_started_mutex);
690
691 stream->quit_feed_thread = false;
692
693 while (!stream->quit_feed_thread) {
694 char *fragment;
695 ALLEGRO_EVENT event;
696
697 al_wait_for_event(queue, &event);
698
699 if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT
700 && !stream->is_draining) {
701 unsigned long bytes;
702 unsigned long bytes_written;
703 ALLEGRO_MUTEX *stream_mutex;
704
705 fragment = al_get_audio_stream_fragment(stream);
706 if (!fragment) {
707 /* This is not an error. */
708 continue;
709 }
710
711 bytes = (stream->spl.spl_data.len) *
712 al_get_channel_count(stream->spl.spl_data.chan_conf) *
713 al_get_audio_depth_size(stream->spl.spl_data.depth);
714
715 stream_mutex = maybe_lock_mutex(stream->spl.mutex);
716 bytes_written = stream->feeder(stream, fragment, bytes);
717 maybe_unlock_mutex(stream_mutex);
718
719 if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) {
720 /* Keep rewinding until the fragment is filled. */
721 while (bytes_written < bytes &&
722 stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) {
723 size_t bw;
724 al_rewind_audio_stream(stream);
725 stream_mutex = maybe_lock_mutex(stream->spl.mutex);
726 bw = stream->feeder(stream, fragment + bytes_written,
727 bytes - bytes_written);
728 bytes_written += bw;
729 maybe_unlock_mutex(stream_mutex);
730 }
731 }
732 else if (bytes_written < bytes) {
733 /* Fill the rest of the fragment with silence. */
734 int silence_samples = (bytes - bytes_written) /
735 (al_get_channel_count(stream->spl.spl_data.chan_conf) *
736 al_get_audio_depth_size(stream->spl.spl_data.depth));
737 al_fill_silence(fragment + bytes_written, silence_samples,
738 stream->spl.spl_data.depth, stream->spl.spl_data.chan_conf);
739 }
740
741 if (!al_set_audio_stream_fragment(stream, fragment)) {
742 ALLEGRO_ERROR("Error setting stream buffer.\n");
743 continue;
744 }
745
746 /* The streaming source doesn't feed any more, so drain buffers.
747 * Don't quit in case the user decides to seek and then restart the
748 * stream. */
749 if (bytes_written != bytes &&
750 stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE) {
751 al_drain_audio_stream(stream);
752
753 if (!finished_event_sent) {
754 ALLEGRO_EVENT fin_event;
755 fin_event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FINISHED;
756 fin_event.user.timestamp = al_get_time();
757 al_emit_user_event(&stream->spl.es, &fin_event, NULL);
758 finished_event_sent = true;
759 }
760 } else {
761 finished_event_sent = false;
762 }
763 }
764 else if (event.type == _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE) {
765 ALLEGRO_EVENT fin_event;
766 stream->quit_feed_thread = true;
767
768 fin_event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FINISHED;
769 fin_event.user.timestamp = al_get_time();
770 al_emit_user_event(&stream->spl.es, &fin_event, NULL);
771 }
772 }
773
774 al_destroy_event_queue(queue);
775
776 ALLEGRO_DEBUG("Stream feeder thread finished.\n");
777
778 return NULL;
779 }
780
781
_al_kcm_emit_stream_events(ALLEGRO_AUDIO_STREAM * stream)782 void _al_kcm_emit_stream_events(ALLEGRO_AUDIO_STREAM *stream)
783 {
784 /* Emit one event for each stream fragment available right now.
785 *
786 * There may already be an event corresponding to an available fragment in
787 * some event queue, but there's nothing we can do about that. Streams may
788 * be added and removed from queues, events may be lost by the user, etc.
789 * so it would be dangerous to assume that each fragment event would be
790 * responded to, once and exactly once.
791 *
792 * Having said that, event queues are empty in the steady state so it is
793 * relatively rare that this situation occurs.
794 */
795 int count = al_get_available_audio_stream_fragments(stream);
796
797 while (count--) {
798 ALLEGRO_EVENT event;
799 event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT;
800 event.user.timestamp = al_get_time();
801 al_emit_user_event(&stream->spl.es, &event, NULL);
802 }
803 }
804
805
806 /* Function: al_rewind_audio_stream
807 */
al_rewind_audio_stream(ALLEGRO_AUDIO_STREAM * stream)808 bool al_rewind_audio_stream(ALLEGRO_AUDIO_STREAM *stream)
809 {
810 bool ret;
811
812 if (stream->rewind_feeder) {
813 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
814 ret = stream->rewind_feeder(stream);
815 maybe_unlock_mutex(stream_mutex);
816 return ret;
817 }
818
819 return false;
820 }
821
822
823 /* Function: al_seek_audio_stream_secs
824 */
al_seek_audio_stream_secs(ALLEGRO_AUDIO_STREAM * stream,double time)825 bool al_seek_audio_stream_secs(ALLEGRO_AUDIO_STREAM *stream, double time)
826 {
827 bool ret;
828
829 if (stream->seek_feeder) {
830 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
831 ret = stream->seek_feeder(stream, time);
832 maybe_unlock_mutex(stream_mutex);
833 return ret;
834 }
835
836 return false;
837 }
838
839
840 /* Function: al_get_audio_stream_position_secs
841 */
al_get_audio_stream_position_secs(ALLEGRO_AUDIO_STREAM * stream)842 double al_get_audio_stream_position_secs(ALLEGRO_AUDIO_STREAM *stream)
843 {
844 double ret;
845
846 if (stream->get_feeder_position) {
847 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
848 ret = stream->get_feeder_position(stream);
849 maybe_unlock_mutex(stream_mutex);
850 return ret;
851 }
852
853 return 0.0;
854 }
855
856
857 /* Function: al_get_audio_stream_length_secs
858 */
al_get_audio_stream_length_secs(ALLEGRO_AUDIO_STREAM * stream)859 double al_get_audio_stream_length_secs(ALLEGRO_AUDIO_STREAM *stream)
860 {
861 double ret;
862
863 if (stream->get_feeder_length) {
864 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
865 ret = stream->get_feeder_length(stream);
866 maybe_unlock_mutex(stream_mutex);
867 return ret;
868 }
869
870 return 0.0;
871 }
872
873
874 /* Function: al_set_audio_stream_loop_secs
875 */
al_set_audio_stream_loop_secs(ALLEGRO_AUDIO_STREAM * stream,double start,double end)876 bool al_set_audio_stream_loop_secs(ALLEGRO_AUDIO_STREAM *stream,
877 double start, double end)
878 {
879 bool ret;
880
881 if (start >= end)
882 return false;
883
884 if (stream->set_feeder_loop) {
885 ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex);
886 ret = stream->set_feeder_loop(stream, start, end);
887 maybe_unlock_mutex(stream_mutex);
888 return ret;
889 }
890
891 return false;
892 }
893
894
895 /* Function: al_get_audio_stream_event_source
896 */
al_get_audio_stream_event_source(ALLEGRO_AUDIO_STREAM * stream)897 ALLEGRO_EVENT_SOURCE *al_get_audio_stream_event_source(
898 ALLEGRO_AUDIO_STREAM *stream)
899 {
900 return &stream->spl.es;
901 }
902
al_set_audio_stream_channel_matrix(ALLEGRO_AUDIO_STREAM * stream,const float * matrix)903 bool al_set_audio_stream_channel_matrix(ALLEGRO_AUDIO_STREAM *stream, const float *matrix)
904 {
905 ASSERT(stream);
906
907 if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) {
908 _al_set_error(ALLEGRO_GENERIC_ERROR,
909 "Could not set channel matrix of stream attached to voice");
910 return false;
911 }
912
913 return al_set_sample_instance_channel_matrix(&stream->spl, matrix);
914 }
915
916 /* vim: set sts=3 sw=3 et: */
917