Document Replay Gain
[cmus.git] / player.c
blobdcbeb5f287894063eb99619daedd1ca12a13c405
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 .vol_left = 0,
58 .vol_right = 0,
59 .buffer_fill = 0,
60 .buffer_size = 0,
61 .error_msg = NULL,
62 .file_changed = 0,
63 .metadata_changed = 0,
64 .status_changed = 0,
65 .position_changed = 0,
66 .buffer_fill_changed = 0,
67 .vol_changed = 0,
70 /* continue playing after track is finished? */
71 int player_cont = 1;
73 enum replaygain replaygain;
74 int replaygain_limit = 1;
75 double replaygain_preamp = 6.0;
77 static const struct player_callbacks *player_cbs = NULL;
79 static sample_format_t buffer_sf;
81 static pthread_t producer_thread;
82 static pthread_mutex_t producer_mutex = CMUS_MUTEX_INITIALIZER;
83 static int producer_running = 1;
84 static enum producer_status producer_status = PS_UNLOADED;
85 static struct input_plugin *ip = NULL;
87 static pthread_t consumer_thread;
88 static pthread_mutex_t consumer_mutex = CMUS_MUTEX_INITIALIZER;
89 static int consumer_running = 1;
90 static enum consumer_status consumer_status = CS_STOPPED;
91 static unsigned int consumer_pos = 0;
93 /* for replay gain and soft vol
94 * usually same as consumer_pos, sometimes less than consumer_pos
96 static unsigned int scale_pos;
97 static double replaygain_scale = 1.0;
99 /* locking {{{ */
101 #define producer_lock() cmus_mutex_lock(&producer_mutex)
102 #define producer_unlock() cmus_mutex_unlock(&producer_mutex)
104 #define consumer_lock() cmus_mutex_lock(&consumer_mutex)
105 #define consumer_unlock() cmus_mutex_unlock(&consumer_mutex)
107 #define player_lock() \
108 do { \
109 consumer_lock(); \
110 producer_lock(); \
111 } while (0)
113 #define player_unlock() \
114 do { \
115 producer_unlock(); \
116 consumer_unlock(); \
117 } while (0)
119 /* locking }}} */
121 static void reset_buffer(void)
123 buffer_reset();
124 consumer_pos = 0;
125 scale_pos = 0;
128 static void set_buffer_sf(sample_format_t sf)
130 buffer_sf = sf;
132 /* ip_read converts samples to this format */
133 if (sf_get_channels(buffer_sf) <= 2 && sf_get_bits(buffer_sf) <= 16) {
134 buffer_sf &= SF_RATE_MASK;
135 buffer_sf |= sf_channels(2) | sf_bits(16) | sf_signed(1);
139 #define SOFT_VOL_SCALE 65536
141 /* coefficients for volumes 0..99, for 100 65536 is used
142 * data copied from alsa-lib src/pcm/pcm_softvol.c
144 static const unsigned short soft_vol_db[100] = {
145 0x0000, 0x0110, 0x011c, 0x012f, 0x013d, 0x0152, 0x0161, 0x0179,
146 0x018a, 0x01a5, 0x01c1, 0x01d5, 0x01f5, 0x020b, 0x022e, 0x0247,
147 0x026e, 0x028a, 0x02b6, 0x02d5, 0x0306, 0x033a, 0x035f, 0x0399,
148 0x03c2, 0x0403, 0x0431, 0x0479, 0x04ac, 0x04fd, 0x0553, 0x058f,
149 0x05ef, 0x0633, 0x069e, 0x06ea, 0x0761, 0x07b5, 0x083a, 0x0898,
150 0x092c, 0x09cb, 0x0a3a, 0x0aeb, 0x0b67, 0x0c2c, 0x0cb6, 0x0d92,
151 0x0e2d, 0x0f21, 0x1027, 0x10de, 0x1202, 0x12cf, 0x1414, 0x14f8,
152 0x1662, 0x1761, 0x18f5, 0x1a11, 0x1bd3, 0x1db4, 0x1f06, 0x211d,
153 0x2297, 0x24ec, 0x2690, 0x292a, 0x2aff, 0x2de5, 0x30fe, 0x332b,
154 0x369f, 0x390d, 0x3ce6, 0x3f9b, 0x43e6, 0x46eb, 0x4bb3, 0x4f11,
155 0x5466, 0x5a18, 0x5e19, 0x6472, 0x68ea, 0x6ffd, 0x74f8, 0x7cdc,
156 0x826a, 0x8b35, 0x9499, 0x9b35, 0xa5ad, 0xad0b, 0xb8b7, 0xc0ee,
157 0xcdf1, 0xd71a, 0xe59c, 0xefd3
160 static inline void scale_sample(signed short *buf, int i, int vol)
162 int sample = buf[i];
164 if (sample < 0) {
165 sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
166 if (sample < -32768)
167 sample = -32768;
168 } else {
169 sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
170 if (sample > 32767)
171 sample = 32767;
173 buf[i] = sample;
176 static void scale_samples(char *buffer, unsigned int *countp)
178 signed short *buf;
179 unsigned int count = *countp;
180 int ch, bits, l, r, i;
182 BUG_ON(scale_pos < consumer_pos);
184 if (consumer_pos != scale_pos) {
185 unsigned int offs = scale_pos - consumer_pos;
187 if (offs >= count)
188 return;
189 buffer += offs;
190 count -= offs;
192 scale_pos += count;
193 buf = (signed short *)buffer;
195 if (replaygain_scale == 1.0 && soft_vol_l == 100 && soft_vol_r == 100)
196 return;
198 ch = sf_get_channels(buffer_sf);
199 bits = sf_get_bits(buffer_sf);
200 if (ch != 2 || bits != 16)
201 return;
203 l = SOFT_VOL_SCALE;
204 r = SOFT_VOL_SCALE;
205 if (soft_vol_l != 100)
206 l = soft_vol_db[soft_vol_l];
207 if (soft_vol_r != 100)
208 r = soft_vol_db[soft_vol_r];
210 l *= replaygain_scale;
211 r *= replaygain_scale;
213 for (i = 0; i < count / 4; i++) {
214 scale_sample(buf, i * 2, l);
215 scale_sample(buf, i * 2 + 1, r);
219 static int parse_double(const char *str, double *val)
221 char *end;
223 *val = strtod(str, &end);
224 return str == end;
227 static void update_rg_scale(void)
229 const char *g, *p;
230 double gain, peak, db, scale, limit;
232 replaygain_scale = 1.0;
233 if (!player_info.ti || !replaygain)
234 return;
236 if (replaygain == RG_TRACK) {
237 g = comments_get_val(player_info.ti->comments, "replaygain_track_gain");
238 p = comments_get_val(player_info.ti->comments, "replaygain_track_peak");
239 } else {
240 g = comments_get_val(player_info.ti->comments, "replaygain_album_gain");
241 p = comments_get_val(player_info.ti->comments, "replaygain_album_peak");
244 if (!g || !p) {
245 d_print("gain or peak not available\n");
246 return;
248 if (parse_double(g, &gain) || parse_double(p, &peak)) {
249 d_print("could not parse gain (%s) or peak (%s)\n", g, p);
250 return;
252 if (peak < 0.05) {
253 d_print("peak (%g) is too small\n", peak);
254 return;
257 db = replaygain_preamp + gain;
259 scale = pow(10.0, db / 20.0);
260 replaygain_scale = scale;
261 limit = 1.0 / peak;
262 if (replaygain_limit && replaygain_scale > limit)
263 replaygain_scale = limit;
265 d_print("gain = %f, peak = %f, db = %f, scale = %f, limit = %f, replaygain_scale = %f\n",
266 gain, peak, db, scale, limit, replaygain_scale);
269 static inline unsigned int buffer_second_size(void)
271 return sf_get_second_size(buffer_sf);
274 static inline int get_next(struct track_info **ti)
276 return player_cbs->get_next(ti);
279 /* updating player status {{{ */
281 static inline void file_changed(struct track_info *ti)
283 player_info_lock();
284 if (player_info.ti)
285 track_info_unref(player_info.ti);
287 player_info.ti = ti;
288 if (ti) {
289 d_print("file: %s\n", ti->filename);
290 } else {
291 d_print("unloaded\n");
293 update_rg_scale();
294 player_info.metadata[0] = 0;
295 player_info.file_changed = 1;
296 player_info_unlock();
299 static inline void metadata_changed(void)
301 player_info_lock();
302 d_print("metadata changed: %s\n", ip_get_metadata(ip));
303 memcpy(player_info.metadata, ip_get_metadata(ip), 255 * 16 + 1);
304 player_info.metadata_changed = 1;
305 player_info_unlock();
308 static inline void volume_update(int left, int right)
310 if (player_info.vol_left == left && player_info.vol_right == right)
311 return;
313 player_info_lock();
314 player_info.vol_left = left;
315 player_info.vol_right = right;
316 player_info.vol_changed = 1;
317 player_info_unlock();
320 static void player_error(const char *msg)
322 player_info_lock();
323 player_info.status = consumer_status;
324 player_info.pos = 0;
325 player_info.buffer_fill = buffer_get_filled_chunks();
326 player_info.buffer_size = buffer_nr_chunks;
327 player_info.status_changed = 1;
329 free(player_info.error_msg);
330 player_info.error_msg = xstrdup(msg);
331 player_info_unlock();
333 d_print("ERROR: '%s'\n", msg);
336 static void __FORMAT(2, 3) player_ip_error(int rc, const char *format, ...)
338 char buffer[1024];
339 va_list ap;
340 char *msg;
341 int save = errno;
343 va_start(ap, format);
344 vsnprintf(buffer, sizeof(buffer), format, ap);
345 va_end(ap);
347 errno = save;
348 msg = ip_get_error_msg(ip, rc, buffer);
349 player_error(msg);
350 free(msg);
353 static void __FORMAT(2, 3) player_op_error(int rc, const char *format, ...)
355 char buffer[1024];
356 va_list ap;
357 char *msg;
358 int save = errno;
360 va_start(ap, format);
361 vsnprintf(buffer, sizeof(buffer), format, ap);
362 va_end(ap);
364 errno = save;
365 msg = op_get_error_msg(rc, buffer);
366 player_error(msg);
367 free(msg);
370 /* FIXME: don't poll */
371 static void mixer_check(void)
373 static struct timeval old_t = { 0L, 0L };
374 struct timeval t;
375 long usec, sec;
376 int l, r;
378 gettimeofday(&t, NULL);
379 usec = t.tv_usec - old_t.tv_usec;
380 sec = t.tv_sec - old_t.tv_sec;
381 if (sec) {
382 /* multiplying sec with 1e6 can overflow */
383 usec += 1e6L;
385 if (usec < 300e3)
386 return;
388 old_t = t;
389 if (!op_get_volume(&l, &r))
390 volume_update(l, r);
394 * buffer-fill changed
396 static void __producer_buffer_fill_update(void)
398 int fill;
400 player_info_lock();
401 fill = buffer_get_filled_chunks();
402 if (fill != player_info.buffer_fill) {
403 /* d_print("\n"); */
404 player_info.buffer_fill = fill;
405 player_info.buffer_fill_changed = 1;
407 player_info_unlock();
411 * playing position changed
413 static void __consumer_position_update(void)
415 static unsigned int old_pos = -1;
416 unsigned int pos = 0;
418 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
419 pos = consumer_pos / buffer_second_size();
420 if (pos != old_pos) {
421 /* d_print("\n"); */
422 old_pos = pos;
424 player_info_lock();
425 player_info.pos = pos;
426 player_info.position_changed = 1;
427 player_info_unlock();
432 * something big happened (stopped/paused/unpaused...)
434 static void __player_status_changed(void)
436 unsigned int pos = 0;
438 /* d_print("\n"); */
439 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
440 pos = consumer_pos / buffer_second_size();
442 player_info_lock();
443 player_info.status = consumer_status;
444 player_info.pos = pos;
445 player_info.buffer_fill = buffer_get_filled_chunks();
446 player_info.buffer_size = buffer_nr_chunks;
447 player_info.status_changed = 1;
448 player_info_unlock();
451 /* updating player status }}} */
453 static void __prebuffer(void)
455 int limit_chunks;
457 BUG_ON(producer_status != PS_PLAYING);
458 if (ip_is_remote(ip)) {
459 limit_chunks = buffer_nr_chunks;
460 } else {
461 int limit_ms, limit_size;
463 limit_ms = 250;
464 limit_size = limit_ms * buffer_second_size() / 1000;
465 limit_chunks = limit_size / CHUNK_SIZE;
466 if (limit_chunks < 1)
467 limit_chunks = 1;
469 while (1) {
470 int nr_read, size, filled;
471 char *wpos;
473 filled = buffer_get_filled_chunks();
474 /* d_print("PREBUF: %2d / %2d\n", filled, limit_chunks); */
476 /* not fatal */
477 //BUG_ON(filled > limit_chunks);
479 if (filled >= limit_chunks)
480 break;
482 size = buffer_get_wpos(&wpos);
483 nr_read = ip_read(ip, wpos, size);
484 if (nr_read < 0) {
485 if (nr_read == -1 && errno == EAGAIN)
486 continue;
487 player_ip_error(nr_read, "reading file %s", ip_get_filename(ip));
488 /* ip_read sets eof */
489 nr_read = 0;
491 if (ip_metadata_changed(ip))
492 metadata_changed();
494 /* buffer_fill with 0 count marks current chunk filled */
495 buffer_fill(nr_read);
497 __producer_buffer_fill_update();
498 if (nr_read == 0) {
499 /* EOF */
500 break;
505 /* setting producer status {{{ */
507 static void __producer_play(void)
509 if (producer_status == PS_UNLOADED) {
510 struct track_info *ti;
512 if (get_next(&ti) == 0) {
513 int rc;
515 ip = ip_new(ti->filename);
516 rc = ip_open(ip);
517 if (rc) {
518 player_ip_error(rc, "opening file `%s'", ti->filename);
519 ip_delete(ip);
520 track_info_unref(ti);
521 file_changed(NULL);
522 } else {
523 ip_setup(ip);
524 producer_status = PS_PLAYING;
525 file_changed(ti);
528 } else if (producer_status == PS_PLAYING) {
529 if (ip_seek(ip, 0.0) == 0) {
530 reset_buffer();
532 } else if (producer_status == PS_STOPPED) {
533 int rc;
535 rc = ip_open(ip);
536 if (rc) {
537 player_ip_error(rc, "opening file `%s'", ip_get_filename(ip));
538 ip_delete(ip);
539 producer_status = PS_UNLOADED;
540 } else {
541 ip_setup(ip);
542 producer_status = PS_PLAYING;
544 } else if (producer_status == PS_PAUSED) {
545 producer_status = PS_PLAYING;
549 static void __producer_stop(void)
551 if (producer_status == PS_PLAYING || producer_status == PS_PAUSED) {
552 ip_close(ip);
553 producer_status = PS_STOPPED;
554 reset_buffer();
558 static void __producer_unload(void)
560 __producer_stop();
561 if (producer_status == PS_STOPPED) {
562 ip_delete(ip);
563 producer_status = PS_UNLOADED;
567 static void __producer_pause(void)
569 if (producer_status == PS_PLAYING) {
570 producer_status = PS_PAUSED;
571 } else if (producer_status == PS_PAUSED) {
572 producer_status = PS_PLAYING;
576 static void __producer_set_file(struct track_info *ti)
578 __producer_unload();
579 ip = ip_new(ti->filename);
580 producer_status = PS_STOPPED;
581 file_changed(ti);
584 /* setting producer status }}} */
586 /* setting consumer status {{{ */
588 static void __consumer_play(void)
590 if (consumer_status == CS_PLAYING) {
591 op_drop();
592 } else if (consumer_status == CS_STOPPED) {
593 int rc;
595 set_buffer_sf(ip_get_sf(ip));
596 rc = op_open(buffer_sf);
597 if (rc) {
598 player_op_error(rc, "opening audio device");
599 } else {
600 consumer_status = CS_PLAYING;
602 } else if (consumer_status == CS_PAUSED) {
603 op_unpause();
604 consumer_status = CS_PLAYING;
608 static void __consumer_drain_and_stop(void)
610 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
611 op_close();
612 consumer_status = CS_STOPPED;
616 static void __consumer_stop(void)
618 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
619 op_drop();
620 op_close();
621 consumer_status = CS_STOPPED;
625 static void __consumer_pause(void)
627 if (consumer_status == CS_PLAYING) {
628 op_pause();
629 consumer_status = CS_PAUSED;
630 } else if (consumer_status == CS_PAUSED) {
631 op_unpause();
632 consumer_status = CS_PLAYING;
636 /* setting consumer status }}} */
638 static int change_sf(sample_format_t sf, int drop)
640 int old_sf = buffer_sf;
642 set_buffer_sf(sf);
643 if (buffer_sf != old_sf) {
644 /* reopen */
645 int rc;
647 if (drop)
648 op_drop();
649 op_close();
650 rc = op_open(buffer_sf);
651 if (rc) {
652 player_op_error(rc, "opening audio device");
653 consumer_status = CS_STOPPED;
654 __producer_stop();
655 return rc;
657 } else if (consumer_status == CS_PAUSED) {
658 op_drop();
659 op_unpause();
661 consumer_status = CS_PLAYING;
662 return 0;
665 static void __consumer_handle_eof(void)
667 struct track_info *ti;
669 if (ip_is_remote(ip)) {
670 __producer_stop();
671 __consumer_drain_and_stop();
672 player_error("lost connection");
673 return;
676 if (get_next(&ti) == 0) {
677 __producer_unload();
678 ip = ip_new(ti->filename);
679 producer_status = PS_STOPPED;
680 /* PS_STOPPED, CS_PLAYING */
681 if (player_cont) {
682 __producer_play();
683 if (producer_status == PS_UNLOADED) {
684 __consumer_stop();
685 track_info_unref(ti);
686 file_changed(NULL);
687 } else {
688 /* PS_PLAYING */
689 file_changed(ti);
690 if (!change_sf(ip_get_sf(ip), 0))
691 __prebuffer();
693 } else {
694 __consumer_drain_and_stop();
695 file_changed(ti);
697 } else {
698 __producer_unload();
699 __consumer_drain_and_stop();
700 file_changed(NULL);
702 __player_status_changed();
705 static void *consumer_loop(void *arg)
707 while (1) {
708 int rc, space;
709 int size;
710 char *rpos;
712 consumer_lock();
713 if (!consumer_running)
714 break;
716 if (consumer_status == CS_PAUSED || consumer_status == CS_STOPPED) {
717 mixer_check();
718 consumer_unlock();
719 ms_sleep(50);
720 continue;
722 space = op_buffer_space();
723 if (space == -1) {
724 /* busy */
725 __consumer_position_update();
726 consumer_unlock();
727 ms_sleep(50);
728 continue;
730 /* d_print("BS: %6d %3d\n", space, space * 1000 / (44100 * 2 * 2)); */
732 while (1) {
733 /* 25 ms is 4410 B */
734 if (space < 4096) {
735 __consumer_position_update();
736 mixer_check();
737 consumer_unlock();
738 ms_sleep(25);
739 break;
741 size = buffer_get_rpos(&rpos);
742 if (size == 0) {
743 producer_lock();
744 if (producer_status != PS_PLAYING) {
745 producer_unlock();
746 consumer_unlock();
747 break;
749 /* must recheck rpos */
750 size = buffer_get_rpos(&rpos);
751 if (size == 0) {
752 /* OK. now it's safe to check if we are at EOF */
753 if (ip_eof(ip)) {
754 /* EOF */
755 __consumer_handle_eof();
756 producer_unlock();
757 consumer_unlock();
758 break;
759 } else {
760 /* possible underrun */
761 producer_unlock();
762 __consumer_position_update();
763 consumer_unlock();
764 /* d_print("possible underrun\n"); */
765 ms_sleep(10);
766 break;
770 /* player_buffer and ip.eof were inconsistent */
771 producer_unlock();
773 if (size > space)
774 size = space;
775 if (soft_vol || replaygain)
776 scale_samples(rpos, &size);
777 rc = op_write(rpos, size);
778 if (rc < 0) {
779 d_print("op_write returned %d %s\n", rc,
780 rc == -1 ? strerror(errno) : "");
782 /* try to reopen */
783 op_close();
784 consumer_status = CS_STOPPED;
785 __consumer_play();
787 consumer_unlock();
788 break;
790 buffer_consume(rc);
791 consumer_pos += rc;
792 space -= rc;
795 __consumer_stop();
796 consumer_unlock();
797 return NULL;
800 static void *producer_loop(void *arg)
802 while (1) {
803 /* number of chunks to fill
804 * too big => seeking is slow
805 * too small => underruns?
807 const int chunks = 1;
808 int size, nr_read, i;
809 char *wpos;
811 producer_lock();
812 if (!producer_running)
813 break;
815 if (producer_status == PS_UNLOADED ||
816 producer_status == PS_PAUSED ||
817 producer_status == PS_STOPPED || ip_eof(ip)) {
818 producer_unlock();
819 ms_sleep(50);
820 continue;
822 for (i = 0; ; i++) {
823 size = buffer_get_wpos(&wpos);
824 if (size == 0) {
825 /* buffer is full */
826 producer_unlock();
827 ms_sleep(50);
828 break;
830 nr_read = ip_read(ip, wpos, size);
831 if (nr_read < 0) {
832 if (nr_read != -1 || errno != EAGAIN) {
833 player_ip_error(nr_read, "reading file %s",
834 ip_get_filename(ip));
835 /* ip_read sets eof */
836 nr_read = 0;
837 } else {
838 producer_unlock();
839 ms_sleep(50);
840 break;
843 if (ip_metadata_changed(ip))
844 metadata_changed();
846 /* buffer_fill with 0 count marks current chunk filled */
847 buffer_fill(nr_read);
848 if (nr_read == 0) {
849 /* consumer handles EOF */
850 producer_unlock();
851 ms_sleep(50);
852 break;
854 if (i == chunks) {
855 producer_unlock();
856 /* don't sleep! */
857 break;
860 __producer_buffer_fill_update();
862 __producer_unload();
863 producer_unlock();
864 return NULL;
867 void player_load_plugins(void)
869 ip_load_plugins();
870 op_load_plugins();
873 void player_init(const struct player_callbacks *callbacks)
875 int rc;
876 #if defined(__linux__) || defined(__FreeBSD__)
877 pthread_attr_t attr;
878 #endif
879 pthread_attr_t *attrp = NULL;
881 /* 1 s is 176400 B (0.168 MB)
882 * 10 s is 1.68 MB
884 buffer_nr_chunks = 10 * 44100 * 16 / 8 * 2 / CHUNK_SIZE;
885 buffer_init();
887 player_cbs = callbacks;
889 #if defined(__linux__) || defined(__FreeBSD__)
890 rc = pthread_attr_init(&attr);
891 BUG_ON(rc);
892 rc = pthread_attr_setschedpolicy(&attr, SCHED_RR);
893 if (rc) {
894 d_print("could not set real-time scheduling priority: %s\n", strerror(rc));
895 } else {
896 struct sched_param param;
898 d_print("using real-time scheduling\n");
899 param.sched_priority = sched_get_priority_max(SCHED_RR);
900 d_print("setting priority to %d\n", param.sched_priority);
901 rc = pthread_attr_setschedparam(&attr, &param);
902 BUG_ON(rc);
903 attrp = &attr;
905 #endif
907 rc = pthread_create(&producer_thread, NULL, producer_loop, NULL);
908 BUG_ON(rc);
910 rc = pthread_create(&consumer_thread, attrp, consumer_loop, NULL);
911 if (rc && attrp) {
912 d_print("could not create thread using real-time scheduling: %s\n", strerror(rc));
913 rc = pthread_create(&consumer_thread, NULL, consumer_loop, NULL);
915 BUG_ON(rc);
917 /* update player_info.cont etc. */
918 player_lock();
919 __player_status_changed();
920 player_unlock();
923 void player_exit(void)
925 int rc;
927 player_lock();
928 consumer_running = 0;
929 producer_running = 0;
930 player_unlock();
932 rc = pthread_join(consumer_thread, NULL);
933 BUG_ON(rc);
934 rc = pthread_join(producer_thread, NULL);
935 BUG_ON(rc);
937 op_exit_plugins();
940 void player_stop(void)
942 player_lock();
943 __consumer_stop();
944 __producer_stop();
945 __player_status_changed();
946 player_unlock();
949 void player_play(void)
951 int prebuffer;
953 player_lock();
954 if (producer_status == PS_PLAYING && ip_is_remote(ip)) {
955 /* seeking not allowed */
956 player_unlock();
957 return;
959 prebuffer = consumer_status == CS_STOPPED;
960 __producer_play();
961 if (producer_status == PS_PLAYING) {
962 __consumer_play();
963 if (consumer_status != CS_PLAYING)
964 __producer_stop();
965 } else {
966 __consumer_stop();
968 __player_status_changed();
969 if (consumer_status == CS_PLAYING && prebuffer)
970 __prebuffer();
971 player_unlock();
974 void player_pause(void)
976 player_lock();
978 if (consumer_status == CS_STOPPED) {
979 __producer_play();
980 if (producer_status == PS_PLAYING) {
981 __consumer_play();
982 if (consumer_status != CS_PLAYING)
983 __producer_stop();
985 __player_status_changed();
986 if (consumer_status == CS_PLAYING)
987 __prebuffer();
988 player_unlock();
989 return;
992 if (ip && ip_is_remote(ip)) {
993 /* pausing not allowed */
994 player_unlock();
995 return;
997 __producer_pause();
998 __consumer_pause();
999 __player_status_changed();
1000 player_unlock();
1003 void player_set_file(struct track_info *ti)
1005 player_lock();
1006 __producer_set_file(ti);
1007 if (producer_status == PS_UNLOADED) {
1008 __consumer_stop();
1009 goto out;
1012 /* PS_STOPPED */
1013 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1014 __producer_play();
1015 if (producer_status == PS_UNLOADED) {
1016 __consumer_stop();
1017 goto out;
1019 change_sf(ip_get_sf(ip), 1);
1021 out:
1022 __player_status_changed();
1023 if (producer_status == PS_PLAYING)
1024 __prebuffer();
1025 player_unlock();
1028 void player_play_file(struct track_info *ti)
1030 player_lock();
1031 __producer_set_file(ti);
1032 if (producer_status == PS_UNLOADED) {
1033 __consumer_stop();
1034 goto out;
1037 /* PS_STOPPED */
1038 __producer_play();
1040 /* PS_UNLOADED,PS_PLAYING */
1041 if (producer_status == PS_UNLOADED) {
1042 __consumer_stop();
1043 goto out;
1046 /* PS_PLAYING */
1047 if (consumer_status == CS_STOPPED) {
1048 __consumer_play();
1049 if (consumer_status == CS_STOPPED)
1050 __producer_stop();
1051 } else {
1052 change_sf(ip_get_sf(ip), 1);
1054 out:
1055 __player_status_changed();
1056 if (producer_status == PS_PLAYING)
1057 __prebuffer();
1058 player_unlock();
1061 void player_seek(double offset, int relative)
1063 player_lock();
1064 if (consumer_status == CS_STOPPED) {
1065 __producer_play();
1066 if (producer_status == PS_PLAYING) {
1067 __consumer_play();
1068 if (consumer_status != CS_PLAYING) {
1069 __producer_stop();
1070 player_unlock();
1071 return;
1075 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1076 double pos, duration, new_pos;
1077 int rc;
1079 pos = (double)consumer_pos / (double)buffer_second_size();
1080 duration = ip_duration(ip);
1081 if (duration < 0) {
1082 /* can't seek */
1083 d_print("can't seek\n");
1084 player_unlock();
1085 return;
1087 if (relative) {
1088 new_pos = pos + offset;
1089 if (new_pos < 0.0)
1090 new_pos = 0.0;
1091 if (offset > 0.0) {
1092 /* seeking forward */
1093 if (new_pos > duration - 5.0)
1094 new_pos = duration - 5.0;
1095 if (new_pos < 0.0)
1096 new_pos = 0.0;
1097 if (new_pos < pos - 0.5) {
1098 /* must seek at least 0.5s */
1099 d_print("must seek at least 0.5s\n");
1100 player_unlock();
1101 return;
1104 } else {
1105 new_pos = offset;
1106 if (new_pos < 0.0) {
1107 d_print("seek offset negative\n");
1108 player_unlock();
1109 return;
1111 if (new_pos > duration - 5.0) {
1112 new_pos = duration - 5.0;
1113 if (new_pos < 0.0)
1114 new_pos = 0.0;
1117 /* d_print("seeking %g/%g (%g from eof)\n", new_pos, duration, duration - new_pos); */
1118 rc = ip_seek(ip, new_pos);
1119 if (rc == 0) {
1120 /* d_print("doing op_drop after seek\n"); */
1121 op_drop();
1122 reset_buffer();
1123 consumer_pos = new_pos * buffer_second_size();
1124 scale_pos = consumer_pos;
1125 __consumer_position_update();
1126 } else {
1127 d_print("error: ip_seek returned %d\n", rc);
1130 player_unlock();
1134 * change output plugin without stopping playback
1136 void player_set_op(const char *name)
1138 int rc, l, r;
1140 player_lock();
1142 /* drop needed because close drains the buffer */
1143 if (consumer_status == CS_PAUSED)
1144 op_drop();
1146 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
1147 op_close();
1149 if (name) {
1150 d_print("setting op to '%s'\n", name);
1151 rc = op_select(name);
1152 } else {
1153 /* first initialized plugin */
1154 d_print("selecting first initialized op\n");
1155 rc = op_select_any();
1157 if (rc) {
1158 consumer_status = CS_STOPPED;
1160 __producer_stop();
1161 player_op_error(rc, "selecting output plugin '%s'", name);
1162 player_unlock();
1163 return;
1166 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1167 set_buffer_sf(ip_get_sf(ip));
1168 rc = op_open(buffer_sf);
1169 if (rc) {
1170 consumer_status = CS_STOPPED;
1171 __producer_stop();
1172 player_op_error(rc, "opening audio device");
1173 player_unlock();
1174 return;
1176 if (consumer_status == CS_PAUSED)
1177 op_pause();
1180 if (!op_get_volume(&l, &r))
1181 volume_update(l, r);
1183 player_unlock();
1186 char *player_get_op(void)
1188 return op_get_current();
1191 void player_set_buffer_chunks(unsigned int nr_chunks)
1193 if (nr_chunks < 3)
1194 nr_chunks = 3;
1195 if (nr_chunks > 30)
1196 nr_chunks = 30;
1198 player_lock();
1199 __producer_stop();
1200 __consumer_stop();
1202 buffer_nr_chunks = nr_chunks;
1203 buffer_init();
1205 __player_status_changed();
1206 player_unlock();
1209 int player_get_buffer_chunks(void)
1211 return buffer_nr_chunks;
1214 int player_get_fileinfo(const char *filename, int *duration,
1215 struct keyval **comments)
1217 struct input_plugin *plug;
1218 int rc;
1220 *comments = NULL;
1221 *duration = -1;
1222 plug = ip_new(filename);
1223 if (ip_is_remote(plug)) {
1224 *comments = xnew0(struct keyval, 1);
1225 ip_delete(plug);
1226 return 0;
1228 rc = ip_open(plug);
1229 if (rc) {
1230 int save = errno;
1232 ip_delete(plug);
1233 errno = save;
1234 if (rc != -1)
1235 rc = -PLAYER_ERROR_NOT_SUPPORTED;
1236 return rc;
1238 *duration = ip_duration(plug);
1239 rc = ip_read_comments(plug, comments);
1240 ip_delete(plug);
1241 return rc;
1244 int player_get_volume(int *left, int *right)
1246 int rc;
1248 consumer_lock();
1249 rc = op_get_volume(left, right);
1250 consumer_unlock();
1251 return rc;
1254 int player_set_volume(int left, int right)
1256 int rc;
1258 consumer_lock();
1259 rc = op_set_volume(left, right);
1260 if (!rc)
1261 volume_update(left, right);
1262 consumer_unlock();
1263 return rc;
1266 void player_set_soft_vol(int soft)
1268 int l, r;
1270 consumer_lock();
1271 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1272 if (!soft_vol && !replaygain)
1273 scale_pos = consumer_pos;
1274 op_set_soft_vol(soft);
1275 if (!op_get_volume(&l, &r))
1276 volume_update(l, r);
1277 consumer_unlock();
1280 void player_set_rg(enum replaygain rg)
1282 player_lock();
1283 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1284 if (!soft_vol && !replaygain)
1285 scale_pos = consumer_pos;
1286 replaygain = rg;
1288 player_info_lock();
1289 update_rg_scale();
1290 player_info_unlock();
1292 player_unlock();
1295 void player_set_rg_limit(int limit)
1297 player_lock();
1298 replaygain_limit = limit;
1300 player_info_lock();
1301 update_rg_scale();
1302 player_info_unlock();
1304 player_unlock();
1307 void player_set_rg_preamp(double db)
1309 player_lock();
1310 replaygain_preamp = db;
1312 player_info_lock();
1313 update_rg_scale();
1314 player_info_unlock();
1316 player_unlock();
1319 int player_set_op_option(unsigned int id, const char *val)
1321 int rc;
1323 player_lock();
1324 __consumer_stop();
1325 __producer_stop();
1326 rc = op_set_option(id, val);
1327 __player_status_changed();
1328 player_unlock();
1329 return rc;
1332 int player_get_op_option(unsigned int id, char **val)
1334 int rc;
1336 player_lock();
1337 rc = op_get_option(id, val);
1338 player_unlock();
1339 return rc;
1342 int player_for_each_op_option(void (*callback)(unsigned int id, const char *key))
1344 player_lock();
1345 __consumer_stop();
1346 __producer_stop();
1347 op_for_each_option(callback);
1348 __player_status_changed();
1349 player_unlock();
1350 return 0;
1353 void player_dump_plugins(void)
1355 ip_dump_plugins();
1356 op_dump_plugins();