Handle streams separately in tree_add_track()
[cmus.git] / player.c
blob4e0c04663066a7ee10c31e6152c45bf64859214f
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 /* repeat current track forever? */
71 int player_repeat_current;
73 enum replaygain replaygain;
74 int replaygain_limit = 1;
75 double replaygain_preamp = 6.0;
77 int soft_vol;
78 int soft_vol_l;
79 int soft_vol_r;
81 static const struct player_callbacks *player_cbs = NULL;
83 static sample_format_t buffer_sf;
85 static pthread_t producer_thread;
86 static pthread_mutex_t producer_mutex = CMUS_MUTEX_INITIALIZER;
87 static int producer_running = 1;
88 static enum producer_status producer_status = PS_UNLOADED;
89 static struct input_plugin *ip = NULL;
91 static pthread_t consumer_thread;
92 static pthread_mutex_t consumer_mutex = CMUS_MUTEX_INITIALIZER;
93 static int consumer_running = 1;
94 static enum consumer_status consumer_status = CS_STOPPED;
95 static unsigned int consumer_pos = 0;
97 /* for replay gain and soft vol
98 * usually same as consumer_pos, sometimes less than consumer_pos
100 static unsigned int scale_pos;
101 static double replaygain_scale = 1.0;
103 /* locking {{{ */
105 #define producer_lock() cmus_mutex_lock(&producer_mutex)
106 #define producer_unlock() cmus_mutex_unlock(&producer_mutex)
108 #define consumer_lock() cmus_mutex_lock(&consumer_mutex)
109 #define consumer_unlock() cmus_mutex_unlock(&consumer_mutex)
111 #define player_lock() \
112 do { \
113 consumer_lock(); \
114 producer_lock(); \
115 } while (0)
117 #define player_unlock() \
118 do { \
119 producer_unlock(); \
120 consumer_unlock(); \
121 } while (0)
123 /* locking }}} */
125 static void reset_buffer(void)
127 buffer_reset();
128 consumer_pos = 0;
129 scale_pos = 0;
132 static void set_buffer_sf(sample_format_t sf)
134 buffer_sf = sf;
136 /* ip_read converts samples to this format */
137 if (sf_get_channels(buffer_sf) <= 2 && sf_get_bits(buffer_sf) <= 16) {
138 buffer_sf &= SF_RATE_MASK;
139 buffer_sf |= sf_channels(2) | sf_bits(16) | sf_signed(1);
143 #define SOFT_VOL_SCALE 65536
145 /* coefficients for volumes 0..99, for 100 65536 is used
146 * data copied from alsa-lib src/pcm/pcm_softvol.c
148 static const unsigned short soft_vol_db[100] = {
149 0x0000, 0x0110, 0x011c, 0x012f, 0x013d, 0x0152, 0x0161, 0x0179,
150 0x018a, 0x01a5, 0x01c1, 0x01d5, 0x01f5, 0x020b, 0x022e, 0x0247,
151 0x026e, 0x028a, 0x02b6, 0x02d5, 0x0306, 0x033a, 0x035f, 0x0399,
152 0x03c2, 0x0403, 0x0431, 0x0479, 0x04ac, 0x04fd, 0x0553, 0x058f,
153 0x05ef, 0x0633, 0x069e, 0x06ea, 0x0761, 0x07b5, 0x083a, 0x0898,
154 0x092c, 0x09cb, 0x0a3a, 0x0aeb, 0x0b67, 0x0c2c, 0x0cb6, 0x0d92,
155 0x0e2d, 0x0f21, 0x1027, 0x10de, 0x1202, 0x12cf, 0x1414, 0x14f8,
156 0x1662, 0x1761, 0x18f5, 0x1a11, 0x1bd3, 0x1db4, 0x1f06, 0x211d,
157 0x2297, 0x24ec, 0x2690, 0x292a, 0x2aff, 0x2de5, 0x30fe, 0x332b,
158 0x369f, 0x390d, 0x3ce6, 0x3f9b, 0x43e6, 0x46eb, 0x4bb3, 0x4f11,
159 0x5466, 0x5a18, 0x5e19, 0x6472, 0x68ea, 0x6ffd, 0x74f8, 0x7cdc,
160 0x826a, 0x8b35, 0x9499, 0x9b35, 0xa5ad, 0xad0b, 0xb8b7, 0xc0ee,
161 0xcdf1, 0xd71a, 0xe59c, 0xefd3
164 static inline unsigned short swap16(unsigned short u)
166 return (u << 8) | (u >> 8);
169 static inline void scale_sample(signed short *buf, int i, int vol)
171 #ifdef WORDS_BIGENDIAN
172 int sample = (short)swap16(buf[i]);
173 #else
174 int sample = buf[i];
175 #endif
177 if (sample < 0) {
178 sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
179 if (sample < -32768)
180 sample = -32768;
181 } else {
182 sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
183 if (sample > 32767)
184 sample = 32767;
186 #ifdef WORDS_BIGENDIAN
187 buf[i] = swap16(sample);
188 #else
189 buf[i] = sample;
190 #endif
193 static void scale_samples(char *buffer, unsigned int *countp)
195 signed short *buf;
196 unsigned int count = *countp;
197 int ch, bits, l, r, i;
199 BUG_ON(scale_pos < consumer_pos);
201 if (consumer_pos != scale_pos) {
202 unsigned int offs = scale_pos - consumer_pos;
204 if (offs >= count)
205 return;
206 buffer += offs;
207 count -= offs;
209 scale_pos += count;
210 buf = (signed short *)buffer;
212 if (replaygain_scale == 1.0 && soft_vol_l == 100 && soft_vol_r == 100)
213 return;
215 ch = sf_get_channels(buffer_sf);
216 bits = sf_get_bits(buffer_sf);
217 if (ch != 2 || bits != 16)
218 return;
220 l = SOFT_VOL_SCALE;
221 r = SOFT_VOL_SCALE;
222 if (soft_vol_l != 100)
223 l = soft_vol_db[soft_vol_l];
224 if (soft_vol_r != 100)
225 r = soft_vol_db[soft_vol_r];
227 l *= replaygain_scale;
228 r *= replaygain_scale;
230 /* avoid underflowing -32768 to 32767 when scale is 65536 */
231 if (l != SOFT_VOL_SCALE && r != SOFT_VOL_SCALE) {
232 for (i = 0; i < count / 4; i++) {
233 scale_sample(buf, i * 2, l);
234 scale_sample(buf, i * 2 + 1, r);
236 } else if (l != SOFT_VOL_SCALE) {
237 for (i = 0; i < count / 4; i++)
238 scale_sample(buf, i * 2, l);
239 } else if (r != SOFT_VOL_SCALE) {
240 for (i = 0; i < count / 4; i++)
241 scale_sample(buf, i * 2 + 1, r);
245 static int parse_double(const char *str, double *val)
247 char *end;
249 *val = strtod(str, &end);
250 return str == end;
253 static void update_rg_scale(void)
255 const char *g, *p;
256 double gain, peak, db, scale, limit;
258 replaygain_scale = 1.0;
259 if (!player_info.ti || !replaygain)
260 return;
262 if (replaygain == RG_TRACK) {
263 g = keyvals_get_val(player_info.ti->comments, "replaygain_track_gain");
264 p = keyvals_get_val(player_info.ti->comments, "replaygain_track_peak");
265 } else {
266 g = keyvals_get_val(player_info.ti->comments, "replaygain_album_gain");
267 p = keyvals_get_val(player_info.ti->comments, "replaygain_album_peak");
270 if (!g || !p) {
271 d_print("gain or peak not available\n");
272 return;
274 if (parse_double(g, &gain) || parse_double(p, &peak)) {
275 d_print("could not parse gain (%s) or peak (%s)\n", g, p);
276 return;
278 if (peak < 0.05) {
279 d_print("peak (%g) is too small\n", peak);
280 return;
283 db = replaygain_preamp + gain;
285 scale = pow(10.0, db / 20.0);
286 replaygain_scale = scale;
287 limit = 1.0 / peak;
288 if (replaygain_limit && replaygain_scale > limit)
289 replaygain_scale = limit;
291 d_print("gain = %f, peak = %f, db = %f, scale = %f, limit = %f, replaygain_scale = %f\n",
292 gain, peak, db, scale, limit, replaygain_scale);
295 static inline unsigned int buffer_second_size(void)
297 return sf_get_second_size(buffer_sf);
300 static inline int get_next(struct track_info **ti)
302 return player_cbs->get_next(ti);
305 /* updating player status {{{ */
307 static inline void file_changed(struct track_info *ti)
309 player_info_lock();
310 if (player_info.ti)
311 track_info_unref(player_info.ti);
313 player_info.ti = ti;
314 if (ti) {
315 d_print("file: %s\n", ti->filename);
316 } else {
317 d_print("unloaded\n");
319 update_rg_scale();
320 player_info.metadata[0] = 0;
321 player_info.file_changed = 1;
322 player_info_unlock();
325 static inline void metadata_changed(void)
327 player_info_lock();
328 d_print("metadata changed: %s\n", ip_get_metadata(ip));
329 memcpy(player_info.metadata, ip_get_metadata(ip), 255 * 16 + 1);
330 player_info.metadata_changed = 1;
331 player_info_unlock();
334 static void player_error(const char *msg)
336 player_info_lock();
337 player_info.status = consumer_status;
338 player_info.pos = 0;
339 player_info.buffer_fill = buffer_get_filled_chunks();
340 player_info.buffer_size = buffer_nr_chunks;
341 player_info.status_changed = 1;
343 free(player_info.error_msg);
344 player_info.error_msg = xstrdup(msg);
345 player_info_unlock();
347 d_print("ERROR: '%s'\n", msg);
350 static void __FORMAT(2, 3) player_ip_error(int rc, const char *format, ...)
352 char buffer[1024];
353 va_list ap;
354 char *msg;
355 int save = errno;
357 va_start(ap, format);
358 vsnprintf(buffer, sizeof(buffer), format, ap);
359 va_end(ap);
361 errno = save;
362 msg = ip_get_error_msg(ip, rc, buffer);
363 player_error(msg);
364 free(msg);
367 static void __FORMAT(2, 3) player_op_error(int rc, const char *format, ...)
369 char buffer[1024];
370 va_list ap;
371 char *msg;
372 int save = errno;
374 va_start(ap, format);
375 vsnprintf(buffer, sizeof(buffer), format, ap);
376 va_end(ap);
378 errno = save;
379 msg = op_get_error_msg(rc, buffer);
380 player_error(msg);
381 free(msg);
385 * buffer-fill changed
387 static void __producer_buffer_fill_update(void)
389 int fill;
391 player_info_lock();
392 fill = buffer_get_filled_chunks();
393 if (fill != player_info.buffer_fill) {
394 /* d_print("\n"); */
395 player_info.buffer_fill = fill;
396 player_info.buffer_fill_changed = 1;
398 player_info_unlock();
402 * playing position changed
404 static void __consumer_position_update(void)
406 static unsigned int old_pos = -1;
407 unsigned int pos = 0;
409 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
410 pos = consumer_pos / buffer_second_size();
411 if (pos != old_pos) {
412 /* d_print("\n"); */
413 old_pos = pos;
415 player_info_lock();
416 player_info.pos = pos;
417 player_info.position_changed = 1;
418 player_info_unlock();
423 * something big happened (stopped/paused/unpaused...)
425 static void __player_status_changed(void)
427 unsigned int pos = 0;
429 /* d_print("\n"); */
430 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
431 pos = consumer_pos / buffer_second_size();
433 player_info_lock();
434 player_info.status = consumer_status;
435 player_info.pos = pos;
436 player_info.buffer_fill = buffer_get_filled_chunks();
437 player_info.buffer_size = buffer_nr_chunks;
438 player_info.status_changed = 1;
439 player_info_unlock();
442 /* updating player status }}} */
444 static void __prebuffer(void)
446 int limit_chunks;
448 BUG_ON(producer_status != PS_PLAYING);
449 if (ip_is_remote(ip)) {
450 limit_chunks = buffer_nr_chunks;
451 } else {
452 int limit_ms, limit_size;
454 limit_ms = 250;
455 limit_size = limit_ms * buffer_second_size() / 1000;
456 limit_chunks = limit_size / CHUNK_SIZE;
457 if (limit_chunks < 1)
458 limit_chunks = 1;
460 while (1) {
461 int nr_read, size, filled;
462 char *wpos;
464 filled = buffer_get_filled_chunks();
465 /* d_print("PREBUF: %2d / %2d\n", filled, limit_chunks); */
467 /* not fatal */
468 //BUG_ON(filled > limit_chunks);
470 if (filled >= limit_chunks)
471 break;
473 size = buffer_get_wpos(&wpos);
474 nr_read = ip_read(ip, wpos, size);
475 if (nr_read < 0) {
476 if (nr_read == -1 && errno == EAGAIN)
477 continue;
478 player_ip_error(nr_read, "reading file %s", ip_get_filename(ip));
479 /* ip_read sets eof */
480 nr_read = 0;
482 if (ip_metadata_changed(ip))
483 metadata_changed();
485 /* buffer_fill with 0 count marks current chunk filled */
486 buffer_fill(nr_read);
488 __producer_buffer_fill_update();
489 if (nr_read == 0) {
490 /* EOF */
491 break;
496 /* setting producer status {{{ */
498 static void __producer_play(void)
500 if (producer_status == PS_UNLOADED) {
501 struct track_info *ti;
503 if (get_next(&ti) == 0) {
504 int rc;
506 ip = ip_new(ti->filename);
507 rc = ip_open(ip);
508 if (rc) {
509 player_ip_error(rc, "opening file `%s'", ti->filename);
510 ip_delete(ip);
511 track_info_unref(ti);
512 file_changed(NULL);
513 } else {
514 ip_setup(ip);
515 producer_status = PS_PLAYING;
516 file_changed(ti);
519 } else if (producer_status == PS_PLAYING) {
520 if (ip_seek(ip, 0.0) == 0) {
521 reset_buffer();
523 } else if (producer_status == PS_STOPPED) {
524 int rc;
526 rc = ip_open(ip);
527 if (rc) {
528 player_ip_error(rc, "opening file `%s'", ip_get_filename(ip));
529 ip_delete(ip);
530 producer_status = PS_UNLOADED;
531 } else {
532 ip_setup(ip);
533 producer_status = PS_PLAYING;
535 } else if (producer_status == PS_PAUSED) {
536 producer_status = PS_PLAYING;
540 static void __producer_stop(void)
542 if (producer_status == PS_PLAYING || producer_status == PS_PAUSED) {
543 ip_close(ip);
544 producer_status = PS_STOPPED;
545 reset_buffer();
549 static void __producer_unload(void)
551 __producer_stop();
552 if (producer_status == PS_STOPPED) {
553 ip_delete(ip);
554 producer_status = PS_UNLOADED;
558 static void __producer_pause(void)
560 if (producer_status == PS_PLAYING) {
561 producer_status = PS_PAUSED;
562 } else if (producer_status == PS_PAUSED) {
563 producer_status = PS_PLAYING;
567 static void __producer_set_file(struct track_info *ti)
569 __producer_unload();
570 ip = ip_new(ti->filename);
571 producer_status = PS_STOPPED;
572 file_changed(ti);
575 /* setting producer status }}} */
577 /* setting consumer status {{{ */
579 static void __consumer_play(void)
581 if (consumer_status == CS_PLAYING) {
582 op_drop();
583 } else if (consumer_status == CS_STOPPED) {
584 int rc;
586 set_buffer_sf(ip_get_sf(ip));
587 rc = op_open(buffer_sf);
588 if (rc) {
589 player_op_error(rc, "opening audio device");
590 } else {
591 consumer_status = CS_PLAYING;
593 } else if (consumer_status == CS_PAUSED) {
594 op_unpause();
595 consumer_status = CS_PLAYING;
599 static void __consumer_drain_and_stop(void)
601 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
602 op_close();
603 consumer_status = CS_STOPPED;
607 static void __consumer_stop(void)
609 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
610 op_drop();
611 op_close();
612 consumer_status = CS_STOPPED;
616 static void __consumer_pause(void)
618 if (consumer_status == CS_PLAYING) {
619 op_pause();
620 consumer_status = CS_PAUSED;
621 } else if (consumer_status == CS_PAUSED) {
622 op_unpause();
623 consumer_status = CS_PLAYING;
627 /* setting consumer status }}} */
629 static int change_sf(sample_format_t sf, int drop)
631 int old_sf = buffer_sf;
633 set_buffer_sf(sf);
634 if (buffer_sf != old_sf) {
635 /* reopen */
636 int rc;
638 if (drop)
639 op_drop();
640 op_close();
641 rc = op_open(buffer_sf);
642 if (rc) {
643 player_op_error(rc, "opening audio device");
644 consumer_status = CS_STOPPED;
645 __producer_stop();
646 return rc;
648 } else if (consumer_status == CS_PAUSED) {
649 op_drop();
650 op_unpause();
652 consumer_status = CS_PLAYING;
653 return 0;
656 static void __consumer_handle_eof(void)
658 struct track_info *ti;
660 if (ip_is_remote(ip)) {
661 __producer_stop();
662 __consumer_drain_and_stop();
663 player_error("lost connection");
664 return;
667 if (player_repeat_current) {
668 if (player_cont) {
669 ip_seek(ip, 0);
670 reset_buffer();
671 } else {
672 __producer_stop();
673 __consumer_drain_and_stop();
674 __player_status_changed();
676 return;
679 if (get_next(&ti) == 0) {
680 __producer_unload();
681 ip = ip_new(ti->filename);
682 producer_status = PS_STOPPED;
683 /* PS_STOPPED, CS_PLAYING */
684 if (player_cont) {
685 __producer_play();
686 if (producer_status == PS_UNLOADED) {
687 __consumer_stop();
688 track_info_unref(ti);
689 file_changed(NULL);
690 } else {
691 /* PS_PLAYING */
692 file_changed(ti);
693 if (!change_sf(ip_get_sf(ip), 0))
694 __prebuffer();
696 } else {
697 __consumer_drain_and_stop();
698 file_changed(ti);
700 } else {
701 __producer_unload();
702 __consumer_drain_and_stop();
703 file_changed(NULL);
705 __player_status_changed();
708 static void *consumer_loop(void *arg)
710 while (1) {
711 int rc, space;
712 int size;
713 char *rpos;
715 consumer_lock();
716 if (!consumer_running)
717 break;
719 if (consumer_status == CS_PAUSED || consumer_status == CS_STOPPED) {
720 consumer_unlock();
721 ms_sleep(50);
722 continue;
724 space = op_buffer_space();
725 if (space == -1) {
726 /* busy */
727 __consumer_position_update();
728 consumer_unlock();
729 ms_sleep(50);
730 continue;
732 /* d_print("BS: %6d %3d\n", space, space * 1000 / (44100 * 2 * 2)); */
734 while (1) {
735 /* 25 ms is 4410 B */
736 if (space < 4096) {
737 __consumer_position_update();
738 consumer_unlock();
739 ms_sleep(25);
740 break;
742 size = buffer_get_rpos(&rpos);
743 if (size == 0) {
744 producer_lock();
745 if (producer_status != PS_PLAYING) {
746 producer_unlock();
747 consumer_unlock();
748 break;
750 /* must recheck rpos */
751 size = buffer_get_rpos(&rpos);
752 if (size == 0) {
753 /* OK. now it's safe to check if we are at EOF */
754 if (ip_eof(ip)) {
755 /* EOF */
756 __consumer_handle_eof();
757 producer_unlock();
758 consumer_unlock();
759 break;
760 } else {
761 /* possible underrun */
762 producer_unlock();
763 __consumer_position_update();
764 consumer_unlock();
765 /* d_print("possible underrun\n"); */
766 ms_sleep(10);
767 break;
771 /* player_buffer and ip.eof were inconsistent */
772 producer_unlock();
774 if (size > space)
775 size = space;
776 if (soft_vol || replaygain)
777 scale_samples(rpos, &size);
778 rc = op_write(rpos, size);
779 if (rc < 0) {
780 d_print("op_write returned %d %s\n", rc,
781 rc == -1 ? strerror(errno) : "");
783 /* try to reopen */
784 op_close();
785 consumer_status = CS_STOPPED;
786 __consumer_play();
788 consumer_unlock();
789 break;
791 buffer_consume(rc);
792 consumer_pos += rc;
793 space -= rc;
796 __consumer_stop();
797 consumer_unlock();
798 return NULL;
801 static void *producer_loop(void *arg)
803 while (1) {
804 /* number of chunks to fill
805 * too big => seeking is slow
806 * too small => underruns?
808 const int chunks = 1;
809 int size, nr_read, i;
810 char *wpos;
812 producer_lock();
813 if (!producer_running)
814 break;
816 if (producer_status == PS_UNLOADED ||
817 producer_status == PS_PAUSED ||
818 producer_status == PS_STOPPED || ip_eof(ip)) {
819 producer_unlock();
820 ms_sleep(50);
821 continue;
823 for (i = 0; ; i++) {
824 size = buffer_get_wpos(&wpos);
825 if (size == 0) {
826 /* buffer is full */
827 producer_unlock();
828 ms_sleep(50);
829 break;
831 nr_read = ip_read(ip, wpos, size);
832 if (nr_read < 0) {
833 if (nr_read != -1 || errno != EAGAIN) {
834 player_ip_error(nr_read, "reading file %s",
835 ip_get_filename(ip));
836 /* ip_read sets eof */
837 nr_read = 0;
838 } else {
839 producer_unlock();
840 ms_sleep(50);
841 break;
844 if (ip_metadata_changed(ip))
845 metadata_changed();
847 /* buffer_fill with 0 count marks current chunk filled */
848 buffer_fill(nr_read);
849 if (nr_read == 0) {
850 /* consumer handles EOF */
851 producer_unlock();
852 ms_sleep(50);
853 break;
855 if (i == chunks) {
856 producer_unlock();
857 /* don't sleep! */
858 break;
861 __producer_buffer_fill_update();
863 __producer_unload();
864 producer_unlock();
865 return NULL;
868 void player_init(const struct player_callbacks *callbacks)
870 int rc;
871 #ifdef REALTIME_SCHEDULING
872 pthread_attr_t attr;
873 #endif
874 pthread_attr_t *attrp = NULL;
876 /* 1 s is 176400 B (0.168 MB)
877 * 10 s is 1.68 MB
879 buffer_nr_chunks = 10 * 44100 * 16 / 8 * 2 / CHUNK_SIZE;
880 buffer_init();
882 player_cbs = callbacks;
884 #ifdef REALTIME_SCHEDULING
885 rc = pthread_attr_init(&attr);
886 BUG_ON(rc);
887 rc = pthread_attr_setschedpolicy(&attr, SCHED_RR);
888 if (rc) {
889 d_print("could not set real-time scheduling priority: %s\n", strerror(rc));
890 } else {
891 struct sched_param param;
893 d_print("using real-time scheduling\n");
894 param.sched_priority = sched_get_priority_max(SCHED_RR);
895 d_print("setting priority to %d\n", param.sched_priority);
896 rc = pthread_attr_setschedparam(&attr, &param);
897 BUG_ON(rc);
898 attrp = &attr;
900 #endif
902 rc = pthread_create(&producer_thread, NULL, producer_loop, NULL);
903 BUG_ON(rc);
905 rc = pthread_create(&consumer_thread, attrp, consumer_loop, NULL);
906 if (rc && attrp) {
907 d_print("could not create thread using real-time scheduling: %s\n", strerror(rc));
908 rc = pthread_create(&consumer_thread, NULL, consumer_loop, NULL);
910 BUG_ON(rc);
912 /* update player_info.cont etc. */
913 player_lock();
914 __player_status_changed();
915 player_unlock();
918 void player_exit(void)
920 int rc;
922 player_lock();
923 consumer_running = 0;
924 producer_running = 0;
925 player_unlock();
927 rc = pthread_join(consumer_thread, NULL);
928 BUG_ON(rc);
929 rc = pthread_join(producer_thread, NULL);
930 BUG_ON(rc);
933 void player_stop(void)
935 player_lock();
936 __consumer_stop();
937 __producer_stop();
938 __player_status_changed();
939 player_unlock();
942 void player_play(void)
944 int prebuffer;
946 player_lock();
947 if (producer_status == PS_PLAYING && ip_is_remote(ip)) {
948 /* seeking not allowed */
949 player_unlock();
950 return;
952 prebuffer = consumer_status == CS_STOPPED;
953 __producer_play();
954 if (producer_status == PS_PLAYING) {
955 __consumer_play();
956 if (consumer_status != CS_PLAYING)
957 __producer_stop();
958 } else {
959 __consumer_stop();
961 __player_status_changed();
962 if (consumer_status == CS_PLAYING && prebuffer)
963 __prebuffer();
964 player_unlock();
967 void player_pause(void)
969 player_lock();
971 if (consumer_status == CS_STOPPED) {
972 __producer_play();
973 if (producer_status == PS_PLAYING) {
974 __consumer_play();
975 if (consumer_status != CS_PLAYING)
976 __producer_stop();
978 __player_status_changed();
979 if (consumer_status == CS_PLAYING)
980 __prebuffer();
981 player_unlock();
982 return;
985 if (ip && ip_is_remote(ip)) {
986 /* pausing not allowed */
987 player_unlock();
988 return;
990 __producer_pause();
991 __consumer_pause();
992 __player_status_changed();
993 player_unlock();
996 void player_set_file(struct track_info *ti)
998 player_lock();
999 __producer_set_file(ti);
1000 if (producer_status == PS_UNLOADED) {
1001 __consumer_stop();
1002 goto out;
1005 /* PS_STOPPED */
1006 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1007 __producer_play();
1008 if (producer_status == PS_UNLOADED) {
1009 __consumer_stop();
1010 goto out;
1012 change_sf(ip_get_sf(ip), 1);
1014 out:
1015 __player_status_changed();
1016 if (producer_status == PS_PLAYING)
1017 __prebuffer();
1018 player_unlock();
1021 void player_play_file(struct track_info *ti)
1023 player_lock();
1024 __producer_set_file(ti);
1025 if (producer_status == PS_UNLOADED) {
1026 __consumer_stop();
1027 goto out;
1030 /* PS_STOPPED */
1031 __producer_play();
1033 /* PS_UNLOADED,PS_PLAYING */
1034 if (producer_status == PS_UNLOADED) {
1035 __consumer_stop();
1036 goto out;
1039 /* PS_PLAYING */
1040 if (consumer_status == CS_STOPPED) {
1041 __consumer_play();
1042 if (consumer_status == CS_STOPPED)
1043 __producer_stop();
1044 } else {
1045 change_sf(ip_get_sf(ip), 1);
1047 out:
1048 __player_status_changed();
1049 if (producer_status == PS_PLAYING)
1050 __prebuffer();
1051 player_unlock();
1054 void player_seek(double offset, int relative)
1056 player_lock();
1057 if (consumer_status == CS_STOPPED) {
1058 __producer_play();
1059 if (producer_status == PS_PLAYING) {
1060 __consumer_play();
1061 if (consumer_status != CS_PLAYING) {
1062 __producer_stop();
1063 player_unlock();
1064 return;
1065 } else
1066 __player_status_changed();
1069 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1070 double pos, duration, new_pos;
1071 int rc;
1073 pos = (double)consumer_pos / (double)buffer_second_size();
1074 duration = ip_duration(ip);
1075 if (duration < 0) {
1076 /* can't seek */
1077 d_print("can't seek\n");
1078 player_unlock();
1079 return;
1081 if (relative) {
1082 new_pos = pos + offset;
1083 if (new_pos < 0.0)
1084 new_pos = 0.0;
1085 if (offset > 0.0) {
1086 /* seeking forward */
1087 if (new_pos > duration - 5.0)
1088 new_pos = duration - 5.0;
1089 if (new_pos < 0.0)
1090 new_pos = 0.0;
1091 if (new_pos < pos - 0.5) {
1092 /* must seek at least 0.5s */
1093 d_print("must seek at least 0.5s\n");
1094 player_unlock();
1095 return;
1098 } else {
1099 new_pos = offset;
1100 if (new_pos < 0.0) {
1101 d_print("seek offset negative\n");
1102 player_unlock();
1103 return;
1105 if (new_pos > duration - 5.0) {
1106 new_pos = duration - 5.0;
1107 if (new_pos < 0.0)
1108 new_pos = 0.0;
1111 /* d_print("seeking %g/%g (%g from eof)\n", new_pos, duration, duration - new_pos); */
1112 rc = ip_seek(ip, new_pos);
1113 if (rc == 0) {
1114 /* d_print("doing op_drop after seek\n"); */
1115 op_drop();
1116 reset_buffer();
1117 consumer_pos = new_pos * buffer_second_size();
1118 scale_pos = consumer_pos;
1119 __consumer_position_update();
1120 } else {
1121 d_print("error: ip_seek returned %d\n", rc);
1124 player_unlock();
1128 * change output plugin without stopping playback
1130 void player_set_op(const char *name)
1132 int rc;
1134 player_lock();
1136 /* drop needed because close drains the buffer */
1137 if (consumer_status == CS_PAUSED)
1138 op_drop();
1140 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
1141 op_close();
1143 if (name) {
1144 d_print("setting op to '%s'\n", name);
1145 rc = op_select(name);
1146 } else {
1147 /* first initialized plugin */
1148 d_print("selecting first initialized op\n");
1149 rc = op_select_any();
1151 if (rc) {
1152 consumer_status = CS_STOPPED;
1154 __producer_stop();
1155 player_op_error(rc, "selecting output plugin '%s'", name);
1156 player_unlock();
1157 return;
1160 if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1161 set_buffer_sf(ip_get_sf(ip));
1162 rc = op_open(buffer_sf);
1163 if (rc) {
1164 consumer_status = CS_STOPPED;
1165 __producer_stop();
1166 player_op_error(rc, "opening audio device");
1167 player_unlock();
1168 return;
1170 if (consumer_status == CS_PAUSED)
1171 op_pause();
1174 player_unlock();
1177 void player_set_buffer_chunks(unsigned int nr_chunks)
1179 if (nr_chunks < 3)
1180 nr_chunks = 3;
1181 if (nr_chunks > 30)
1182 nr_chunks = 30;
1184 player_lock();
1185 __producer_stop();
1186 __consumer_stop();
1188 buffer_nr_chunks = nr_chunks;
1189 buffer_init();
1191 __player_status_changed();
1192 player_unlock();
1195 int player_get_buffer_chunks(void)
1197 return buffer_nr_chunks;
1200 void player_set_soft_volume(int l, int r)
1202 consumer_lock();
1203 soft_vol_l = l;
1204 soft_vol_r = r;
1205 consumer_unlock();
1208 void player_set_soft_vol(int soft)
1210 consumer_lock();
1211 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1212 if (!soft_vol && !replaygain)
1213 scale_pos = consumer_pos;
1214 soft_vol = soft;
1215 consumer_unlock();
1218 void player_set_rg(enum replaygain rg)
1220 player_lock();
1221 /* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1222 if (!soft_vol && !replaygain)
1223 scale_pos = consumer_pos;
1224 replaygain = rg;
1226 player_info_lock();
1227 update_rg_scale();
1228 player_info_unlock();
1230 player_unlock();
1233 void player_set_rg_limit(int limit)
1235 player_lock();
1236 replaygain_limit = limit;
1238 player_info_lock();
1239 update_rg_scale();
1240 player_info_unlock();
1242 player_unlock();
1245 void player_set_rg_preamp(double db)
1247 player_lock();
1248 replaygain_preamp = db;
1250 player_info_lock();
1251 update_rg_scale();
1252 player_info_unlock();
1254 player_unlock();