From: Richard Kettlewell Date: Sat, 26 Apr 2008 18:56:15 +0000 (+0100) Subject: Separate notion of configured audio backend from Disobedience/playrtp X-Git-Tag: 4.0~93 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/3c499fe72ea3c8527663a4fb7df9f6d627fc42b7 Separate notion of configured audio backend from Disobedience/playrtp audio backend. This allows Disobedience to show the volume widget iff it'll work. If RTP is enabled then it uses the default audio backend (which is what playrtp will pick); if not then it assumes the server is capable of setting the volume. Currently this will still go wrong on a Mac without RTP. --- diff --git a/clients/playrtp.c b/clients/playrtp.c index 6496daf..3f02e0c 100644 --- a/clients/playrtp.c +++ b/clients/playrtp.c @@ -175,18 +175,16 @@ pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; /** @brief Condition variable signalled whenever @ref packets is changed */ pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -#if HAVE_ALSA_ASOUNDLIB_H -# define DEFAULT_BACKEND playrtp_alsa -#elif HAVE_SYS_SOUNDCARD_H || EMPEG_HOST -# define DEFAULT_BACKEND playrtp_oss -#elif HAVE_COREAUDIO_AUDIOHARDWARE_H -# define DEFAULT_BACKEND playrtp_coreaudio -#else -# error No known backend +#if DEFAULT_BACKEND == BACKEND_ALSA +# define DEFAULT_PLAYRTP_BACKEND playrtp_alsa +#elif DEFAULT_BACKEND == BACKEND_OSS +# define DEFAULT_PLAYRTP_BACKEND playrtp_oss +#elif DEFAULT_BACKEND == BACKEND_COREAUDIO +# define DEFAULT_PLAYRTP_BACKEND playrtp_coreaudio #endif /** @brief Backend to play with */ -static void (*backend)(void) = &DEFAULT_BACKEND; +static void (*backend)(void) = DEFAULT_PLAYRTP_BACKEND; HEAP_DEFINE(pheap, struct packet *, lt_packet); diff --git a/disobedience/control.c b/disobedience/control.c index e1f44f2..57931be 100644 --- a/disobedience/control.c +++ b/disobedience/control.c @@ -208,20 +208,30 @@ static struct icon icons[] = { static GtkAdjustment *volume_adj; static GtkAdjustment *balance_adj; +static GtkWidget *volume_widget; +static GtkWidget *balance_widget; /** @brief Called whenever last_state changes in any way */ void control_monitor(void attribute((unused)) *u) { int n; + gboolean volume_supported; D(("control_monitor")); for(n = 0; n < NICONS; ++n) icons[n].update(&icons[n]); + /* Only display volume/balance controls if they will work */ + if(!rtp_supported + || (rtp_supported && mixer_supported(DEFAULT_BACKEND))) + volume_supported = TRUE; + else + volume_supported = FALSE; + (volume_supported ? gtk_widget_show : gtk_widget_hide)(volume_widget); + (volume_supported ? gtk_widget_show : gtk_widget_hide)(balance_widget); } /** @brief Create the control bar */ GtkWidget *control_widget(void) { GtkWidget *hbox = gtk_hbox_new(FALSE, 1), *vbox; - GtkWidget *v, *b; int n; NW(hbox); @@ -266,31 +276,31 @@ GtkWidget *control_widget(void) { 0.2, 0.2, 0)); /* the volume control */ NW(hscale); - v = gtk_hscale_new(volume_adj); + volume_widget = gtk_hscale_new(volume_adj); NW(hscale); - b = gtk_hscale_new(balance_adj); - gtk_widget_set_style(v, tool_style); - gtk_widget_set_style(b, tool_style); - gtk_scale_set_digits(GTK_SCALE(v), 10); - gtk_scale_set_digits(GTK_SCALE(b), 10); - gtk_widget_set_size_request(v, 192, -1); - gtk_widget_set_size_request(b, 192, -1); - gtk_tooltips_set_tip(tips, v, "Volume", ""); - gtk_tooltips_set_tip(tips, b, "Balance", ""); - gtk_box_pack_start(GTK_BOX(hbox), v, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(hbox), b, FALSE, TRUE, 0); + balance_widget = gtk_hscale_new(balance_adj); + gtk_widget_set_style(volume_widget, tool_style); + gtk_widget_set_style(balance_widget, tool_style); + gtk_scale_set_digits(GTK_SCALE(volume_widget), 10); + gtk_scale_set_digits(GTK_SCALE(balance_widget), 10); + gtk_widget_set_size_request(volume_widget, 192, -1); + gtk_widget_set_size_request(balance_widget, 192, -1); + gtk_tooltips_set_tip(tips, volume_widget, "Volume", ""); + gtk_tooltips_set_tip(tips, balance_widget, "Balance", ""); + gtk_box_pack_start(GTK_BOX(hbox), volume_widget, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), balance_widget, FALSE, TRUE, 0); /* space updates rather than hammering the server */ - gtk_range_set_update_policy(GTK_RANGE(v), GTK_UPDATE_DELAYED); - gtk_range_set_update_policy(GTK_RANGE(b), GTK_UPDATE_DELAYED); + gtk_range_set_update_policy(GTK_RANGE(volume_widget), GTK_UPDATE_DELAYED); + gtk_range_set_update_policy(GTK_RANGE(balance_widget), GTK_UPDATE_DELAYED); /* notice when the adjustments are changed */ g_signal_connect(G_OBJECT(volume_adj), "value-changed", G_CALLBACK(volume_adjusted), 0); g_signal_connect(G_OBJECT(balance_adj), "value-changed", G_CALLBACK(volume_adjusted), 0); /* format the volume/balance values ourselves */ - g_signal_connect(G_OBJECT(v), "format-value", + g_signal_connect(G_OBJECT(volume_widget), "format-value", G_CALLBACK(format_volume), 0); - g_signal_connect(G_OBJECT(b), "format-value", + g_signal_connect(G_OBJECT(balance_widget), "format-value", G_CALLBACK(format_balance), 0); register_monitor(control_monitor, 0, -1UL); return hbox; @@ -447,7 +457,7 @@ static void volume_adjusted(GtkAdjustment attribute((unused)) *a, * from the log. */ if(rtp_supported) { int l = nearbyint(left(v, b) * 100), r = nearbyint(right(v, b) * 100); - mixer_control(&l, &r, 1); + mixer_control(DEFAULT_BACKEND, &l, &r, 1); } else /* We don't want a reply, we'll get the actual new volume from the log. */ disorder_eclient_volume(client, 0, diff --git a/disobedience/disobedience.c b/disobedience/disobedience.c index 2cab9aa..d6aa599 100644 --- a/disobedience/disobedience.c +++ b/disobedience/disobedience.c @@ -312,9 +312,10 @@ static gboolean periodic_fast(gpointer attribute((unused)) data) { } last = now; #endif - if(rtp_supported) { + if(rtp_supported && mixer_supported(DEFAULT_BACKEND)) { int nl, nr; - if(!mixer_control(&nl, &nr, 0) && (nl != volume_l || nr != volume_r)) { + if(!mixer_control(DEFAULT_BACKEND, &nl, &nr, 0) + && (nl != volume_l || nr != volume_r)) { volume_l = nl; volume_r = nr; volume_update(); diff --git a/lib/configuration.h b/lib/configuration.h index 78c31ef..a06524c 100644 --- a/lib/configuration.h +++ b/lib/configuration.h @@ -189,6 +189,16 @@ struct config { #define BACKEND_COREAUDIO 3 /**< Use Core Audio (Mac only) */ #define BACKEND_OSS 4 /**< Use OSS */ +#if HAVE_ALSA_ASOUNDLIB_H +# define DEFAULT_BACKEND BACKEND_ALSA +#elif HAVE_SYS_SOUNDCARD_H || EMPEG_HOST +# define DEFAULT_BACKEND BACKEND_OSS +#elif HAVE_COREAUDIO_AUDIOHARDWARE_H +# define DEFAULT_BACKEND BACKEND_COREAUDIO +#else +# error Cannot choose a default backend +#endif + /** @brief Home directory for state files */ const char *home; diff --git a/lib/mixer.c b/lib/mixer.c index 58d9e60..ee88fbb 100644 --- a/lib/mixer.c +++ b/lib/mixer.c @@ -69,13 +69,25 @@ static const struct mixer *mixers[] = { static const struct mixer *find_mixer(int api) { size_t n; + if(api == -1) + api = config->api; for(n = 0; n < NMIXERS; ++n) if(mixers[n]->api == api) return mixers[n]; return &mixer_none; } +/** @brief Return true if we know how to drive the mixer + * @param api Sound api or -1 for default + * @return true if suppored, false otherwise + */ +int mixer_supported(int api) { + const struct mixer *const m = find_mixer(api); + return m != &mixer_none; +} + /** @brief Get/set volume + * @param api Sound api or -1 for default * @param left Left channel level, 0-100 * @param right Right channel level, 0-100 * @param set Set volume if non-0 @@ -86,8 +98,8 @@ static const struct mixer *find_mixer(int api) { * If setting the volume then the target levels are read from @p left and * @p right, and the actual level set is stored in them. */ -int mixer_control(int *left, int *right, int set) { - const struct mixer *const m = find_mixer(config->api); +int mixer_control(int api, int *left, int *right, int set) { + const struct mixer *const m = find_mixer(api); /* We impose defaults bizarrely late, but this has the advantage of * not making everything depend on sound libraries */ diff --git a/lib/mixer.h b/lib/mixer.h index 6739ed8..5e05c6a 100644 --- a/lib/mixer.h +++ b/lib/mixer.h @@ -52,9 +52,10 @@ struct mixer { const char *channel; }; -int mixer_control(int *left, int *right, int set); +int mixer_control(int api, int *left, int *right, int set); const char *mixer_default_device(int api); const char *mixer_default_channel(int api); +int mixer_supported(int api); extern const struct mixer mixer_oss; extern const struct mixer mixer_alsa; diff --git a/server/disorderd.c b/server/disorderd.c index c770354..3a5e093 100644 --- a/server/disorderd.c +++ b/server/disorderd.c @@ -171,7 +171,7 @@ static void periodic_volume_check(ev_source attribute((unused)) *ev_) { int l, r; char lb[32], rb[32]; - if(!mixer_control(&l, &r, 0)) { + if(!mixer_control(-1/*as configured*/, &l, &r, 0)) { if(l != volume_left || r != volume_right) { volume_left = l; volume_right = r; diff --git a/server/server.c b/server/server.c index cbeb0ab..90aaa77 100644 --- a/server/server.c +++ b/server/server.c @@ -767,7 +767,7 @@ static int c_volume(struct conn *c, sink_writes(ev_writer_sink(c->w), "510 Prohibited\n"); return 1; } - if(mixer_control(&l, &r, set)) + if(mixer_control(-1/*as configured*/, &l, &r, set)) sink_writes(ev_writer_sink(c->w), "550 error accessing mixer\n"); else { sink_printf(ev_writer_sink(c->w), "252 %d %d\n", l, r);