Re: [Musicpd-dev-team] State of the pulse mixer
Hi, From Max Kellermann: there have been lots of problems with the pulse mixer code since it was merged, and a good bunch of bug reports are still open. Please tell me what is being done to fix the remaining bugs, and when I will receive patches. Yes, Avuton has reported a lot of isssues. Unfortunately the steps are missing to reproduce here. I'm trying to clone the code from the xmms-pulse plugin [1] to fix the code. 1. In the open, this should better work with the mainloop lock/unlock issues. One question about this: What is the current state of a mixer when the output is not available? As an example, the pulse output associated with a not connected bluetooth headset can't obtained a valid mixer. what should 'mpc volume' returns? The answer can close the issue 0002214. 2. The pulse community has pointed that we should lock the mainloop when getting the volume. The patch is done waiting Point 1. 3. The same lock/unlock stuff has to been done when we set the volume. These bugs must be fixed before the 0.15 release, or we will have to remove it. When do you plan the next release? In the next few days, I expect to send patches. [1] git://git.0pointer.de/xmms-pulse.git -- David -- ___ Musicpd-dev-team mailing list Musicpd-dev-team@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team
[Musicpd-dev-team] [PATCH] pulse_mixer: close
when the mixer is closed, - the mainloop is stopped. - the context is disconnected. - then the mainloop is freed. Signed-off-by: David Guibert david.guib...@gmail.com --- src/mixer/pulse_mixer.c | 15 ++- 1 files changed, 14 insertions(+), 1 deletions(-) diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c index 481fec2..a300a29 100644 --- a/src/mixer/pulse_mixer.c +++ b/src/mixer/pulse_mixer.c @@ -237,7 +237,20 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data) static void pulse_mixer_close(G_GNUC_UNUSED struct mixer *data) { - return; + struct pulse_mixer *pm=(struct pulse_mixer *) data; + if (pm-mainloop) + pa_threaded_mainloop_stop(pm-mainloop); + + if (pm-context) { + pa_context_disconnect(pm-context); + pa_context_unref(pm-context); + pm-context = NULL; + } + + if (pm-mainloop) { + pa_threaded_mainloop_free(pm-mainloop); + pm-mainloop = NULL; + } } static int -- tg: (b4de244..) t/pulse_mixer_close (depends on: t/offline-only-removed-sink) -- Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are powering Web 2.0 with engaging, cross-platform capabilities. Quickly and easily build your RIAs with Flex Builder, the Eclipse(TM)based development software that enables intelligent coding and step-through debugging. Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com ___ Musicpd-dev-team mailing list Musicpd-dev-team@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team
[Musicpd-dev-team] [PATCH] pulse_mixer: clarify debug messages.
Signed-off-by: David Guibert david.guib...@gmail.com --- Avuton, I hope this help to find which part clearly fails. It should give me more information about bugs - 2136 - 2138 - 2139 Regards src/mixer/pulse_mixer.c | 45 ++--- 1 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c index a300a29..7f2651a 100644 --- a/src/mixer/pulse_mixer.c +++ b/src/mixer/pulse_mixer.c @@ -48,22 +48,19 @@ sink_input_cb(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, { struct pulse_mixer *pm = userdata; - if (eol) { - g_debug(eol error sink_input_cb); + if (eol) return; - } if (!i) { g_debug(Sink input callback failure); return; } - g_debug(sink input cb %s, index %d ,i-name,i-index); - if(strcmp(i-name,pm-output_name)==0) { - pm-index=i-index; - pm-online=true; - *pm-volume=i-volume; - } else - g_debug(bad name); + if(strcmp(i-name,pm-output_name) == 0) { + g_debug(Sink input cb %s, index %d,i-name,i-index); + pm-index = i-index; + pm-online = true; + *pm-volume = i-volume; + } } static void @@ -72,21 +69,19 @@ sink_input_vol(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, { struct pulse_mixer *pm = userdata; - if (eol) { - g_debug(eol error sink_input_vol); + if (eol) return; - } if (!i) { - g_debug(Sink input callback failure); + g_debug(Sink input volume failure); return; } - g_debug(sink input vol %s, index %d , i-name, i-index); - *pm-volume=i-volume; + g_debug(Sink input vol %s, index %d, i-name, i-index); + *pm-volume = i-volume; } static void -subscribe_cb(G_GNUC_UNUSED pa_context *c, pa_subscription_event_type_t t, +subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { @@ -101,7 +96,7 @@ subscribe_cb(G_GNUC_UNUSED pa_context *c, pa_subscription_event_type_t t, else { pa_operation *o; - if (!(o = pa_context_get_sink_input_info(pm-context, idx, sink_input_cb, pm))) { + if (!(o = pa_context_get_sink_input_info(context, idx, sink_input_cb, pm))) { g_debug(pa_context_get_sink_input_info() failed); return; } @@ -202,8 +197,9 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data) return false; } + pa_threaded_mainloop_lock(pm-mainloop); if(!(pm-context = pa_context_new(pa_threaded_mainloop_get_api(pm-mainloop), - Mixer mpd))) { + Mixer MPD))) { g_debug(failed context); return false; } @@ -212,20 +208,21 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data) if (pa_context_connect(pm-context, pm-server, (pa_context_flags_t)0, NULL) 0) { - g_debug(context server fail); + g_warning(Failed to connect to server: %s, pa_strerror(pa_context_errno(pm-context))); return false; } - pa_threaded_mainloop_lock(pm-mainloop); if (pa_threaded_mainloop_start(pm-mainloop) 0) { - g_debug(error start mainloop); + g_warning(Failed to start main loop); return false; } + /* Wait until the context is ready */ pa_threaded_mainloop_wait(pm-mainloop); if (pa_context_get_state(pm-context) != PA_CONTEXT_READY) { - g_debug(error context not ready); + g_warning(Failed to connect to server: %s, pa_strerror(pa_context_errno(pm-context))); + pa_threaded_mainloop_unlock(pm-mainloop); return false; } @@ -283,6 +280,8 @@ pulse_mixer_set_volume(struct mixer *mixer, unsigned volume) { struct pulse_mixer *pm=(struct pulse_mixer *) mixer; pa_operation *o; + g_debug(set_volume %s %d, + pm-online == TRUE ? online : offline, volume); if (pm-online) { pa_cvolume_set(pm-volume, (pm-volume)-channels, (pa_volume_t)(volume)*PA_VOLUME_NORM/100+0.5); -- tg: (8137a4f..) t/debug-messages (depends on: t/pulse_mixer_close) -- Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are powering Web 2.0 with engaging, cross-platform capabilities. Quickly and easily build your RIAs with Flex Builder, the Eclipse(TM
[Musicpd-dev-team] [PATCH] pulse mixer
This patch introduces the mixer for the pulse output. Technically speaking, the pulse index is needed to get or set the volume. You must define callback fonctions to get this index since the pulse output in mpd is done using the simpe api. The pulse simple api does not provide the index of the newly defined output. So callback fonctions are associated to the pulse context. The list of all the sink input is then retreived. Then we select the name of the mpd pulse output and control its volume by its associated index number. Signed-off-by: Patrice Linel patnathan...@gmail.com Signed-off-by: David Guibert david.guib...@gmail.com --- Makefile.am |1 + src/main.c|3 +- src/mixer/pulse_mixer.c | 284 + src/mixer_api.h |1 + src/output/pulse_plugin.c | 16 +++ 5 files changed, 303 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 25478f8..2511680 100644 --- a/Makefile.am +++ b/Makefile.am @@ -489,6 +489,7 @@ endif if HAVE_PULSE OUTPUT_SRC += src/output/pulse_plugin.c +MIXER_SRC += src/mixer/pulse_mixer.c endif if HAVE_SHOUT diff --git a/src/main.c b/src/main.c index a3f613d..2889933 100644 --- a/src/main.c +++ b/src/main.c @@ -259,6 +259,7 @@ int main(int argc, char *argv[]) command_init(); initialize_decoder_and_player(); + daemonize(options.daemon); volume_init(); initAudioConfig(); audio_output_all_init(); @@ -267,8 +268,6 @@ int main(int argc, char *argv[]) initNormalization(); input_stream_global_init(); - daemonize(options.daemon); - setup_log_output(options.stdOutput); initSigHandlers(); diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c new file mode 100644 index 000..78b77c0 --- /dev/null +++ b/src/mixer/pulse_mixer.c @@ -0,0 +1,284 @@ +#include ../output_api.h +#include ../mixer_api.h + +#include glib.h +#include pulse/volume.h +#include pulse/pulseaudio.h + +struct pulse_mixer { + struct mixer base; + char *server; + char *sink; + char *output_name; + uint32_t index; + boolonline; + struct pa_context *context; + struct pa_threaded_mainloop *mainloop; + struct pa_cvolume *volume; + +}; + + + +static void sink_input_cb(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) +{ + + struct pulse_mixer *pm = userdata; + if (eol) { + g_debug(eol error sink_input_cb\n); + return; + } + + if (!i) { + g_debug(Sink input callback failure\n); + return; + } + g_debug(sink input cb %s, index %d \n,i-name,i-index); + if(strcmp(i-name,pm-output_name)==0) + { + pm-index=i-index; + pm-online=true; + *pm-volume=i-volume; + } + else g_debug(bad name\n); +} + +static void sink_input_vol(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) +{ + + struct pulse_mixer *pm = userdata; + if (eol) { + g_debug(eol error sink_input_vol\n); + return; + } + + if (!i) { + g_debug(Sink input callback failure\n); + return; + } + g_debug(sink input vol %s, index %d \n,i-name,i-index); + *pm-volume=i-volume; +} + +static void +subscribe_cb(G_GNUC_UNUSED pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) +{ + + struct pulse_mixer *pm = userdata; + g_debug(pulse_mixer: subscribe call back\n); + switch (t PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + { + + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t PA_SUBSCRIPTION_EVENT_TYPE_MASK) == + PA_SUBSCRIPTION_EVENT_REMOVE) + pm-online =false; + else + { + pa_operation *o; + + if (!(o = pa_context_get_sink_input_info(pm-context, idx, sink_input_cb, pm))) + { + g_debug(pulse_mixer: pa_context_get_sink_input_info() failed\n); + return; + } + pa_operation_unref(o); + } + break; + } +} + +static void +context_state_cb(pa_context *context, void *userdata) +{ + struct pulse_mixer *pm = userdata; + switch (pa_context_get_state(context)) + { + case PA_CONTEXT_READY: + { + pa_operation *o; + + pa_context_set_subscribe_callback(context, subscribe_cb, pm); + + if (!(o = pa_context_subscribe(context
[Musicpd-dev-team] [PATCH] pulse mixer
Sorry. I forgot to do the make after minor changes... I resend the patch wich compiles cleanly. -- Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise -Strategies to boost innovation and cut costs with open source participation -Receive a $600 discount off the registration fee with the source code: SFAD http://p.sf.net/sfu/XcvMzF8H ___ Musicpd-dev-team mailing list Musicpd-dev-team@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team
[Musicpd-dev-team] [PATCH] pulse mixer
This patch introduces the mixer for the pulse output. Technically speaking, the pulse index is needed to get or set the volume. You must define callback fonctions to get this index since the pulse output in mpd is done using the simpe api. The pulse simple api does not provide the index of the newly defined output. So callback fonctions are associated to the pulse context. The list of all the sink input is then retreived. Then we select the name of the mpd pulse output and control its volume by its associated index number. Signed-off-by: Patrice Linel patnathan...@gmail.com Signed-off-by: David Guibert david.guib...@gmail.com --- Makefile.am |1 + src/main.c|3 +- src/mixer/pulse_mixer.c | 284 + src/mixer_api.h |1 + src/output/pulse_plugin.c | 16 +++ 5 files changed, 303 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 25478f8..2511680 100644 --- a/Makefile.am +++ b/Makefile.am @@ -489,6 +489,7 @@ endif if HAVE_PULSE OUTPUT_SRC += src/output/pulse_plugin.c +MIXER_SRC += src/mixer/pulse_mixer.c endif if HAVE_SHOUT diff --git a/src/main.c b/src/main.c index a3f613d..2889933 100644 --- a/src/main.c +++ b/src/main.c @@ -259,6 +259,7 @@ int main(int argc, char *argv[]) command_init(); initialize_decoder_and_player(); + daemonize(options.daemon); volume_init(); initAudioConfig(); audio_output_all_init(); @@ -267,8 +268,6 @@ int main(int argc, char *argv[]) initNormalization(); input_stream_global_init(); - daemonize(options.daemon); - setup_log_output(options.stdOutput); initSigHandlers(); diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c new file mode 100644 index 000..e12a844 --- /dev/null +++ b/src/mixer/pulse_mixer.c @@ -0,0 +1,284 @@ +#include ../output_api.h +#include ../mixer_api.h + +#include glib.h +#include pulse/volume.h +#include pulse/pulseaudio.h + +struct pulse_mixer { + struct mixer base; + char *server; + char *sink; + char *output_name; + uint32_t index; + boolonline; + struct pa_context *context; + struct pa_threaded_mainloop *mainloop; + struct pa_cvolume *volume; + +}; + + + +static void sink_input_cb(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) +{ + + struct pulse_mixer *pm = userdata; + if (eol) { + g_debug(eol error sink_input_cb\n); + return; + } + + if (!i) { + g_debug(Sink input callback failure\n); + return; + } + g_debug(sink input cb %s, index %d \n,i-name,i-index); + if(strcmp(i-name,pm-output_name)==0) + { + pm-index=i-index; + pm-online=true; + *pm-volume=i-volume; + } + else g_debug(bad name\n); +} + +static void sink_input_vol(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) +{ + + struct pulse_mixer *pm = userdata; + if (eol) { + g_debug(eol error sink_input_vol\n); + return; + } + + if (!i) { + g_debug(Sink input callback failure\n); + return; + } + g_debug(sink input vol %s, index %d \n,i-name,i-index); + *pm-volume=i-volume; +} + +static void +subscribe_cb(G_GNUC_UNUSED pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) +{ + + struct pulse_mixer *pm = userdata; + g_debug(pulse_mixer: subscribe call back\n); + switch (t PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + { + + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t PA_SUBSCRIPTION_EVENT_TYPE_MASK) == + PA_SUBSCRIPTION_EVENT_REMOVE) + pm-online =false; + else + { + pa_operation *o; + + if (!(o = pa_context_get_sink_input_info(pm-context, idx, sink_input_cb, pm))) + { + g_debug(pulse_mixer: pa_context_get_sink_input_info() failed\n); + return; + } + pa_operation_unref(o); + } + break; + } +} + +static void +context_state_cb(pa_context *context, void *userdata) +{ + struct pulse_mixer *pm = userdata; + switch (pa_context_get_state(context)) + { + case PA_CONTEXT_READY: + { + pa_operation *o; + + pa_context_set_subscribe_callback(context, subscribe_cb, pm); + + if (!(o = pa_context_subscribe(context