From cc2178e5c39f0c2da2d4d5dff14210d5934bcc32 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 22 Feb 2006 14:11:23 +0000 Subject: Support for setting volume on sources. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@560 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + src/polyp/introspect.c | 55 +++++++++++++++++++++++++++++++++++++++++ src/polyp/introspect.h | 7 ++++++ src/polypcore/cli-command.c | 54 +++++++++++++++++++++++++++++++++++++--- src/polypcore/core-def.h | 30 ++++++++++++++++++++++ src/polypcore/native-common.h | 2 ++ src/polypcore/pdispatch.c | 1 + src/polypcore/protocol-native.c | 36 ++++++++++++++++++--------- src/polypcore/sink.h | 6 +---- src/polypcore/source.c | 51 ++++++++++++++++++++++++++++++++++++++ src/polypcore/source.h | 9 +++++++ 11 files changed, 232 insertions(+), 20 deletions(-) create mode 100644 src/polypcore/core-def.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 410fd702..f36630e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -425,6 +425,7 @@ polypcoreinclude_HEADERS = \ polypcore/cli-text.h \ polypcore/client.h \ polypcore/core.h \ + polypcore/core-def.h \ polypcore/core-scache.h \ polypcore/core-subscribe.h \ polypcore/conf-parser.h \ diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 043d2076..4fa23841 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -252,6 +252,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || @@ -727,6 +728,60 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons return o; } +pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + +pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + /** Sample Cache **/ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index d4ff65fb..d7fad9c4 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -84,6 +84,7 @@ typedef struct pa_source_info { pa_sample_spec sample_spec; /**< Sample spec of this source */ pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ + pa_cvolume volume; /**< Volume of the source \since 0.8 */ uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ @@ -213,6 +214,12 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name /** Set the volume of a sink input stream */ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Set the volume of a source device specified by its index \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a source device specified by its name \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + /** Memory block statistics */ typedef struct pa_stat_info { uint32_t memblock_total; /**< Currently allocated memory blocks */ diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 6c9fc4b1..cd7993a8 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -77,6 +77,7 @@ static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); @@ -114,6 +115,7 @@ static const struct command commands[] = { { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, + { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3}, { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, { "set-default-source", pa_cli_command_source_default, "Set the default source (args: index|name)", 2}, { "kill-client", pa_cli_command_kill_client, "Kill a client (args: index)", 2}, @@ -376,6 +378,37 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb return 0; } +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *v; + pa_source *source; + uint32_t volume; + pa_cvolume cvolume; + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); + return -1; + } + + if (!(v = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); + return -1; + } + + if (pa_atou(v, &volume) < 0) { + pa_strbuf_puts(buf, "Failed to parse volume.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { + pa_strbuf_puts(buf, "No source found by this name or index.\n"); + return -1; + } + + pa_cvolume_set(&cvolume, source->sample_spec.channels, volume); + pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume); + return 0; +} + static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; assert(c && t); @@ -633,7 +666,8 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { pa_module *m; - pa_sink *s; + pa_sink *sink; + pa_source *source; int nl; const char *p; uint32_t idx; @@ -667,8 +701,20 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 0; - for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { - if (s->owner && s->owner->auto_unload) + for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { + if (sink->owner && sink->owner->auto_unload) + continue; + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE))); + } + + for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { + if (source->owner && source->owner->auto_unload) continue; if (!nl) { @@ -676,7 +722,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 1; } - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE))); + pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE))); } diff --git a/src/polypcore/core-def.h b/src/polypcore/core-def.h new file mode 100644 index 00000000..89cc47f1 --- /dev/null +++ b/src/polypcore/core-def.h @@ -0,0 +1,30 @@ +#ifndef foocoredefhfoo +#define foocoredefhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef enum pa_mixer { + PA_MIXER_SOFTWARE, + PA_MIXER_HARDWARE +} pa_mixer_t; + +#endif diff --git a/src/polypcore/native-common.h b/src/polypcore/native-common.h index 0d17b022..a5ca5c96 100644 --- a/src/polypcore/native-common.h +++ b/src/polypcore/native-common.h @@ -71,6 +71,8 @@ enum { PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, + PA_COMMAND_SET_SOURCE_VOLUME, + PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index c082b8cc..2cc90bc2 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -82,6 +82,7 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME", + [PA_COMMAND_SET_SOURCE_VOLUME] = "SET_SOURCE_VOLME", [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index e73ff761..cd1a685f 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -216,6 +216,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, + [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, @@ -1254,16 +1255,20 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { assert(t && source); - pa_tagstruct_putu32(t, source->index); - pa_tagstruct_puts(t, source->name); - pa_tagstruct_puts(t, source->description); - pa_tagstruct_put_sample_spec(t, &source->sample_spec); - pa_tagstruct_put_channel_map(t, &source->channel_map); - pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); - pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); - pa_tagstruct_put_usec(t, pa_source_get_latency(source)); - pa_tagstruct_puts(t, source->driver); + pa_tagstruct_put( + t, + PA_TAG_U32, source->index, + PA_TAG_STRING, source->name, + PA_TAG_STRING, source->description, + PA_TAG_SAMPLE_SPEC, &source->sample_spec, + PA_TAG_CHANNEL_MAP, &source->channel_map, + PA_TAG_U32, source->owner ? source->owner->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_source_get_volume(source, PA_MIXER_HARDWARE), + PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, + PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, + PA_TAG_USEC, pa_source_get_latency(source), + PA_TAG_STRING, source->driver, + PA_TAG_INVALID); } static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { @@ -1558,12 +1563,14 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t idx; pa_cvolume volume; pa_sink *sink = NULL; + pa_source *source = NULL; pa_sink_input *si = NULL; const char *name = NULL; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || + (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) || pa_tagstruct_get_cvolume(t, &volume) || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1580,18 +1587,25 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else if (command == PA_COMMAND_SET_SOURCE_VOLUME) { + if (idx != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); } else { assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); } - if (!si && !sink) { + if (!si && !sink && !source) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } if (sink) pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); + else if (source) + pa_source_set_volume(source, PA_MIXER_HARDWARE, &volume); else if (si) pa_sink_input_set_volume(si, &volume); diff --git a/src/polypcore/sink.h b/src/polypcore/sink.h index fa120ebf..5f1a6cc8 100644 --- a/src/polypcore/sink.h +++ b/src/polypcore/sink.h @@ -29,6 +29,7 @@ typedef struct pa_sink pa_sink; #include #include #include +#include #include #include #include @@ -41,11 +42,6 @@ typedef enum pa_sink_state { PA_SINK_DISCONNECTED } pa_sink_state_t; -typedef enum pa_mixer { - PA_MIXER_SOFTWARE, - PA_MIXER_HARDWARE -} pa_mixer_t; - struct pa_sink { int ref; uint32_t index; diff --git a/src/polypcore/source.c b/src/polypcore/source.c index b70cb129..47325a1b 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -77,8 +77,13 @@ pa_source* pa_source_new( s->outputs = pa_idxset_new(NULL, NULL); s->monitor_of = NULL; + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); + s->get_latency = NULL; s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; s->userdata = NULL; r = pa_idxset_put(core->sources, s, &s->index); @@ -110,6 +115,8 @@ void pa_source_disconnect(pa_source *s) { s->get_latency = NULL; s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; s->state = PA_SOURCE_DISCONNECTED; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); @@ -173,7 +180,14 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { assert(chunk); pa_source_ref(s); + + if (!pa_cvolume_is_norm(&s->sw_volume)) { + pa_memchunk_make_writable(chunk, s->core->memblock_stat, 0); + pa_volume_memchunk(chunk, &s->sample_spec, &s->sw_volume); + } + pa_idxset_foreach(s->outputs, do_post, (void*) chunk); + pa_source_unref(s); } @@ -194,3 +208,40 @@ pa_usec_t pa_source_get_latency(pa_source *s) { return s->get_latency(s); } +void pa_source_set_volume(pa_source *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; + + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; +} diff --git a/src/polypcore/source.h b/src/polypcore/source.h index a267e73c..3c5bb6c4 100644 --- a/src/polypcore/source.h +++ b/src/polypcore/source.h @@ -28,6 +28,8 @@ typedef struct pa_source pa_source; #include #include +#include +#include #include #include #include @@ -56,9 +58,13 @@ struct pa_source { pa_idxset *outputs; pa_sink *monitor_of; + + pa_cvolume hw_volume, sw_volume; void (*notify)(pa_source*source); pa_usec_t (*get_latency)(pa_source *s); + int (*set_hw_volume)(pa_source *s); + int (*get_hw_volume)(pa_source *s); void *userdata; }; @@ -84,4 +90,7 @@ void pa_source_set_owner(pa_source *s, pa_module *m); pa_usec_t pa_source_get_latency(pa_source *s); +void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolume *volume); +const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m); + #endif -- cgit