volume.c 11.6 KB
Newer Older
Warren Dukes's avatar
Warren Dukes committed
1
/* the Music Player Daemon (MPD)
2
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
Warren Dukes's avatar
Warren Dukes committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * This project's homepage is: http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "volume.h"

#include "conf.h"
#include "log.h"
22
#include "player_control.h"
23
#include "utils.h"
24
#include "os_compat.h"
Warren Dukes's avatar
Warren Dukes committed
25

Max Kellermann's avatar
Max Kellermann committed
26 27
#include "../config.h"

28
#ifdef HAVE_OSS
Warren Dukes's avatar
Warren Dukes committed
29 30 31 32 33 34
#include <sys/soundcard.h>
#endif
#ifdef HAVE_ALSA
#include <alsa/asoundlib.h>
#endif

35 36 37
#define VOLUME_MIXER_TYPE_SOFTWARE		0
#define VOLUME_MIXER_TYPE_OSS			1
#define VOLUME_MIXER_TYPE_ALSA			2
Warren Dukes's avatar
Warren Dukes committed
38

39 40 41
#define VOLUME_MIXER_SOFTWARE_DEFAULT		""
#define VOLUME_MIXER_OSS_DEFAULT		"/dev/mixer"
#define VOLUME_MIXER_ALSA_DEFAULT		"default"
42
#define VOLUME_MIXER_ALSA_CONTROL_DEFAULT	"PCM"
43
#define SW_VOLUME_STATE                         "sw_volume: "
Warren Dukes's avatar
Warren Dukes committed
44

45
#ifdef HAVE_OSS
46 47 48 49 50 51 52 53 54 55 56 57
#define VOLUME_MIXER_TYPE_DEFAULT               VOLUME_MIXER_TYPE_OSS
#define VOLUME_MIXER_DEVICE_DEFAULT             VOLUME_MIXER_OSS_DEFAULT
#else
#ifdef HAVE_ALSA
#define VOLUME_MIXER_TYPE_DEFAULT               VOLUME_MIXER_TYPE_ALSA
#define VOLUME_MIXER_DEVICE_DEFAULT             VOLUME_MIXER_ALSA_DEFAULT
#else
#define VOLUME_MIXER_TYPE_DEFAULT               VOLUME_MIXER_TYPE_SOFTWARE
#define VOLUME_MIXER_DEVICE_DEFAULT             VOLUME_MIXER_SOFTWARE_DEFAULT
#endif
#endif

58
static int volume_mixerType = VOLUME_MIXER_TYPE_DEFAULT;
Max Kellermann's avatar
Max Kellermann committed
59
static const char *volume_mixerDevice = VOLUME_MIXER_DEVICE_DEFAULT;
Warren Dukes's avatar
Warren Dukes committed
60

61
static int volume_softwareSet = 100;
Warren Dukes's avatar
Warren Dukes committed
62

63
#ifdef HAVE_OSS
64
static int volume_ossFd = -1;
65
static int volume_ossControl = SOUND_MIXER_PCM;
Warren Dukes's avatar
Warren Dukes committed
66 67 68
#endif

#ifdef HAVE_ALSA
69
static snd_mixer_t *volume_alsaMixerHandle;
Avuton Olrich's avatar
Avuton Olrich committed
70
static snd_mixer_elem_t *volume_alsaElem;
71 72 73
static long volume_alsaMin;
static long volume_alsaMax;
static int volume_alsaSet = -1;
Warren Dukes's avatar
Warren Dukes committed
74 75
#endif

76
#ifdef HAVE_OSS
77

78 79
#include <alloca.h> /* only alloca user in mpd atm, may change ... */

80 81
static void closeOssMixer(void)
{
Avuton Olrich's avatar
Avuton Olrich committed
82
	while (close(volume_ossFd) && errno == EINTR) ;
83 84 85
	volume_ossFd = -1;
}

Max Kellermann's avatar
Max Kellermann committed
86
static int prepOssMixer(const char *device)
Avuton Olrich's avatar
Avuton Olrich committed
87 88
{
	ConfigParam *param;
Warren Dukes's avatar
Warren Dukes committed
89

Avuton Olrich's avatar
Avuton Olrich committed
90 91
	if ((volume_ossFd = open(device, O_RDONLY)) < 0) {
		WARNING("unable to open oss mixer \"%s\"\n", device);
Warren Dukes's avatar
Warren Dukes committed
92 93 94
		return -1;
	}

95
	if ((param = getConfigParam(CONF_MIXER_CONTROL))) {
Max Kellermann's avatar
Max Kellermann committed
96
		const char *labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
97
		int i;
98
		int devmask = 0;
Warren Dukes's avatar
Warren Dukes committed
99

Avuton Olrich's avatar
Avuton Olrich committed
100
		if (ioctl(volume_ossFd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) {
101
			WARNING("errors getting read_devmask for oss mixer\n");
102
			closeOssMixer();
Warren Dukes's avatar
Warren Dukes committed
103 104 105
			return -1;
		}

Avuton Olrich's avatar
Avuton Olrich committed
106
		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
107 108 109
			ssize_t len = strlen(labels[i]);
			char *duplicated = alloca(len + 1);

Warren Dukes's avatar
Warren Dukes committed
110
			/* eliminate spaces at the end */
111 112 113 114 115
			memcpy(duplicated, labels[i], len + 1);
			len -= 2;
			while (len >= 0 && duplicated[len] == ' ')
				duplicated[len--] = '\0';
			if (strcasecmp(duplicated, param->value) == 0)
Warren Dukes's avatar
Warren Dukes committed
116 117 118
				break;
		}

Avuton Olrich's avatar
Avuton Olrich committed
119
		if (i >= SOUND_MIXER_NRDEVICES) {
120
			WARNING("mixer control \"%s\" not found at line %i\n",
Avuton Olrich's avatar
Avuton Olrich committed
121
				param->value, param->line);
122
			closeOssMixer();
Warren Dukes's avatar
Warren Dukes committed
123
			return -1;
Avuton Olrich's avatar
Avuton Olrich committed
124
		} else if (!((1 << i) & devmask)) {
125
			WARNING("mixer control \"%s\" not usable at line %i\n",
Avuton Olrich's avatar
Avuton Olrich committed
126
				param->value, param->line);
127
			closeOssMixer();
Warren Dukes's avatar
Warren Dukes committed
128 129 130 131 132 133 134 135 136
			return -1;
		}

		volume_ossControl = i;
	}

	return 0;
}

137 138 139 140 141
static int ensure_oss_open(void)
{
	if ((volume_ossFd < 0 && prepOssMixer(volume_mixerDevice) < 0))
		return -1;
	return 0;
Warren Dukes's avatar
Warren Dukes committed
142 143
}

Avuton Olrich's avatar
Avuton Olrich committed
144 145
static int getOssVolumeLevel(void)
{
Warren Dukes's avatar
Warren Dukes committed
146 147
	int left, right, level;

148 149 150
	if (ensure_oss_open() < 0)
		return -1;

Avuton Olrich's avatar
Avuton Olrich committed
151
	if (ioctl(volume_ossFd, MIXER_READ(volume_ossControl), &level) < 0) {
152
		closeOssMixer();
153
		WARNING("unable to read volume\n");
Warren Dukes's avatar
Warren Dukes committed
154 155 156 157 158 159
		return -1;
	}

	left = level & 0xff;
	right = (level & 0xff00) >> 8;

Avuton Olrich's avatar
Avuton Olrich committed
160
	if (left != right) {
161
		WARNING("volume for left and right is not the same, \"%i\" and "
Avuton Olrich's avatar
Avuton Olrich committed
162
			"\"%i\"\n", left, right);
Warren Dukes's avatar
Warren Dukes committed
163 164 165 166 167
	}

	return left;
}

168
static int changeOssVolumeLevel(int change, int rel)
Avuton Olrich's avatar
Avuton Olrich committed
169
{
Warren Dukes's avatar
Warren Dukes committed
170 171 172 173 174
	int current;
	int new;
	int level;

	if (rel) {
175
		if ((current = getOssVolumeLevel()) < 0)
Warren Dukes's avatar
Warren Dukes committed
176 177
			return -1;

Avuton Olrich's avatar
Avuton Olrich committed
178
		new = current + change;
179 180 181 182
	} else {
		if (ensure_oss_open() < 0)
			return -1;
		new = change;
Warren Dukes's avatar
Warren Dukes committed
183 184
	}

Avuton Olrich's avatar
Avuton Olrich committed
185 186 187 188
	if (new < 0)
		new = 0;
	else if (new > 100)
		new = 100;
Warren Dukes's avatar
Warren Dukes committed
189 190 191

	level = (new << 8) + new;

Avuton Olrich's avatar
Avuton Olrich committed
192
	if (ioctl(volume_ossFd, MIXER_WRITE(volume_ossControl), &level) < 0) {
193
		closeOssMixer();
Warren Dukes's avatar
Warren Dukes committed
194 195 196 197 198 199 200 201
		return -1;
	}

	return 0;
}
#endif

#ifdef HAVE_ALSA
Avuton Olrich's avatar
Avuton Olrich committed
202 203
static void closeAlsaMixer(void)
{
204 205 206 207
	snd_mixer_close(volume_alsaMixerHandle);
	volume_alsaMixerHandle = NULL;
}

Max Kellermann's avatar
Max Kellermann committed
208
static int prepAlsaMixer(const char *card)
Avuton Olrich's avatar
Avuton Olrich committed
209
{
Warren Dukes's avatar
Warren Dukes committed
210
	int err;
Avuton Olrich's avatar
Avuton Olrich committed
211
	snd_mixer_elem_t *elem;
Max Kellermann's avatar
Max Kellermann committed
212
	const char *controlName = VOLUME_MIXER_ALSA_CONTROL_DEFAULT;
Avuton Olrich's avatar
Avuton Olrich committed
213
	ConfigParam *param;
Warren Dukes's avatar
Warren Dukes committed
214

Avuton Olrich's avatar
Avuton Olrich committed
215
	err = snd_mixer_open(&volume_alsaMixerHandle, 0);
216 217
	snd_config_update_free_global();
	if (err < 0) {
Avuton Olrich's avatar
Avuton Olrich committed
218
		WARNING("problems opening alsa mixer: %s\n", snd_strerror(err));
Warren Dukes's avatar
Warren Dukes committed
219 220
		return -1;
	}
221

Avuton Olrich's avatar
Avuton Olrich committed
222
	if ((err = snd_mixer_attach(volume_alsaMixerHandle, card)) < 0) {
223
		closeAlsaMixer();
Avuton Olrich's avatar
Avuton Olrich committed
224
		WARNING("problems attaching alsa mixer: %s\n",
Warren Dukes's avatar
Warren Dukes committed
225 226 227
			snd_strerror(err));
		return -1;
	}
228

Avuton Olrich's avatar
Avuton Olrich committed
229 230 231
	if ((err =
	     snd_mixer_selem_register(volume_alsaMixerHandle, NULL,
				      NULL)) < 0) {
232
		closeAlsaMixer();
233
		WARNING("problems snd_mixer_selem_register'ing: %s\n",
Warren Dukes's avatar
Warren Dukes committed
234 235 236
			snd_strerror(err));
		return -1;
	}
237

Avuton Olrich's avatar
Avuton Olrich committed
238
	if ((err = snd_mixer_load(volume_alsaMixerHandle)) < 0) {
239
		closeAlsaMixer();
240
		WARNING("problems snd_mixer_selem_register'ing: %s\n",
Warren Dukes's avatar
Warren Dukes committed
241 242 243 244 245
			snd_strerror(err));
		return -1;
	}

	elem = snd_mixer_first_elem(volume_alsaMixerHandle);
246

247
	param = getConfigParam(CONF_MIXER_CONTROL);
248

Avuton Olrich's avatar
Avuton Olrich committed
249
	if (param) {
250
		controlName = param->value;
251 252
	}

Avuton Olrich's avatar
Avuton Olrich committed
253 254 255 256
	while (elem) {
		if (snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE) {
			if (strcasecmp(controlName,
				       snd_mixer_selem_get_name(elem)) == 0) {
257
				break;
Warren Dukes's avatar
Warren Dukes committed
258 259
			}
		}
260
		elem = snd_mixer_elem_next(elem);
Warren Dukes's avatar
Warren Dukes committed
261
	}
262

Avuton Olrich's avatar
Avuton Olrich committed
263
	if (elem) {
Warren Dukes's avatar
Warren Dukes committed
264
		volume_alsaElem = elem;
Avuton Olrich's avatar
Avuton Olrich committed
265 266 267
		snd_mixer_selem_get_playback_volume_range(volume_alsaElem,
							  &volume_alsaMin,
							  &volume_alsaMax);
268
		return 0;
Warren Dukes's avatar
Warren Dukes committed
269 270
	}

Avuton Olrich's avatar
Avuton Olrich committed
271
	WARNING("can't find alsa mixer_control \"%s\"\n", controlName);
272

273
	closeAlsaMixer();
Warren Dukes's avatar
Warren Dukes committed
274 275 276
	return -1;
}

277 278 279 280 281
static int prep_alsa_get_level(long *level)
{
	const char *cmd;
	int err;

Avuton Olrich's avatar
Avuton Olrich committed
282
	if (!volume_alsaMixerHandle && prepAlsaMixer(volume_mixerDevice) < 0)
283 284 285 286 287 288
		return -1;

	if ((err = snd_mixer_handle_events(volume_alsaMixerHandle)) < 0) {
		cmd = "handle_events";
		goto error;
	}
Avuton Olrich's avatar
Avuton Olrich committed
289 290 291
	if ((err = snd_mixer_selem_get_playback_volume(volume_alsaElem,
						       SND_MIXER_SCHN_FRONT_LEFT,
						       level)) < 0) {
292 293 294 295
		cmd = "selem_get_playback_volume";
		goto error;
	}
	return 0;
296 297

error:
298
	WARNING("problems getting alsa volume: %s (snd_mixer_%s)\n",
Avuton Olrich's avatar
Avuton Olrich committed
299
		snd_strerror(err), cmd);
300 301
	closeAlsaMixer();
	return -1;
Warren Dukes's avatar
Warren Dukes committed
302 303
}

Avuton Olrich's avatar
Avuton Olrich committed
304 305
static int getAlsaVolumeLevel(void)
{
Warren Dukes's avatar
Warren Dukes committed
306 307 308 309
	int ret;
	long level;
	long max = volume_alsaMax;
	long min = volume_alsaMin;
Warren Dukes's avatar
Warren Dukes committed
310

311
	if (prep_alsa_get_level(&level) < 0)
Warren Dukes's avatar
Warren Dukes committed
312 313
		return -1;

Avuton Olrich's avatar
Avuton Olrich committed
314 315
	ret = ((volume_alsaSet / 100.0) * (max - min) + min) + 0.5;
	if (volume_alsaSet > 0 && ret == level) {
Warren Dukes's avatar
Warren Dukes committed
316
		ret = volume_alsaSet;
Avuton Olrich's avatar
Avuton Olrich committed
317 318
	} else
		ret = (int)(100 * (((float)(level - min)) / (max - min)) + 0.5);
Warren Dukes's avatar
Warren Dukes committed
319 320 321 322

	return ret;
}

323
static int changeAlsaVolumeLevel(int change, int rel)
Avuton Olrich's avatar
Avuton Olrich committed
324
{
Warren Dukes's avatar
Warren Dukes committed
325 326
	float vol;
	long level;
Warren Dukes's avatar
Warren Dukes committed
327
	long test;
Warren Dukes's avatar
Warren Dukes committed
328 329 330 331
	long max = volume_alsaMax;
	long min = volume_alsaMin;
	int err;

332
	if (prep_alsa_get_level(&level) < 0)
Warren Dukes's avatar
Warren Dukes committed
333 334 335
		return -1;

	if (rel) {
Avuton Olrich's avatar
Avuton Olrich committed
336 337
		test = ((volume_alsaSet / 100.0) * (max - min) + min) + 0.5;
		if (volume_alsaSet >= 0 && level == test) {
Warren Dukes's avatar
Warren Dukes committed
338
			vol = volume_alsaSet;
Avuton Olrich's avatar
Avuton Olrich committed
339 340 341 342
		} else
			vol = 100.0 * (((float)(level - min)) / (max - min));
		vol += change;
	} else
Warren Dukes's avatar
Warren Dukes committed
343 344
		vol = change;

Avuton Olrich's avatar
Avuton Olrich committed
345 346 347
	volume_alsaSet = vol + 0.5;
	volume_alsaSet = volume_alsaSet > 100 ? 100 :
	    (volume_alsaSet < 0 ? 0 : volume_alsaSet);
Warren Dukes's avatar
Warren Dukes committed
348

Avuton Olrich's avatar
Avuton Olrich committed
349 350 351
	level = (long)(((vol / 100.0) * (max - min) + min) + 0.5);
	level = level > max ? max : level;
	level = level < min ? min : level;
Warren Dukes's avatar
Warren Dukes committed
352

Avuton Olrich's avatar
Avuton Olrich committed
353 354 355 356 357
	if ((err =
	     snd_mixer_selem_set_playback_volume_all(volume_alsaElem,
						     level)) < 0) {
		WARNING("problems setting alsa volume: %s\n",
			snd_strerror(err));
358
		closeAlsaMixer();
Warren Dukes's avatar
Warren Dukes committed
359 360 361 362 363 364 365
		return -1;
	}

	return 0;
}
#endif

Max Kellermann's avatar
Max Kellermann committed
366
static int prepMixer(const char *device)
Avuton Olrich's avatar
Avuton Olrich committed
367 368
{
	switch (volume_mixerType) {
Warren Dukes's avatar
Warren Dukes committed
369 370 371 372
#ifdef HAVE_ALSA
	case VOLUME_MIXER_TYPE_ALSA:
		return prepAlsaMixer(device);
#endif
373
#ifdef HAVE_OSS
Warren Dukes's avatar
Warren Dukes committed
374 375 376 377 378 379 380 381
	case VOLUME_MIXER_TYPE_OSS:
		return prepOssMixer(device);
#endif
	}

	return 0;
}

Avuton Olrich's avatar
Avuton Olrich committed
382 383 384
void finishVolume(void)
{
	switch (volume_mixerType) {
Warren Dukes's avatar
Warren Dukes committed
385 386 387 388 389
#ifdef HAVE_ALSA
	case VOLUME_MIXER_TYPE_ALSA:
		closeAlsaMixer();
		break;
#endif
390
#ifdef HAVE_OSS
Warren Dukes's avatar
Warren Dukes committed
391 392 393 394 395 396 397
	case VOLUME_MIXER_TYPE_OSS:
		closeOssMixer();
		break;
#endif
	}
}

Avuton Olrich's avatar
Avuton Olrich committed
398 399 400
void initVolume(void)
{
	ConfigParam *param = getConfigParam(CONF_MIXER_TYPE);
401

Avuton Olrich's avatar
Avuton Olrich committed
402 403
	if (param) {
		if (0) ;
Warren Dukes's avatar
Warren Dukes committed
404
#ifdef HAVE_ALSA
Avuton Olrich's avatar
Avuton Olrich committed
405
		else if (strcmp(param->value, VOLUME_MIXER_ALSA) == 0) {
406 407 408
			volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
			volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
		}
Warren Dukes's avatar
Warren Dukes committed
409
#endif
410
#ifdef HAVE_OSS
Avuton Olrich's avatar
Avuton Olrich committed
411
		else if (strcmp(param->value, VOLUME_MIXER_OSS) == 0) {
412 413 414
			volume_mixerType = VOLUME_MIXER_TYPE_OSS;
			volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
		}
Warren Dukes's avatar
Warren Dukes committed
415
#endif
Avuton Olrich's avatar
Avuton Olrich committed
416
		else if (strcmp(param->value, VOLUME_MIXER_SOFTWARE) == 0) {
417 418
			volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
			volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT;
Avuton Olrich's avatar
Avuton Olrich committed
419
		} else {
420
			FATAL("unknown mixer type %s at line %i\n",
Avuton Olrich's avatar
Avuton Olrich committed
421
			      param->value, param->line);
422
		}
Warren Dukes's avatar
Warren Dukes committed
423
	}
424 425

	param = getConfigParam(CONF_MIXER_DEVICE);
426

Avuton Olrich's avatar
Avuton Olrich committed
427
	if (param) {
428
		volume_mixerDevice = param->value;
Warren Dukes's avatar
Warren Dukes committed
429 430 431
	}
}

Avuton Olrich's avatar
Avuton Olrich committed
432 433 434
void openVolumeDevice(void)
{
	if (prepMixer(volume_mixerDevice) < 0) {
435
		WARNING("using software volume\n");
Warren Dukes's avatar
Warren Dukes committed
436 437 438 439
		volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
	}
}

Avuton Olrich's avatar
Avuton Olrich committed
440 441
static int getSoftwareVolume(void)
{
442
	return volume_softwareSet;
Warren Dukes's avatar
Warren Dukes committed
443 444
}

Avuton Olrich's avatar
Avuton Olrich committed
445 446 447
int getVolumeLevel(void)
{
	switch (volume_mixerType) {
Warren Dukes's avatar
Warren Dukes committed
448 449 450 451
#ifdef HAVE_ALSA
	case VOLUME_MIXER_TYPE_ALSA:
		return getAlsaVolumeLevel();
#endif
452
#ifdef HAVE_OSS
Warren Dukes's avatar
Warren Dukes committed
453 454 455 456 457 458 459 460 461 462
	case VOLUME_MIXER_TYPE_OSS:
		return getOssVolumeLevel();
#endif
	case VOLUME_MIXER_TYPE_SOFTWARE:
		return getSoftwareVolume();
	default:
		return -1;
	}
}

463
static int changeSoftwareVolume(int change, int rel)
Avuton Olrich's avatar
Avuton Olrich committed
464
{
Warren Dukes's avatar
Warren Dukes committed
465 466
	int new = change;

Avuton Olrich's avatar
Avuton Olrich committed
467 468
	if (rel)
		new += volume_softwareSet;
Warren Dukes's avatar
Warren Dukes committed
469

Avuton Olrich's avatar
Avuton Olrich committed
470 471 472 473
	if (new > 100)
		new = 100;
	else if (new < 0)
		new = 0;
Warren Dukes's avatar
Warren Dukes committed
474

Warren Dukes's avatar
Warren Dukes committed
475 476
	volume_softwareSet = new;

Avuton Olrich's avatar
Avuton Olrich committed
477 478 479 480 481 482 483 484
	/*new = 100.0*(exp(new/50.0)-1)/(M_E*M_E-1)+0.5; */
	if (new >= 100)
		new = 1000;
	else if (new <= 0)
		new = 0;
	else
		new =
		    1000.0 * (exp(new / 25.0) - 1) / (54.5981500331F - 1) + 0.5;
Warren Dukes's avatar
Warren Dukes committed
485 486 487 488 489 490

	setPlayerSoftwareVolume(new);

	return 0;
}

491
int changeVolumeLevel(int change, int rel)
Avuton Olrich's avatar
Avuton Olrich committed
492 493
{
	switch (volume_mixerType) {
Warren Dukes's avatar
Warren Dukes committed
494 495
#ifdef HAVE_ALSA
	case VOLUME_MIXER_TYPE_ALSA:
496
		return changeAlsaVolumeLevel(change, rel);
Warren Dukes's avatar
Warren Dukes committed
497
#endif
498
#ifdef HAVE_OSS
Warren Dukes's avatar
Warren Dukes committed
499
	case VOLUME_MIXER_TYPE_OSS:
500
		return changeOssVolumeLevel(change, rel);
Warren Dukes's avatar
Warren Dukes committed
501 502
#endif
	case VOLUME_MIXER_TYPE_SOFTWARE:
503
		return changeSoftwareVolume(change, rel);
Warren Dukes's avatar
Warren Dukes committed
504
	default:
505
		return 0;
Warren Dukes's avatar
Warren Dukes committed
506 507
	}
}
508 509 510

void read_sw_volume_state(FILE *fp)
{
Eric Wong's avatar
Eric Wong committed
511
	char buf[sizeof(SW_VOLUME_STATE) + sizeof("100") - 1];
512 513 514 515 516
	char *end = NULL;
	long int sv;

	if (volume_mixerType != VOLUME_MIXER_TYPE_SOFTWARE)
		return;
Eric Wong's avatar
Eric Wong committed
517 518
	while (myFgets(buf, sizeof(buf), fp)) {
		if (prefixcmp(buf, SW_VOLUME_STATE))
519
			continue;
Eric Wong's avatar
Eric Wong committed
520
		sv = strtol(buf + strlen(SW_VOLUME_STATE), &end, 10);
521
		if (mpd_likely(!*end))
522
			changeSoftwareVolume(sv, 0);
523 524 525 526 527 528 529 530 531 532 533 534
		else
			ERROR("Can't parse software volume: %s\n", buf);
		return;
	}
}

void save_sw_volume_state(FILE *fp)
{
	if (volume_mixerType == VOLUME_MIXER_TYPE_SOFTWARE)
		fprintf(fp, SW_VOLUME_STATE "%d\n", volume_softwareSet);
}