2 * Copyright 2004-2006 Timo Hirvonen
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
37 enum producer_status
{
44 enum consumer_status
{
50 struct player_info player_info
= {
51 .mutex
= CMUS_MUTEX_INITIALIZER
,
54 .status
= PLAYER_STATUS_STOPPED
,
62 .metadata_changed
= 0,
64 .position_changed
= 0,
65 .buffer_fill_changed
= 0,
69 /* continue playing after track is finished? */
72 static const struct player_callbacks
*player_cbs
= NULL
;
74 static sample_format_t buffer_sf
;
76 static pthread_t producer_thread
;
77 static pthread_mutex_t producer_mutex
= CMUS_MUTEX_INITIALIZER
;
78 static int producer_running
= 1;
79 static enum producer_status producer_status
= PS_UNLOADED
;
80 static struct input_plugin
*ip
= NULL
;
82 static pthread_t consumer_thread
;
83 static pthread_mutex_t consumer_mutex
= CMUS_MUTEX_INITIALIZER
;
84 static int consumer_running
= 1;
85 static enum consumer_status consumer_status
= CS_STOPPED
;
86 static int consumer_pos
= 0;
88 /* usually same as consumer_pos, sometimes less than consumer_pos */
89 static int soft_vol_pos
;
93 #define producer_lock() cmus_mutex_lock(&producer_mutex)
94 #define producer_unlock() cmus_mutex_unlock(&producer_mutex)
96 #define consumer_lock() cmus_mutex_lock(&consumer_mutex)
97 #define consumer_unlock() cmus_mutex_unlock(&consumer_mutex)
99 #define player_lock() \
105 #define player_unlock() \
113 static void reset_buffer(void)
120 static void set_buffer_sf(sample_format_t sf
)
124 /* ip_read converts samples to this format */
125 if (sf_get_channels(buffer_sf
) <= 2 && sf_get_bits(buffer_sf
) <= 16) {
126 buffer_sf
&= SF_RATE_MASK
;
127 buffer_sf
|= sf_channels(2) | sf_bits(16) | sf_signed(1);
131 #define SOFT_VOL_SCALE 65536
133 /* coefficients for volumes 0..99, for 100 65536 is used
134 * data copied from alsa-lib src/pcm/pcm_softvol.c
136 static const unsigned short soft_vol_db
[100] = {
137 0x0000, 0x0110, 0x011c, 0x012f, 0x013d, 0x0152, 0x0161, 0x0179,
138 0x018a, 0x01a5, 0x01c1, 0x01d5, 0x01f5, 0x020b, 0x022e, 0x0247,
139 0x026e, 0x028a, 0x02b6, 0x02d5, 0x0306, 0x033a, 0x035f, 0x0399,
140 0x03c2, 0x0403, 0x0431, 0x0479, 0x04ac, 0x04fd, 0x0553, 0x058f,
141 0x05ef, 0x0633, 0x069e, 0x06ea, 0x0761, 0x07b5, 0x083a, 0x0898,
142 0x092c, 0x09cb, 0x0a3a, 0x0aeb, 0x0b67, 0x0c2c, 0x0cb6, 0x0d92,
143 0x0e2d, 0x0f21, 0x1027, 0x10de, 0x1202, 0x12cf, 0x1414, 0x14f8,
144 0x1662, 0x1761, 0x18f5, 0x1a11, 0x1bd3, 0x1db4, 0x1f06, 0x211d,
145 0x2297, 0x24ec, 0x2690, 0x292a, 0x2aff, 0x2de5, 0x30fe, 0x332b,
146 0x369f, 0x390d, 0x3ce6, 0x3f9b, 0x43e6, 0x46eb, 0x4bb3, 0x4f11,
147 0x5466, 0x5a18, 0x5e19, 0x6472, 0x68ea, 0x6ffd, 0x74f8, 0x7cdc,
148 0x826a, 0x8b35, 0x9499, 0x9b35, 0xa5ad, 0xad0b, 0xb8b7, 0xc0ee,
149 0xcdf1, 0xd71a, 0xe59c, 0xefd3
152 static inline void scale_sample(signed short *buf
, int i
, int vol
)
157 buf
[i
] = (sample
* vol
- SOFT_VOL_SCALE
/ 2) / SOFT_VOL_SCALE
;
159 buf
[i
] = (sample
* vol
+ SOFT_VOL_SCALE
/ 2) / SOFT_VOL_SCALE
;
163 static void soft_vol_scale(char *buffer
, int *countp
)
167 int ch
, bits
, l
, r
, i
;
169 if (consumer_pos
!= soft_vol_pos
) {
170 int offs
= soft_vol_pos
- consumer_pos
;
178 soft_vol_pos
+= count
;
179 buf
= (signed short *)buffer
;
181 if (soft_vol_l
== 100 && soft_vol_r
== 100)
184 ch
= sf_get_channels(buffer_sf
);
185 bits
= sf_get_bits(buffer_sf
);
186 if (ch
!= 2 || bits
!= 16)
191 if (soft_vol_l
!= 100)
192 l
= soft_vol_db
[soft_vol_l
];
193 if (soft_vol_r
!= 100)
194 r
= soft_vol_db
[soft_vol_r
];
196 for (i
= 0; i
< count
/ 4; i
++) {
197 scale_sample(buf
, i
* 2, l
);
198 scale_sample(buf
, i
* 2 + 1, r
);
202 static inline int buffer_second_size(void)
204 return sf_get_second_size(buffer_sf
);
207 static inline int get_next(char **filename
)
209 return player_cbs
->get_next(filename
);
212 /* updating player status {{{ */
214 static inline void file_changed(void)
217 if (producer_status
== PS_UNLOADED
) {
218 player_info
.filename
[0] = 0;
220 strncpy(player_info
.filename
, ip_get_filename(ip
), sizeof(player_info
.filename
));
221 player_info
.filename
[sizeof(player_info
.filename
) - 1] = 0;
223 d_print("%s\n", player_info
.filename
);
224 player_info
.metadata
[0] = 0;
225 player_info
.file_changed
= 1;
226 player_info_unlock();
229 static inline void metadata_changed(void)
232 d_print("metadata changed: %s\n", ip_get_metadata(ip
));
233 memcpy(player_info
.metadata
, ip_get_metadata(ip
), 255 * 16 + 1);
234 player_info
.metadata_changed
= 1;
235 player_info_unlock();
238 static inline void volume_update(int left
, int right
)
240 if (player_info
.vol_left
== left
&& player_info
.vol_right
== right
)
244 player_info
.vol_left
= left
;
245 player_info
.vol_right
= right
;
246 player_info
.vol_changed
= 1;
247 player_info_unlock();
250 static void player_error(const char *msg
)
253 player_info
.status
= consumer_status
;
255 player_info
.buffer_fill
= buffer_get_filled_chunks();
256 player_info
.buffer_size
= buffer_nr_chunks
;
257 player_info
.status_changed
= 1;
259 free(player_info
.error_msg
);
260 player_info
.error_msg
= xstrdup(msg
);
261 player_info_unlock();
263 d_print("ERROR: '%s'\n", msg
);
266 static void __FORMAT(2, 3) player_ip_error(int rc
, const char *format
, ...)
273 va_start(ap
, format
);
274 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
278 msg
= ip_get_error_msg(ip
, rc
, buffer
);
283 static void __FORMAT(2, 3) player_op_error(int rc
, const char *format
, ...)
290 va_start(ap
, format
);
291 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
295 msg
= op_get_error_msg(rc
, buffer
);
300 /* FIXME: don't poll */
301 static void mixer_check(void)
303 static struct timeval old_t
= { 0L, 0L };
308 gettimeofday(&t
, NULL
);
309 usec
= t
.tv_usec
- old_t
.tv_usec
;
310 sec
= t
.tv_sec
- old_t
.tv_sec
;
312 /* multiplying sec with 1e6 can overflow */
319 if (!op_get_volume(&l
, &r
))
324 * buffer-fill changed
326 static void __producer_buffer_fill_update(void)
331 fill
= buffer_get_filled_chunks();
332 if (fill
!= player_info
.buffer_fill
) {
334 player_info
.buffer_fill
= fill
;
335 player_info
.buffer_fill_changed
= 1;
337 player_info_unlock();
341 * playing position changed
343 static void __consumer_position_update(void)
345 static int old_pos
= -1;
349 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
)
350 pos
= consumer_pos
/ buffer_second_size();
351 if (pos
!= old_pos
) {
356 player_info
.pos
= pos
;
357 player_info
.position_changed
= 1;
358 player_info_unlock();
363 * something big happened (stopped/paused/unpaused...)
365 static void __player_status_changed(void)
370 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
)
371 pos
= consumer_pos
/ buffer_second_size();
374 player_info
.status
= consumer_status
;
375 player_info
.pos
= pos
;
376 player_info
.buffer_fill
= buffer_get_filled_chunks();
377 player_info
.buffer_size
= buffer_nr_chunks
;
378 player_info
.status_changed
= 1;
379 player_info_unlock();
382 /* updating player status }}} */
384 static void __prebuffer(void)
388 BUG_ON(producer_status
!= PS_PLAYING
);
389 if (ip_is_remote(ip
)) {
390 limit_chunks
= buffer_nr_chunks
;
392 int limit_ms
, limit_size
;
395 limit_size
= limit_ms
* buffer_second_size() / 1000;
396 limit_chunks
= limit_size
/ CHUNK_SIZE
;
397 if (limit_chunks
< 1)
401 int nr_read
, size
, filled
;
404 filled
= buffer_get_filled_chunks();
405 /* d_print("PREBUF: %2d / %2d\n", filled, limit_chunks); */
408 //BUG_ON(filled > limit_chunks);
410 if (filled
>= limit_chunks
)
413 size
= buffer_get_wpos(&wpos
);
414 nr_read
= ip_read(ip
, wpos
, size
);
416 if (nr_read
== -1 && errno
== EAGAIN
)
418 player_ip_error(nr_read
, "reading file %s", ip_get_filename(ip
));
419 /* ip_read sets eof */
422 if (ip_metadata_changed(ip
))
425 /* buffer_fill with 0 count marks current chunk filled */
426 buffer_fill(nr_read
);
428 __producer_buffer_fill_update();
436 /* setting producer status {{{ */
438 static void __producer_play(void)
440 if (producer_status
== PS_UNLOADED
) {
443 if (get_next(&filename
) == 0) {
446 ip
= ip_new(filename
);
449 player_ip_error(rc
, "opening file `%s'", filename
);
453 producer_status
= PS_PLAYING
;
458 } else if (producer_status
== PS_PLAYING
) {
459 if (ip_seek(ip
, 0.0) == 0) {
462 } else if (producer_status
== PS_STOPPED
) {
467 player_ip_error(rc
, "opening file `%s'", ip_get_filename(ip
));
469 producer_status
= PS_UNLOADED
;
472 producer_status
= PS_PLAYING
;
474 } else if (producer_status
== PS_PAUSED
) {
475 producer_status
= PS_PLAYING
;
479 static void __producer_stop(void)
481 if (producer_status
== PS_PLAYING
|| producer_status
== PS_PAUSED
) {
483 producer_status
= PS_STOPPED
;
488 static void __producer_unload(void)
491 if (producer_status
== PS_STOPPED
) {
493 producer_status
= PS_UNLOADED
;
497 static void __producer_pause(void)
499 if (producer_status
== PS_PLAYING
) {
500 producer_status
= PS_PAUSED
;
501 } else if (producer_status
== PS_PAUSED
) {
502 producer_status
= PS_PLAYING
;
506 static void __producer_set_file(const char *filename
)
509 ip
= ip_new(filename
);
510 producer_status
= PS_STOPPED
;
514 /* setting producer status }}} */
516 /* setting consumer status {{{ */
518 static void __consumer_play(void)
520 if (consumer_status
== CS_PLAYING
) {
522 } else if (consumer_status
== CS_STOPPED
) {
525 set_buffer_sf(ip_get_sf(ip
));
526 rc
= op_open(buffer_sf
);
528 player_op_error(rc
, "opening audio device");
530 consumer_status
= CS_PLAYING
;
532 } else if (consumer_status
== CS_PAUSED
) {
534 consumer_status
= CS_PLAYING
;
538 static void __consumer_drain_and_stop(void)
540 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
542 consumer_status
= CS_STOPPED
;
546 static void __consumer_stop(void)
548 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
551 consumer_status
= CS_STOPPED
;
555 static void __consumer_pause(void)
557 if (consumer_status
== CS_PLAYING
) {
559 consumer_status
= CS_PAUSED
;
560 } else if (consumer_status
== CS_PAUSED
) {
562 consumer_status
= CS_PLAYING
;
566 /* setting consumer status }}} */
568 static int change_sf(sample_format_t sf
, int drop
)
570 int old_sf
= buffer_sf
;
573 if (buffer_sf
!= old_sf
) {
580 rc
= op_open(buffer_sf
);
582 player_op_error(rc
, "opening audio device");
583 consumer_status
= CS_STOPPED
;
587 } else if (consumer_status
== CS_PAUSED
) {
591 consumer_status
= CS_PLAYING
;
595 static void __consumer_handle_eof(void)
599 if (ip_is_remote(ip
)) {
601 __consumer_drain_and_stop();
602 player_error("lost connection");
606 if (get_next(&filename
) == 0) {
608 ip
= ip_new(filename
);
609 producer_status
= PS_STOPPED
;
610 /* PS_STOPPED, CS_PLAYING */
613 if (producer_status
== PS_UNLOADED
) {
619 if (!change_sf(ip_get_sf(ip
), 0))
623 __consumer_drain_and_stop();
629 __consumer_drain_and_stop();
632 __player_status_changed();
635 static void *consumer_loop(void *arg
)
643 if (!consumer_running
)
646 if (consumer_status
== CS_PAUSED
|| consumer_status
== CS_STOPPED
) {
652 space
= op_buffer_space();
655 __consumer_position_update();
660 /* d_print("BS: %6d %3d\n", space, space * 1000 / (44100 * 2 * 2)); */
663 /* 25 ms is 4410 B */
665 __consumer_position_update();
671 size
= buffer_get_rpos(&rpos
);
674 if (producer_status
!= PS_PLAYING
) {
679 /* must recheck rpos */
680 size
= buffer_get_rpos(&rpos
);
682 /* OK. now it's safe to check if we are at EOF */
685 __consumer_handle_eof();
690 /* possible underrun */
692 __consumer_position_update();
694 /* d_print("possible underrun\n"); */
700 /* player_buffer and ip.eof were inconsistent */
706 soft_vol_scale(rpos
, &size
);
707 rc
= op_write(rpos
, size
);
709 d_print("op_write returned %d %s\n", rc
,
710 rc
== -1 ? strerror(errno
) : "");
714 consumer_status
= CS_STOPPED
;
730 static void *producer_loop(void *arg
)
733 /* number of chunks to fill
734 * too big => seeking is slow
735 * too small => underruns?
737 const int chunks
= 1;
738 int size
, nr_read
, i
;
742 if (!producer_running
)
745 if (producer_status
== PS_UNLOADED
||
746 producer_status
== PS_PAUSED
||
747 producer_status
== PS_STOPPED
|| ip_eof(ip
)) {
753 size
= buffer_get_wpos(&wpos
);
760 nr_read
= ip_read(ip
, wpos
, size
);
762 if (nr_read
!= -1 || errno
!= EAGAIN
) {
763 player_ip_error(nr_read
, "reading file %s",
764 ip_get_filename(ip
));
765 /* ip_read sets eof */
773 if (ip_metadata_changed(ip
))
776 /* buffer_fill with 0 count marks current chunk filled */
777 buffer_fill(nr_read
);
779 /* consumer handles EOF */
790 __producer_buffer_fill_update();
797 void player_load_plugins(void)
803 void player_init(const struct player_callbacks
*callbacks
)
806 #if defined(__linux__) || defined(__FreeBSD__)
809 pthread_attr_t
*attrp
= NULL
;
811 /* 1 s is 176400 B (0.168 MB)
814 buffer_nr_chunks
= 10 * 44100 * 16 / 8 * 2 / CHUNK_SIZE
;
817 player_cbs
= callbacks
;
819 #if defined(__linux__) || defined(__FreeBSD__)
820 rc
= pthread_attr_init(&attr
);
822 rc
= pthread_attr_setschedpolicy(&attr
, SCHED_RR
);
824 d_print("could not set real-time scheduling priority: %s\n", strerror(rc
));
826 struct sched_param param
;
828 d_print("using real-time scheduling\n");
829 param
.sched_priority
= sched_get_priority_max(SCHED_RR
);
830 d_print("setting priority to %d\n", param
.sched_priority
);
831 rc
= pthread_attr_setschedparam(&attr
, ¶m
);
837 rc
= pthread_create(&producer_thread
, NULL
, producer_loop
, NULL
);
840 rc
= pthread_create(&consumer_thread
, attrp
, consumer_loop
, NULL
);
842 d_print("could not create thread using real-time scheduling: %s\n", strerror(rc
));
843 rc
= pthread_create(&consumer_thread
, NULL
, consumer_loop
, NULL
);
847 /* update player_info.cont etc. */
849 __player_status_changed();
853 void player_exit(void)
858 consumer_running
= 0;
859 producer_running
= 0;
862 rc
= pthread_join(consumer_thread
, NULL
);
864 rc
= pthread_join(producer_thread
, NULL
);
870 void player_stop(void)
875 __player_status_changed();
879 void player_play(void)
884 if (producer_status
== PS_PLAYING
&& ip_is_remote(ip
)) {
885 /* seeking not allowed */
889 prebuffer
= consumer_status
== CS_STOPPED
;
891 if (producer_status
== PS_PLAYING
) {
893 if (consumer_status
!= CS_PLAYING
)
898 __player_status_changed();
899 if (consumer_status
== CS_PLAYING
&& prebuffer
)
904 void player_pause(void)
908 if (consumer_status
== CS_STOPPED
) {
910 if (producer_status
== PS_PLAYING
) {
912 if (consumer_status
!= CS_PLAYING
)
915 __player_status_changed();
916 if (consumer_status
== CS_PLAYING
)
922 if (ip
&& ip_is_remote(ip
)) {
923 /* pausing not allowed */
929 __player_status_changed();
933 void player_set_file(const char *filename
)
936 __producer_set_file(filename
);
937 if (producer_status
== PS_UNLOADED
) {
943 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
945 if (producer_status
== PS_UNLOADED
) {
949 change_sf(ip_get_sf(ip
), 1);
952 __player_status_changed();
953 if (producer_status
== PS_PLAYING
)
958 void player_play_file(const char *filename
)
961 __producer_set_file(filename
);
962 if (producer_status
== PS_UNLOADED
) {
970 /* PS_UNLOADED,PS_PLAYING */
971 if (producer_status
== PS_UNLOADED
) {
977 if (consumer_status
== CS_STOPPED
) {
979 if (consumer_status
== CS_STOPPED
)
982 change_sf(ip_get_sf(ip
), 1);
985 __player_status_changed();
986 if (producer_status
== PS_PLAYING
)
991 void player_seek(double offset
, int relative
)
994 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
995 double pos
, duration
, new_pos
;
998 pos
= (double)consumer_pos
/ (double)buffer_second_size();
999 duration
= ip_duration(ip
);
1002 d_print("can't seek\n");
1007 new_pos
= pos
+ offset
;
1011 /* seeking forward */
1012 if (new_pos
> duration
- 5.0)
1013 new_pos
= duration
- 5.0;
1016 if (new_pos
< pos
- 0.5) {
1017 /* must seek at least 0.5s */
1018 d_print("must seek at least 0.5s\n");
1025 if (new_pos
< 0.0) {
1026 d_print("seek offset negative\n");
1030 if (new_pos
> duration
) {
1031 d_print("seek offset too large\n");
1036 /* d_print("seeking %g/%g (%g from eof)\n", new_pos, duration, duration - new_pos); */
1037 rc
= ip_seek(ip
, new_pos
);
1039 /* d_print("doing op_drop after seek\n"); */
1042 consumer_pos
= new_pos
* buffer_second_size();
1043 soft_vol_pos
= consumer_pos
;
1044 __consumer_position_update();
1046 d_print("error: ip_seek returned %d\n", rc
);
1053 * change output plugin without stopping playback
1055 void player_set_op(const char *name
)
1061 /* drop needed because close drains the buffer */
1062 if (consumer_status
== CS_PAUSED
)
1065 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
)
1069 d_print("setting op to '%s'\n", name
);
1070 rc
= op_select(name
);
1072 /* first initialized plugin */
1073 d_print("selecting first initialized op\n");
1074 rc
= op_select_any();
1077 consumer_status
= CS_STOPPED
;
1080 player_op_error(rc
, "selecting output plugin '%s'", name
);
1085 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
1086 set_buffer_sf(ip_get_sf(ip
));
1087 rc
= op_open(buffer_sf
);
1089 consumer_status
= CS_STOPPED
;
1091 player_op_error(rc
, "opening audio device");
1095 if (consumer_status
== CS_PAUSED
)
1099 if (!op_get_volume(&l
, &r
))
1100 volume_update(l
, r
);
1105 char *player_get_op(void)
1107 return op_get_current();
1110 void player_set_buffer_chunks(unsigned int nr_chunks
)
1121 buffer_nr_chunks
= nr_chunks
;
1124 __player_status_changed();
1128 int player_get_buffer_chunks(void)
1130 return buffer_nr_chunks
;
1133 int player_get_fileinfo(const char *filename
, int *duration
,
1134 struct keyval
**comments
)
1136 struct input_plugin
*plug
;
1141 plug
= ip_new(filename
);
1142 if (ip_is_remote(plug
)) {
1143 *comments
= xnew0(struct keyval
, 1);
1154 rc
= -PLAYER_ERROR_NOT_SUPPORTED
;
1157 *duration
= ip_duration(plug
);
1158 rc
= ip_read_comments(plug
, comments
);
1163 int player_get_volume(int *left
, int *right
)
1168 rc
= op_get_volume(left
, right
);
1173 int player_set_volume(int left
, int right
)
1178 rc
= op_set_volume(left
, right
);
1180 volume_update(left
, right
);
1185 void player_set_soft_vol(int soft
)
1190 /* don't mess with soft_vol_pos if soft_vol is already true */
1192 soft_vol_pos
= consumer_pos
;
1193 op_set_soft_vol(soft
);
1194 if (!op_get_volume(&l
, &r
))
1195 volume_update(l
, r
);
1199 int player_set_op_option(unsigned int id
, const char *val
)
1206 rc
= op_set_option(id
, val
);
1207 __player_status_changed();
1212 int player_get_op_option(unsigned int id
, char **val
)
1217 rc
= op_get_option(id
, val
);
1222 int player_for_each_op_option(void (*callback
)(unsigned int id
, const char *key
))
1227 op_for_each_option(callback
);
1228 __player_status_changed();
1233 void player_dump_plugins(void)