Skip to content

Commit

Permalink
Implement sound cards list auto update on devices connect/disconnect.
Browse files Browse the repository at this point in the history
Change API for window and devs_list_combo.
  • Loading branch information
rozhuk-im committed Feb 1, 2021
1 parent 222772c commit 0023a2a
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 82 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ GPL2 licence.\


## Features
* plugins to support different sound backens
* plugins for support different sound backens
* change system default sound card
* set volume per line/channel
* enable/disable lines (mute/unmute)
* detect sound cards connect/disconnect
* detect default sound card change


## Compilation
Expand Down
4 changes: 2 additions & 2 deletions gtk-mixer.project
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
<ResourceCompiler Options=""/>
</GlobalSettings>
<Configuration Name="Debug" CompilerType="clang" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-g;-O0;-Wall" C_Options="-Weverything;-ftrapv;-g -DDEBUG;-O0;-fwrapv;-fstack-protector-all;-Wall;-g3 -ggdb;-Wno-reserved-id-macro;-Wno-gnu-zero-variadic-macro-arguments;-Wno-variadic-macros;-Wno-documentation;-Wno-documentation-unknown-command;-Wno-padded;-Wno-cast-qual;-fsanitize=address;-fsanitize-recover=address" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0"/>
<Linker Options="-fsanitize=address;-fsanitize-recover=address" Required="yes"/>
<Compiler Options="-g;-O0;-Wall" C_Options="-Weverything;-ftrapv;-g -DDEBUG;-O0;-fwrapv;-fstack-protector-all;-Wall;-g3 -ggdb;-Wno-reserved-id-macro;-Wno-gnu-zero-variadic-macro-arguments;-Wno-variadic-macros;-Wno-documentation;-Wno-documentation-unknown-command;-Wno-padded;-Wno-cast-qual" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0"/>
<Linker Options="" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="$(ProjectPath)/build/src/" Command="$(OutputFile)" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<BuildSystem Name="Default"/>
Expand Down
4 changes: 2 additions & 2 deletions gtk-mixer.workspace
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
<CodeLite_Workspace Name="gtk-mixer" Database="" Version="10000">
<Project Name="gtk-mixer" Path="gtk-mixer.project" Active="Yes"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="no">
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Environment/>
<Project Name="gtk-mixer" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="yes">
<WorkspaceConfiguration Name="Release" Selected="no">
<Environment/>
<Project Name="gtk-mixer" ConfigName="Release"/>
</WorkspaceConfiguration>
Expand Down
74 changes: 48 additions & 26 deletions src/gtk-mixer-devs_combo.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ gtk_mixer_devs_combo_destroy(GtkWidget *combo __unused, gpointer user_data) {
}

GtkWidget *
gtk_mixer_devs_combo_create(gmp_dev_list_p dev_list, gmp_dev_p dev) {
gtk_mixer_devs_combo_create(void) {
GtkWidget *combo;
GtkListStore *list_store;
GtkCellRenderer *renderer;
Expand All @@ -87,18 +87,11 @@ gtk_mixer_devs_combo_create(gmp_dev_list_p dev_list, gmp_dev_p dev) {
gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo), renderer,
"text", GM_CMB_DEVS_COLUMN_NAME);

gtk_mixer_devs_combo_update(combo, dev_list);

if (NULL == dev) {
dev = gmp_dev_list_get_default(dev_list);
}
gtk_mixer_devs_combo_set_active_device(combo, dev);

return (combo);
}

gmp_dev_p
gtk_mixer_devs_combo_get_dev(GtkWidget *combo) {
gtk_mixer_devs_combo_cur_get(GtkWidget *combo) {

if (NULL == combo)
return (NULL);
Expand All @@ -107,7 +100,7 @@ gtk_mixer_devs_combo_get_dev(GtkWidget *combo) {
}

void
gtk_mixer_devs_combo_set_active_device(GtkWidget *combo,
gtk_mixer_devs_combo_cur_set(GtkWidget *combo,
gmp_dev_p dev) {
gmp_dev_p device_cur = NULL;
GtkTreeIter iter;
Expand All @@ -134,37 +127,66 @@ gtk_mixer_devs_combo_set_active_device(GtkWidget *combo,
}
}

static inline void
gtk_mixer_devs_combo_dev_descr(gmp_dev_p dev, char *buf, size_t buf_size) {

if (NULL == buf || 0 == buf_size)
return;
if (NULL == dev) {
buf[0] = 0x00;
return;
}
snprintf(buf, buf_size,
"%s: %s (%s)%s",
dev->plugin->descr->name,
dev->description,
dev->name,
((gmp_dev_is_default(dev)) ? " [default]" : ""));
}

void
gtk_mixer_devs_combo_update(GtkWidget *combo, gmp_dev_list_p dev_list) {
gmp_dev_p device_cur = NULL;
gtk_mixer_devs_combo_dev_list_set(GtkWidget *combo, gmp_dev_list_p dev_list) {
gmp_dev_p dev = NULL;
GtkTreeIter iter;
gboolean valid_iter;
GtkListStore *list_store = g_object_get_data(G_OBJECT(combo),
"__gtk_mixer_devs_combo_list_store");
char display_name[256];

if (NULL == list_store)
return;

if (NULL != dev_list) {
for (size_t i = 0; i < dev_list->count; i ++) {
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter,
GM_CMB_DEVS_COLUMN_CARD, &dev_list->devs[i], -1);
}
gtk_list_store_clear(list_store);
if (NULL == dev_list)
return;
for (size_t i = 0; i < dev_list->count; i ++) {
gtk_list_store_append(list_store, &iter);
dev = &dev_list->devs[i];
gtk_mixer_devs_combo_dev_descr(dev,
display_name, sizeof(display_name));
gtk_list_store_set(list_store, &iter,
GM_CMB_DEVS_COLUMN_CARD, dev,
GM_CMB_DEVS_COLUMN_NAME, display_name, -1);
}
}
void
gtk_mixer_devs_combo_update(GtkWidget *combo) {
gmp_dev_p dev = NULL;
GtkTreeIter iter;
gboolean valid_iter;
GtkListStore *list_store = g_object_get_data(G_OBJECT(combo),
"__gtk_mixer_devs_combo_list_store");
char display_name[256];

if (NULL == list_store)
return;

valid_iter = gtk_tree_model_get_iter_first(
GTK_TREE_MODEL(list_store), &iter);
while (valid_iter) {
gtk_tree_model_get(GTK_TREE_MODEL(list_store),
&iter, GM_CMB_DEVS_COLUMN_CARD, &device_cur, -1);
snprintf(display_name, sizeof(display_name),
"%s: %s (%s)%s",
device_cur->plugin->descr->name,
device_cur->description,
device_cur->name,
((gmp_dev_is_default(device_cur)) ? " [default]" : ""));
&iter, GM_CMB_DEVS_COLUMN_CARD, &dev, -1);
gtk_mixer_devs_combo_dev_descr(dev,
display_name, sizeof(display_name));
gtk_list_store_set(list_store, &iter,
GM_CMB_DEVS_COLUMN_NAME, display_name, -1);
valid_iter = gtk_tree_model_iter_next(
Expand Down
51 changes: 27 additions & 24 deletions src/gtk-mixer-window.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ gtk_mixer_window_soundcard_changed(GtkWidget *combo __unused,
gmp_dev_p dev;

/* Update mixer controls for the active sound card */
dev = gtk_mixer_devs_combo_get_dev(gm_win->soundcard_combo);
dev = gtk_mixer_devs_combo_cur_get(gm_win->soundcard_combo);
if (NULL != dev) {
snprintf(title, sizeof(title),
"%s - %s", _("Audio Mixer"),
Expand All @@ -72,11 +72,11 @@ gtk_mixer_makedef_button(GtkButton *button __unused, gpointer user_data) {
gm_window_p gm_win = user_data;
gmp_dev_p dev;

dev = gtk_mixer_devs_combo_get_dev(gm_win->soundcard_combo);
dev = gtk_mixer_devs_combo_cur_get(gm_win->soundcard_combo);
if (NULL == dev)
return;
gmp_dev_set_default(dev);
gtk_mixer_devs_combo_update(gm_win->soundcard_combo, NULL);
gtk_mixer_devs_combo_update(gm_win->soundcard_combo);
}

static void
Expand All @@ -91,10 +91,9 @@ gtk_mixer_window_destroy(GtkWidget *window __unused, gpointer user_data) {
}

GtkWidget *
gtk_mixer_window_create(gmp_dev_list_p dev_list) {
gtk_mixer_window_create(void) {
gm_window_p gm_win;
GtkWidget *label, *vbox, *hbox, *mixer_frame;
gmp_dev_p dev = NULL;

gm_win = calloc(1, sizeof(gm_window_t));
if (NULL == gm_win)
Expand All @@ -110,16 +109,6 @@ gtk_mixer_window_create(gmp_dev_list_p dev_list) {
#if 0
g_object_get(gm_win->preferences, "window-width",
&gm_win->width, "window-height", &gm_win->height,
"sound-card", &card_name, NULL);

if (card_name != NULL) {
dev = gtk_mixer_get_card(card_name);
} else {
dev = gtk_mixer_get_default_card();
g_object_set(gm_win->preferences, "sound-card",
gtk_mixer_get_card_internal_name(dev), NULL);
}
g_free(card_name);
#endif

/* Configure the main window. */
Expand All @@ -146,8 +135,7 @@ gtk_mixer_window_create(gmp_dev_list_p dev_list) {
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
gtk_widget_show(label);

gm_win->soundcard_combo = gtk_mixer_devs_combo_create(dev_list,
dev);
gm_win->soundcard_combo = gtk_mixer_devs_combo_create();
g_signal_connect(gm_win->soundcard_combo, "changed",
G_CALLBACK(gtk_mixer_window_soundcard_changed), gm_win);
gtk_box_pack_start(
Expand Down Expand Up @@ -199,17 +187,27 @@ gtk_mixer_window_connect_dev_changed(GtkWidget *window,
}

gmp_dev_p
gtk_mixer_window_get_dev(GtkWidget *window) {
gtk_mixer_window_dev_cur_get(GtkWidget *window) {
gm_window_p gm_win = g_object_get_data(G_OBJECT(window),
"__gtk_mixer_window");

if (NULL == gm_win)
return (0);
return (gtk_mixer_devs_combo_get_dev(gm_win->soundcard_combo));
return (gtk_mixer_devs_combo_cur_get(gm_win->soundcard_combo));
}

void
gtk_mixer_window_dev_cur_set(GtkWidget *window, gmp_dev_p dev) {
gm_window_p gm_win = g_object_get_data(G_OBJECT(window),
"__gtk_mixer_window");

if (NULL == gm_win)
return;
gtk_mixer_devs_combo_cur_set(gm_win->soundcard_combo, dev);
}

void
gtk_mixer_window_update_dev_list(GtkWidget *window) {
gtk_mixer_window_dev_list_update(GtkWidget *window, gmp_dev_list_p dev_list) {
gmp_dev_p dev;
gm_window_p gm_win = g_object_get_data(G_OBJECT(window),
"__gtk_mixer_window");
Expand All @@ -218,16 +216,21 @@ gtk_mixer_window_update_dev_list(GtkWidget *window) {
return;

/* Update dev list only if it can be changed. */
dev = gtk_mixer_devs_combo_get_dev(gm_win->soundcard_combo);
if (dev->plugin->descr->can_set_default_device) {
gtk_mixer_devs_combo_update(gm_win->soundcard_combo, NULL);
dev = gtk_mixer_devs_combo_cur_get(gm_win->soundcard_combo);
if (NULL != dev_list) {
gtk_mixer_devs_combo_dev_list_set(gm_win->soundcard_combo,
dev_list);
}
if (NULL != dev &&
dev->plugin->descr->can_set_default_device) {
gtk_mixer_devs_combo_update(gm_win->soundcard_combo);
gtk_widget_set_sensitive(gm_win->makedef_button,
(0 == gmp_dev_is_default(dev)));
}
}

void
gtk_mixer_window_update_lines(GtkWidget *window) {
gtk_mixer_window_lines_update(GtkWidget *window) {
gm_window_p gm_win = g_object_get_data(G_OBJECT(window),
"__gtk_mixer_window");

Expand Down
70 changes: 54 additions & 16 deletions src/gtk-mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ typedef struct gtk_mixer_app_s {
size_t update_force_counter;
} gm_app_t, *gm_app_p;

/* Check updates every 1s if no changes and every 100ms if something was
* changes in last 5 second. */
#define UPDATE_INTERVAL 100
/* If no chenges - check every (UPDATE_INTERVAL * UPDATE_SKIP_MAX_COUNT) ms. */
#define UPDATE_SKIP_MAX_COUNT 10
Expand All @@ -63,31 +65,50 @@ static gboolean
gtk_mixer_check_update(gm_app_p app) {
int error;
size_t changes = 0;
gmp_dev_list_t dev_list;
gmp_dev_p dev = NULL;

if (NULL == app->dev)
return (TRUE); /* No device. */
/* GUI update rate scaler. */
app->update_skip_counter ++;
if (UPDATE_SKIP_MAX_COUNT > app->update_skip_counter)
return (TRUE);
app->update_skip_counter = 0;

/* Default device change handle. */
if (0 != gmp_is_def_dev_changed(app->plugins,
app->plugins_count)) {
/* Devices list update check. */
if (gmp_is_list_devs_changed(app->plugins, app->plugins_count)) {
changes ++;
gtk_mixer_window_update_dev_list(app->window);
memset(&dev_list, 0x00, sizeof(dev_list));
error = gmp_list_devs(app->plugins, app->plugins_count,
&dev_list);
if (0 == error) {
/* Try to find old current dev in updated dev list. */
dev = gmp_dev_find_same(&dev_list, app->dev);
gtk_mixer_window_dev_list_update(app->window,
&dev_list);
gmp_dev_list_clear(&app->dev_list);
app->dev_list = dev_list;
/* Select new current device. */
if (NULL == dev) {
dev = gmp_dev_list_get_default(&app->dev_list);
}
gtk_mixer_window_dev_cur_set(app->window, dev);
}
} else if (0 != gmp_is_def_dev_changed(app->plugins,
app->plugins_count)) { /* Default device changed. */
changes ++;
gtk_mixer_window_dev_list_update(app->window, NULL);
}

/* Check lines update for current device. */
error = gmp_dev_read(app->dev, 1);
if (0 != error)
return (TRUE);
if (gmp_dev_is_updated(app->dev)) {
/* GUI update. */
gtk_mixer_window_update_lines(app->window);
gtk_mixer_tray_icon_update(app->status_icon);
changes += gmp_dev_is_updated_clear(app->dev);
if (NULL != app->dev) {
error = gmp_dev_read(app->dev, 1);
if (0 == error &&
gmp_dev_is_updated(app->dev)) {
/* GUI update. */
gtk_mixer_window_lines_update(app->window);
gtk_mixer_tray_icon_update(app->status_icon);
changes += gmp_dev_is_updated_clear(app->dev);
}
}

/* GUI update rate scaler. */
Expand All @@ -111,7 +132,7 @@ gtk_mixer_soundcard_changed(GtkWidget *combo __unused,
if (NULL == app)
return;

app->dev = gtk_mixer_window_get_dev(app->window);
app->dev = gtk_mixer_window_dev_cur_get(app->window);

/* Tray icon.*/
gtk_mixer_tray_icon_dev_set(app->status_icon, app->dev);
Expand Down Expand Up @@ -204,6 +225,7 @@ int
main(int argc, char **argv) {
int error;
gm_app_t app;
gmp_dev_p dev = NULL;

memset(&app, 0x00, sizeof(gm_app_t));

Expand All @@ -224,7 +246,23 @@ main(int argc, char **argv) {
gtk_window_set_default_icon_name(APP_ICON_NAME);

/* Main window. */
app.window = gtk_mixer_window_create(&app.dev_list);
app.window = gtk_mixer_window_create();
gtk_mixer_window_dev_list_update(app.window, &app.dev_list);
#if 0
if (card_name != NULL) {
dev = gtk_mixer_get_card(card_name);
} else {
dev = gtk_mixer_get_default_card();
g_object_set(gm_win->preferences, "sound-card",
gtk_mixer_get_card_internal_name(dev), NULL);
}
g_free(card_name);
#endif
if (NULL == dev) {
dev = gmp_dev_list_get_default(&app.dev_list);
}
gtk_mixer_window_dev_cur_set(app.window, dev);


/* Tray icon. */
app.status_icon = gtk_mixer_tray_icon_create();
Expand Down
Loading

0 comments on commit 0023a2a

Please sign in to comment.