wavpack: Pass correct sample count to format_samples()
[cmus.git] / player.c
blobfc28f905fbfa9d45e81f35421a61b9a5c56747f1
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_PLAYING || consumer_status == CS_PAUSED) {
1065 double pos, duration, new_pos;
1066 int rc;
1068 pos = (double)consumer_pos / (double)buffer_second_size();
1069 duration = ip_duration(ip);
1070 if (duration < 0) {
1071 /* can't seek */
1072 d_print("can't seek\n");
1073 player_unlock();
1074 return;
1076 if (relative) {
1077 new_pos = pos + offset;
1078 if (new_pos < 0.0)
1079 new_pos = 0.0;
1080 if (offset > 0.0) {
1081 /* seeking forward */
1082 if (new_pos > duration - 5.0)
1083 new_pos = duration - 5.0;
1084 if (new_pos < 0.0)
1085 new_pos = 0.0;
1086 if (new_pos < pos - 0.5) {
1087 /* must seek at least 0.5s */
1088 d_print("must seek at least 0.5s\n");
1089 player_unlock();
1090 return;
1093 } else {
1094 new_pos = offset;
1095 if (new_pos < 0.0) {
1096 d_print("seek offset negative\n");
1097 player_unlock();
1098 return;
1100 if (new_pos > duration) {
1101 d_print("seek offset too large\n");
1102 player_unlock();
1103 return;
1106 /* d_print("seeking %g/%g (%g from eof)\n", new_pos, duration, duration - new_pos); */
1107 rc = ip_seek(ip, new_pos);
1108 if (rc == 0) {
1109 /* d_print("doing op_drop after seek\n"); */
1110 op_drop();
1111 reset_buffer();
1112 consumer_pos = new_pos * buffer_second_size();
1113 scale_pos = consumer_pos;
1114 __consumer_position_update();
1115 } else {
1116 d_print("error: ip_seek returned %d\n", rc);
1119 player_unlock();
1123 * change output plugin without stopping playback
1125 void player_set_op(const char *name)
1127 int rc, l, r;
1129 player_lock();
1131 /* drop needed because close drains the buffer */
1132 if (consumer_status == CS_PAUSED)
1133 op_drop();
1135 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
1136 op_close();
1138 if (name) {
1139 d_print("setting op to '%s'\n", name);
1140 rc = op_select(name);
1141 } else {
1142 /* first initialized plugin */
1143 d_print("selecting first initialized op\n");
1144 rc = op_select_any();
1146 if (rc) {
1147 consumer_status = CS_STOPPED;
1149 __producer_stop();
1150 player_op_error(rc, "selecting output plugin '%s'", name);
1151 player_unlock();
1152 return;
1155 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1156 set_buffer_sf(ip_get_sf(ip));
1157 rc = op_open(buffer_sf);
1158 if (rc) {
1159 consumer_status = CS_STOPPED;
1160 __producer_stop();
1161 player_op_error(rc, "opening audio device");
1162 player_unlock();
1163 return;
1165 if (consumer_status == CS_PAUSED)
1166 op_pause();
1169 if (!op_get_volume(&l, &r))
1170 volume_update(l, r);
1172 player_unlock();
1175 char *player_get_op(void)
1177 return op_get_current();
1180 void player_set_buffer_chunks(unsigned int nr_chunks)
1182 if (nr_chunks < 3)
1183 nr_chunks = 3;
1184 if (nr_chunks > 30)
1185 nr_chunks = 30;
1187 player_lock();
1188 __producer_stop();
1189 __consumer_stop();
1191 buffer_nr_chunks = nr_chunks;
1192 buffer_init();
1194 __player_status_changed();
1195 player_unlock();
1198 int player_get_buffer_chunks(void)
1200 return buffer_nr_chunks;
1203 int player_get_fileinfo(const char *filename, int *duration,
1204 struct keyval **comments)
1206 struct input_plugin *plug;
1207 int rc;
1209 *comments = NULL;
1210 *duration = -1;
1211 plug = ip_new(filename);
1212 if (ip_is_remote(plug)) {
1213 *comments = xnew0(struct keyval, 1);
1214 ip_delete(plug);
1215 return 0;
1217 rc = ip_open(plug);
1218 if (rc) {
1219 int save = errno;
1221 ip_delete(plug);
1222 errno = save;
1223 if (rc != -1)
1224 rc = -PLAYER_ERROR_NOT_SUPPORTED;
1225 return rc;
1227 *duration = ip_duration(plug);
1228 rc = ip_read_comments(plug, comments);
1229 ip_delete(plug);
1230 return rc;
1233 int player_get_volume(int *left, int *right)
1235 int rc;
1237 consumer_lock();
1238 rc = op_get_volume(left, right);
1239 consumer_unlock();
1240 return rc;
1243 int player_set_volume(int left, int right)
1245 int rc;
1247 consumer_lock();
1248 rc = op_set_volume(left, right);
1249 if (!rc)
1250 volume_update(left, right);
1251 consumer_unlock();
1252 return rc;
1255 void player_set_soft_vol(int soft)
1257 int l, r;
1259 consumer_lock();
1260 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1261 if (!soft_vol && !replaygain)
1262 scale_pos = consumer_pos;
1263 op_set_soft_vol(soft);
1264 if (!op_get_volume(&l, &r))
1265 volume_update(l, r);
1266 consumer_unlock();
1269 void player_set_rg(enum replaygain rg)
1271 player_lock();
1272 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1273 if (!soft_vol && !replaygain)
1274 scale_pos = consumer_pos;
1275 replaygain = rg;
1277 player_info_lock();
1278 update_rg_scale();
1279 player_info_unlock();
1281 player_unlock();
1284 void player_set_rg_limit(int limit)
1286 player_lock();
1287 replaygain_limit = limit;
1289 player_info_lock();
1290 update_rg_scale();
1291 player_info_unlock();
1293 player_unlock();
1296 void player_set_rg_preamp(double db)
1298 player_lock();
1299 replaygain_preamp = db;
1301 player_info_lock();
1302 update_rg_scale();
1303 player_info_unlock();
1305 player_unlock();
1308 int player_set_op_option(unsigned int id, const char *val)
1310 int rc;
1312 player_lock();
1313 __consumer_stop();
1314 __producer_stop();
1315 rc = op_set_option(id, val);
1316 __player_status_changed();
1317 player_unlock();
1318 return rc;
1321 int player_get_op_option(unsigned int id, char **val)
1323 int rc;
1325 player_lock();
1326 rc = op_get_option(id, val);
1327 player_unlock();
1328 return rc;
1331 int player_for_each_op_option(void (*callback)(unsigned int id, const char *key))
1333 player_lock();
1334 __consumer_stop();
1335 __producer_stop();
1336 op_for_each_option(callback);
1337 __player_status_changed();
1338 player_unlock();
1339 return 0;
1342 void player_dump_plugins(void)
1344 ip_dump_plugins();
1345 op_dump_plugins();