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