volume.c 3.17 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2011 The Music Player Daemon Project
3
 * http://www.musicpd.org
Warren Dukes's avatar
Warren Dukes committed
4 5 6 7 8 9 10 11 12 13
 *
 * 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.
14 15 16 17
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Warren Dukes's avatar
Warren Dukes committed
18
 */
19

20
#include "config.h"
21
#include "volume.h"
Warren Dukes's avatar
Warren Dukes committed
22
#include "conf.h"
23
#include "idle.h"
24
#include "pcm_volume.h"
25
#include "output_all.h"
26
#include "mixer_control.h"
27
#include "mixer_all.h"
28
#include "mixer_type.h"
29
#include "event_pipe.h"
Max Kellermann's avatar
Max Kellermann committed
30

31
#include <glib.h>
32

33
#include <assert.h>
Max Kellermann's avatar
Max Kellermann committed
34 35
#include <math.h>
#include <string.h>
36
#include <stdlib.h>
Max Kellermann's avatar
Max Kellermann committed
37

38 39 40
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "volume"

41
#define SW_VOLUME_STATE                         "sw_volume: "
Warren Dukes's avatar
Warren Dukes committed
42

43
static unsigned volume_software_set = 100;
44

45 46 47 48 49
/** the cached hardware mixer value; invalid if negative */
static int last_hardware_volume = -1;
/** the age of #last_hardware_volume */
static GTimer *hardware_volume_timer;

50 51 52 53 54 55 56 57 58 59 60 61 62
/**
 * Handler for #PIPE_EVENT_MIXER.
 */
static void
mixer_event_callback(void)
{
	/* flush the hardware volume cache */
	last_hardware_volume = -1;

	/* notify clients */
	idle_add(IDLE_MIXER);
}

63
void volume_finish(void)
64
{
65
	g_timer_destroy(hardware_volume_timer);
66 67
}

68
void volume_init(void)
Avuton Olrich's avatar
Avuton Olrich committed
69
{
70
	hardware_volume_timer = g_timer_new();
71 72

	event_pipe_register(PIPE_EVENT_MIXER, mixer_event_callback);
Warren Dukes's avatar
Warren Dukes committed
73 74
}

75
int volume_level_get(void)
Avuton Olrich's avatar
Avuton Olrich committed
76
{
77 78 79 80 81 82 83
	assert(hardware_volume_timer != NULL);

	if (last_hardware_volume >= 0 &&
	    g_timer_elapsed(hardware_volume_timer, NULL) < 1.0)
		/* throttle access to hardware mixers */
		return last_hardware_volume;

84 85 86
	last_hardware_volume = mixer_all_get_volume();
	g_timer_start(hardware_volume_timer);
	return last_hardware_volume;
Warren Dukes's avatar
Warren Dukes committed
87 88
}

89
static bool software_volume_change(unsigned volume)
Avuton Olrich's avatar
Avuton Olrich committed
90
{
91
	assert(volume <= 100);
Warren Dukes's avatar
Warren Dukes committed
92

93
	volume_software_set = volume;
94
	mixer_all_set_software_volume(volume);
Warren Dukes's avatar
Warren Dukes committed
95

96
	return true;
Warren Dukes's avatar
Warren Dukes committed
97 98
}

99
static bool hardware_volume_change(unsigned volume)
100
{
101 102 103
	/* reset the cache */
	last_hardware_volume = -1;

104
	return mixer_all_set_volume(volume);
105 106
}

107
bool volume_level_change(unsigned volume)
Avuton Olrich's avatar
Avuton Olrich committed
108
{
109 110
	assert(volume <= 100);

111 112
	volume_software_set = volume;

113 114
	idle_add(IDLE_MIXER);

115
	return hardware_volume_change(volume);
Warren Dukes's avatar
Warren Dukes committed
116
}
117

118 119
bool
read_sw_volume_state(const char *line)
120 121 122 123
{
	char *end = NULL;
	long int sv;

124 125 126 127 128 129 130 131 132 133
	if (!g_str_has_prefix(line, SW_VOLUME_STATE))
		return false;

	line += sizeof(SW_VOLUME_STATE) - 1;
	sv = strtol(line, &end, 10);
	if (*end == 0 && sv >= 0 && sv <= 100)
		software_volume_change(sv);
	else
		g_warning("Can't parse software volume: %s\n", line);
	return true;
134 135 136 137
}

void save_sw_volume_state(FILE *fp)
{
138
	fprintf(fp, SW_VOLUME_STATE "%u\n", volume_software_set);
139
}
140 141 142 143 144 145

unsigned
sw_volume_state_get_hash(void)
{
	return volume_software_set;
}