chiark / gitweb /
disobedience: menu item to select network playback API
authorRichard Kettlewell <rjk@terraraq.org.uk>
Thu, 7 Nov 2013 17:02:16 +0000 (17:02 +0000)
committerRichard Kettlewell <rjk@terraraq.org.uk>
Thu, 7 Nov 2013 17:02:16 +0000 (17:02 +0000)
disobedience/disobedience.h
disobedience/manual/window.html
disobedience/menu.c
disobedience/rtp.c

index 0ff76d3..8e1d7f7 100644 (file)
@@ -48,6 +48,7 @@
 #include "split.h"
 #include "timeval.h"
 #include "uaudio.h"
+#include "inputline.h"
 
 #include <glib.h>
 #include <gtk/gtk.h>
@@ -247,6 +248,10 @@ void globals_init(void);
 int rtp_running(void);
 void start_rtp(void);
 void stop_rtp(void);
+void load_rtp_config(void);
+void save_rtp_config(void);
+void change_rtp_api(const char *api);
+const char *rtp_api;
 
 /* Settings */
 
index a4c1642..26a656d 100644 (file)
@@ -150,6 +150,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
      <li><b>Compact Mode</b> which switches Disobedience's window to a smaller format.</li>
      <li><b>Global Preferences</b> which allows global server settings to be modified.</li>
      <li><b>Activate Playlist</b> which allows you to play a <A href="playlists.html">playlist</a>.</li>
+     <li><b>Network Playback API</b> which allows you to select the audio playback API used when playing over the network.</li>
    </ul>
 
    <p class=image><img src="menu-help.png"></p>
index 57f1865..50611e6 100644 (file)
@@ -30,6 +30,7 @@ GtkWidget *menu_playlists_widget;
 GtkWidget *playlists_menu;
 GtkWidget *menu_editplaylists_widget;
 static GtkWidget *menu_minimode_widget;
+static GtkWidget *apis_menu;
 
 /** @brief Main menu widgets */
 GtkItemFactory *mainmenufactory;
@@ -234,6 +235,13 @@ static void menu_rights_changed(const char attribute((unused)) *event,
     users_set_sensitive(FALSE);
 }
 
+/** @brief Called to select the network playback API */
+static void rtp_menu_activate(GtkMenuItem *menuitem,
+                              gpointer user_data) {
+  if(GTK_CHECK_MENU_ITEM(menuitem)->active)
+    change_rtp_api(user_data);
+}
+
 /** @brief Create the menu bar widget */
 GtkWidget *menubar(GtkWidget *window) {
   GtkWidget *m;
@@ -388,6 +396,14 @@ GtkWidget *menubar(GtkWidget *window) {
       (char *)"<Branch>",               /* item_type */
       0                                 /* extra_data */
     },
+    {
+      (char *)"/Control/Network Playback API", /* path */
+      0,                                /* accelerator */
+      0,                                /* callback */
+      0,                                /* callback_action */
+      (char *)"<Branch>",               /* item_type */
+      0                                 /* extra_data */
+    },
 
     {
       (char *)"/Help",                  /* path */
@@ -436,6 +452,8 @@ GtkWidget *menubar(GtkWidget *window) {
                                                "<GdisorderMain>/Control/Activate playlist");
   playlists_menu = gtk_item_factory_get_widget(mainmenufactory,
                                                "<GdisorderMain>/Control/Activate playlist");
+  apis_menu = gtk_item_factory_get_widget(mainmenufactory,
+                                               "<GdisorderMain>/Control/Network Playback API");
   menu_editplaylists_widget = gtk_item_factory_get_widget(mainmenufactory,
                                                      "<GdisorderMain>/Edit/Edit playlists");
   menu_minimode_widget = gtk_item_factory_get_widget(mainmenufactory,
@@ -446,6 +464,7 @@ GtkWidget *menubar(GtkWidget *window) {
   assert(menu_playlists_widget != 0);
   assert(playlists_menu != 0);
   assert(menu_editplaylists_widget != 0);
+  assert(apis_menu != 0);
 
   GtkWidget *edit_widget = gtk_item_factory_get_widget(mainmenufactory,
                                                        "<GdisorderMain>/Edit");
@@ -459,6 +478,26 @@ GtkWidget *menubar(GtkWidget *window) {
   if(menu_minimode_widget)
     g_signal_connect(G_OBJECT(menu_minimode_widget), "toggled",
                      G_CALLBACK(toggled_minimode), NULL);
+
+  /* Populate the APIs menu */
+  GSList *playback_menu_group = NULL;
+  load_rtp_config();
+  assert(rtp_api != NULL);
+  for(int n = 0; uaudio_apis[n]; ++n) {
+    if(uaudio_apis[n]->flags & UAUDIO_API_CLIENT) {
+      GtkWidget *mw = gtk_radio_menu_item_new_with_label(playback_menu_group,
+                                                         uaudio_apis[n]->name);
+      playback_menu_group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mw));
+      gtk_menu_shell_append(GTK_MENU_SHELL(apis_menu), mw);
+      /* Tick the currently selected API... */
+      if(!strcmp(uaudio_apis[n]->name, rtp_api))
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mw), TRUE);
+      /* ...and only then connect the signal */
+      g_signal_connect(mw, "toggled", G_CALLBACK(rtp_menu_activate),
+                       (char *)uaudio_apis[n]->name);
+    }
+  }
+
   return m;
 }
 
index 4693173..d88c3ec 100644 (file)
@@ -129,7 +129,10 @@ void start_rtp(void) {
        disorder_fatal(errno, "close");
       /* execute the player */
       execlp("disorder-playrtp",
-            "disorder-playrtp", "--socket", rtp_socket, (char *)0);
+            "disorder-playrtp",
+             "--socket", rtp_socket,
+             "--api", rtp_api,
+             (char *)0);
       disorder_fatal(errno, "disorder-playrtp");
     } else {
       /* child */
@@ -152,6 +155,75 @@ void stop_rtp(void) {
   fclose(fp);
 }
 
+static char *rtp_config_file(void) {
+  static char *rtp_config;
+  const char *home = getenv("HOME");
+  if(!rtp_config)
+    byte_xasprintf(&rtp_config, "%s/.disorder/api", home);
+  return rtp_config;
+}
+
+const char *rtp_api;
+
+void load_rtp_config(void) {
+  char *rtp_config = rtp_config_file();
+  FILE *fp;
+  if((fp = fopen(rtp_config, "r"))) {
+    char *line;
+    if(inputline(rtp_config, fp, &line, '\n') == 0) {
+      for(int n = 0; uaudio_apis[n]; ++n)
+        if(!strcmp(uaudio_apis[n]->name, line))
+          rtp_api = line;
+    }
+    fclose(fp);
+  }
+  if(!rtp_api)
+    rtp_api = uaudio_default(uaudio_apis, UAUDIO_API_CLIENT)->name;
+}
+
+void save_rtp_config(void) {
+  if(rtp_api) {
+    char *rtp_config = rtp_config_file();
+    char *tmp;
+    byte_xasprintf(&tmp, "%s.tmp", rtp_config);
+    FILE *fp;
+    if(!(fp = fopen(tmp, "w"))){
+      fpopup_msg(GTK_MESSAGE_ERROR, "error opening %s: %s",
+                 tmp, strerror(errno));
+      return;
+    }
+    if(fprintf(fp, "%s\n", rtp_api) < 0) {
+      fpopup_msg(GTK_MESSAGE_ERROR, "error writing to %s: %s",
+                 tmp, strerror(errno));
+      fclose(fp);
+      return;
+    }
+    if(fclose(fp) < 0) {
+      fpopup_msg(GTK_MESSAGE_ERROR, "error closing %s: %s",
+                 tmp, strerror(errno));
+      return;
+    }
+    if(rename(tmp, rtp_config) < 0) {
+      fpopup_msg(GTK_MESSAGE_ERROR, "error renaming %s: %s",
+                 tmp, strerror(errno));
+    }
+  }
+}
+
+void change_rtp_api(const char *api) {
+  if(rtp_api && !strcmp(api, rtp_api))
+    return;                             /* no change */
+  int running = rtp_running();
+  if(running)
+    stop_rtp();
+  rtp_api = api;
+  save_rtp_config();
+  // TODO this is racy and does not work; the player doesn't shut down quickly
+  // enough.
+  if(running)
+    start_rtp();
+}
+
 /*
 Local Variables:
 c-basic-offset:2