diff options
Diffstat (limited to 'voss_devctl_gtk.c')
| -rw-r--r-- | voss_devctl_gtk.c | 180 |
1 files changed, 135 insertions, 45 deletions
diff --git a/voss_devctl_gtk.c b/voss_devctl_gtk.c index 3066fdf..6bbef1e 100644 --- a/voss_devctl_gtk.c +++ b/voss_devctl_gtk.c @@ -32,40 +32,80 @@ char voss_opts[2] = { [DEVTYPE_REC] = 'R' }; -struct device_selection_cb_data { +struct device_controls_cb_data { GtkWidget *combo; + GtkWidget *slider; int type; }; static void -voss_cmd_from_selections(GtkWidget *combo, int type) +update_volume_slider(GtkWidget *slider, int type) +{ + char devnode_mixer[PATH_MAX]; + unsigned int devnum; + size_t len = sizeof(int); + int mixer_fd, pcm_curr, vol_curr; + + /* associate mixer to dsp */ + sysctlbyname("hw.snd.default_unit", &devnum, &len, NULL, len); + snprintf(devnode_mixer, PATH_MAX, "/dev/mixer%u", devnum); + + gdouble vol_avg = 0.0; + + if (type == DEVTYPE_PLAY) { + if ((mixer_fd = open(devnode_mixer, O_RDONLY, 0)) > 0) { + ioctl(mixer_fd, MIXER_READ(SOUND_MIXER_VOLUME), &vol_curr); + ioctl(mixer_fd, MIXER_READ(SOUND_MIXER_PCM), &pcm_curr); + /* average of 4 channels - vol/pcm left/right */ + vol_avg = (double)((((vol_curr & 0xff) + ((vol_curr >> 8) & 0xff)) + + ((pcm_curr & 0xff) + ((pcm_curr >> 8) & 0xff))) >> 2); + (void)close(mixer_fd); + } + } else if (type == DEVTYPE_REC) { + if ((mixer_fd = open(devnode_mixer, O_RDONLY, 0)) > 0) { + ioctl(mixer_fd, MIXER_READ(SOUND_MIXER_MIC), &vol_curr); + /* average of 2 channels - left/right */ + vol_avg = (double)(((vol_curr & 0xff) + ((vol_curr >> 8) & 0xff)) >> 1); + (void)close(mixer_fd); + } + } + + if (vol_avg) { + gtk_range_set_value(GTK_RANGE(slider), vol_avg); + } +} + + +static void +apply_device_selections(GtkWidget *combo, int type) { GtkTreeModel *model; GtkTreeIter iter; - gchar *oss_devnode; - int voss_dsp_fd; + gchar *devnode_oss; + int voss_ctrl_fd; char options[VIRTUAL_OSS_OPTIONS_MAX]; if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) { model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo)); - gtk_tree_model_get(model, &iter, COL_VALUE, &oss_devnode, -1); + gtk_tree_model_get(model, &iter, COL_VALUE, &devnode_oss, -1); - if ((voss_dsp_fd = open(VOSS_DEV, O_WRONLY)) > 0) { + if ((voss_ctrl_fd = open(VOSS_DEV, O_WRONLY)) > 0) { snprintf(options, VIRTUAL_OSS_OPTIONS_MAX, - "-%c %s", voss_opts[type], oss_devnode); - ioctl(voss_dsp_fd, VIRTUAL_OSS_ADD_OPTIONS, &options); - close(voss_dsp_fd); + "-%c %s", voss_opts[type], devnode_oss); + ioctl(voss_ctrl_fd, VIRTUAL_OSS_ADD_OPTIONS, &options); + close(voss_ctrl_fd); } /* set the default mixer device - playback only */ unsigned int devnum; size_t len = sizeof(int); - if (type == DEVTYPE_PLAY && sscanf(oss_devnode, "/dev/dsp%u", &devnum)) { + if ((type == DEVTYPE_PLAY) + && (sscanf(devnode_oss, "/dev/dsp%u", &devnum) == 1)) { sysctlbyname("hw.snd.default_unit", NULL, &len, &devnum, len); } - g_free(oss_devnode); + g_free(devnode_oss); } } @@ -73,28 +113,29 @@ voss_cmd_from_selections(GtkWidget *combo, int type) static void cb_toggle_enabled(GtkToggleButton *button, gpointer user_data) { - struct device_selection_cb_data *data = user_data; + struct device_controls_cb_data *data = user_data; gboolean checked = gtk_toggle_button_get_active(button); assert(data->type < _NUM_DEVTYPES); /* disable the combo when checked */ gtk_widget_set_sensitive(data->combo, !checked); + gtk_widget_set_sensitive(GTK_WIDGET(data->slider), !checked); char options[VIRTUAL_OSS_OPTIONS_MAX]; - int voss_dsp_fd; + int voss_ctrl_fd; /* if disabled, set to /dev/null */ if (checked) { - if ((voss_dsp_fd = open(VOSS_DEV, O_WRONLY)) > 0) { + if ((voss_ctrl_fd = open(VOSS_DEV, O_WRONLY)) > 0) { snprintf(options, VIRTUAL_OSS_OPTIONS_MAX, "-%c /dev/null", voss_opts[data->type]); - ioctl(voss_dsp_fd, VIRTUAL_OSS_ADD_OPTIONS, &options); - close(voss_dsp_fd); + ioctl(voss_ctrl_fd, VIRTUAL_OSS_ADD_OPTIONS, &options); + close(voss_ctrl_fd); } - } - else { - voss_cmd_from_selections(GTK_WIDGET(data->combo), data->type); + } else { + apply_device_selections(GTK_WIDGET(data->combo), data->type); + update_volume_slider(GTK_WIDGET(data->slider), data->type); } } @@ -103,9 +144,44 @@ static void cb_dev_selected(GtkComboBox *combo, gpointer user_data) { int type = GPOINTER_TO_INT(user_data); - printf("%d\n", type); assert(type == DEVTYPE_PLAY || type == DEVTYPE_REC); - voss_cmd_from_selections(GTK_WIDGET(combo), type); + apply_device_selections(GTK_WIDGET(combo), type); +} + + +static gboolean +cb_volume_set(GtkWidget *slider, GdkEventButton *event, gpointer user_data) +{ + char devnode_mixer[PATH_MAX]; + unsigned int devnum; + size_t len = sizeof(int); + int mixer_fd, vol_targ, slider_val; + + (void)event; //unused + unsigned int type = GPOINTER_TO_INT(user_data); + + /* associate mixer to dsp */ + sysctlbyname("hw.snd.default_unit", &devnum, &len, NULL, len); + snprintf(devnode_mixer, PATH_MAX, "/dev/mixer%u", devnum); + + slider_val = (int)gtk_range_get_value(GTK_RANGE(slider)); + vol_targ = slider_val | (slider_val << 8); + + if (type == DEVTYPE_PLAY) { + if ((mixer_fd = open(devnode_mixer, O_WRONLY, 0)) > 0) { + ioctl(mixer_fd, SOUND_MIXER_WRITE_VOLUME, (int *)&vol_targ); + ioctl(mixer_fd, SOUND_MIXER_WRITE_PCM, (int *)&vol_targ); + (void)close(mixer_fd); + } + } else if (type == DEVTYPE_REC) { + if ((mixer_fd = open(devnode_mixer, O_WRONLY, 0)) > 0) { + ioctl(mixer_fd, SOUND_MIXER_WRITE_MIC, (int *)&vol_targ); + (void)close(mixer_fd); + } + } + + /* button release callback needs a return value */ + return FALSE; } @@ -145,8 +221,8 @@ combo_select_by_value(GtkWidget *combo, const char *val_target) static void -setup_device_selection(GtkListStore *store, GtkWidget *combo, - GtkWidget *check, int type) +setup_device_controls(GtkListStore *store, GtkWidget *combo, + GtkWidget *check, GtkWidget *slider, int type) { assert(type < _NUM_DEVTYPES); @@ -187,66 +263,72 @@ setup_device_selection(GtkListStore *store, GtkWidget *combo, close(oss_dsp_fd); struct virtual_oss_system_info vsi; - int voss_dsp_fd; + int voss_ctrl_fd; char options[VIRTUAL_OSS_OPTIONS_MAX]; /* the same for Virtual OSS */ - if ((voss_dsp_fd = open(VOSS_DEV, O_WRONLY)) == -1) { + if ((voss_ctrl_fd = open(VOSS_DEV, O_WRONLY)) == -1) { printf("Failed to open device %s: %s\n", VOSS_DEV, strerror(errno)); } - if (ioctl(voss_dsp_fd, VIRTUAL_OSS_GET_SYSTEM_INFO, &vsi) < 0) { + if (ioctl(voss_ctrl_fd, VIRTUAL_OSS_GET_SYSTEM_INFO, &vsi) < 0) { printf("Cannot get Virtual OSS system info: %s\n", strerror(errno)); } - close(voss_dsp_fd); + close(voss_ctrl_fd); char current_dev[OSS_DEVNODE_SIZE]; if (type == DEVTYPE_PLAY) { strncpy(current_dev, vsi.tx_device_name, OSS_DEVNODE_SIZE); - } - else if (type == DEVTYPE_REC) { + } else if (type == DEVTYPE_REC) { strncpy(current_dev, vsi.rx_device_name, OSS_DEVNODE_SIZE); } bool active = true; if (strncmp("/dev/null", current_dev, OSS_DEVNODE_SIZE)) { combo_select_by_value(combo, current_dev); - } - else { + } else { active = false; } /* if no match and not already /dev/null, revert to /dev/null */ if (active && gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) < 0) { active = false; - if ((voss_dsp_fd = open(VOSS_DEV, O_WRONLY)) > 0) { + if ((voss_ctrl_fd = open(VOSS_DEV, O_WRONLY)) > 0) { snprintf(options, VIRTUAL_OSS_OPTIONS_MAX, "-%c /dev/null", voss_opts[type]); - ioctl(voss_dsp_fd, VIRTUAL_OSS_ADD_OPTIONS, &options); - close(voss_dsp_fd); + ioctl(voss_ctrl_fd, VIRTUAL_OSS_ADD_OPTIONS, &options); + close(voss_ctrl_fd); } } if (!active) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE); gtk_widget_set_sensitive(combo, FALSE); + gtk_widget_set_sensitive(slider, FALSE); gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); } - struct device_selection_cb_data *data = g_new(struct device_selection_cb_data, 1); - data->combo = combo; - data->type = type; - GtkCellRenderer *render = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), render, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), render, "text", COL_TEXT, NULL); - g_signal_connect(combo, "changed", G_CALLBACK(cb_dev_selected), - GINT_TO_POINTER(type)); - g_signal_connect(check, "toggled", G_CALLBACK(cb_toggle_enabled), data); + gtk_scale_set_draw_value(GTK_SCALE(slider), FALSE); + update_volume_slider(slider, type); + + struct device_controls_cb_data *cb_data = g_new(struct device_controls_cb_data, 1); + cb_data->combo = combo; + cb_data->slider = slider; + cb_data->type = type; + + g_signal_connect(combo, "changed", + G_CALLBACK(cb_dev_selected), GINT_TO_POINTER(type)); + g_signal_connect(check, "toggled", + G_CALLBACK(cb_toggle_enabled), cb_data); + g_signal_connect(slider, "button-release-event", + G_CALLBACK(cb_volume_set), GINT_TO_POINTER(type)); } @@ -254,8 +336,8 @@ static void cb_init(GtkApplication* app, gpointer user_data) { GtkWidget *window, *vbox_main, - *hbox_play, *combo_play, *check_play, - *hbox_rec, *combo_rec, *check_rec; + *hbox_play, *combo_play, *check_play, *slider_play, + *hbox_rec, *combo_rec, *check_rec, *slider_rec; GtkListStore *store_play, *store_rec; (void)user_data; @@ -270,12 +352,18 @@ cb_init(GtkApplication* app, gpointer user_data) store_play = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); combo_play = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store_play)); check_play = gtk_check_button_new_with_label("Disabled"); - setup_device_selection(store_play, combo_play, check_play, DEVTYPE_PLAY); + slider_play = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, + 0.0, 100.0, 1.0); + setup_device_controls(store_play, combo_play, check_play, + slider_play, DEVTYPE_PLAY); store_rec = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); combo_rec = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store_rec)); check_rec = gtk_check_button_new_with_label("Disabled"); - setup_device_selection(store_rec, combo_rec, check_rec, DEVTYPE_REC); + slider_rec = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, + 0.0, 100.0, 1.0); + setup_device_controls(store_rec, combo_rec, check_rec, + slider_rec, DEVTYPE_REC); hbox_play = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); gtk_box_pack_start(GTK_BOX(hbox_play), combo_play, TRUE, TRUE, 0); @@ -287,7 +375,9 @@ cb_init(GtkApplication* app, gpointer user_data) vbox_main = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); gtk_box_pack_start(GTK_BOX(vbox_main), hbox_play, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox_main), slider_play, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox_main), hbox_rec, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox_main), slider_rec, FALSE, FALSE, 0); gtk_widget_set_margin_start(vbox_main, 12); gtk_widget_set_margin_end(vbox_main, 12); |
