From a2364abbe6ed9e8e4dd71b9410f985acbf20b18f Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Thu, 7 Nov 2013 17:02:16 +0000 Subject: [PATCH] disobedience: menu item to select network playback API Organization: Straylight/Edgeware From: Richard Kettlewell --- disobedience/disobedience.h | 5 +++ disobedience/manual/window.html | 1 + disobedience/menu.c | 39 +++++++++++++++++ disobedience/rtp.c | 74 ++++++++++++++++++++++++++++++++- 4 files changed, 118 insertions(+), 1 deletion(-) diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index 0ff76d3..8e1d7f7 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -48,6 +48,7 @@ #include "split.h" #include "timeval.h" #include "uaudio.h" +#include "inputline.h" #include #include @@ -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 */ diff --git a/disobedience/manual/window.html b/disobedience/manual/window.html index a4c1642..26a656d 100644 --- a/disobedience/manual/window.html +++ b/disobedience/manual/window.html @@ -150,6 +150,7 @@ along with this program. If not, see .
  • Compact Mode which switches Disobedience's window to a smaller format.
  • Global Preferences which allows global server settings to be modified.
  • Activate Playlist which allows you to play a playlist.
  • +
  • Network Playback API which allows you to select the audio playback API used when playing over the network.
  • diff --git a/disobedience/menu.c b/disobedience/menu.c index 57f1865..50611e6 100644 --- a/disobedience/menu.c +++ b/disobedience/menu.c @@ -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 *)"", /* item_type */ 0 /* extra_data */ }, + { + (char *)"/Control/Network Playback API", /* path */ + 0, /* accelerator */ + 0, /* callback */ + 0, /* callback_action */ + (char *)"", /* item_type */ + 0 /* extra_data */ + }, { (char *)"/Help", /* path */ @@ -436,6 +452,8 @@ GtkWidget *menubar(GtkWidget *window) { "/Control/Activate playlist"); playlists_menu = gtk_item_factory_get_widget(mainmenufactory, "/Control/Activate playlist"); + apis_menu = gtk_item_factory_get_widget(mainmenufactory, + "/Control/Network Playback API"); menu_editplaylists_widget = gtk_item_factory_get_widget(mainmenufactory, "/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, "/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; } diff --git a/disobedience/rtp.c b/disobedience/rtp.c index 4693173..d88c3ec 100644 --- a/disobedience/rtp.c +++ b/disobedience/rtp.c @@ -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 -- [mdw]