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 unsigned int consumer_pos
= 0;
88 /* usually same as consumer_pos, sometimes less than consumer_pos */
89 static unsigned 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
, unsigned int *countp
)
166 unsigned int count
= *countp
;
167 int ch
, bits
, l
, r
, i
;
169 BUG_ON(soft_vol_pos
< consumer_pos
);
171 if (consumer_pos
!= soft_vol_pos
) {
172 unsigned int offs
= soft_vol_pos
- consumer_pos
;
179 soft_vol_pos
+= count
;
180 buf
= (signed short *)buffer
;
182 if (soft_vol_l
== 100 && soft_vol_r
== 100)
185 ch
= sf_get_channels(buffer_sf
);
186 bits
= sf_get_bits(buffer_sf
);
187 if (ch
!= 2 || bits
!= 16)
192 if (soft_vol_l
!= 100)
193 l
= soft_vol_db
[soft_vol_l
];
194 if (soft_vol_r
!= 100)
195 r
= soft_vol_db
[soft_vol_r
];
197 for (i
= 0; i
< count
/ 4; i
++) {
198 scale_sample(buf
, i
* 2, l
);
199 scale_sample(buf
, i
* 2 + 1, r
);
203 static inline unsigned int buffer_second_size(void)
205 return sf_get_second_size(buffer_sf
);
208 static inline int get_next(struct track_info
**ti
)
210 return player_cbs
->get_next(ti
);
213 /* updating player status {{{ */
215 static inline void file_changed(struct track_info
*ti
)
219 track_info_unref(player_info
.ti
);
223 d_print("file: %s\n", ti
->filename
);
225 d_print("unloaded\n");
227 player_info
.metadata
[0] = 0;
228 player_info
.file_changed
= 1;
229 player_info_unlock();
232 static inline void metadata_changed(void)
235 d_print("metadata changed: %s\n", ip_get_metadata(ip
));
236 memcpy(player_info
.metadata
, ip_get_metadata(ip
), 255 * 16 + 1);
237 player_info
.metadata_changed
= 1;
238 player_info_unlock();
241 static inline void volume_update(int left
, int right
)
243 if (player_info
.vol_left
== left
&& player_info
.vol_right
== right
)
247 player_info
.vol_left
= left
;
248 player_info
.vol_right
= right
;
249 player_info
.vol_changed
= 1;
250 player_info_unlock();
253 static void player_error(const char *msg
)
256 player_info
.status
= consumer_status
;
258 player_info
.buffer_fill
= buffer_get_filled_chunks();
259 player_info
.buffer_size
= buffer_nr_chunks
;
260 player_info
.status_changed
= 1;
262 free(player_info
.error_msg
);
263 player_info
.error_msg
= xstrdup(msg
);
264 player_info_unlock();
266 d_print("ERROR: '%s'\n", msg
);
269 static void __FORMAT(2, 3) player_ip_error(int rc
, const char *format
, ...)
276 va_start(ap
, format
);
277 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
281 msg
= ip_get_error_msg(ip
, rc
, buffer
);
286 static void __FORMAT(2, 3) player_op_error(int rc
, const char *format
, ...)
293 va_start(ap
, format
);
294 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
298 msg
= op_get_error_msg(rc
, buffer
);
303 /* FIXME: don't poll */
304 static void mixer_check(void)
306 static struct timeval old_t
= { 0L, 0L };
311 gettimeofday(&t
, NULL
);
312 usec
= t
.tv_usec
- old_t
.tv_usec
;
313 sec
= t
.tv_sec
- old_t
.tv_sec
;
315 /* multiplying sec with 1e6 can overflow */
322 if (!op_get_volume(&l
, &r
))
327 * buffer-fill changed
329 static void __producer_buffer_fill_update(void)
334 fill
= buffer_get_filled_chunks();
335 if (fill
!= player_info
.buffer_fill
) {
337 player_info
.buffer_fill
= fill
;
338 player_info
.buffer_fill_changed
= 1;
340 player_info_unlock();
344 * playing position changed
346 static void __consumer_position_update(void)
348 static unsigned int old_pos
= -1;
349 unsigned int pos
= 0;
351 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
)
352 pos
= consumer_pos
/ buffer_second_size();
353 if (pos
!= old_pos
) {
358 player_info
.pos
= pos
;
359 player_info
.position_changed
= 1;
360 player_info_unlock();
365 * something big happened (stopped/paused/unpaused...)
367 static void __player_status_changed(void)
369 unsigned int pos
= 0;
372 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
)
373 pos
= consumer_pos
/ buffer_second_size();
376 player_info
.status
= consumer_status
;
377 player_info
.pos
= pos
;
378 player_info
.buffer_fill
= buffer_get_filled_chunks();
379 player_info
.buffer_size
= buffer_nr_chunks
;
380 player_info
.status_changed
= 1;
381 player_info_unlock();
384 /* updating player status }}} */
386 static void __prebuffer(void)
390 BUG_ON(producer_status
!= PS_PLAYING
);
391 if (ip_is_remote(ip
)) {
392 limit_chunks
= buffer_nr_chunks
;
394 int limit_ms
, limit_size
;
397 limit_size
= limit_ms
* buffer_second_size() / 1000;
398 limit_chunks
= limit_size
/ CHUNK_SIZE
;
399 if (limit_chunks
< 1)
403 int nr_read
, size
, filled
;
406 filled
= buffer_get_filled_chunks();
407 /* d_print("PREBUF: %2d / %2d\n", filled, limit_chunks); */
410 //BUG_ON(filled > limit_chunks);
412 if (filled
>= limit_chunks
)
415 size
= buffer_get_wpos(&wpos
);
416 nr_read
= ip_read(ip
, wpos
, size
);
418 if (nr_read
== -1 && errno
== EAGAIN
)
420 player_ip_error(nr_read
, "reading file %s", ip_get_filename(ip
));
421 /* ip_read sets eof */
424 if (ip_metadata_changed(ip
))
427 /* buffer_fill with 0 count marks current chunk filled */
428 buffer_fill(nr_read
);
430 __producer_buffer_fill_update();
438 /* setting producer status {{{ */
440 static void __producer_play(void)
442 if (producer_status
== PS_UNLOADED
) {
443 struct track_info
*ti
;
445 if (get_next(&ti
) == 0) {
448 ip
= ip_new(ti
->filename
);
451 player_ip_error(rc
, "opening file `%s'", ti
->filename
);
453 track_info_unref(ti
);
457 producer_status
= PS_PLAYING
;
461 } else if (producer_status
== PS_PLAYING
) {
462 if (ip_seek(ip
, 0.0) == 0) {
465 } else if (producer_status
== PS_STOPPED
) {
470 player_ip_error(rc
, "opening file `%s'", ip_get_filename(ip
));
472 producer_status
= PS_UNLOADED
;
475 producer_status
= PS_PLAYING
;
477 } else if (producer_status
== PS_PAUSED
) {
478 producer_status
= PS_PLAYING
;
482 static void __producer_stop(void)
484 if (producer_status
== PS_PLAYING
|| producer_status
== PS_PAUSED
) {
486 producer_status
= PS_STOPPED
;
491 static void __producer_unload(void)
494 if (producer_status
== PS_STOPPED
) {
496 producer_status
= PS_UNLOADED
;
500 static void __producer_pause(void)
502 if (producer_status
== PS_PLAYING
) {
503 producer_status
= PS_PAUSED
;
504 } else if (producer_status
== PS_PAUSED
) {
505 producer_status
= PS_PLAYING
;
509 static void __producer_set_file(struct track_info
*ti
)
512 ip
= ip_new(ti
->filename
);
513 producer_status
= PS_STOPPED
;
517 /* setting producer status }}} */
519 /* setting consumer status {{{ */
521 static void __consumer_play(void)
523 if (consumer_status
== CS_PLAYING
) {
525 } else if (consumer_status
== CS_STOPPED
) {
528 set_buffer_sf(ip_get_sf(ip
));
529 rc
= op_open(buffer_sf
);
531 player_op_error(rc
, "opening audio device");
533 consumer_status
= CS_PLAYING
;
535 } else if (consumer_status
== CS_PAUSED
) {
537 consumer_status
= CS_PLAYING
;
541 static void __consumer_drain_and_stop(void)
543 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
545 consumer_status
= CS_STOPPED
;
549 static void __consumer_stop(void)
551 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
554 consumer_status
= CS_STOPPED
;
558 static void __consumer_pause(void)
560 if (consumer_status
== CS_PLAYING
) {
562 consumer_status
= CS_PAUSED
;
563 } else if (consumer_status
== CS_PAUSED
) {
565 consumer_status
= CS_PLAYING
;
569 /* setting consumer status }}} */
571 static int change_sf(sample_format_t sf
, int drop
)
573 int old_sf
= buffer_sf
;
576 if (buffer_sf
!= old_sf
) {
583 rc
= op_open(buffer_sf
);
585 player_op_error(rc
, "opening audio device");
586 consumer_status
= CS_STOPPED
;
590 } else if (consumer_status
== CS_PAUSED
) {
594 consumer_status
= CS_PLAYING
;
598 static void __consumer_handle_eof(void)
600 struct track_info
*ti
;
602 if (ip_is_remote(ip
)) {
604 __consumer_drain_and_stop();
605 player_error("lost connection");
609 if (get_next(&ti
) == 0) {
611 ip
= ip_new(ti
->filename
);
612 producer_status
= PS_STOPPED
;
613 /* PS_STOPPED, CS_PLAYING */
616 if (producer_status
== PS_UNLOADED
) {
618 track_info_unref(ti
);
623 if (!change_sf(ip_get_sf(ip
), 0))
627 __consumer_drain_and_stop();
632 __consumer_drain_and_stop();
635 __player_status_changed();
638 static void *consumer_loop(void *arg
)
646 if (!consumer_running
)
649 if (consumer_status
== CS_PAUSED
|| consumer_status
== CS_STOPPED
) {
655 space
= op_buffer_space();
658 __consumer_position_update();
663 /* d_print("BS: %6d %3d\n", space, space * 1000 / (44100 * 2 * 2)); */
666 /* 25 ms is 4410 B */
668 __consumer_position_update();
674 size
= buffer_get_rpos(&rpos
);
677 if (producer_status
!= PS_PLAYING
) {
682 /* must recheck rpos */
683 size
= buffer_get_rpos(&rpos
);
685 /* OK. now it's safe to check if we are at EOF */
688 __consumer_handle_eof();
693 /* possible underrun */
695 __consumer_position_update();
697 /* d_print("possible underrun\n"); */
703 /* player_buffer and ip.eof were inconsistent */
709 soft_vol_scale(rpos
, &size
);
710 rc
= op_write(rpos
, size
);
712 d_print("op_write returned %d %s\n", rc
,
713 rc
== -1 ? strerror(errno
) : "");
717 consumer_status
= CS_STOPPED
;
733 static void *producer_loop(void *arg
)
736 /* number of chunks to fill
737 * too big => seeking is slow
738 * too small => underruns?
740 const int chunks
= 1;
741 int size
, nr_read
, i
;
745 if (!producer_running
)
748 if (producer_status
== PS_UNLOADED
||
749 producer_status
== PS_PAUSED
||
750 producer_status
== PS_STOPPED
|| ip_eof(ip
)) {
756 size
= buffer_get_wpos(&wpos
);
763 nr_read
= ip_read(ip
, wpos
, size
);
765 if (nr_read
!= -1 || errno
!= EAGAIN
) {
766 player_ip_error(nr_read
, "reading file %s",
767 ip_get_filename(ip
));
768 /* ip_read sets eof */
776 if (ip_metadata_changed(ip
))
779 /* buffer_fill with 0 count marks current chunk filled */
780 buffer_fill(nr_read
);
782 /* consumer handles EOF */
793 __producer_buffer_fill_update();
800 void player_load_plugins(void)
806 void player_init(const struct player_callbacks
*callbacks
)
809 #if defined(__linux__) || defined(__FreeBSD__)
812 pthread_attr_t
*attrp
= NULL
;
814 /* 1 s is 176400 B (0.168 MB)
817 buffer_nr_chunks
= 10 * 44100 * 16 / 8 * 2 / CHUNK_SIZE
;
820 player_cbs
= callbacks
;
822 #if defined(__linux__) || defined(__FreeBSD__)
823 rc
= pthread_attr_init(&attr
);
825 rc
= pthread_attr_setschedpolicy(&attr
, SCHED_RR
);
827 d_print("could not set real-time scheduling priority: %s\n", strerror(rc
));
829 struct sched_param param
;
831 d_print("using real-time scheduling\n");
832 param
.sched_priority
= sched_get_priority_max(SCHED_RR
);
833 d_print("setting priority to %d\n", param
.sched_priority
);
834 rc
= pthread_attr_setschedparam(&attr
, ¶m
);
840 rc
= pthread_create(&producer_thread
, NULL
, producer_loop
, NULL
);
843 rc
= pthread_create(&consumer_thread
, attrp
, consumer_loop
, NULL
);
845 d_print("could not create thread using real-time scheduling: %s\n", strerror(rc
));
846 rc
= pthread_create(&consumer_thread
, NULL
, consumer_loop
, NULL
);
850 /* update player_info.cont etc. */
852 __player_status_changed();
856 void player_exit(void)
861 consumer_running
= 0;
862 producer_running
= 0;
865 rc
= pthread_join(consumer_thread
, NULL
);
867 rc
= pthread_join(producer_thread
, NULL
);
873 void player_stop(void)
878 __player_status_changed();
882 void player_play(void)
887 if (producer_status
== PS_PLAYING
&& ip_is_remote(ip
)) {
888 /* seeking not allowed */
892 prebuffer
= consumer_status
== CS_STOPPED
;
894 if (producer_status
== PS_PLAYING
) {
896 if (consumer_status
!= CS_PLAYING
)
901 __player_status_changed();
902 if (consumer_status
== CS_PLAYING
&& prebuffer
)
907 void player_pause(void)
911 if (consumer_status
== CS_STOPPED
) {
913 if (producer_status
== PS_PLAYING
) {
915 if (consumer_status
!= CS_PLAYING
)
918 __player_status_changed();
919 if (consumer_status
== CS_PLAYING
)
925 if (ip
&& ip_is_remote(ip
)) {
926 /* pausing not allowed */
932 __player_status_changed();
936 void player_set_file(struct track_info
*ti
)
939 __producer_set_file(ti
);
940 if (producer_status
== PS_UNLOADED
) {
946 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
948 if (producer_status
== PS_UNLOADED
) {
952 change_sf(ip_get_sf(ip
), 1);
955 __player_status_changed();
956 if (producer_status
== PS_PLAYING
)
961 void player_play_file(struct track_info
*ti
)
964 __producer_set_file(ti
);
965 if (producer_status
== PS_UNLOADED
) {
973 /* PS_UNLOADED,PS_PLAYING */
974 if (producer_status
== PS_UNLOADED
) {
980 if (consumer_status
== CS_STOPPED
) {
982 if (consumer_status
== CS_STOPPED
)
985 change_sf(ip_get_sf(ip
), 1);
988 __player_status_changed();
989 if (producer_status
== PS_PLAYING
)
994 void player_seek(double offset
, int relative
)
997 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
998 double pos
, duration
, new_pos
;
1001 pos
= (double)consumer_pos
/ (double)buffer_second_size();
1002 duration
= ip_duration(ip
);
1005 d_print("can't seek\n");
1010 new_pos
= pos
+ offset
;
1014 /* seeking forward */
1015 if (new_pos
> duration
- 5.0)
1016 new_pos
= duration
- 5.0;
1019 if (new_pos
< pos
- 0.5) {
1020 /* must seek at least 0.5s */
1021 d_print("must seek at least 0.5s\n");
1028 if (new_pos
< 0.0) {
1029 d_print("seek offset negative\n");
1033 if (new_pos
> duration
) {
1034 d_print("seek offset too large\n");
1039 /* d_print("seeking %g/%g (%g from eof)\n", new_pos, duration, duration - new_pos); */
1040 rc
= ip_seek(ip
, new_pos
);
1042 /* d_print("doing op_drop after seek\n"); */
1045 consumer_pos
= new_pos
* buffer_second_size();
1046 soft_vol_pos
= consumer_pos
;
1047 __consumer_position_update();
1049 d_print("error: ip_seek returned %d\n", rc
);
1056 * change output plugin without stopping playback
1058 void player_set_op(const char *name
)
1064 /* drop needed because close drains the buffer */
1065 if (consumer_status
== CS_PAUSED
)
1068 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
)
1072 d_print("setting op to '%s'\n", name
);
1073 rc
= op_select(name
);
1075 /* first initialized plugin */
1076 d_print("selecting first initialized op\n");
1077 rc
= op_select_any();
1080 consumer_status
= CS_STOPPED
;
1083 player_op_error(rc
, "selecting output plugin '%s'", name
);
1088 if (consumer_status
== CS_PLAYING
|| consumer_status
== CS_PAUSED
) {
1089 set_buffer_sf(ip_get_sf(ip
));
1090 rc
= op_open(buffer_sf
);
1092 consumer_status
= CS_STOPPED
;
1094 player_op_error(rc
, "opening audio device");
1098 if (consumer_status
== CS_PAUSED
)
1102 if (!op_get_volume(&l
, &r
))
1103 volume_update(l
, r
);
1108 char *player_get_op(void)
1110 return op_get_current();
1113 void player_set_buffer_chunks(unsigned int nr_chunks
)
1124 buffer_nr_chunks
= nr_chunks
;
1127 __player_status_changed();
1131 int player_get_buffer_chunks(void)
1133 return buffer_nr_chunks
;
1136 int player_get_fileinfo(const char *filename
, int *duration
,
1137 struct keyval
**comments
)
1139 struct input_plugin
*plug
;
1144 plug
= ip_new(filename
);
1145 if (ip_is_remote(plug
)) {
1146 *comments
= xnew0(struct keyval
, 1);
1157 rc
= -PLAYER_ERROR_NOT_SUPPORTED
;
1160 *duration
= ip_duration(plug
);
1161 rc
= ip_read_comments(plug
, comments
);
1166 int player_get_volume(int *left
, int *right
)
1171 rc
= op_get_volume(left
, right
);
1176 int player_set_volume(int left
, int right
)
1181 rc
= op_set_volume(left
, right
);
1183 volume_update(left
, right
);
1188 void player_set_soft_vol(int soft
)
1193 /* don't mess with soft_vol_pos if soft_vol is already true */
1195 soft_vol_pos
= consumer_pos
;
1196 op_set_soft_vol(soft
);
1197 if (!op_get_volume(&l
, &r
))
1198 volume_update(l
, r
);
1202 int player_set_op_option(unsigned int id
, const char *val
)
1209 rc
= op_set_option(id
, val
);
1210 __player_status_changed();
1215 int player_get_op_option(unsigned int id
, char **val
)
1220 rc
= op_get_option(id
, val
);
1225 int player_for_each_op_option(void (*callback
)(unsigned int id
, const char *key
))
1230 op_for_each_option(callback
);
1231 __player_status_changed();
1236 void player_dump_plugins(void)