aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2009-07-06 22:00:50 +0200
committerMax Kellermann <max@duempel.org>2009-07-06 22:00:50 +0200
commit0275690b5cd133f992e9e34d6c76eb134aef26bd (patch)
tree3ce67839d522420ff7b99224cdc8892c86395036 /src
parentda8095db546544bb9fe3a455ef5742bfef9c2f4f (diff)
downloadmpd-0275690b5cd133f992e9e34d6c76eb134aef26bd.tar.gz
mpd-0275690b5cd133f992e9e34d6c76eb134aef26bd.tar.xz
mpd-0275690b5cd133f992e9e34d6c76eb134aef26bd.zip
output: use the software mixer plugin
Do all the software volume stuff inside each output thread, not in the player thread. This allows one software mixer per output device, and also allows the user to configure the mixer type (hardware or software) for each audio output. This moves the global "mixer_type" setting into the "audio_output" section, deprecating the "mixer_enabled" flag.
Diffstat (limited to 'src')
-rw-r--r--src/mixer_control.c13
-rw-r--r--src/mixer_control.h3
-rw-r--r--src/output_init.c58
-rw-r--r--src/player_control.c11
-rw-r--r--src/player_control.h3
-rw-r--r--src/player_thread.c14
-rw-r--r--src/volume.c79
7 files changed, 60 insertions, 121 deletions
diff --git a/src/mixer_control.c b/src/mixer_control.c
index a17885935..927a1276c 100644
--- a/src/mixer_control.c
+++ b/src/mixer_control.c
@@ -28,24 +28,11 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "mixer"
-static bool mixers_enabled = true;
-
-void
-mixer_disable_all(void)
-{
- g_debug("mixer api is disabled");
- mixers_enabled = false;
-}
-
struct mixer *
mixer_new(const struct mixer_plugin *plugin, const struct config_param *param)
{
struct mixer *mixer;
- //mixers are disabled (by using software volume)
- if (!mixers_enabled) {
- return NULL;
- }
assert(plugin != NULL);
mixer = plugin->init(param);
diff --git a/src/mixer_control.h b/src/mixer_control.h
index 0f73e8f75..b8997a795 100644
--- a/src/mixer_control.h
+++ b/src/mixer_control.h
@@ -31,9 +31,6 @@ struct mixer;
struct mixer_plugin;
struct config_param;
-void
-mixer_disable_all(void);
-
struct mixer *
mixer_new(const struct mixer_plugin *plugin, const struct config_param *param);
diff --git a/src/output_init.c b/src/output_init.c
index eba665e77..08873ac20 100644
--- a/src/output_init.c
+++ b/src/output_init.c
@@ -23,6 +23,9 @@
#include "output_list.h"
#include "audio_parser.h"
#include "mixer_control.h"
+#include "mixer_type.h"
+#include "mixer_list.h"
+#include "mixer/software_mixer_plugin.h"
#include "filter_plugin.h"
#include "filter_registry.h"
#include "filter/chain_filter_plugin.h"
@@ -61,17 +64,59 @@ audio_output_detect(GError **error)
return NULL;
}
+/**
+ * Determines the mixer type which should be used for the specified
+ * configuration block.
+ *
+ * This handles the deprecated options mixer_type (global) and
+ * mixer_enabled, if the mixer_type setting is not configured.
+ */
+static enum mixer_type
+audio_output_mixer_type(const struct config_param *param)
+{
+ /* read the local "mixer_type" setting */
+ const char *p = config_get_block_string(param, "mixer_type", NULL);
+ if (p != NULL)
+ return mixer_type_parse(p);
+
+ /* try the local "mixer_enabled" setting next (deprecated) */
+ if (!config_get_block_bool(param, "mixer_enabled", true))
+ return MIXER_TYPE_NONE;
+
+ /* fall back to the global "mixer_type" setting (also
+ deprecated) */
+ return mixer_type_parse(config_get_string("mixer_type", "hardware"));
+}
+
static struct mixer *
audio_output_load_mixer(const struct config_param *param,
- const struct mixer_plugin *plugin)
+ const struct mixer_plugin *plugin,
+ struct filter *filter_chain)
{
- if (!config_get_block_bool(param, "mixer_enabled", true))
- return NULL;
+ struct mixer *mixer;
- if (plugin == NULL)
+ switch (audio_output_mixer_type(param)) {
+ case MIXER_TYPE_NONE:
+ case MIXER_TYPE_UNKNOWN:
return NULL;
- return mixer_new(plugin, param);
+ case MIXER_TYPE_HARDWARE:
+ if (plugin == NULL)
+ return NULL;
+
+ return mixer_new(plugin, param);
+
+ case MIXER_TYPE_SOFTWARE:
+ mixer = mixer_new(&software_mixer_plugin, NULL);
+ assert(mixer != NULL);
+
+ filter_chain_append(filter_chain,
+ software_mixer_get_filter(mixer));
+ return mixer;
+ }
+
+ assert(false);
+ return NULL;
}
bool
@@ -152,7 +197,8 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
if (ao->data == NULL)
return false;
- ao->mixer = audio_output_load_mixer(param, plugin->mixer_plugin);
+ ao->mixer = audio_output_load_mixer(param, plugin->mixer_plugin,
+ ao->filter);
/* the "convert" filter must be the last one in the chain */
diff --git a/src/player_control.c b/src/player_control.c
index ac4b006dd..df80ac4ff 100644
--- a/src/player_control.c
+++ b/src/player_control.c
@@ -40,7 +40,6 @@ void pc_init(unsigned buffer_chunks, unsigned int buffered_before_play)
pc.error = PLAYER_ERROR_NOERROR;
pc.state = PLAYER_STATE_STOP;
pc.cross_fade_seconds = 0;
- pc.software_volume = PCM_VOLUME_1;
}
void pc_deinit(void)
@@ -253,16 +252,6 @@ void setPlayerCrossFade(float crossFadeInSeconds)
idle_add(IDLE_OPTIONS);
}
-void setPlayerSoftwareVolume(int volume)
-{
- if (volume > PCM_VOLUME_1)
- volume = PCM_VOLUME_1;
- else if (volume < 0)
- volume = 0;
-
- pc.software_volume = volume;
-}
-
double getPlayerTotalPlayTime(void)
{
return pc.total_play_time;
diff --git a/src/player_control.h b/src/player_control.h
index b1f7481cd..0cc3c73a8 100644
--- a/src/player_control.h
+++ b/src/player_control.h
@@ -81,7 +81,6 @@ struct player_control {
struct song *errored_song;
volatile double seek_where;
float cross_fade_seconds;
- uint16_t software_volume;
double total_play_time;
};
@@ -145,8 +144,6 @@ void setPlayerCrossFade(float crossFadeInSeconds);
float getPlayerCrossFade(void);
-void setPlayerSoftwareVolume(int volume);
-
double getPlayerTotalPlayTime(void);
static inline const struct audio_format *
diff --git a/src/player_thread.c b/src/player_thread.c
index 7fc55d3d1..657968f6c 100644
--- a/src/player_thread.c
+++ b/src/player_thread.c
@@ -423,8 +423,6 @@ static bool
play_chunk(struct song *song, struct music_chunk *chunk,
const struct audio_format *format, double sizeToTime)
{
- bool success;
-
assert(music_chunk_check_format(chunk, format));
if (chunk->tag != NULL) {
@@ -455,18 +453,6 @@ play_chunk(struct song *song, struct music_chunk *chunk,
pc.elapsed_time = chunk->times;
pc.bit_rate = chunk->bit_rate;
- /* apply software volume */
-
- success = pcm_volume(chunk->data, chunk->length,
- format, pc.software_volume);
- if (!success) {
- g_warning("pcm_volume() failed on %u:%u:%u",
- format->sample_rate, format->bits, format->channels);
- pc.errored_song = dc.current_song;
- pc.error = PLAYER_ERROR_AUDIO;
- return false;
- }
-
/* send the chunk to the audio outputs */
if (!audio_output_all_play(chunk)) {
diff --git a/src/volume.c b/src/volume.c
index 3d240f4e4..3e6079cd6 100644
--- a/src/volume.c
+++ b/src/volume.c
@@ -40,8 +40,6 @@
#define SW_VOLUME_STATE "sw_volume: "
-static enum mixer_type volume_mixer_type = MIXER_TYPE_HARDWARE;
-
static unsigned volume_software_set = 100;
/** the cached hardware mixer value; invalid if negative */
@@ -51,37 +49,15 @@ static GTimer *hardware_volume_timer;
void volume_finish(void)
{
- if (volume_mixer_type == MIXER_TYPE_HARDWARE)
- g_timer_destroy(hardware_volume_timer);
+ g_timer_destroy(hardware_volume_timer);
}
void volume_init(void)
{
- const struct config_param *param = config_get_param(CONF_MIXER_TYPE);
- //hw mixing is by default
- if (param) {
- volume_mixer_type = mixer_type_parse(param->value);
- switch (volume_mixer_type) {
- case MIXER_TYPE_NONE:
- case MIXER_TYPE_SOFTWARE:
- mixer_disable_all();
- break;
-
- case MIXER_TYPE_HARDWARE:
- //nothing to do
- break;
-
- case MIXER_TYPE_UNKNOWN:
- g_error("unknown mixer type %s at line %i\n",
- param->value, param->line);
- }
- }
-
- if (volume_mixer_type == MIXER_TYPE_HARDWARE)
- hardware_volume_timer = g_timer_new();
+ hardware_volume_timer = g_timer_new();
}
-static int hardware_volume_get(void)
+int volume_level_get(void)
{
assert(hardware_volume_timer != NULL);
@@ -95,43 +71,12 @@ static int hardware_volume_get(void)
return last_hardware_volume;
}
-static int software_volume_get(void)
-{
- return volume_software_set;
-}
-
-int volume_level_get(void)
-{
- switch (volume_mixer_type) {
- case MIXER_TYPE_SOFTWARE:
- return software_volume_get();
- case MIXER_TYPE_HARDWARE:
- return hardware_volume_get();
- case MIXER_TYPE_NONE:
- case MIXER_TYPE_UNKNOWN:
- return -1;
- }
-
- /* unreachable */
- assert(false);
- return -1;
-}
-
static bool software_volume_change(unsigned volume)
{
assert(volume <= 100);
volume_software_set = volume;
-
- if (volume >= 100)
- volume = PCM_VOLUME_1;
- else if (volume <= 0)
- volume = 0;
- else
- volume = pcm_float_to_volume((exp(volume / 25.0) - 1) /
- (54.5981500331F - 1));
-
- setPlayerSoftwareVolume(volume);
+ mixer_all_set_software_volume(volume);
return true;
}
@@ -148,16 +93,11 @@ bool volume_level_change(unsigned volume)
{
assert(volume <= 100);
+ volume_software_set = volume;
+
idle_add(IDLE_MIXER);
- switch (volume_mixer_type) {
- case MIXER_TYPE_HARDWARE:
- return hardware_volume_change(volume);
- case MIXER_TYPE_SOFTWARE:
- return software_volume_change(volume);
- default:
- return true;
- }
+ return hardware_volume_change(volume);
}
void read_sw_volume_state(FILE *fp)
@@ -166,8 +106,6 @@ void read_sw_volume_state(FILE *fp)
char *end = NULL;
long int sv;
- if (volume_mixer_type != MIXER_TYPE_SOFTWARE)
- return;
while (fgets(buf, sizeof(buf), fp)) {
if (!g_str_has_prefix(buf, SW_VOLUME_STATE))
continue;
@@ -184,6 +122,5 @@ void read_sw_volume_state(FILE *fp)
void save_sw_volume_state(FILE *fp)
{
- if (volume_mixer_type == MIXER_TYPE_SOFTWARE)
- fprintf(fp, SW_VOLUME_STATE "%u\n", volume_software_set);
+ fprintf(fp, SW_VOLUME_STATE "%u\n", volume_software_set);
}