chiark / gitweb /
Separate notion of configured audio backend from Disobedience/playrtp
authorRichard Kettlewell <rjk@greenend.org.uk>
Sat, 26 Apr 2008 18:56:15 +0000 (19:56 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sat, 26 Apr 2008 18:56:15 +0000 (19:56 +0100)
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.

clients/playrtp.c
disobedience/control.c
disobedience/disobedience.c
lib/configuration.h
lib/mixer.c
lib/mixer.h
server/disorderd.c
server/server.c

index 6496daf5166d8dc586646e73b4acb1df29136775..3f02e0c007eb81477448eceb6b5ec318ffc984a7 100644 (file)
@@ -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);
 
index e1f44f28fcea9102aee9d42b1940575d5b154df5..57931be5cb13645993bc3445bb7c462b72973d5d 100644 (file)
@@ -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,
index 2cab9aa9cd0d3bc1418068ef83ddb666e531d104..d6aa59976c602fd206dd968a7d396e4dc1b35a2d 100644 (file)
@@ -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();
index 78c31ef361c35bcd51d62e4080fb3c531316ebf4..a06524cb3133b8c53c28621242e7075c275d6e14 100644 (file)
@@ -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;
 
index 58d9e60632aeef4daaa5d8c6aec2f9e467da2bba..ee88fbbec63a951bd666df0a2d1ab985cad1dc52 100644 (file)
@@ -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 */
index 6739ed82a31962d386235350192af68f7d9b2826..5e05c6a2cefc83ffc5e471c238c1db0f97d00d45 100644 (file)
@@ -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;
index c7703549c5a77d98b869c349a138e4af0734825e..3a5e09339ce775c814d12731772f36b1e611d006 100644 (file)
@@ -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;
index cbeb0abae1107037e0d2e0e132024b13d8a493d5..90aaa7749a4aae9fbbabf2bd19fb2b96135462f7 100644 (file)
@@ -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);