1 /*
2 * Copyright (c) 2013 Andrew Kelley
3 *
4 * This file is part of libgroove, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8 #include "player.h"
9 #include <groove/queue.h>
10
11 #include <libavutil/mem.h>
12 #include <libavutil/log.h>
13 #include <SDL2/SDL.h>
14 #include <SDL2/SDL_audio.h>
15 #include <pthread.h>
16 #include <time.h>
17 #include <stdbool.h>
18 #include "osx_time_shim.h"
19
20 struct GroovePlayerPrivate {
21 struct GroovePlayer externals;
22 struct GrooveBuffer *audio_buf;
23 size_t audio_buf_size; // in frames
24 size_t audio_buf_index; // in frames
25 int channel_count;
26 int bytes_per_sample;
27 int bytes_per_frame;
28
29 // this mutex applies to the variables in this block
30 pthread_mutex_t play_head_mutex;
31 bool play_head_mutex_inited;
32 // pointer to current item where the buffered audio is reaching the device
33 struct GroovePlaylistItem *play_head;
34 // number of seconds into the play_head song where the buffered audio
35 // is reaching the device
36 double play_pos;
37
38 SDL_AudioDeviceID device_id;
39 struct GrooveSink *sink;
40
41 struct GrooveQueue *eventq;
42
43 // for dummy player
44 pthread_t dummy_thread_id;
45 bool dummy_thread_inited;
46 bool abort_request;
47 uint64_t start_nanos;
48 uint64_t frames_consumed;
49 pthread_cond_t pause_cond;
50 pthread_condattr_t cond_attr;
51 bool pause_cond_inited;
52 int paused;
53
54 // watchdog thread for opening and closing audio device
55 pthread_t device_thread_id;
56 int device_thread_inited;
57 pthread_cond_t device_thread_cond;
58 bool device_thread_cond_inited;
59 int silence_bytes_left;
60 bool request_device_reopen;
61 struct GrooveAudioFormat device_format;
62 int device_buffer_size;
63 };
64
65 static int open_audio_device(struct GroovePlayer *player,
66 const struct GrooveAudioFormat *target_format, struct GrooveAudioFormat *actual_format,
67 int use_exact_audio_format);
68
groove_fmt_to_sdl_fmt(enum GrooveSampleFormat fmt)69 static Uint16 groove_fmt_to_sdl_fmt(enum GrooveSampleFormat fmt) {
70 switch (fmt) {
71 case GROOVE_SAMPLE_FMT_U8:
72 case GROOVE_SAMPLE_FMT_U8P:
73 return AUDIO_U8;
74 case GROOVE_SAMPLE_FMT_S16:
75 case GROOVE_SAMPLE_FMT_S16P:
76 return AUDIO_S16SYS;
77 case GROOVE_SAMPLE_FMT_S32:
78 case GROOVE_SAMPLE_FMT_S32P:
79 return AUDIO_S32SYS;
80 case GROOVE_SAMPLE_FMT_FLT:
81 case GROOVE_SAMPLE_FMT_FLTP:
82 return AUDIO_F32SYS;
83 default:
84 av_log(NULL, AV_LOG_ERROR,
85 "unable to use selected format. using GROOVE_SAMPLE_FMT_S16 instead.\n");
86 return AUDIO_S16SYS;
87 }
88 }
89
sdl_fmt_to_groove_fmt(Uint16 sdl_format)90 static enum GrooveSampleFormat sdl_fmt_to_groove_fmt(Uint16 sdl_format) {
91 switch (sdl_format) {
92 case AUDIO_U8:
93 return GROOVE_SAMPLE_FMT_U8;
94 case AUDIO_S16SYS:
95 return GROOVE_SAMPLE_FMT_S16;
96 case AUDIO_S32SYS:
97 return GROOVE_SAMPLE_FMT_S32;
98 case AUDIO_F32SYS:
99 return GROOVE_SAMPLE_FMT_FLT;
100 default:
101 return GROOVE_SAMPLE_FMT_NONE;
102 }
103 }
104
emit_event(struct GrooveQueue * queue,enum GroovePlayerEventType type)105 static void emit_event(struct GrooveQueue *queue, enum GroovePlayerEventType type) {
106 union GroovePlayerEvent *evt = av_malloc(sizeof(union GroovePlayerEvent));
107 if (!evt) {
108 av_log(NULL, AV_LOG_ERROR, "unable to create event: out of memory\n");
109 return;
110 }
111 evt->type = type;
112 if (groove_queue_put(queue, evt) < 0)
113 av_log(NULL, AV_LOG_ERROR, "unable to put event on queue: out of memory\n");
114 }
115
now_nanos(void)116 static uint64_t now_nanos(void) {
117 struct timespec tms;
118 clock_gettime(CLOCK_MONOTONIC, &tms);
119 uint64_t tv_sec = tms.tv_sec;
120 uint64_t sec_mult = 1000000000;
121 uint64_t tv_nsec = tms.tv_nsec;
122 return tv_sec * sec_mult + tv_nsec;
123 }
124
close_audio_device(struct GroovePlayerPrivate * p)125 static void close_audio_device(struct GroovePlayerPrivate *p) {
126 if (p->device_id > 0) {
127 SDL_CloseAudioDevice(p->device_id);
128 p->device_id = 0;
129 }
130 }
131
device_thread_run(void * arg)132 static void *device_thread_run(void *arg) {
133 struct GroovePlayer *player = arg;
134 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
135
136 for (;;) {
137 if (p->abort_request)
138 break;
139
140 pthread_mutex_lock(&p->play_head_mutex);
141 if (!p->request_device_reopen) {
142 pthread_cond_wait(&p->device_thread_cond, &p->play_head_mutex);
143 pthread_mutex_unlock(&p->play_head_mutex);
144 continue;
145 }
146
147 p->request_device_reopen = false;
148
149 close_audio_device(p);
150
151 p->device_format = p->audio_buf->format;
152 open_audio_device(player, &p->audio_buf->format, NULL, player->use_exact_audio_format);
153 SDL_PauseAudioDevice(p->device_id, 0);
154 emit_event(p->eventq, GROOVE_EVENT_DEVICEREOPENED);
155
156 pthread_mutex_unlock(&p->play_head_mutex);
157 }
158
159 return NULL;
160 }
161
162 // this thread is started if the user selects a dummy device instead of a
163 // real device.
dummy_thread(void * arg)164 static void *dummy_thread(void *arg) {
165 struct GroovePlayer *player = arg;
166 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
167
168 while (!p->abort_request) {
169 pthread_mutex_lock(&p->play_head_mutex);
170 if (p->paused) {
171 pthread_cond_wait(&p->pause_cond, &p->play_head_mutex);
172 pthread_mutex_unlock(&p->play_head_mutex);
173 continue;
174 }
175
176 uint64_t now = now_nanos();
177 int more = 1;
178 while (more) {
179 more = 0;
180 if (!p->audio_buf || p->audio_buf_index >= p->audio_buf->frame_count) {
181 groove_buffer_unref(p->audio_buf);
182 p->audio_buf_index = 0;
183 p->audio_buf_size = 0;
184 int ret = groove_sink_buffer_get(p->sink, &p->audio_buf, 0);
185 if (ret == GROOVE_BUFFER_END) {
186 emit_event(p->eventq, GROOVE_EVENT_NOWPLAYING);
187 p->play_head = NULL;
188 p->play_pos = -1.0;
189 } else if (ret == GROOVE_BUFFER_YES) {
190 if (p->play_head != p->audio_buf->item)
191 emit_event(p->eventq, GROOVE_EVENT_NOWPLAYING);
192
193 p->play_head = p->audio_buf->item;
194 p->play_pos = p->audio_buf->pos;
195 p->audio_buf_size = p->audio_buf->size;
196 } else {
197 // since this is a dummy player whose only job is to keep
198 // track of time, we're going to pretend that we did *not*
199 // just get a buffer underrun. Instead we'll wait patiently
200 // for the next buffer to appear and handle it appropriately.
201 pthread_mutex_unlock(&p->play_head_mutex);
202 break;
203 }
204 }
205 if (p->audio_buf) {
206 uint64_t nanos_per_frame = 1000000000 / p->audio_buf->format.sample_rate;
207 uint64_t total_nanos = now - p->start_nanos;
208 uint64_t total_frames = total_nanos / nanos_per_frame;
209 int frames_to_kill = total_frames - p->frames_consumed;
210 int new_index = p->audio_buf_index + frames_to_kill;
211 if (new_index > p->audio_buf->frame_count) {
212 more = 1;
213 new_index = p->audio_buf->frame_count;
214 frames_to_kill = new_index - p->audio_buf_index;
215 }
216 p->frames_consumed += frames_to_kill;
217 p->audio_buf_index = new_index;
218 p->play_pos += frames_to_kill / (double) p->audio_buf->format.sample_rate;
219 }
220 }
221
222 // sleep for a little while
223 struct timespec tms;
224 clock_gettime(CLOCK_MONOTONIC, &tms);
225 tms.tv_nsec += 10000000;
226 pthread_cond_timedwait(&p->pause_cond, &p->play_head_mutex, &tms);
227 pthread_mutex_unlock(&p->play_head_mutex);
228 }
229 return NULL;
230 }
231
is_planar(enum GrooveSampleFormat fmt)232 static bool is_planar(enum GrooveSampleFormat fmt) {
233 switch (fmt) {
234 default:
235 return false;
236 case GROOVE_SAMPLE_FMT_U8P:
237 case GROOVE_SAMPLE_FMT_S16P:
238 case GROOVE_SAMPLE_FMT_S32P:
239 case GROOVE_SAMPLE_FMT_FLTP:
240 case GROOVE_SAMPLE_FMT_DBLP:
241 return true;
242 }
243 }
244
sdl_audio_callback(void * opaque,Uint8 * stream,int len)245 static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) {
246 struct GroovePlayerPrivate *p = opaque;
247
248 struct GrooveSink *sink = p->sink;
249 struct GroovePlaylist *playlist = sink->playlist;
250
251 double bytes_per_sec = sink->bytes_per_sec;
252 int paused = !groove_playlist_playing(playlist);
253
254 pthread_mutex_lock(&p->play_head_mutex);
255
256 while (len > 0) {
257 bool waiting_for_silence = (p->silence_bytes_left > 0);
258 if (!p->request_device_reopen && !waiting_for_silence &&
259 !paused && p->audio_buf_index >= p->audio_buf_size)
260 {
261 groove_buffer_unref(p->audio_buf);
262 p->audio_buf_index = 0;
263 p->audio_buf_size = 0;
264
265 int ret = groove_sink_buffer_get(p->sink, &p->audio_buf, 0);
266 if (ret == GROOVE_BUFFER_END) {
267 emit_event(p->eventq, GROOVE_EVENT_NOWPLAYING);
268
269 p->play_head = NULL;
270 p->play_pos = -1.0;
271 } else if (ret == GROOVE_BUFFER_YES) {
272 if (p->play_head != p->audio_buf->item)
273 emit_event(p->eventq, GROOVE_EVENT_NOWPLAYING);
274
275 p->play_head = p->audio_buf->item;
276 p->play_pos = p->audio_buf->pos;
277 p->audio_buf_size = p->audio_buf->frame_count;
278 p->channel_count = groove_channel_layout_count(p->audio_buf->format.channel_layout);
279 p->bytes_per_sample = groove_sample_format_bytes_per_sample(p->audio_buf->format.sample_fmt);
280 p->bytes_per_frame = p->bytes_per_sample * p->channel_count;
281
282 if (p->device_thread_inited &&
283 !groove_audio_formats_equal(&p->audio_buf->format, &p->device_format))
284 {
285 p->silence_bytes_left = p->device_buffer_size;
286 waiting_for_silence = true;
287 }
288 } else {
289 // errors are treated the same as no buffer ready
290 emit_event(p->eventq, GROOVE_EVENT_BUFFERUNDERRUN);
291 }
292 }
293 if (p->request_device_reopen || waiting_for_silence || paused || !p->audio_buf) {
294 // fill with silence
295 memset(stream, 0, len);
296
297 if (waiting_for_silence) {
298 p->silence_bytes_left -= len;
299 if (p->silence_bytes_left <= 0) {
300 p->request_device_reopen = true;
301 pthread_cond_signal(&p->device_thread_cond);
302 }
303 }
304 break;
305 }
306 size_t read_frame_count = p->audio_buf_size - p->audio_buf_index;
307 int write_frame_count = len / p->bytes_per_frame;
308 int frame_count = (read_frame_count < write_frame_count) ? read_frame_count : write_frame_count;
309 int bytes_consumed = frame_count * p->bytes_per_frame;
310
311 if (is_planar(p->audio_buf->format.sample_fmt)) {
312 int end_frame = p->audio_buf_index + frame_count;
313 for (; p->audio_buf_index < end_frame; p->audio_buf_index += 1) {
314 for (int ch = 0; ch < p->channel_count; ch += 1) {
315 memcpy(stream,
316 &p->audio_buf->data[ch][p->audio_buf_index * p->bytes_per_sample],
317 p->bytes_per_sample);
318 stream += p->bytes_per_sample;
319 }
320 }
321 } else {
322 memcpy(stream,
323 p->audio_buf->data[0] + p->audio_buf_index * p->bytes_per_frame,
324 bytes_consumed);
325 stream += bytes_consumed;
326 p->audio_buf_index += frame_count;
327 }
328 len -= bytes_consumed;
329 p->play_pos += bytes_consumed / bytes_per_sec;
330 }
331
332 pthread_mutex_unlock(&p->play_head_mutex);
333 }
334
sink_purge(struct GrooveSink * sink,struct GroovePlaylistItem * item)335 static void sink_purge(struct GrooveSink *sink, struct GroovePlaylistItem *item) {
336 struct GroovePlayerPrivate *p = sink->userdata;
337
338 pthread_mutex_lock(&p->play_head_mutex);
339
340 if (p->play_head == item) {
341 p->play_head = NULL;
342 p->play_pos = -1.0;
343 groove_buffer_unref(p->audio_buf);
344 p->audio_buf = NULL;
345 p->audio_buf_index = 0;
346 p->audio_buf_size = 0;
347 p->start_nanos = now_nanos();
348 p->frames_consumed = 0;
349 emit_event(p->eventq, GROOVE_EVENT_NOWPLAYING);
350 }
351
352 pthread_mutex_unlock(&p->play_head_mutex);
353 }
354
sink_pause(struct GrooveSink * sink)355 static void sink_pause(struct GrooveSink *sink) {
356 struct GroovePlayer *player = sink->userdata;
357
358 // only the dummy device needs to handle pausing
359 if (player->device_index != GROOVE_PLAYER_DUMMY_DEVICE)
360 return;
361
362 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
363
364 // mark the position in time that we paused at.
365 // no mutex needed for simple boolean flag
366 p->paused = 1;
367 }
368
sink_play(struct GrooveSink * sink)369 static void sink_play(struct GrooveSink *sink) {
370 struct GroovePlayer *player = sink->userdata;
371
372 // only the dummy device needs to handle playing
373 if (player->device_index != GROOVE_PLAYER_DUMMY_DEVICE)
374 return;
375
376 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
377
378 // mark the position in time that we started playing at.
379 pthread_mutex_lock(&p->play_head_mutex);
380 p->start_nanos = now_nanos();
381 p->frames_consumed = 0;
382 p->paused = 0;
383 pthread_cond_signal(&p->pause_cond);
384 pthread_mutex_unlock(&p->play_head_mutex);
385 }
386
sink_flush(struct GrooveSink * sink)387 static void sink_flush(struct GrooveSink *sink) {
388 struct GroovePlayerPrivate *p = sink->userdata;
389
390 pthread_mutex_lock(&p->play_head_mutex);
391
392 groove_buffer_unref(p->audio_buf);
393 p->audio_buf = NULL;
394 p->audio_buf_index = 0;
395 p->audio_buf_size = 0;
396 p->start_nanos = now_nanos();
397 p->frames_consumed = 0;
398 p->play_pos = -1.0;
399 p->play_head = NULL;
400
401 pthread_mutex_unlock(&p->play_head_mutex);
402 }
403
groove_player_create(void)404 struct GroovePlayer *groove_player_create(void) {
405 struct GroovePlayerPrivate *p = av_mallocz(sizeof(struct GroovePlayerPrivate));
406
407 if (!p) {
408 av_log(NULL, AV_LOG_ERROR, "unable to create player: out of memory\n");
409 return NULL;
410 }
411
412 if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
413 av_free(p);
414 av_log(NULL, AV_LOG_ERROR, "unable to init SDL audio subsystem: %s\n",
415 SDL_GetError());
416 return NULL;
417 }
418
419 struct GroovePlayer *player = &p->externals;
420
421 p->sink = groove_sink_create();
422 if (!p->sink) {
423 groove_player_destroy(player);
424 av_log(NULL, AV_LOG_ERROR,"unable to create sink: out of memory\n");
425 return NULL;
426 }
427
428 p->sink->userdata = player;
429 p->sink->purge = sink_purge;
430 p->sink->flush = sink_flush;
431 p->sink->pause = sink_pause;
432 p->sink->play = sink_play;
433
434 if (pthread_mutex_init(&p->play_head_mutex, NULL) != 0) {
435 groove_player_destroy(player);
436 av_log(NULL, AV_LOG_ERROR,"unable to create play head mutex: out of memory\n");
437 return NULL;
438 }
439 p->play_head_mutex_inited = true;
440
441 pthread_condattr_init(&p->cond_attr);
442 pthread_condattr_setclock(&p->cond_attr, CLOCK_MONOTONIC);
443 if (pthread_cond_init(&p->pause_cond, &p->cond_attr) != 0) {
444 groove_player_destroy(player);
445 av_log(NULL, AV_LOG_ERROR, "unable to create mutex condition\n");
446 return NULL;
447 }
448 p->pause_cond_inited = true;
449
450 p->eventq = groove_queue_create();
451 if (!p->eventq) {
452 groove_player_destroy(player);
453 av_log(NULL, AV_LOG_ERROR,"unable to create event queue: out of memory\n");
454 return NULL;
455 }
456
457 if (pthread_cond_init(&p->device_thread_cond, NULL) != 0) {
458 groove_player_destroy(player);
459 av_log(NULL, AV_LOG_ERROR, "unable to create mutex condition\n");
460 return NULL;
461 }
462 p->device_thread_cond_inited = true;
463
464 // set some nice defaults
465 player->target_audio_format.sample_rate = 44100;
466 player->target_audio_format.channel_layout = GROOVE_CH_LAYOUT_STEREO;
467 player->target_audio_format.sample_fmt = GROOVE_SAMPLE_FMT_S16;
468 // small because there is no way to clear the buffer.
469 player->device_buffer_size = 1024;
470 player->sink_buffer_size = 8192;
471 player->gain = p->sink->gain;
472 player->device_index = -1; // default device
473
474 return player;
475 }
476
groove_player_destroy(struct GroovePlayer * player)477 void groove_player_destroy(struct GroovePlayer *player) {
478 if (!player)
479 return;
480
481 SDL_QuitSubSystem(SDL_INIT_AUDIO);
482
483 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
484
485 if (p->device_thread_cond_inited)
486 pthread_cond_destroy(&p->device_thread_cond);
487
488 if (p->play_head_mutex_inited)
489 pthread_mutex_destroy(&p->play_head_mutex);
490
491 if (p->pause_cond_inited)
492 pthread_cond_destroy(&p->pause_cond);
493
494 if (p->eventq)
495 groove_queue_destroy(p->eventq);
496
497 groove_sink_destroy(p->sink);
498
499 av_free(p);
500 }
501
open_audio_device(struct GroovePlayer * player,const struct GrooveAudioFormat * target_format,struct GrooveAudioFormat * actual_format,int use_exact_audio_format)502 static int open_audio_device(struct GroovePlayer *player,
503 const struct GrooveAudioFormat *target_format,
504 struct GrooveAudioFormat *actual_format,
505 int use_exact_audio_format)
506 {
507 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
508
509 SDL_AudioSpec wanted_spec, spec;
510 wanted_spec.format = groove_fmt_to_sdl_fmt(target_format->sample_fmt);
511 wanted_spec.freq = target_format->sample_rate;
512 wanted_spec.channels = groove_channel_layout_count(target_format->channel_layout);
513 wanted_spec.samples = p->device_buffer_size;
514 wanted_spec.callback = sdl_audio_callback;
515 wanted_spec.userdata = player;
516
517 const char* device_name = NULL;
518
519 if (player->device_index >= 0)
520 device_name = SDL_GetAudioDeviceName(player->device_index, 0);
521
522 int allowed_changes = use_exact_audio_format ? 0 : SDL_AUDIO_ALLOW_ANY_CHANGE;
523 p->device_id = SDL_OpenAudioDevice(device_name, 0, &wanted_spec, &spec, allowed_changes);
524
525 if (p->device_id == 0) {
526 av_log(NULL, AV_LOG_ERROR, "unable to open audio device: %s\n", SDL_GetError());
527 return -1;
528 }
529
530 if (actual_format) {
531 actual_format->sample_rate = spec.freq;
532 actual_format->channel_layout = groove_channel_layout_default(spec.channels);
533 actual_format->sample_fmt = sdl_fmt_to_groove_fmt(spec.format);
534 }
535
536 return 0;
537 }
538
groove_player_attach(struct GroovePlayer * player,struct GroovePlaylist * playlist)539 int groove_player_attach(struct GroovePlayer *player, struct GroovePlaylist *playlist) {
540 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
541
542 p->device_buffer_size = player->device_buffer_size;
543 p->sink->gain = player->gain;
544 p->sink->buffer_size = player->sink_buffer_size;
545
546 if (player->device_index == GROOVE_PLAYER_DUMMY_DEVICE) {
547 // dummy device
548 player->actual_audio_format = player->target_audio_format;
549 p->sink->audio_format = player->actual_audio_format;
550 p->sink->disable_resample = 1;
551 } else {
552 if (open_audio_device(player, &player->target_audio_format, &player->actual_audio_format,
553 player->use_exact_audio_format))
554 {
555 return -1;
556 }
557
558 // based on spec that we got, attach a sink with those properties
559 p->sink->audio_format = player->actual_audio_format;
560
561 if (p->sink->audio_format.sample_fmt == GROOVE_SAMPLE_FMT_NONE) {
562 groove_player_detach(player);
563 av_log(NULL, AV_LOG_ERROR, "unsupported audio device sample format\n");
564 return -1;
565 }
566
567 if (player->use_exact_audio_format) {
568 p->sink->disable_resample = 1;
569
570 if (pthread_create(&p->device_thread_id, NULL, device_thread_run, player) != 0) {
571 groove_player_detach(player);
572 av_log(NULL, AV_LOG_ERROR, "unable to create device thread\n");
573 return -1;
574 }
575 p->device_thread_inited = true;
576 }
577 }
578
579 int err = groove_sink_attach(p->sink, playlist);
580 if (err < 0) {
581 groove_player_detach(player);
582 av_log(NULL, AV_LOG_ERROR, "unable to attach sink\n");
583 return err;
584 }
585
586 p->play_pos = -1.0;
587
588 groove_queue_reset(p->eventq);
589
590 if (player->device_index == GROOVE_PLAYER_DUMMY_DEVICE) {
591 if (groove_playlist_playing(playlist))
592 sink_play(p->sink);
593 else
594 sink_pause(p->sink);
595
596 // set up thread to keep track of time
597 if (pthread_create(&p->dummy_thread_id, NULL, dummy_thread, player) != 0) {
598 groove_player_detach(player);
599 av_log(NULL, AV_LOG_ERROR, "unable to create dummy player thread\n");
600 return -1;
601 }
602 p->dummy_thread_inited = true;
603 } else {
604 SDL_PauseAudioDevice(p->device_id, 0);
605 }
606
607 return 0;
608 }
609
groove_player_detach(struct GroovePlayer * player)610 int groove_player_detach(struct GroovePlayer *player) {
611 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
612 p->abort_request = true;
613 if (p->device_thread_inited) {
614 pthread_mutex_lock(&p->play_head_mutex);
615 pthread_cond_signal(&p->device_thread_cond);
616 pthread_mutex_unlock(&p->play_head_mutex);
617 pthread_join(p->device_thread_id, NULL);
618 p->device_thread_inited = false;
619 }
620 if (p->eventq) {
621 groove_queue_flush(p->eventq);
622 groove_queue_abort(p->eventq);
623 }
624 if (p->sink->playlist) {
625 groove_sink_detach(p->sink);
626 }
627 close_audio_device(p);
628 if (p->dummy_thread_inited) {
629 pthread_mutex_lock(&p->play_head_mutex);
630 pthread_cond_signal(&p->pause_cond);
631 pthread_mutex_unlock(&p->play_head_mutex);
632 pthread_join(p->dummy_thread_id, NULL);
633 p->dummy_thread_inited = false;
634 }
635
636 player->playlist = NULL;
637
638 groove_buffer_unref(p->audio_buf);
639 p->audio_buf = NULL;
640
641 p->request_device_reopen = false;
642 p->silence_bytes_left = 0;
643 p->abort_request = false;
644
645 return 0;
646 }
647
groove_device_count(void)648 int groove_device_count(void) {
649 return SDL_GetNumAudioDevices(0);
650 }
651
groove_device_name(int index)652 const char * groove_device_name(int index) {
653 return SDL_GetAudioDeviceName(index, 0);
654 }
655
groove_player_position(struct GroovePlayer * player,struct GroovePlaylistItem ** item,double * seconds)656 void groove_player_position(struct GroovePlayer *player,
657 struct GroovePlaylistItem **item, double *seconds)
658 {
659 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
660
661 pthread_mutex_lock(&p->play_head_mutex);
662
663 if (item)
664 *item = p->play_head;
665
666 if (seconds)
667 *seconds = p->play_pos;
668
669 pthread_mutex_unlock(&p->play_head_mutex);
670 }
671
groove_player_event_get(struct GroovePlayer * player,union GroovePlayerEvent * event,int block)672 int groove_player_event_get(struct GroovePlayer *player,
673 union GroovePlayerEvent *event, int block)
674 {
675 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
676 union GroovePlayerEvent *tmp;
677 int err = groove_queue_get(p->eventq, (void **)&tmp, block);
678 if (err > 0) {
679 *event = *tmp;
680 av_free(tmp);
681 }
682 return err;
683 }
684
groove_player_event_peek(struct GroovePlayer * player,int block)685 int groove_player_event_peek(struct GroovePlayer *player, int block) {
686 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
687 return groove_queue_peek(p->eventq, block);
688 }
689
groove_player_set_gain(struct GroovePlayer * player,double gain)690 int groove_player_set_gain(struct GroovePlayer *player, double gain) {
691 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
692 player->gain = gain;
693 return groove_sink_set_gain(p->sink, gain);
694 }
695
groove_player_get_device_audio_format(struct GroovePlayer * player)696 struct GrooveAudioFormat groove_player_get_device_audio_format(struct GroovePlayer *player) {
697 struct GroovePlayerPrivate *p = (struct GroovePlayerPrivate *) player;
698 struct GrooveAudioFormat result;
699 pthread_mutex_lock(&p->play_head_mutex);
700 result = p->device_format;
701 pthread_mutex_unlock(&p->play_head_mutex);
702 return result;
703 }
704