1 /*
2  * Copyright 2008-2013 Various Authors
3  * Copyright 2004-2006 Timo Hirvonen
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "player.h"
20 #include "buffer.h"
21 #include "input.h"
22 #include "output.h"
23 #include "sf.h"
24 #include "op.h"
25 #include "utils.h"
26 #include "xmalloc.h"
27 #include "debug.h"
28 #include "compiler.h"
29 #include "options.h"
30 #include "mpris.h"
31 #include "cmus.h"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <pthread.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <sys/time.h>
39 #include <stdarg.h>
40 #include <math.h>
41 
42 const char * const player_status_names[] = {
43 	"stopped", "playing", "paused", NULL
44 };
45 
46 enum producer_status {
47 	PS_UNLOADED,
48 	PS_STOPPED,
49 	PS_PLAYING,
50 	PS_PAUSED
51 };
52 
53 enum consumer_status {
54 	CS_STOPPED,
55 	CS_PLAYING,
56 	CS_PAUSED
57 };
58 
59 /* protects player_info_priv and player_metadata */
60 static pthread_mutex_t player_info_mutex = CMUS_MUTEX_INITIALIZER;
61 struct player_info player_info;
62 char player_metadata[255 * 16 + 1];
63 static struct player_info player_info_priv = {
64 	.ti = NULL,
65 	.status = PLAYER_STATUS_STOPPED,
66 	.pos = 0,
67 	.current_bitrate = -1,
68 	.buffer_fill = 0,
69 	.buffer_size = 0,
70 	.error_msg = NULL,
71 	.file_changed = 0,
72 	.metadata_changed = 0,
73 	.status_changed = 0,
74 	.position_changed = 0,
75 	.buffer_fill_changed = 0,
76 };
77 
78 /* continue playing after track is finished? */
79 int player_cont = 1;
80 
81 /* continue playing after album is finished? */
82 int player_cont_album = 1;
83 
84 /* repeat current track forever? */
85 int player_repeat_current;
86 
87 enum replaygain replaygain;
88 int replaygain_limit = 1;
89 double replaygain_preamp = 0.0;
90 
91 int soft_vol;
92 int soft_vol_l;
93 int soft_vol_r;
94 
95 static sample_format_t buffer_sf;
96 static CHANNEL_MAP(buffer_channel_map);
97 
98 static pthread_t producer_thread;
99 static pthread_mutex_t producer_mutex = CMUS_MUTEX_INITIALIZER;
100 static pthread_cond_t producer_playing = CMUS_COND_INITIALIZER;
101 static int producer_running = 1;
102 static enum producer_status producer_status = PS_UNLOADED;
103 static struct input_plugin *ip = NULL;
104 
105 static pthread_t consumer_thread;
106 static pthread_mutex_t consumer_mutex = CMUS_MUTEX_INITIALIZER;
107 static pthread_cond_t consumer_playing = CMUS_COND_INITIALIZER;
108 static int consumer_running = 1;
109 static enum consumer_status consumer_status = CS_STOPPED;
110 static unsigned long consumer_pos = 0;
111 
112 /* for replay gain and soft vol
113  * usually same as consumer_pos, sometimes more than consumer_pos
114  */
115 static unsigned long scale_pos;
116 static double replaygain_scale = 1.0;
117 
118 /* locking {{{ */
119 
120 #define player_info_priv_lock() cmus_mutex_lock(&player_info_mutex)
121 #define player_info_priv_unlock() cmus_mutex_unlock(&player_info_mutex)
122 
123 #define producer_lock() cmus_mutex_lock(&producer_mutex)
124 #define producer_unlock() cmus_mutex_unlock(&producer_mutex)
125 
126 #define consumer_lock() cmus_mutex_lock(&consumer_mutex)
127 #define consumer_unlock() cmus_mutex_unlock(&consumer_mutex)
128 
129 #define player_lock() \
130 	do { \
131 		consumer_lock(); \
132 		producer_lock(); \
133 	} while (0)
134 
135 #define player_unlock() \
136 	do { \
137 		producer_unlock(); \
138 		consumer_unlock(); \
139 	} while (0)
140 
141 /* locking }}} */
142 
reset_buffer(void)143 static void reset_buffer(void)
144 {
145 	buffer_reset();
146 	consumer_pos = 0;
147 	scale_pos = 0;
148 	pthread_cond_broadcast(&producer_playing);
149 }
150 
set_buffer_sf(void)151 static void set_buffer_sf(void)
152 {
153 	buffer_sf = ip_get_sf(ip);
154 	ip_get_channel_map(ip, buffer_channel_map);
155 
156 	/* ip_read converts samples to this format */
157 	if (sf_get_channels(buffer_sf) <= 2 && sf_get_bits(buffer_sf) <= 16) {
158 		buffer_sf &= SF_RATE_MASK;
159 		buffer_sf |= sf_channels(2) | sf_bits(16) | sf_signed(1);
160 		buffer_sf |= sf_host_endian();
161 		channel_map_init_stereo(buffer_channel_map);
162 	}
163 }
164 
165 #define SOFT_VOL_SCALE 65536
166 
167 /* coefficients for volumes 0..99, for 100 65536 is used
168  * data copied from alsa-lib src/pcm/pcm_softvol.c
169  */
170 static const unsigned short soft_vol_db[100] = {
171 	0x0000, 0x0110, 0x011c, 0x012f, 0x013d, 0x0152, 0x0161, 0x0179,
172 	0x018a, 0x01a5, 0x01c1, 0x01d5, 0x01f5, 0x020b, 0x022e, 0x0247,
173 	0x026e, 0x028a, 0x02b6, 0x02d5, 0x0306, 0x033a, 0x035f, 0x0399,
174 	0x03c2, 0x0403, 0x0431, 0x0479, 0x04ac, 0x04fd, 0x0553, 0x058f,
175 	0x05ef, 0x0633, 0x069e, 0x06ea, 0x0761, 0x07b5, 0x083a, 0x0898,
176 	0x092c, 0x09cb, 0x0a3a, 0x0aeb, 0x0b67, 0x0c2c, 0x0cb6, 0x0d92,
177 	0x0e2d, 0x0f21, 0x1027, 0x10de, 0x1202, 0x12cf, 0x1414, 0x14f8,
178 	0x1662, 0x1761, 0x18f5, 0x1a11, 0x1bd3, 0x1db4, 0x1f06, 0x211d,
179 	0x2297, 0x24ec, 0x2690, 0x292a, 0x2aff, 0x2de5, 0x30fe, 0x332b,
180 	0x369f, 0x390d, 0x3ce6, 0x3f9b, 0x43e6, 0x46eb, 0x4bb3, 0x4f11,
181 	0x5466, 0x5a18, 0x5e19, 0x6472, 0x68ea, 0x6ffd, 0x74f8, 0x7cdc,
182 	0x826a, 0x8b35, 0x9499, 0x9b35, 0xa5ad, 0xad0b, 0xb8b7, 0xc0ee,
183 	0xcdf1, 0xd71a, 0xe59c, 0xefd3
184 };
185 
scale_sample_int16_t(int16_t * buf,int i,int vol,int swap)186 static inline void scale_sample_int16_t(int16_t *buf, int i, int vol, int swap)
187 {
188 	int32_t sample = swap ? (int16_t)swap_uint16(buf[i]) : buf[i];
189 
190 	if (sample < 0) {
191 		sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
192 		if (sample < INT16_MIN)
193 			sample = INT16_MIN;
194 	} else {
195 		sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
196 		if (sample > INT16_MAX)
197 			sample = INT16_MAX;
198 	}
199 	buf[i] = swap ? swap_uint16(sample) : sample;
200 }
201 
scale_sample_s24le(int32_t s,int vol)202 static inline int32_t scale_sample_s24le(int32_t s, int vol)
203 {
204 	int64_t sample = s;
205 	if (sample < 0) {
206 		sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
207 		if (sample < -0x800000)
208 			sample = -0x800000;
209 	} else {
210 		sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
211 		if (sample > 0x7fffff)
212 			sample = 0x7fffff;
213 	}
214 	return sample;
215 }
216 
scale_sample_int32_t(int32_t * buf,int i,int vol,int swap)217 static inline void scale_sample_int32_t(int32_t *buf, int i, int vol, int swap)
218 {
219 	int64_t sample = swap ? (int32_t)swap_uint32(buf[i]) : buf[i];
220 
221 	if (sample < 0) {
222 		sample = (sample * vol - SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
223 		if (sample < INT32_MIN)
224 			sample = INT32_MIN;
225 	} else {
226 		sample = (sample * vol + SOFT_VOL_SCALE / 2) / SOFT_VOL_SCALE;
227 		if (sample > INT32_MAX)
228 			sample = INT32_MAX;
229 	}
230 	buf[i] = swap ? swap_uint32(sample) : sample;
231 }
232 
sf_need_swap(sample_format_t sf)233 static inline int sf_need_swap(sample_format_t sf)
234 {
235 #ifdef WORDS_BIGENDIAN
236 	return !sf_get_bigendian(sf);
237 #else
238 	return sf_get_bigendian(sf);
239 #endif
240 }
241 
242 #define SCALE_SAMPLES(TYPE, buffer, count, l, r, swap)				\
243 {										\
244 	const int frames = count / sizeof(TYPE) / 2;				\
245 	TYPE *buf = (void *) buffer;						\
246 	int i;									\
247 	/* avoid underflowing -32768 to 32767 when scale is 65536 */		\
248 	if (l != SOFT_VOL_SCALE && r != SOFT_VOL_SCALE) {			\
249 		for (i = 0; i < frames; i++) {					\
250 			scale_sample_##TYPE(buf, i * 2, l, swap);		\
251 			scale_sample_##TYPE(buf, i * 2 + 1, r, swap);		\
252 		}								\
253 	} else if (l != SOFT_VOL_SCALE) {					\
254 		for (i = 0; i < frames; i++)					\
255 			scale_sample_##TYPE(buf, i * 2, l, swap);		\
256 	} else if (r != SOFT_VOL_SCALE) {					\
257 		for (i = 0; i < frames; i++)					\
258 			scale_sample_##TYPE(buf, i * 2 + 1, r, swap);		\
259 	}									\
260 }
261 
read_s24le(const char * buf)262 static inline int32_t read_s24le(const char *buf)
263 {
264 	const unsigned char *b = (const unsigned char *) buf;
265 	return b[0] | (b[1] << 8) | (((const signed char *) buf)[2] << 16);
266 }
267 
write_s24le(char * buf,int32_t x)268 static inline void write_s24le(char *buf, int32_t x)
269 {
270 	unsigned char *b = (unsigned char *) buf;
271 	b[0] = x;
272 	b[1] = x >> 8;
273 	b[2] = x >> 16;
274 }
275 
scale_samples_s24le(char * buf,unsigned int count,int l,int r)276 static void scale_samples_s24le(char *buf, unsigned int count, int l, int r)
277 {
278 	int frames = count / 3 / 2;
279 	if (l != SOFT_VOL_SCALE && r != SOFT_VOL_SCALE) {
280 		while (frames--) {
281 			write_s24le(buf, scale_sample_s24le(read_s24le(buf), l));
282 			buf += 3;
283 			write_s24le(buf, scale_sample_s24le(read_s24le(buf), r));
284 			buf += 3;
285 		}
286 	} else if (l != SOFT_VOL_SCALE) {
287 		while (frames--) {
288 			write_s24le(buf, scale_sample_s24le(read_s24le(buf), l));
289 			buf += 3 * 2;
290 		}
291 	} else if (r != SOFT_VOL_SCALE) {
292 		buf += 3;
293 		while (frames--) {
294 			write_s24le(buf, scale_sample_s24le(read_s24le(buf), r));
295 			buf += 3 * 2;
296 		}
297 	}
298 }
299 
scale_samples(char * buffer,unsigned int * countp)300 static void scale_samples(char *buffer, unsigned int *countp)
301 {
302 	unsigned int count = *countp;
303 	int ch, bits, l, r;
304 
305 	BUG_ON(scale_pos < consumer_pos);
306 
307 	if (consumer_pos != scale_pos) {
308 		unsigned int offs = scale_pos - consumer_pos;
309 
310 		if (offs >= count)
311 			return;
312 		buffer += offs;
313 		count -= offs;
314 	}
315 	scale_pos += count;
316 
317 	if (replaygain_scale == 1.0 && soft_vol_l == 100 && soft_vol_r == 100)
318 		return;
319 
320 	ch = sf_get_channels(buffer_sf);
321 	bits = sf_get_bits(buffer_sf);
322 	if (ch != 2 || (bits != 16 && bits != 24 && bits != 32))
323 		return;
324 
325 	l = SOFT_VOL_SCALE;
326 	r = SOFT_VOL_SCALE;
327 	if (soft_vol && soft_vol_l != 100)
328 		l = soft_vol_db[soft_vol_l];
329 	if (soft_vol && soft_vol_r != 100)
330 		r = soft_vol_db[soft_vol_r];
331 
332 	l *= replaygain_scale;
333 	r *= replaygain_scale;
334 
335 	switch (bits) {
336 	case 16:
337 		SCALE_SAMPLES(int16_t, buffer, count, l, r, sf_need_swap(buffer_sf));
338 		break;
339 	case 24:
340 		if (likely(!sf_get_bigendian(buffer_sf)))
341 			scale_samples_s24le(buffer, count, l, r);
342 		break;
343 	case 32:
344 		SCALE_SAMPLES(int32_t, buffer, count, l, r, sf_need_swap(buffer_sf));
345 		break;
346 	}
347 }
348 
update_rg_scale(void)349 static void update_rg_scale(void)
350 {
351 	double gain, peak, db, scale, limit;
352 
353 	replaygain_scale = 1.0;
354 	if (!player_info_priv.ti || !replaygain)
355 		return;
356 
357 	if (replaygain == RG_TRACK || replaygain == RG_TRACK_PREFERRED) {
358 		gain = player_info_priv.ti->rg_track_gain;
359 		peak = player_info_priv.ti->rg_track_peak;
360 	} else {
361 		gain = player_info_priv.ti->rg_album_gain;
362 		peak = player_info_priv.ti->rg_album_peak;
363 	}
364 
365 	if (isnan(gain)) {
366 		if (replaygain == RG_TRACK_PREFERRED) {
367 			gain = player_info_priv.ti->rg_album_gain;
368 			peak = player_info_priv.ti->rg_album_peak;
369 		} else if (replaygain == RG_ALBUM_PREFERRED) {
370 			gain = player_info_priv.ti->rg_track_gain;
371 			peak = player_info_priv.ti->rg_track_peak;
372 		}
373 	}
374 
375 	if (isnan(gain)) {
376 		d_print("gain not available\n");
377 		return;
378 	}
379 	if (isnan(peak)) {
380 		d_print("peak not available, defaulting to 1\n");
381 		peak = 1;
382 	}
383 	if (peak < 0.05) {
384 		d_print("peak (%g) is too small\n", peak);
385 		return;
386 	}
387 
388 	db = replaygain_preamp + gain;
389 
390 	scale = pow(10.0, db / 20.0);
391 	replaygain_scale = scale;
392 	limit = 1.0 / peak;
393 	if (replaygain_limit && !isnan(peak)) {
394 		if (replaygain_scale > limit)
395 			replaygain_scale = limit;
396 	}
397 
398 	d_print("gain = %f, peak = %f, db = %f, scale = %f, limit = %f, replaygain_scale = %f\n",
399 			gain, peak, db, scale, limit, replaygain_scale);
400 }
401 
buffer_second_size(void)402 static inline unsigned int buffer_second_size(void)
403 {
404 	return sf_get_second_size(buffer_sf);
405 }
406 
407 /* updating player status {{{ */
408 
_file_changed(struct track_info * ti)409 static inline void _file_changed(struct track_info *ti)
410 {
411 	player_info_priv_lock();
412 	if (player_info_priv.ti)
413 		track_info_unref(player_info_priv.ti);
414 
415 	player_info_priv.ti = ti;
416 	update_rg_scale();
417 	player_metadata[0] = 0;
418 	player_info_priv.file_changed = 1;
419 	player_info_priv_unlock();
420 }
421 
file_changed(struct track_info * ti)422 static inline void file_changed(struct track_info *ti)
423 {
424 	if (ti) {
425 		d_print("file: %s\n", ti->filename);
426 	} else {
427 		d_print("unloaded\n");
428 	}
429 	_file_changed(ti);
430 }
431 
metadata_changed(void)432 static inline void metadata_changed(void)
433 {
434 	struct keyval *comments;
435 	int rc;
436 
437 	player_info_priv_lock();
438 	if (ip_get_metadata(ip)) {
439 		d_print("metadata changed: %s\n", ip_get_metadata(ip));
440 		memcpy(player_metadata, ip_get_metadata(ip), 255 * 16 + 1);
441 	}
442 
443 	rc = ip_read_comments(ip, &comments);
444 	if (!rc) {
445 		if (player_info_priv.ti->comments)
446 			keyvals_free(player_info_priv.ti->comments);
447 		track_info_set_comments(player_info_priv.ti, comments);
448 	}
449 
450 	player_info_priv.metadata_changed = 1;
451 	player_info_priv_unlock();
452 }
453 
player_error(const char * msg)454 static void player_error(const char *msg)
455 {
456 	player_info_priv_lock();
457 	player_info_priv.status = (enum player_status)consumer_status;
458 	player_info_priv.pos = 0;
459 	player_info_priv.current_bitrate = -1;
460 	player_info_priv.buffer_fill = buffer_get_filled_chunks();
461 	player_info_priv.buffer_size = buffer_nr_chunks;
462 	player_info_priv.status_changed = 1;
463 
464 	free(player_info_priv.error_msg);
465 	player_info_priv.error_msg = xstrdup(msg);
466 	player_info_priv_unlock();
467 
468 	d_print("ERROR: '%s'\n", msg);
469 }
470 
player_ip_error(int rc,const char * format,...)471 static void CMUS_FORMAT(2, 3) player_ip_error(int rc, const char *format, ...)
472 {
473 	char buffer[1024];
474 	va_list ap;
475 	char *msg;
476 	int save = errno;
477 
478 	va_start(ap, format);
479 	vsnprintf(buffer, sizeof(buffer), format, ap);
480 	va_end(ap);
481 
482 	errno = save;
483 	msg = ip_get_error_msg(ip, rc, buffer);
484 	player_error(msg);
485 	free(msg);
486 }
487 
player_op_error(int rc,const char * format,...)488 static void CMUS_FORMAT(2, 3) player_op_error(int rc, const char *format, ...)
489 {
490 	char buffer[1024];
491 	va_list ap;
492 	char *msg;
493 	int save = errno;
494 
495 	va_start(ap, format);
496 	vsnprintf(buffer, sizeof(buffer), format, ap);
497 	va_end(ap);
498 
499 	errno = save;
500 	msg = op_get_error_msg(rc, buffer);
501 	player_error(msg);
502 	free(msg);
503 }
504 
505 /*
506  * buffer-fill changed
507  */
_producer_buffer_fill_update(void)508 static void _producer_buffer_fill_update(void)
509 {
510 	int fill;
511 
512 	player_info_priv_lock();
513 	fill = buffer_get_filled_chunks();
514 	if (fill != player_info_priv.buffer_fill) {
515 /* 		d_print("\n"); */
516 		player_info_priv.buffer_fill = fill;
517 		player_info_priv.buffer_fill_changed = 1;
518 	}
519 	player_info_priv_unlock();
520 }
521 
522 /*
523  * playing position changed
524  */
_consumer_position_update(void)525 static void _consumer_position_update(void)
526 {
527 	static unsigned int old_pos = -1;
528 	unsigned int pos = 0;
529 	long bitrate;
530 
531 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
532 		pos = consumer_pos / buffer_second_size();
533 	if (pos != old_pos) {
534 		old_pos = pos;
535 
536 		player_info_priv_lock();
537 		player_info_priv.pos = pos;
538 
539 		if (show_current_bitrate) {
540 			bitrate = ip_current_bitrate(ip);
541 			if (bitrate != -1)
542 				player_info_priv.current_bitrate = bitrate;
543 		}
544 		player_info_priv.position_changed = 1;
545 		player_info_priv_unlock();
546 	}
547 }
548 
549 /*
550  * something big happened (stopped/paused/unpaused...)
551  */
_player_status_changed(void)552 static void _player_status_changed(void)
553 {
554 	unsigned int pos = 0;
555 
556 /* 	d_print("\n"); */
557 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
558 		pos = consumer_pos / buffer_second_size();
559 
560 	player_info_priv_lock();
561 	player_info_priv.status = (enum player_status)consumer_status;
562 	player_info_priv.pos = pos;
563 	player_info_priv.current_bitrate = -1;
564 	player_info_priv.buffer_fill = buffer_get_filled_chunks();
565 	player_info_priv.buffer_size = buffer_nr_chunks;
566 	player_info_priv.status_changed = 1;
567 	player_info_priv_unlock();
568 }
569 
570 /* updating player status }}} */
571 
_prebuffer(void)572 static void _prebuffer(void)
573 {
574 	int limit_chunks;
575 
576 	BUG_ON(producer_status != PS_PLAYING);
577 	if (ip_is_remote(ip)) {
578 		limit_chunks = buffer_nr_chunks;
579 	} else {
580 		int limit_ms, limit_size;
581 
582 		limit_ms = 250;
583 		limit_size = limit_ms * buffer_second_size() / 1000;
584 		limit_chunks = limit_size / CHUNK_SIZE;
585 		if (limit_chunks < 1)
586 			limit_chunks = 1;
587 	}
588 	while (1) {
589 		int nr_read, size, filled;
590 		char *wpos;
591 
592 		filled = buffer_get_filled_chunks();
593 /* 		d_print("PREBUF: %2d / %2d\n", filled, limit_chunks); */
594 
595 		/* not fatal */
596 		//BUG_ON(filled > limit_chunks);
597 
598 		if (filled >= limit_chunks)
599 			break;
600 
601 		size = buffer_get_wpos(&wpos);
602 		nr_read = ip_read(ip, wpos, size);
603 		if (nr_read < 0) {
604 			if (nr_read == -1 && errno == EAGAIN)
605 				continue;
606 			player_ip_error(nr_read, "reading file %s", ip_get_filename(ip));
607 			/* ip_read sets eof */
608 			nr_read = 0;
609 		}
610 		if (ip_metadata_changed(ip))
611 			metadata_changed();
612 
613 		/* buffer_fill with 0 count marks current chunk filled */
614 		buffer_fill(nr_read);
615 
616 		_producer_buffer_fill_update();
617 		if (nr_read == 0) {
618 			/* EOF */
619 			break;
620 		}
621 	}
622 }
623 
624 /* setting producer status {{{ */
625 
_producer_status_update(enum producer_status status)626 static void _producer_status_update(enum producer_status status)
627 {
628 	producer_status =  status;
629 	pthread_cond_broadcast(&producer_playing);
630 }
631 
_producer_play(void)632 static void _producer_play(void)
633 {
634 	if (producer_status == PS_UNLOADED) {
635 		struct track_info *ti;
636 
637 		if ((ti = cmus_get_next_track())) {
638 			int rc;
639 
640 			ip = ip_new(ti->filename);
641 			rc = ip_open(ip);
642 			if (rc) {
643 				player_ip_error(rc, "opening file `%s'", ti->filename);
644 				ip_delete(ip);
645 				track_info_unref(ti);
646 				file_changed(NULL);
647 			} else {
648 				ip_setup(ip);
649 				_producer_status_update(PS_PLAYING);
650 				file_changed(ti);
651 			}
652 		}
653 	} else if (producer_status == PS_PLAYING) {
654 		if (ip_seek(ip, 0.0) == 0) {
655 			reset_buffer();
656 		}
657 	} else if (producer_status == PS_STOPPED) {
658 		int rc;
659 
660 		rc = ip_open(ip);
661 		if (rc) {
662 			player_ip_error(rc, "opening file `%s'", ip_get_filename(ip));
663 			ip_delete(ip);
664 			_producer_status_update(PS_UNLOADED);
665 		} else {
666 			ip_setup(ip);
667 			_producer_status_update(PS_PLAYING);
668 		}
669 	} else if (producer_status == PS_PAUSED) {
670 		_producer_status_update(PS_PLAYING);
671 	}
672 }
673 
_producer_stop(void)674 static void _producer_stop(void)
675 {
676 	if (producer_status == PS_PLAYING || producer_status == PS_PAUSED) {
677 		ip_close(ip);
678 		_producer_status_update(PS_STOPPED);
679 		reset_buffer();
680 	}
681 }
682 
_producer_unload(void)683 static void _producer_unload(void)
684 {
685 	_producer_stop();
686 	if (producer_status == PS_STOPPED) {
687 		ip_delete(ip);
688 		_producer_status_update(PS_UNLOADED);
689 	}
690 }
691 
_producer_pause(void)692 static void _producer_pause(void)
693 {
694 	if (producer_status == PS_PLAYING) {
695 		_producer_status_update(PS_PAUSED);
696 	} else if (producer_status == PS_PAUSED) {
697 		_producer_status_update(PS_PLAYING);
698 	}
699 }
700 
_producer_set_file(struct track_info * ti)701 static void _producer_set_file(struct track_info *ti)
702 {
703 	_producer_unload();
704 	ip = ip_new(ti->filename);
705 	_producer_status_update(PS_STOPPED);
706 	file_changed(ti);
707 }
708 
709 /* setting producer status }}} */
710 
711 /* setting consumer status {{{ */
712 
_consumer_status_update(enum consumer_status status)713 static void _consumer_status_update(enum consumer_status status)
714 {
715 	consumer_status = status;
716 	pthread_cond_broadcast(&consumer_playing);
717 }
718 
_consumer_play(void)719 static void _consumer_play(void)
720 {
721 	if (consumer_status == CS_PLAYING) {
722 		op_drop();
723 	} else if (consumer_status == CS_STOPPED) {
724 		int rc;
725 
726 		set_buffer_sf();
727 		rc = op_open(buffer_sf, buffer_channel_map);
728 		if (rc) {
729 			player_op_error(rc, "opening audio device");
730 		} else {
731 			_consumer_status_update(CS_PLAYING);
732 		}
733 	} else if (consumer_status == CS_PAUSED) {
734 		op_unpause();
735 		_consumer_status_update(CS_PLAYING);
736 	}
737 }
738 
_consumer_drain_and_stop(void)739 static void _consumer_drain_and_stop(void)
740 {
741 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
742 		op_close();
743 		_consumer_status_update(CS_STOPPED);
744 	}
745 }
746 
_consumer_stop(void)747 static void _consumer_stop(void)
748 {
749 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
750 		op_drop();
751 		op_close();
752 		_consumer_status_update(CS_STOPPED);
753 	}
754 }
755 
_consumer_pause(void)756 static void _consumer_pause(void)
757 {
758 	if (consumer_status == CS_PLAYING) {
759 		op_pause();
760 		_consumer_status_update(CS_PAUSED);
761 	} else if (consumer_status == CS_PAUSED) {
762 		op_unpause();
763 		_consumer_status_update(CS_PLAYING);
764 	}
765 }
766 
767 /* setting consumer status }}} */
768 
change_sf(int drop)769 static int change_sf(int drop)
770 {
771 	int old_sf = buffer_sf;
772 	CHANNEL_MAP(old_channel_map);
773 	channel_map_copy(old_channel_map, buffer_channel_map);
774 
775 	set_buffer_sf();
776 	if (buffer_sf != old_sf || !channel_map_equal(buffer_channel_map, old_channel_map, sf_get_channels(buffer_sf))) {
777 		/* reopen */
778 		int rc;
779 
780 		if (drop)
781 			op_drop();
782 		op_close();
783 		rc = op_open(buffer_sf, buffer_channel_map);
784 		if (rc) {
785 			player_op_error(rc, "opening audio device");
786 			_consumer_status_update(CS_STOPPED);
787 			_producer_stop();
788 			return rc;
789 		}
790 	} else if (consumer_status == CS_PAUSED) {
791 		op_drop();
792 		op_unpause();
793 	}
794 	_consumer_status_update(CS_PLAYING);
795 	return 0;
796 }
797 
_consumer_handle_eof(void)798 static void _consumer_handle_eof(void)
799 {
800 	struct track_info *ti;
801 
802 	if (ip_is_remote(ip)) {
803 		_producer_stop();
804 		_consumer_drain_and_stop();
805 		player_error("lost connection");
806 		return;
807 	}
808 
809 	if (player_info_priv.ti)
810 		player_info_priv.ti->play_count++;
811 
812 	if (player_repeat_current) {
813 		if (player_cont) {
814 			ip_seek(ip, 0);
815 			reset_buffer();
816 		} else {
817 			_producer_stop();
818 			_consumer_drain_and_stop();
819 		}
820 		_player_status_changed();
821 		return;
822 	}
823 
824 	if ((ti = cmus_get_next_track())) {
825 		_producer_unload();
826 		ip = ip_new(ti->filename);
827 		_producer_status_update(PS_STOPPED);
828 		/* PS_STOPPED, CS_PLAYING */
829 		if (player_cont && (player_cont_album == 1 || strcmp(player_info_priv.ti->album,ti->album) == 0)) {
830 			_producer_play();
831 			if (producer_status == PS_UNLOADED) {
832 				_consumer_stop();
833 				track_info_unref(ti);
834 				file_changed(NULL);
835 			} else {
836 				/* PS_PLAYING */
837 				file_changed(ti);
838 				if (!change_sf(0))
839 					_prebuffer();
840 			}
841 		} else {
842 			_consumer_drain_and_stop();
843 			file_changed(ti);
844 		}
845 	} else {
846 		_producer_unload();
847 		_consumer_drain_and_stop();
848 		file_changed(NULL);
849 	}
850 	_player_status_changed();
851 }
852 
consumer_loop(void * arg)853 static void *consumer_loop(void *arg)
854 {
855 	while (1) {
856 		int rc, space;
857 		int size;
858 		char *rpos;
859 
860 		consumer_lock();
861 		if (!consumer_running)
862 			break;
863 
864 		if (consumer_status == CS_PAUSED || consumer_status == CS_STOPPED) {
865 			pthread_cond_wait(&consumer_playing, &consumer_mutex);
866 			consumer_unlock();
867 			continue;
868 		}
869 		space = op_buffer_space();
870 		if (space < 0) {
871 			d_print("op_buffer_space returned %d %s\n", space,
872 					space == -1 ? strerror(errno) : "");
873 
874 			/* try to reopen */
875 			op_close();
876 			_consumer_status_update(CS_STOPPED);
877 			_consumer_play();
878 
879 			consumer_unlock();
880 			continue;
881 		}
882 /* 		d_print("BS: %6d %3d\n", space, space * 1000 / (44100 * 2 * 2)); */
883 
884 		while (1) {
885 			if (space == 0) {
886 				_consumer_position_update();
887 				consumer_unlock();
888 				ms_sleep(25);
889 				break;
890 			}
891 			size = buffer_get_rpos(&rpos);
892 			if (size == 0) {
893 				producer_lock();
894 				if (producer_status != PS_PLAYING) {
895 					producer_unlock();
896 					consumer_unlock();
897 					break;
898 				}
899 				/* must recheck rpos */
900 				size = buffer_get_rpos(&rpos);
901 				if (size == 0) {
902 					/* OK. now it's safe to check if we are at EOF */
903 					if (ip_eof(ip)) {
904 						/* EOF */
905 						_consumer_handle_eof();
906 						producer_unlock();
907 						consumer_unlock();
908 						break;
909 					} else {
910 						/* possible underrun */
911 						producer_unlock();
912 						_consumer_position_update();
913 						consumer_unlock();
914 /* 						d_print("possible underrun\n"); */
915 						ms_sleep(10);
916 						break;
917 					}
918 				}
919 
920 				/* player_buffer and ip.eof were inconsistent */
921 				producer_unlock();
922 			}
923 			if (size > space)
924 				size = space;
925 			if (soft_vol || replaygain)
926 				scale_samples(rpos, (unsigned int *)&size);
927 			rc = op_write(rpos, size);
928 			if (rc < 0) {
929 				d_print("op_write returned %d %s\n", rc,
930 						rc == -1 ? strerror(errno) : "");
931 
932 				/* try to reopen */
933 				op_close();
934 				_consumer_status_update(CS_STOPPED);
935 				_consumer_play();
936 
937 				consumer_unlock();
938 				break;
939 			}
940 			buffer_consume(rc);
941 			consumer_pos += rc;
942 			space -= rc;
943 		}
944 	}
945 	_consumer_stop();
946 	consumer_unlock();
947 	return NULL;
948 }
949 
producer_loop(void * arg)950 static void *producer_loop(void *arg)
951 {
952 	while (1) {
953 		/* number of chunks to fill
954 		 * too big   => seeking is slow
955 		 * too small => underruns?
956 		 */
957 		const int chunks = 1;
958 		int size, nr_read, i;
959 		char *wpos;
960 
961 		producer_lock();
962 		if (!producer_running)
963 			break;
964 
965 		if (producer_status == PS_UNLOADED ||
966 		    producer_status == PS_PAUSED ||
967 		    producer_status == PS_STOPPED || ip_eof(ip)) {
968 			pthread_cond_wait(&producer_playing, &producer_mutex);
969 			producer_unlock();
970 			continue;
971 		}
972 		for (i = 0; ; i++) {
973 			size = buffer_get_wpos(&wpos);
974 			if (size == 0) {
975 				/* buffer is full */
976 				producer_unlock();
977 				ms_sleep(50);
978 				break;
979 			}
980 			nr_read = ip_read(ip, wpos, size);
981 			if (nr_read < 0) {
982 				if (nr_read != -1 || errno != EAGAIN) {
983 					player_ip_error(nr_read, "reading file %s",
984 							ip_get_filename(ip));
985 					/* ip_read sets eof */
986 					nr_read = 0;
987 				} else {
988 					producer_unlock();
989 					ms_sleep(50);
990 					break;
991 				}
992 			}
993 			if (ip_metadata_changed(ip))
994 				metadata_changed();
995 
996 			/* buffer_fill with 0 count marks current chunk filled */
997 			buffer_fill(nr_read);
998 			if (nr_read == 0) {
999 				/* consumer handles EOF */
1000 				producer_unlock();
1001 				ms_sleep(50);
1002 				break;
1003 			}
1004 			if (i == chunks) {
1005 				producer_unlock();
1006 				/* don't sleep! */
1007 				break;
1008 			}
1009 		}
1010 		_producer_buffer_fill_update();
1011 	}
1012 	_producer_unload();
1013 	producer_unlock();
1014 	return NULL;
1015 }
1016 
player_init(void)1017 void player_init(void)
1018 {
1019 	int rc;
1020 #ifdef REALTIME_SCHEDULING
1021 	pthread_attr_t attr;
1022 #endif
1023 	pthread_attr_t *attrp = NULL;
1024 
1025 	/*  1 s is 176400 B (0.168 MB)
1026 	 * 10 s is 1.68 MB
1027 	 */
1028 	buffer_nr_chunks = 10 * 44100 * 16 / 8 * 2 / CHUNK_SIZE;
1029 	buffer_init();
1030 
1031 #ifdef REALTIME_SCHEDULING
1032 	rc = pthread_attr_init(&attr);
1033 	BUG_ON(rc);
1034 	rc = pthread_attr_setschedpolicy(&attr, SCHED_RR);
1035 	if (rc) {
1036 		d_print("could not set real-time scheduling priority: %s\n", strerror(rc));
1037 	} else {
1038 		struct sched_param param;
1039 
1040 		d_print("using real-time scheduling\n");
1041 		param.sched_priority = sched_get_priority_max(SCHED_RR);
1042 		d_print("setting priority to %d\n", param.sched_priority);
1043 		rc = pthread_attr_setschedparam(&attr, &param);
1044 		BUG_ON(rc);
1045 		attrp = &attr;
1046 	}
1047 #endif
1048 
1049 	rc = pthread_create(&producer_thread, NULL, producer_loop, NULL);
1050 	BUG_ON(rc);
1051 
1052 	rc = pthread_create(&consumer_thread, attrp, consumer_loop, NULL);
1053 	if (rc && attrp) {
1054 		d_print("could not create thread using real-time scheduling: %s\n", strerror(rc));
1055 		rc = pthread_create(&consumer_thread, NULL, consumer_loop, NULL);
1056 	}
1057 	BUG_ON(rc);
1058 
1059 	/* update player_info_priv.cont etc. */
1060 	player_lock();
1061 	_player_status_changed();
1062 	player_unlock();
1063 }
1064 
player_exit(void)1065 void player_exit(void)
1066 {
1067 	int rc;
1068 
1069 	player_lock();
1070 	consumer_running = 0;
1071 	pthread_cond_broadcast(&consumer_playing);
1072 	producer_running = 0;
1073 	pthread_cond_broadcast(&producer_playing);
1074 	player_unlock();
1075 
1076 	rc = pthread_join(consumer_thread, NULL);
1077 	BUG_ON(rc);
1078 	rc = pthread_join(producer_thread, NULL);
1079 	BUG_ON(rc);
1080 	buffer_free();
1081 }
1082 
player_stop(void)1083 void player_stop(void)
1084 {
1085 	player_lock();
1086 	_consumer_stop();
1087 	_producer_stop();
1088 	_player_status_changed();
1089 	player_unlock();
1090 }
1091 
player_play(void)1092 void player_play(void)
1093 {
1094 	int prebuffer;
1095 
1096 	player_lock();
1097 	if (producer_status == PS_PLAYING && ip_is_remote(ip)) {
1098 		/* seeking not allowed */
1099 		player_unlock();
1100 		return;
1101 	}
1102 	prebuffer = consumer_status == CS_STOPPED;
1103 	_producer_play();
1104 	if (producer_status == PS_PLAYING) {
1105 		_consumer_play();
1106 		if (consumer_status != CS_PLAYING)
1107 			_producer_stop();
1108 	} else {
1109 		_consumer_stop();
1110 	}
1111 	_player_status_changed();
1112 	if (consumer_status == CS_PLAYING && prebuffer)
1113 		_prebuffer();
1114 	player_unlock();
1115 }
1116 
player_pause(void)1117 void player_pause(void)
1118 {
1119 	if (ip && ip_is_remote(ip) && consumer_status == CS_PLAYING) {
1120 		/* pausing not allowed */
1121 		player_stop();
1122 		return;
1123 	}
1124 	player_lock();
1125 
1126 	if (consumer_status == CS_STOPPED) {
1127 		_producer_play();
1128 		if (producer_status == PS_PLAYING) {
1129 			_consumer_play();
1130 			if (consumer_status != CS_PLAYING)
1131 				_producer_stop();
1132 		}
1133 		_player_status_changed();
1134 		if (consumer_status == CS_PLAYING)
1135 			_prebuffer();
1136 		player_unlock();
1137 		return;
1138 	}
1139 
1140 	_producer_pause();
1141 	_consumer_pause();
1142 	_player_status_changed();
1143 	player_unlock();
1144 }
1145 
player_pause_playback(void)1146 void player_pause_playback(void)
1147 {
1148 	if (consumer_status == CS_PLAYING)
1149 		player_pause();
1150 }
1151 
player_set_file(struct track_info * ti)1152 void player_set_file(struct track_info *ti)
1153 {
1154 	player_lock();
1155 	_producer_set_file(ti);
1156 	if (producer_status == PS_UNLOADED) {
1157 		_consumer_stop();
1158 		goto out;
1159 	}
1160 
1161 	/* PS_STOPPED */
1162 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1163 		op_drop();
1164 		_producer_play();
1165 		if (producer_status == PS_UNLOADED) {
1166 			_consumer_stop();
1167 			goto out;
1168 		}
1169 		change_sf(1);
1170 	}
1171 out:
1172 	_player_status_changed();
1173 	if (producer_status == PS_PLAYING)
1174 		_prebuffer();
1175 	player_unlock();
1176 }
1177 
player_play_file(struct track_info * ti)1178 void player_play_file(struct track_info *ti)
1179 {
1180 	player_lock();
1181 	_producer_set_file(ti);
1182 	if (producer_status == PS_UNLOADED) {
1183 		_consumer_stop();
1184 		goto out;
1185 	}
1186 
1187 	/* PS_STOPPED */
1188 	_producer_play();
1189 
1190 	/* PS_UNLOADED,PS_PLAYING */
1191 	if (producer_status == PS_UNLOADED) {
1192 		_consumer_stop();
1193 		goto out;
1194 	}
1195 
1196 	/* PS_PLAYING */
1197 	if (consumer_status == CS_STOPPED) {
1198 		_consumer_play();
1199 		if (consumer_status == CS_STOPPED)
1200 			_producer_stop();
1201 	} else {
1202 		op_drop();
1203 		change_sf(1);
1204 	}
1205 out:
1206 	_player_status_changed();
1207 	if (producer_status == PS_PLAYING)
1208 		_prebuffer();
1209 	player_unlock();
1210 }
1211 
player_file_changed(struct track_info * ti)1212 void player_file_changed(struct track_info *ti)
1213 {
1214 	_file_changed(ti);
1215 }
1216 
player_seek(double offset,int relative,int start_playing)1217 void player_seek(double offset, int relative, int start_playing)
1218 {
1219 	int stopped = 0;
1220 	player_lock();
1221 	if (consumer_status == CS_STOPPED) {
1222 		stopped = 1;
1223 		_producer_play();
1224 		if (producer_status == PS_PLAYING) {
1225 			_consumer_play();
1226 			if (consumer_status != CS_PLAYING) {
1227 				_producer_stop();
1228 				player_unlock();
1229 				return;
1230 			} else
1231 				_player_status_changed();
1232 		}
1233 	}
1234 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1235 		double pos, duration, new_pos;
1236 		int rc;
1237 
1238 		pos = (double)consumer_pos / (double)buffer_second_size();
1239 		duration = ip_duration(ip);
1240 		if (duration < 0) {
1241 			/* can't seek */
1242 			d_print("can't seek\n");
1243 			player_unlock();
1244 			return;
1245 		}
1246 		if (relative) {
1247 			new_pos = pos + offset;
1248 			if (new_pos < 0.0)
1249 				new_pos = 0.0;
1250 			if (offset > 0.0) {
1251 				/* seeking forward */
1252 				if (new_pos > duration) {
1253 					player_unlock();
1254 					cmus_next();
1255 					return;
1256 				}
1257 				if (new_pos < 0.0)
1258 					new_pos = 0.0;
1259 				if (new_pos < pos - 0.5) {
1260 					/* must seek at least 0.5s */
1261 					d_print("must seek at least 0.5s\n");
1262 					player_unlock();
1263 					return;
1264 				}
1265 			}
1266 		} else {
1267 			new_pos = offset;
1268 			if (new_pos < 0.0) {
1269 				d_print("seek offset negative\n");
1270 				player_unlock();
1271 				return;
1272 			}
1273 			if (new_pos > duration - 5.0) {
1274 				new_pos = duration - 5.0;
1275 				if (new_pos < 0.0)
1276 					new_pos = 0.0;
1277 			}
1278 		}
1279 /* 		d_print("seeking %g/%g (%g from eof)\n", new_pos, duration, duration - new_pos); */
1280 		rc = ip_seek(ip, new_pos);
1281 		if (rc == 0) {
1282 			d_print("doing op_drop after seek\n");
1283 			op_drop();
1284 			reset_buffer();
1285 			consumer_pos = new_pos * buffer_second_size();
1286 			scale_pos = consumer_pos;
1287 			_consumer_position_update();
1288 			if (stopped && !start_playing) {
1289 				_producer_pause();
1290 				_consumer_pause();
1291 				_player_status_changed();
1292 			}
1293 		} else {
1294 			player_ip_error(rc, "seeking in file %s", ip_get_filename(ip));
1295 			d_print("error: ip_seek returned %d\n", rc);
1296 		}
1297 	}
1298 	mpris_seeked();
1299 	player_unlock();
1300 }
1301 
1302 /*
1303  * change output plugin without stopping playback
1304  */
player_set_op(const char * name)1305 void player_set_op(const char *name)
1306 {
1307 	int rc;
1308 
1309 	player_lock();
1310 
1311 	/* drop needed because close drains the buffer */
1312 	if (consumer_status == CS_PAUSED)
1313 		op_drop();
1314 
1315 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
1316 		op_close();
1317 
1318 	if (name) {
1319 		d_print("setting op to '%s'\n", name);
1320 		rc = op_select(name);
1321 	} else {
1322 		/* first initialized plugin */
1323 		d_print("selecting first initialized op\n");
1324 		rc = op_select_any();
1325 	}
1326 	if (rc) {
1327 		_consumer_status_update(CS_STOPPED);
1328 
1329 		_producer_stop();
1330 		if (name)
1331 			player_op_error(rc, "selecting output plugin '%s'", name);
1332 		else
1333 			player_op_error(rc, "selecting any output plugin");
1334 		player_unlock();
1335 		return;
1336 	}
1337 
1338 	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
1339 		set_buffer_sf();
1340 		rc = op_open(buffer_sf, buffer_channel_map);
1341 		if (rc) {
1342 			_consumer_status_update(CS_STOPPED);
1343 			_producer_stop();
1344 			player_op_error(rc, "opening audio device");
1345 			player_unlock();
1346 			return;
1347 		}
1348 		if (consumer_status == CS_PAUSED)
1349 			op_pause();
1350 	}
1351 
1352 	player_unlock();
1353 }
1354 
player_set_buffer_chunks(unsigned int nr_chunks)1355 void player_set_buffer_chunks(unsigned int nr_chunks)
1356 {
1357 	player_lock();
1358 	_producer_stop();
1359 	_consumer_stop();
1360 
1361 	buffer_nr_chunks = nr_chunks;
1362 	buffer_init();
1363 
1364 	_player_status_changed();
1365 	player_unlock();
1366 }
1367 
player_get_buffer_chunks(void)1368 int player_get_buffer_chunks(void)
1369 {
1370 	return buffer_nr_chunks;
1371 }
1372 
player_set_soft_volume(int l,int r)1373 void player_set_soft_volume(int l, int r)
1374 {
1375 	consumer_lock();
1376 	soft_vol_l = l;
1377 	soft_vol_r = r;
1378 	consumer_unlock();
1379 }
1380 
player_set_soft_vol(int soft)1381 void player_set_soft_vol(int soft)
1382 {
1383 	consumer_lock();
1384 	/* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1385 	if (!soft_vol && !replaygain)
1386 		scale_pos = consumer_pos;
1387 	soft_vol = soft;
1388 	consumer_unlock();
1389 }
1390 
calc_vol(int val,int old,int max_vol,unsigned int flags)1391 static int calc_vol(int val, int old, int max_vol, unsigned int flags)
1392 {
1393 	if (flags & VF_RELATIVE) {
1394 		if (flags & VF_PERCENTAGE)
1395 			val = scale_from_percentage(val, max_vol);
1396 		val += old;
1397 	} else if (flags & VF_PERCENTAGE) {
1398 		val = scale_from_percentage(val, max_vol);
1399 	}
1400 	return clamp(val, 0, max_vol);
1401 }
1402 
player_set_vol(int l,int lf,int r,int rf)1403 int player_set_vol(int l, int lf, int r, int rf)
1404 {
1405 	int rc = OP_ERROR_SUCCESS;
1406 	if (soft_vol) {
1407 		l = calc_vol(l, soft_vol_l, 100, lf);
1408 		r = calc_vol(r, soft_vol_r, 100, rf);
1409 		player_set_soft_volume(l, r);
1410 	} else {
1411 		mixer_read_volume();
1412 		l = calc_vol(l, volume_l, volume_max, lf);
1413 		r = calc_vol(r, volume_r, volume_max, rf);
1414 		rc = mixer_set_volume(l, r);
1415 		mixer_read_volume();
1416 	}
1417 	return rc;
1418 }
1419 
player_set_rg(enum replaygain rg)1420 void player_set_rg(enum replaygain rg)
1421 {
1422 	player_lock();
1423 	/* don't mess with scale_pos if soft_vol or replaygain is already enabled */
1424 	if (!soft_vol && !replaygain)
1425 		scale_pos = consumer_pos;
1426 	replaygain = rg;
1427 
1428 	player_info_priv_lock();
1429 	update_rg_scale();
1430 	player_info_priv_unlock();
1431 
1432 	player_unlock();
1433 }
1434 
player_set_rg_limit(int limit)1435 void player_set_rg_limit(int limit)
1436 {
1437 	player_lock();
1438 	replaygain_limit = limit;
1439 
1440 	player_info_priv_lock();
1441 	update_rg_scale();
1442 	player_info_priv_unlock();
1443 
1444 	player_unlock();
1445 }
1446 
player_set_rg_preamp(double db)1447 void player_set_rg_preamp(double db)
1448 {
1449 	player_lock();
1450 	replaygain_preamp = db;
1451 
1452 	player_info_priv_lock();
1453 	update_rg_scale();
1454 	player_info_priv_unlock();
1455 
1456 	player_unlock();
1457 }
1458 
player_info_snapshot(void)1459 void player_info_snapshot(void)
1460 {
1461 	player_info_priv_lock();
1462 
1463 	free(player_info.error_msg);
1464 	if (player_info.ti)
1465 		track_info_unref(player_info.ti);
1466 	memcpy(&player_info, &player_info_priv, sizeof(player_info));
1467 	if (player_info.ti)
1468 		track_info_ref(player_info.ti);
1469 
1470 	player_info_priv.file_changed = 0;
1471 	player_info_priv.metadata_changed = 0;
1472 	player_info_priv.status_changed = 0;
1473 	player_info_priv.position_changed = 0;
1474 	player_info_priv.buffer_fill_changed = 0;
1475 	player_info_priv.error_msg = NULL;
1476 
1477 	player_info_priv_unlock();
1478 }
1479 
player_metadata_lock(void)1480 void player_metadata_lock(void)
1481 {
1482 	cmus_mutex_lock(&player_info_mutex);
1483 }
1484 
player_metadata_unlock(void)1485 void player_metadata_unlock(void)
1486 {
1487 	cmus_mutex_unlock(&player_info_mutex);
1488 }
1489