aac: Collect all interesting ID3 frames
[cmus.git] / player.c
blobef1b18dde4dd75723766bcbea697986c5b739943
1 /*
2 * Copyright 2004-2006 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include "player.h"
21 #include "buffer.h"
22 #include "input.h"
23 #include "output.h"
24 #include "sf.h"
25 #include "utils.h"
26 #include "xmalloc.h"
27 #include "debug.h"
28 #include "compiler.h"
30 #include <stdlib.h>
31 #include <pthread.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <sys/time.h>
35 #include <stdarg.h>
36 #include <math.h>
38 enum producer_status {
39 PS_UNLOADED,
40 PS_STOPPED,
41 PS_PLAYING,
42 PS_PAUSED
45 enum consumer_status {
46 CS_STOPPED,
47 CS_PLAYING,
48 CS_PAUSED
51 struct player_info player_info = {
52 .mutex = CMUS_MUTEX_INITIALIZER,
53 .ti = NULL,
54 .metadata = { 0, },
55 .status = PLAYER_STATUS_STOPPED,
56 .pos = 0,
57 .buffer_fill = 0,
58 .buffer_size = 0,
59 .error_msg = NULL,
60 .file_changed = 0,
61 .metadata_changed = 0,
62 .status_changed = 0,
63 .position_changed = 0,
64 .buffer_fill_changed = 0,
67 /* continue playing after track is finished? */
68 int player_cont = 1;
70 enum replaygain replaygain;
71 int replaygain_limit = 1;
72 double replaygain_preamp = 6.0;
74 int soft_vol;
75 int soft_vol_l;
76 int soft_vol_r;
78 static const struct player_callbacks *player_cbs = NULL;
80 static sample_format_t buffer_sf;
82 static pthread_t producer_thread;
83 static pthread_mutex_t producer_mutex = CMUS_MUTEX_INITIALIZER;
84 static int producer_running = 1;
85 static enum producer_status producer_status = PS_UNLOADED;
86 static struct input_plugin *ip = NULL;
88 static pthread_t consumer_thread;
89 static pthread_mutex_t consumer_mutex = CMUS_MUTEX_INITIALIZER;
90 static int consumer_running = 1;
91 static enum consumer_status consumer_status = CS_STOPPED;
92 static unsigned int consumer_pos = 0;
94 /* for replay gain and soft vol
95 * usually same as consumer_pos, sometimes less than consumer_pos
97 static unsigned int scale_pos;
98 static double replaygain_scale = 1.0;
100 /* locking {{{ */
102 #define producer_lock() cmus_mutex_lock(&producer_mutex)
103 #define producer_unlock() cmus_mutex_unlock(&producer_mutex)
105 #define consumer_lock() cmus_mutex_lock(&consumer_mutex)
106 #define consumer_unlock() cmus_mutex_unlock(&consumer_mutex)
108 #define player_lock() \
109 do { \
110 consumer_lock(); \
111 producer_lock(); \
112 } while (0)
114 #define player_unlock() \
115 do { \
116 producer_unlock(); \
117 consumer_unlock(); \
118 } while (0)
120 /* locking }}} */
122 static void reset_buffer(void)
124 buffer_reset();
125 consumer_pos = 0;
126 scale_pos = 0;
129 static void set_buffer_sf(sample_format_t sf)
131 buffer_sf = sf;
133 /* ip_read converts samples to this format */
134 if (sf_get_channels(buffer_sf) <= 2 && sf_get_bits(buffer_sf) <= 16) {
135 buffer_sf &= SF_RATE_MASK;
136 buffer_sf |= sf_channels(2) | sf_bits(16) | sf_signed(1);
140 #define SOFT_VOL_SCALE 65536
142 /* coefficients for volumes 0..99, for 100 65536 is used
143 * data copied from alsa-lib src/pcm/pcm_softvol.c
145 static const unsigned short soft_vol_db[100] = {
146 0x0000, 0x0110, 0x011c, 0x012f, 0x013d, 0x0152, 0x0161, 0x0179,
147 0x018a, 0x01a5, 0x01c1, 0x01d5, 0x01f5, 0x020b, 0x022e, 0x0247,
148 0x026e, 0x028a, 0x02b6, 0x02d5, 0x0306, 0x033a, 0x035f, 0x0399,
149 0x03c2, 0x0403, 0x0431, 0x0479, 0x04ac, 0x04fd, 0x0553, 0x058f,
150 0x05ef, 0x0633, 0x069e, 0x06ea, 0x0761, 0x07b5, 0x083a, 0x0898,
151 0x092c, 0x09cb, 0x0a3a, 0x0aeb, 0x0b67, 0x0c2c, 0x0cb6, 0x0d92,
152 0x0e2d, 0x0f21, 0x1027, 0x10de, 0x1202, 0x12cf, 0x1414, 0x14f8,
153 0x1662, 0x1761, 0x18f5, 0x1a11, 0x1bd3, 0x1db4, 0x1f06, 0x211d,
154 0x2297, 0x24ec, 0x2690, 0x292a, 0x2aff, 0x2de5, 0x30fe, 0x332b,
155 0x369f, 0x390d, 0x3ce6, 0x3f9b, 0x43e6, 0x46eb, 0x4bb3, 0x4f11,
156 0x5466, 0x5a18, 0x5e19, 0x6472, 0x68ea, 0x6ffd, 0x74f8, 0x7cdc,
157 0x826a, 0x8b35, 0x9499, 0x9b35, 0xa5ad, 0xad0b, 0xb8b7, 0xc0ee,
158 0xcdf1, 0xd71a, 0xe59c, 0xefd3
161 static inline void scale_sample(signed short *buf, int i, int vol)
163 int sample = buf[i];
165 if (sample < 0) {
166 sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
167 if (sample < -32768)
168 sample = -32768;
169 } else {
170 sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
171 if (sample > 32767)
172 sample = 32767;
174 buf[i] = sample;
177 static void scale_samples(char *buffer, unsigned int *countp)
179 signed short *buf;
180 unsigned int count = *countp;
181 int ch, bits, l, r, i;
183 BUG_ON(scale_pos < consumer_pos);
185 if (consumer_pos != scale_pos) {
186 unsigned int offs = scale_pos - consumer_pos;
188 if (offs >= count)
189 return;
190 buffer += offs;
191 count -= offs;
193 scale_pos += count;
194 buf = (signed short *)buffer;
196 if (replaygain_scale == 1.0 && soft_vol_l == 100 && soft_vol_r == 100)
197 return;
199 ch = sf_get_channels(buffer_sf);
200 bits = sf_get_bits(buffer_sf);
201 if (ch != 2 || bits != 16)
202 return;
204 l = SOFT_VOL_SCALE;
205 r = SOFT_VOL_SCALE;
206 if (soft_vol_l != 100)
207 l = soft_vol_db[soft_vol_l];
208 if (soft_vol_r != 100)
209 r = soft_vol_db[soft_vol_r];
211 l *= replaygain_scale;
212 r *= replaygain_scale;
214 for (i = 0; i < count / 4; i++) {
215 scale_sample(buf, i * 2, l);
216 scale_sample(buf, i * 2 + 1, r);
220 static int parse_double(const char *str, double *val)
222 char *end;
224 *val = strtod(str, &end);
225 return str == end;
228 static void update_rg_scale(void)
230 const char *g, *p;
231 double gain, peak, db, scale, limit;
233 replaygain_scale = 1.0;
234 if (!player_info.ti || !replaygain)
235 return;
237 if (replaygain == RG_TRACK) {
238 g = comments_get_val(player_info.ti->comments, "replaygain_track_gain");
239 p = comments_get_val(player_info.ti->comments, "replaygain_track_peak");
240 } else {
241 g = comments_get_val(player_info.ti->comments, "replaygain_album_gain");
242 p = comments_get_val(player_info.ti->comments, "replaygain_album_peak");
245 if (!g || !p) {
246 d_print("gain or peak not available\n");
247 return;
249 if (parse_double(g, &gain) || parse_double(p, &peak)) {
250 d_print("could not parse gain (%s) or peak (%s)\n", g, p);
251 return;
253 if (peak < 0.05) {
254 d_print("peak (%g) is too small\n", peak);
255 return;
258 db = replaygain_preamp + gain;
260 scale = pow(10.0, db / 20.0);
261 replaygain_scale = scale;
262 limit = 1.0 / peak;
263 if (replaygain_limit && replaygain_scale > limit)
264 replaygain_scale = limit;
266 d_print("gain = %f, peak = %f, db = %f, scale = %f, limit = %f, replaygain_scale = %f\n",
267 gain, peak, db, scale, limit, replaygain_scale);
270 static inline unsigned int buffer_second_size(void)
272 return sf_get_second_size(buffer_sf);
275 static inline int get_next(struct track_info **ti)
277 return player_cbs->get_next(ti);
280 /* updating player status {{{ */
282 static inline void file_changed(struct track_info *ti)
284 player_info_lock();
285 if (player_info.ti)
286 track_info_unref(player_info.ti);
288 player_info.ti = ti;
289 if (ti) {
290 d_print("file: %s\n", ti->filename);
291 } else {
292 d_print("unloaded\n");
294 update_rg_scale();
295 player_info.metadata[0] = 0;
296 player_info.file_changed = 1;
297 player_info_unlock();
300 static inline void metadata_changed(void)
302 player_info_lock();
303 d_print("metadata changed: %s\n", ip_get_metadata(ip));
304 memcpy(player_info.metadata, ip_get_metadata(ip), 255 * 16 + 1);
305 player_info.metadata_changed = 1;
306 player_info_unlock();
309 static void player_error(const char *msg)
311 player_info_lock();
312 player_info.status = consumer_status;
313 player_info.pos = 0;
314 player_info.buffer_fill = buffer_get_filled_chunks();
315 player_info.buffer_size = buffer_nr_chunks;
316 player_info.status_changed = 1;
318 free(player_info.error_msg);
319 player_info.error_msg = xstrdup(msg);
320 player_info_unlock();
322 d_print("ERROR: '%s'\n", msg);
325 static void __FORMAT(2, 3) player_ip_error(int rc, const char *format, ...)
327 char buffer[1024];
328 va_list ap;
329 char *msg;
330 int save = errno;
332 va_start(ap, format);
333 vsnprintf(buffer, sizeof(buffer), format, ap);
334 va_end(ap);
336 errno = save;
337 msg = ip_get_error_msg(ip, rc, buffer);
338 player_error(msg);
339 free(msg);
342 static void __FORMAT(2, 3) player_op_error(int rc, const char *format, ...)
344 char buffer[1024];
345 va_list ap;
346 char *msg;
347 int save = errno;
349 va_start(ap, format);
350 vsnprintf(buffer, sizeof(buffer), format, ap);
351 va_end(ap);
353 errno = save;
354 msg = op_get_error_msg(rc, buffer);
355 player_error(msg);
356 free(msg);
360 * buffer-fill changed
362 static void __producer_buffer_fill_update(void)
364 int fill;
366 player_info_lock();
367 fill = buffer_get_filled_chunks();
368 if (fill != player_info.buffer_fill) {
369 /* d_print("\n"); */
370 player_info.buffer_fill = fill;
371 player_info.buffer_fill_changed = 1;
373 player_info_unlock();
377 * playing position changed
379 static void __consumer_position_update(void)
381 static unsigned int old_pos = -1;
382 unsigned int pos = 0;
384 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
385 pos = consumer_pos / buffer_second_size();
386 if (pos != old_pos) {
387 /* d_print("\n"); */
388 old_pos = pos;
390 player_info_lock();
391 player_info.pos = pos;
392 player_info.position_changed = 1;
393 player_info_unlock();
398 * something big happened (stopped/paused/unpaused...)
400 static void __player_status_changed(void)
402 unsigned int pos = 0;
404 /* d_print("\n"); */
405 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
406 pos = consumer_pos / buffer_second_size();
408 player_info_lock();
409 player_info.status = consumer_status;
410 player_info.pos = pos;
411 player_info.buffer_fill = buffer_get_filled_chunks();
412 player_info.buffer_size = buffer_nr_chunks;
413 player_info.status_changed = 1;
414 player_info_unlock();
417 /* updating player status }}} */
419 static void __prebuffer(void)
421 int limit_chunks;
423 BUG_ON(producer_status != PS_PLAYING);
424 if (ip_is_remote(ip)) {
425 limit_chunks = buffer_nr_chunks;
426 } else {
427 int limit_ms, limit_size;
429 limit_ms = 250;
430 limit_size = limit_ms * buffer_second_size() / 1000;
431 limit_chunks = limit_size / CHUNK_SIZE;
432 if (limit_chunks < 1)
433 limit_chunks = 1;
435 while (1) {
436 int nr_read, size, filled;
437 char *wpos;
439 filled = buffer_get_filled_chunks();
440 /* d_print("PREBUF: %2d / %2d\n", filled, limit_chunks); */
442 /* not fatal */
443 //BUG_ON(filled > limit_chunks);
445 if (filled >= limit_chunks)
446 break;
448 size = buffer_get_wpos(&wpos);
449 nr_read = ip_read(ip, wpos, size);
450 if (nr_read < 0) {
451 if (nr_read == -1 && errno == EAGAIN)
452 continue;
453 player_ip_error(nr_read, "reading file %s", ip_get_filename(ip));
454 /* ip_read sets eof */
455 nr_read = 0;
457 if (ip_metadata_changed(ip))
458 metadata_changed();
460 /* buffer_fill with 0 count marks current chunk filled */
461 buffer_fill(nr_read);
463 __producer_buffer_fill_update();
464 if (nr_read == 0) {
465 /* EOF */
466 break;
471 /* setting producer status {{{ */
473 static void __producer_play(void)
475 if (producer_status == PS_UNLOADED) {
476 struct track_info *ti;
478 if (get_next(&ti) == 0) {
479 int rc;
481 ip = ip_new(ti->filename);
482 rc = ip_open(ip);
483 if (rc) {
484 player_ip_error(rc, "opening file `%s'", ti->filename);
485 ip_delete(ip);
486 track_info_unref(ti);
487 file_changed(NULL);
488 } else {
489 ip_setup(ip);
490 producer_status = PS_PLAYING;
491 file_changed(ti);
494 } else if (producer_status == PS_PLAYING) {
495 if (ip_seek(ip, 0.0) == 0) {
496 reset_buffer();
498 } else if (producer_status == PS_STOPPED) {
499 int rc;
501 rc = ip_open(ip);
502 if (rc) {
503 player_ip_error(rc, "opening file `%s'", ip_get_filename(ip));
504 ip_delete(ip);
505 producer_status = PS_UNLOADED;
506 } else {
507 ip_setup(ip);
508 producer_status = PS_PLAYING;
510 } else if (producer_status == PS_PAUSED) {
511 producer_status = PS_PLAYING;
515 static void __producer_stop(void)
517 if (producer_status == PS_PLAYING || producer_status == PS_PAUSED) {
518 ip_close(ip);
519 producer_status = PS_STOPPED;
520 reset_buffer();
524 static void __producer_unload(void)
526 __producer_stop();
527 if (producer_status == PS_STOPPED) {
528 ip_delete(ip);
529 producer_status = PS_UNLOADED;
533 static void __producer_pause(void)
535 if (producer_status == PS_PLAYING) {
536 producer_status = PS_PAUSED;
537 } else if (producer_status == PS_PAUSED) {
538 producer_status = PS_PLAYING;
542 static void __producer_set_file(struct track_info *ti)
544 __producer_unload();
545 ip = ip_new(ti->filename);
546 producer_status = PS_STOPPED;
547 file_changed(ti);
550 /* setting producer status }}} */
552 /* setting consumer status {{{ */
554 static void __consumer_play(void)
556 if (consumer_status == CS_PLAYING) {
557 op_drop();
558 } else if (consumer_status == CS_STOPPED) {
559 int rc;
561 set_buffer_sf(ip_get_sf(ip));
562 rc = op_open(buffer_sf);
563 if (rc) {
564 player_op_error(rc, "opening audio device");
565 } else {
566 consumer_status = CS_PLAYING;
568 } else if (consumer_status == CS_PAUSED) {
569 op_unpause();
570 consumer_status = CS_PLAYING;
574 static void __consumer_drain_and_stop(void)
576 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
577 op_close();
578 consumer_status = CS_STOPPED;
582 static void __consumer_stop(void)
584 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
585 op_drop();
586 op_close();
587 consumer_status = CS_STOPPED;
591 static void __consumer_pause(void)
593 if (consumer_status == CS_PLAYING) {
594 op_pause();
595 consumer_status = CS_PAUSED;
596 } else if (consumer_status == CS_PAUSED) {
597 op_unpause();
598 consumer_status = CS_PLAYING;
602 /* setting consumer status }}} */
604 static int change_sf(sample_format_t sf, int drop)
606 int old_sf = buffer_sf;
608 set_buffer_sf(sf);
609 if (buffer_sf != old_sf) {
610 /* reopen */
611 int rc;
613 if (drop)
614 op_drop();
615 op_close();
616 rc = op_open(buffer_sf);
617 if (rc) {
618 player_op_error(rc, "opening audio device");
619 consumer_status = CS_STOPPED;
620 __producer_stop();
621 return rc;
623 } else if (consumer_status == CS_PAUSED) {
624 op_drop();
625 op_unpause();
627 consumer_status = CS_PLAYING;
628 return 0;
631 static void __consumer_handle_eof(void)
633 struct track_info *ti;
635 if (ip_is_remote(ip)) {
636 __producer_stop();
637 __consumer_drain_and_stop();
638 player_error("lost connection");
639 return;
642 if (get_next(&ti) == 0) {
643 __producer_unload();
644 ip = ip_new(ti->filename);
645 producer_status = PS_STOPPED;
646 /* PS_STOPPED, CS_PLAYING */
647 if (player_cont) {
648 __producer_play();
649 if (producer_status == PS_UNLOADED) {
650 __consumer_stop();
651 track_info_unref(ti);
652 file_changed(NULL);
653 } else {
654 /* PS_PLAYING */
655 file_changed(ti);
656 if (!change_sf(ip_get_sf(ip), 0))
657 __prebuffer();
659 } else {
660 __consumer_drain_and_stop();
661 file_changed(ti);
663 } else {
664 __producer_unload();
665 __consumer_drain_and_stop();
666 file_changed(NULL);
668 __player_status_changed();
671 static void *consumer_loop(void *arg)
673 while (1) {
674 int rc, space;
675 int size;
676 char *rpos;
678 consumer_lock();
679 if (!consumer_running)
680 break;
682 if (consumer_status == CS_PAUSED || consumer_status == CS_STOPPED) {
683 consumer_unlock();
684 ms_sleep(50);
685 continue;
687 space = op_buffer_space();
688 if (space == -1) {
689 /* busy */
690 __consumer_position_update();
691 consumer_unlock();
692 ms_sleep(50);
693 continue;
695 /* d_print("BS: %6d %3d\n", space, space * 1000 / (44100 * 2 * 2)); */
697 while (1) {
698 /* 25 ms is 4410 B */
699 if (space < 4096) {
700 __consumer_position_update();
701 consumer_unlock();
702 ms_sleep(25);
703 break;
705 size = buffer_get_rpos(&rpos);
706 if (size == 0) {
707 producer_lock();
708 if (producer_status != PS_PLAYING) {
709 producer_unlock();
710 consumer_unlock();
711 break;
713 /* must recheck rpos */
714 size = buffer_get_rpos(&rpos);
715 if (size == 0) {
716 /* OK. now it's safe to check if we are at EOF */
717 if (ip_eof(ip)) {
718 /* EOF */
719 __consumer_handle_eof();
720 producer_unlock();
721 consumer_unlock();
722 break;
723 } else {
724 /* possible underrun */
725 producer_unlock();
726 __consumer_position_update();
727 consumer_unlock();
728 /* d_print("possible underrun\n"); */
729 ms_sleep(10);
730 break;
734 /* player_buffer and ip.eof were inconsistent */
735 producer_unlock();
737 if (size > space)
738 size = space;
739 if (soft_vol || replaygain)
740 scale_samples(rpos, &size);
741 rc = op_write(rpos, size);
742 if (rc < 0) {
743 d_print("op_write returned %d %s\n", rc,
744 rc == -1 ? strerror(errno) : "");
746 /* try to reopen */
747 op_close();
748 consumer_status = CS_STOPPED;
749 __consumer_play();
751 consumer_unlock();
752 break;
754 buffer_consume(rc);
755 consumer_pos += rc;
756 space -= rc;
759 __consumer_stop();
760 consumer_unlock();
761 return NULL;
764 static void *producer_loop(void *arg)
766 while (1) {
767 /* number of chunks to fill
768 * too big => seeking is slow
769 * too small => underruns?
771 const int chunks = 1;
772 int size, nr_read, i;
773 char *wpos;
775 producer_lock();
776 if (!producer_running)
777 break;
779 if (producer_status == PS_UNLOADED ||
780 producer_status == PS_PAUSED ||
781 producer_status == PS_STOPPED || ip_eof(ip)) {
782 producer_unlock();
783 ms_sleep(50);
784 continue;
786 for (i = 0; ; i++) {
787 size = buffer_get_wpos(&wpos);
788 if (size == 0) {
789 /* buffer is full */
790 producer_unlock();
791 ms_sleep(50);
792 break;
794 nr_read = ip_read(ip, wpos, size);
795 if (nr_read < 0) {
796 if (nr_read != -1 || errno != EAGAIN) {
797 player_ip_error(nr_read, "reading file %s",
798 ip_get_filename(ip));
799 /* ip_read sets eof */
800 nr_read = 0;
801 } else {
802 producer_unlock();
803 ms_sleep(50);
804 break;
807 if (ip_metadata_changed(ip))
808 metadata_changed();
810 /* buffer_fill with 0 count marks current chunk filled */
811 buffer_fill(nr_read);
812 if (nr_read == 0) {
813 /* consumer handles EOF */
814 producer_unlock();
815 ms_sleep(50);
816 break;
818 if (i == chunks) {
819 producer_unlock();
820 /* don't sleep! */
821 break;
824 __producer_buffer_fill_update();
826 __producer_unload();
827 producer_unlock();
828 return NULL;
831 void player_load_plugins(void)
833 ip_load_plugins();
834 op_load_plugins();
837 void player_init(const struct player_callbacks *callbacks)
839 int rc;
840 #if defined(__linux__) || defined(__FreeBSD__)
841 pthread_attr_t attr;
842 #endif
843 pthread_attr_t *attrp = NULL;
845 /* 1 s is 176400 B (0.168 MB)
846 * 10 s is 1.68 MB
848 buffer_nr_chunks = 10 * 44100 * 16 / 8 * 2 / CHUNK_SIZE;
849 buffer_init();
851 player_cbs = callbacks;
853 #if defined(__linux__) || defined(__FreeBSD__)
854 rc = pthread_attr_init(&attr);
855 BUG_ON(rc);
856 rc = pthread_attr_setschedpolicy(&attr, SCHED_RR);
857 if (rc) {
858 d_print("could not set real-time scheduling priority: %s\n", strerror(rc));
859 } else {
860 struct sched_param param;
862 d_print("using real-time scheduling\n");
863 param.sched_priority = sched_get_priority_max(SCHED_RR);
864 d_print("setting priority to %d\n", param.sched_priority);
865 rc = pthread_attr_setschedparam(&attr, &param);
866 BUG_ON(rc);
867 attrp = &attr;
869 #endif
871 rc = pthread_create(&producer_thread, NULL, producer_loop, NULL);
872 BUG_ON(rc);
874 rc = pthread_create(&consumer_thread, attrp, consumer_loop, NULL);
875 if (rc && attrp) {
876 d_print("could not create thread using real-time scheduling: %s\n", strerror(rc));
877 rc = pthread_create(&consumer_thread, NULL, consumer_loop, NULL);
879 BUG_ON(rc);
881 /* update player_info.cont etc. */
882 player_lock();
883 __player_status_changed();
884 player_unlock();
887 void player_exit(void)
889 int rc;
891 player_lock();
892 consumer_running = 0;
893 producer_running = 0;
894 player_unlock();
896 rc = pthread_join(consumer_thread, NULL);
897 BUG_ON(rc);
898 rc = pthread_join(producer_thread, NULL);
899 BUG_ON(rc);
901 op_exit_plugins();
904 void player_stop(void)
906 player_lock();
907 __consumer_stop();
908 __producer_stop();
909 __player_status_changed();
910 player_unlock();
913 void player_play(void)
915 int prebuffer;
917 player_lock();
918 if (producer_status == PS_PLAYING && ip_is_remote(ip)) {
919 /* seeking not allowed */
920 player_unlock();
921 return;
923 prebuffer = consumer_status == CS_STOPPED;
924 __producer_play();
925 if (producer_status == PS_PLAYING) {
926 __consumer_play();
927 if (consumer_status != CS_PLAYING)
928 __producer_stop();
929 } else {
930 __consumer_stop();
932 __player_status_changed();
933 if (consumer_status == CS_PLAYING && prebuffer)
934 __prebuffer();
935 player_unlock();
938 void player_pause(void)
940 player_lock();
942 if (consumer_status == CS_STOPPED) {
943 __producer_play();
944 if (producer_status == PS_PLAYING) {
945 __consumer_play();
946 if (consumer_status != CS_PLAYING)
947 __producer_stop();
949 __player_status_changed();
950 if (consumer_status == CS_PLAYING)
951 __prebuffer();
952 player_unlock();
953 return;
956 if (ip && ip_is_remote(ip)) {
957 /* pausing not allowed */
958 player_unlock();
959 return;
961 __producer_pause();
962 __consumer_pause();
963 __player_status_changed();
964 player_unlock();
967 void player_set_file(struct track_info *ti)
969 player_lock();
970 __producer_set_file(ti);
971 if (producer_status == PS_UNLOADED) {
972 __consumer_stop();
973 goto out;
976 /* PS_STOPPED */
977 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
978 __producer_play();
979 if (producer_status == PS_UNLOADED) {
980 __consumer_stop();
981 goto out;
983 change_sf(ip_get_sf(ip), 1);
985 out:
986 __player_status_changed();
987 if (producer_status == PS_PLAYING)
988 __prebuffer();
989 player_unlock();
992 void player_play_file(struct track_info *ti)
994 player_lock();
995 __producer_set_file(ti);
996 if (producer_status == PS_UNLOADED) {
997 __consumer_stop();
998 goto out;
1001 /* PS_STOPPED */
1002 __producer_play();
1004 /* PS_UNLOADED,PS_PLAYING */
1005 if (producer_status == PS_UNLOADED) {
1006 __consumer_stop();
1007 goto out;
1010 /* PS_PLAYING */
1011 if (consumer_status == CS_STOPPED) {
1012 __consumer_play();
1013 if (consumer_status == CS_STOPPED)
1014 __producer_stop();
1015 } else {
1016 change_sf(ip_get_sf(ip), 1);
1018 out:
1019 __player_status_changed();
1020 if (producer_status == PS_PLAYING)
1021 __prebuffer();
1022 player_unlock();
1025 void player_seek(double offset, int relative)
1027 player_lock();
1028 if (consumer_status == CS_STOPPED) {
1029 __producer_play();
1030 if (producer_status == PS_PLAYING) {
1031 __consumer_play();
1032 if (consumer_status != CS_PLAYING) {
1033 __producer_stop();
1034 player_unlock();
1035 return;
1036 } else
1037 __player_status_changed();
1040 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1041 double pos, duration, new_pos;
1042 int rc;
1044 pos = (double)consumer_pos / (double)buffer_second_size();
1045 duration = ip_duration(ip);
1046 if (duration < 0) {
1047 /* can't seek */
1048 d_print("can't seek\n");
1049 player_unlock();
1050 return;
1052 if (relative) {
1053 new_pos = pos + offset;
1054 if (new_pos < 0.0)
1055 new_pos = 0.0;
1056 if (offset > 0.0) {
1057 /* seeking forward */
1058 if (new_pos > duration - 5.0)
1059 new_pos = duration - 5.0;
1060 if (new_pos < 0.0)
1061 new_pos = 0.0;
1062 if (new_pos < pos - 0.5) {
1063 /* must seek at least 0.5s */
1064 d_print("must seek at least 0.5s\n");
1065 player_unlock();
1066 return;
1069 } else {
1070 new_pos = offset;
1071 if (new_pos < 0.0) {
1072 d_print("seek offset negative\n");
1073 player_unlock();
1074 return;
1076 if (new_pos > duration - 5.0) {
1077 new_pos = duration - 5.0;
1078 if (new_pos < 0.0)
1079 new_pos = 0.0;
1082 /* d_print("seeking %g/%g (%g from eof)\n", new_pos, duration, duration - new_pos); */
1083 rc = ip_seek(ip, new_pos);
1084 if (rc == 0) {
1085 /* d_print("doing op_drop after seek\n"); */
1086 op_drop();
1087 reset_buffer();
1088 consumer_pos = new_pos * buffer_second_size();
1089 scale_pos = consumer_pos;
1090 __consumer_position_update();
1091 } else {
1092 d_print("error: ip_seek returned %d\n", rc);
1095 player_unlock();
1099 * change output plugin without stopping playback
1101 void player_set_op(const char *name)
1103 int rc;
1105 player_lock();
1107 /* drop needed because close drains the buffer */
1108 if (consumer_status == CS_PAUSED)
1109 op_drop();
1111 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
1112 op_close();
1114 if (name) {
1115 d_print("setting op to '%s'\n", name);
1116 rc = op_select(name);
1117 } else {
1118 /* first initialized plugin */
1119 d_print("selecting first initialized op\n");
1120 rc = op_select_any();
1122 if (rc) {
1123 consumer_status = CS_STOPPED;
1125 __producer_stop();
1126 player_op_error(rc, "selecting output plugin '%s'", name);
1127 player_unlock();
1128 return;
1131 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1132 set_buffer_sf(ip_get_sf(ip));
1133 rc = op_open(buffer_sf);
1134 if (rc) {
1135 consumer_status = CS_STOPPED;
1136 __producer_stop();
1137 player_op_error(rc, "opening audio device");
1138 player_unlock();
1139 return;
1141 if (consumer_status == CS_PAUSED)
1142 op_pause();
1145 player_unlock();
1148 char *player_get_op(void)
1150 return op_get_current();
1153 void player_set_buffer_chunks(unsigned int nr_chunks)
1155 if (nr_chunks < 3)
1156 nr_chunks = 3;
1157 if (nr_chunks > 30)
1158 nr_chunks = 30;
1160 player_lock();
1161 __producer_stop();
1162 __consumer_stop();
1164 buffer_nr_chunks = nr_chunks;
1165 buffer_init();
1167 __player_status_changed();
1168 player_unlock();
1171 int player_get_buffer_chunks(void)
1173 return buffer_nr_chunks;
1176 int player_get_fileinfo(const char *filename, int *duration,
1177 struct keyval **comments)
1179 struct input_plugin *plug;
1180 int rc;
1182 *comments = NULL;
1183 *duration = -1;
1184 plug = ip_new(filename);
1185 if (ip_is_remote(plug)) {
1186 *comments = xnew0(struct keyval, 1);
1187 ip_delete(plug);
1188 return 0;
1190 rc = ip_open(plug);
1191 if (rc) {
1192 int save = errno;
1194 ip_delete(plug);
1195 errno = save;
1196 if (rc != -1)
1197 rc = -PLAYER_ERROR_NOT_SUPPORTED;
1198 return rc;
1200 *duration = ip_duration(plug);
1201 rc = ip_read_comments(plug, comments);
1202 ip_delete(plug);
1203 return rc;
1206 void player_set_soft_volume(int l, int r)
1208 consumer_lock();
1209 soft_vol_l = l;
1210 soft_vol_r = r;
1211 consumer_unlock();
1214 void player_set_soft_vol(int soft)
1216 consumer_lock();
1217 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1218 if (!soft_vol && !replaygain)
1219 scale_pos = consumer_pos;
1220 soft_vol = soft;
1221 consumer_unlock();
1224 void player_set_rg(enum replaygain rg)
1226 player_lock();
1227 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1228 if (!soft_vol && !replaygain)
1229 scale_pos = consumer_pos;
1230 replaygain = rg;
1232 player_info_lock();
1233 update_rg_scale();
1234 player_info_unlock();
1236 player_unlock();
1239 void player_set_rg_limit(int limit)
1241 player_lock();
1242 replaygain_limit = limit;
1244 player_info_lock();
1245 update_rg_scale();
1246 player_info_unlock();
1248 player_unlock();
1251 void player_set_rg_preamp(double db)
1253 player_lock();
1254 replaygain_preamp = db;
1256 player_info_lock();
1257 update_rg_scale();
1258 player_info_unlock();
1260 player_unlock();
1263 int player_set_op_option(unsigned int id, const char *val)
1265 int rc;
1267 player_lock();
1268 __consumer_stop();
1269 __producer_stop();
1270 rc = op_set_option(id, val);
1271 __player_status_changed();
1272 player_unlock();
1273 return rc;
1276 int player_get_op_option(unsigned int id, char **val)
1278 int rc;
1280 player_lock();
1281 rc = op_get_option(id, val);
1282 player_unlock();
1283 return rc;
1286 int player_for_each_op_option(void (*callback)(unsigned int id, const char *key))
1288 player_lock();
1289 __consumer_stop();
1290 __producer_stop();
1291 op_for_each_option(callback);
1292 __player_status_changed();
1293 player_unlock();
1294 return 0;
1297 void player_dump_plugins(void)
1299 ip_dump_plugins();
1300 op_dump_plugins();