From 563ebdbbabbc419bda6e1a8bd1150e490fada4e9 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Sun, 22 Feb 2026 02:35:17 +0545 Subject: [PATCH] feat(src): improve logging and refactor console output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhancements - Replace printf and LOG_ERROR with LOG_INFO, LOG_WARN, LOG_PERROR throughout src/app/process.c, src/app/watch.c, and src/audio/config.c - Use LOG_INFO for headings and formatted tables in sound‑pack listing - Add missing includes and clean up header organization Bug Fixes - Use LOG_PERROR for pipe, fork, and execl failures to log errno correctly - Ensure proper newline handling in config‑watcher log messages New Features - Introduce structured logging for configuration file changes and reload notifications - Provide clearer usage guidance via LOG_INFO --- src/app/process.c | 10 +- src/app/watch.c | 16 +- src/audio/config.c | 241 ++++++++++++++---------------- src/audio/main.c | 84 +++++------ src/audio/playback.c | 345 ++++++++++++++++--------------------------- src/cli.c | 10 +- src/input.c | 35 +++-- src/main.c | 58 ++++---- src/soundpacks.c | 75 +++++----- 9 files changed, 376 insertions(+), 498 deletions(-) diff --git a/src/app/process.c b/src/app/process.c index ddfb849..a959c33 100644 --- a/src/app/process.c +++ b/src/app/process.c @@ -100,12 +100,12 @@ int start_children(const char *sound_dir, const char *config_path, int volume, (void)mouse_sound_dir; int pipefd[2]; if (pipe(pipefd) == -1) { - LOG_ERROR("pipe: %s", strerror(errno)); + LOG_PERROR("pipe"); return 0; } sound_pid = fork(); if (sound_pid == -1) { - LOG_ERROR("fork: %s", strerror(errno)); + LOG_PERROR("fork"); close(pipefd[0]); close(pipefd[1]); return 0; @@ -141,12 +141,12 @@ int start_children(const char *sound_dir, const char *config_path, int volume, verbose_str, mute_str, mouse_config_path, mouse_volume_str, keyboard_mute_str, mouse_mute_str, keyboard_enabled_str, mouse_enabled_str, system_volume_following_str, (char *)NULL); - LOG_ERROR("execl vbx-audio: %s", strerror(errno)); + LOG_PERROR("execl vbx-audio"); exit(1); } keyboard_pid = fork(); if (keyboard_pid == -1) { - LOG_ERROR("fork: %s", strerror(errno)); + LOG_PERROR("fork"); kill(sound_pid, SIGTERM); close(pipefd[0]); close(pipefd[1]); @@ -160,7 +160,7 @@ int start_children(const char *sound_dir, const char *config_path, int volume, dup2(pipefd[1], STDOUT_FILENO); close(pipefd[1]); execl(get_key_presses_path, "vbx-input", (char *)NULL); - LOG_ERROR("execl vbx-input: %s", strerror(errno)); + LOG_PERROR("execl vbx-input"); exit(1); } close(pipefd[0]); diff --git a/src/app/watch.c b/src/app/watch.c index b9e56d4..d13c1d6 100644 --- a/src/app/watch.c +++ b/src/app/watch.c @@ -1,6 +1,7 @@ #include "app/watch.h" -#include "common/utils.h" #include "app/process.h" +#include "common/log.h" +#include "common/utils.h" #include #include #include @@ -17,18 +18,17 @@ static void *inotify_thread_fn(void *arg) { struct inotify_thread_args *a = (struct inotify_thread_args *)arg; int fd = inotify_init1(IN_NONBLOCK); if (fd < 0) { - printf("Failed to initialize inotify: %s\n", strerror(errno)); + LOG_PERROR("Failed to initialize inotify"); return NULL; } int wd = inotify_add_watch( fd, a->path, IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB | IN_MODIFY); if (wd < 0) { - printf("Failed to add inotify watch for %s: %s\n", a->path, - strerror(errno)); + LOG_PERROR("Failed to add inotify watch"); close(fd); return NULL; } - printf("Watching config file: %s\n", a->path); + LOG_INFO("Watching config file: %s", a->path); char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); while (1) { ssize_t len = read(fd, buf, sizeof(buf)); @@ -40,10 +40,10 @@ static void *inotify_thread_fn(void *arg) { nanosleep(&ts, NULL); continue; } - printf("inotify read error: %s\n", strerror(errno)); + LOG_PERROR("inotify read error"); break; } - printf("Config file changed, requesting reload...\n"); + LOG_INFO("Config file changed, requesting reload..."); handle_sighup(0); } inotify_rm_watch(fd, wd); @@ -60,7 +60,7 @@ int start_config_watcher(const char *path) { pthread_detach(inotify_thread); return 1; } else { - printf("Warning: Config file %s does not exist, file watching disabled\n", + LOG_WARN("Warning: Config file %s does not exist, file watching disabled", in_args.path); return 0; } diff --git a/src/audio/config.c b/src/audio/config.c index 3d9758d..3b0dada 100644 --- a/src/audio/config.c +++ b/src/audio/config.c @@ -1,4 +1,6 @@ +#include "audio/config.h" #include "audio/types.h" +#include "common/log.h" #include "common/utils.h" #include #include @@ -12,7 +14,6 @@ SoundPack g_sound_pack = {0}; SoundPack g_mouse_sound_pack = {0}; float g_volume = 1.0f; float g_mouse_volume = 1.0f; -int g_verbose = 0; int g_mute = 0; int g_keyboard_mute = 0; int g_mouse_mute = 0; @@ -32,12 +33,36 @@ static void get_full_path(char *buffer, size_t buffer_size, } } +static short *load_pcm_data(const char *path, uint32_t *out_samples, SF_INFO *out_info) { + if (!path || strlen(path) == 0) return NULL; + SF_INFO sf_info = {0}; + SNDFILE *sf = sf_open(path, SFM_READ, &sf_info); + if (!sf) return NULL; + + uint32_t total_samples = (uint32_t)(sf_info.frames * sf_info.channels); + short *buffer = malloc(total_samples * sizeof(short)); + if (!buffer) { + sf_close(sf); + return NULL; + } + + sf_count_t read = sf_readf_short(sf, buffer, sf_info.frames); + if (read < sf_info.frames) { + // Partial read or error + } + + sf_close(sf); + if (out_samples) *out_samples = total_samples; + if (out_info) *out_info = sf_info; + return buffer; +} -int load_sound_config(const char *config_path) { +int load_sound_config(const char *config_path, SoundPack *pack) { + memset(pack, 0, sizeof(SoundPack)); FILE *file = fopen(config_path, "r"); if (!file) { - safe_fprintf(stderr, "Error: Cannot open sound pack config: %s\n", config_path); - perror("fopen"); + LOG_ERROR("Error: Cannot open sound pack config: %s", config_path); + LOG_PERROR("fopen"); return -1; } char config_path_copy[1024]; @@ -47,20 +72,20 @@ int load_sound_config(const char *config_path) { long size = ftell(file); if (size < 0) { fclose(file); - safe_fprintf(stderr, "Error: ftell failed while reading %s\n", config_path); + LOG_ERROR("Error: ftell failed while reading %s", config_path); return -1; } errno = 0; rewind(file); if (errno != 0) { fclose(file); - safe_fprintf(stderr, "Error: rewind failed while reading %s\n", config_path); + LOG_ERROR("Error: rewind failed while reading %s", config_path); return -1; } char *json_string = malloc((size_t)size + 1); if (!json_string) { fclose(file); - safe_fprintf(stderr, "Error: Memory allocation failed\n"); + LOG_ERROR("Error: Memory allocation failed"); return -1; } fread(json_string, 1, size, file); @@ -69,170 +94,124 @@ int load_sound_config(const char *config_path) { json_object *root = json_tokener_parse(json_string); free(json_string); if (!root) { - safe_fprintf(stderr, "Error: Invalid JSON in sound pack config\n"); - safe_fprintf(stderr, "Check that the config.json file is properly formatted.\n"); + LOG_ERROR("Error: Invalid JSON in sound pack config"); return -1; } const char *key_type = "single"; json_object *obj; if (json_object_object_get_ex(root, "key_define_type", &obj)) key_type = json_object_get_string(obj); - g_sound_pack.is_multi = strcmp(key_type, "multi") == 0; - if (g_verbose) { - printf("Config loaded: Using %s mode\n", - g_sound_pack.is_multi ? "multi" : "single"); - } - if (g_sound_pack.is_multi) { - g_sound_pack.num_generic_press_files = 0; + + pack->is_multi = strcmp(key_type, "multi") == 0; + LOG_DEBUG("Config loaded: Using %s mode", pack->is_multi ? "multi" : "single"); + + if (pack->is_multi) { if (json_object_object_get_ex(root, "sound", &obj)) { const char *pattern = json_object_get_string(obj); - if (g_verbose) - printf("Sound pattern: %s\n", pattern); if (strstr(pattern, "%d") || strstr(pattern, "{")) { for (int i = 0; i <= 4; i++) { char temp_filename[256]; if (strstr(pattern, "{")) { - char temp_pattern[256]; - safe_strncpy(temp_pattern, pattern, sizeof(temp_pattern)); - char *brace_start = strstr(temp_pattern, "{"); - char *brace_end = strstr(temp_pattern, "}"); - if (brace_start && brace_end) { - *brace_start = '%'; - *(brace_start + 1) = 'd'; - safe_memmove(brace_start + 2, brace_end + 1, - strlen(brace_end + 1) + 1); - } - safe_snprintf_wrapper(temp_filename, sizeof(temp_filename), temp_pattern, i); + // Simple pattern replacement for {0}, {1}, etc. + safe_snprintf(temp_filename, sizeof(temp_filename), "%s", pattern); + char *brace = strstr(temp_filename, "{"); + if (brace) { + *brace = '0' + i; + safe_memmove(brace + 1, brace + 3, strlen(brace + 3) + 1); + } } else { - safe_snprintf_wrapper(temp_filename, sizeof(temp_filename), pattern, i); - } - get_full_path(g_sound_pack.generic_press_files[i], - sizeof(g_sound_pack.generic_press_files[i]), config_dir, - temp_filename); - if (access(g_sound_pack.generic_press_files[i], R_OK) == 0) { - g_sound_pack.num_generic_press_files = i + 1; - } else { - if (g_verbose) - printf("Generic sound file not found: %s\n", - g_sound_pack.generic_press_files[i]); - break; + safe_snprintf(temp_filename, sizeof(temp_filename), pattern, i); } + get_full_path(pack->generic_press_files[i], sizeof(pack->generic_press_files[i]), config_dir, temp_filename); + if (access(pack->generic_press_files[i], R_OK) == 0) { + pack->num_generic_press_files = i + 1; + pack->generic_press_data[i] = load_pcm_data(pack->generic_press_files[i], &pack->generic_press_samples[i], NULL); + } else break; } } else { - get_full_path(g_sound_pack.generic_press_files[0], - sizeof(g_sound_pack.generic_press_files[0]), config_dir, - pattern); - if (access(g_sound_pack.generic_press_files[0], R_OK) == 0) { - g_sound_pack.num_generic_press_files = 1; - if (g_verbose) - printf("Found single generic sound file: %s\n", - g_sound_pack.generic_press_files[0]); + get_full_path(pack->generic_press_files[0], sizeof(pack->generic_press_files[0]), config_dir, pattern); + if (access(pack->generic_press_files[0], R_OK) == 0) { + pack->num_generic_press_files = 1; + pack->generic_press_data[0] = load_pcm_data(pack->generic_press_files[0], &pack->generic_press_samples[0], NULL); + LOG_DEBUG("Generic sound cached: %s", pack->generic_press_files[0]); } } - if (g_verbose) - printf("Total generic press sound files: %d\n", - g_sound_pack.num_generic_press_files); } if (json_object_object_get_ex(root, "soundup", &obj)) { - char temp_release_file[256]; - safe_strncpy(temp_release_file, json_object_get_string(obj), - sizeof(temp_release_file)); - get_full_path(g_sound_pack.release_file, - sizeof(g_sound_pack.release_file), config_dir, - temp_release_file); - if (g_verbose) - printf("Release sound file: %s\n", g_sound_pack.release_file); + get_full_path(pack->release_file, sizeof(pack->release_file), config_dir, json_object_get_string(obj)); + pack->release_data = load_pcm_data(pack->release_file, &pack->release_samples, NULL); + LOG_DEBUG("Release sound cached: %s", pack->release_file); } if (json_object_object_get_ex(root, "defines", &obj)) { json_object_object_foreach(obj, key, val) { - int key_code; + int key_code = -1; int is_release = 0; - if (strcmp(key, "MouseLeft") == 0) { - key_code = 272; - } else if (strcmp(key, "MouseRight") == 0) { - key_code = 273; - } else if (strcmp(key, "MouseMiddle") == 0) { - key_code = 274; - } else { - char *dash = strstr(key, "-up"); - if (dash) { - char key_copy[16]; - safe_strncpy(key_copy, key, dash - key + 1); - key_copy[dash - key] = '\0'; - key_code = atoi(key_copy); - is_release = 1; - } else { - key_code = atoi(key); - } + if (strcmp(key, "MouseLeft") == 0) key_code = 272; + else if (strcmp(key, "MouseRight") == 0) key_code = 273; + else if (strcmp(key, "MouseMiddle") == 0) key_code = 274; + else { + char *up = strstr(key, "-up"); + if (up) { is_release = 1; key_code = atoi(key); } + else key_code = atoi(key); } if (key_code >= 0 && key_code < 512) { - const char *filename_relative = json_object_get_string(val); - char full_filename[1024]; - get_full_path(full_filename, sizeof(full_filename), config_dir, - filename_relative); + char full_path[1024]; + get_full_path(full_path, sizeof(full_path), config_dir, json_object_get_string(val)); if (is_release) { - if (g_sound_pack.multi_key_mappings[key_code].release) - free(g_sound_pack.multi_key_mappings[key_code].release); - g_sound_pack.multi_key_mappings[key_code].release = - xstrdup(full_filename); + pack->multi_key_mappings[key_code].release = xstrdup(full_path); + pack->multi_key_mappings[key_code].release_data = load_pcm_data(full_path, &pack->multi_key_mappings[key_code].release_samples, NULL); + LOG_DEBUG("Key %d-up cached: %s", key_code, full_path); } else { - if (g_sound_pack.multi_key_mappings[key_code].press) - free(g_sound_pack.multi_key_mappings[key_code].press); - g_sound_pack.multi_key_mappings[key_code].press = - xstrdup(full_filename); + pack->multi_key_mappings[key_code].press = xstrdup(full_path); + pack->multi_key_mappings[key_code].press_data = load_pcm_data(full_path, &pack->multi_key_mappings[key_code].press_samples, NULL); + LOG_DEBUG("Key %d cached: %s", key_code, full_path); } } } } } else { - if (json_object_object_get_ex(root, "sound", &obj) || - json_object_object_get_ex(root, "audio_file", &obj)) { - char temp_sound_file[256]; - safe_strncpy(temp_sound_file, json_object_get_string(obj), - sizeof(temp_sound_file)); - get_full_path(g_sound_pack.sound_file, sizeof(g_sound_pack.sound_file), - config_dir, temp_sound_file); - if (g_verbose) - printf("Single mode sound file: %s\n", g_sound_pack.sound_file); + if (json_object_object_get_ex(root, "sound", &obj) || json_object_object_get_ex(root, "audio_file", &obj)) { + get_full_path(pack->sound_file, sizeof(pack->sound_file), config_dir, json_object_get_string(obj)); + uint32_t s; + short *d = load_pcm_data(pack->sound_file, &s, &pack->sf_info); + if (d) free(d); + LOG_DEBUG("Single mode sound file: %s (metadata loaded)", pack->sound_file); } json_object *defines_obj = NULL; - if (json_object_object_get_ex(root, "defines", &defines_obj) || - json_object_object_get_ex(root, "definitions", &defines_obj)) { + if (json_object_object_get_ex(root, "defines", &defines_obj) || json_object_object_get_ex(root, "definitions", &defines_obj)) { json_object_object_foreach(defines_obj, key, val) { - int key_code; - if (strcmp(key, "MouseLeft") == 0) { - key_code = 272; - } else if (strcmp(key, "MouseRight") == 0) { - key_code = 273; - } else if (strcmp(key, "MouseMiddle") == 0) { - key_code = 274; - } else { - key_code = atoi(key); - } + int key_code = -1; + if (strcmp(key, "MouseLeft") == 0) key_code = 272; + else if (strcmp(key, "MouseRight") == 0) key_code = 273; + else if (strcmp(key, "MouseMiddle") == 0) key_code = 274; + else key_code = atoi(key); + if (key_code >= 0 && key_code < 512) { if (json_object_is_type(val, json_type_array)) { - if (json_object_array_length(val) >= 2) { - g_sound_pack.key_mappings[key_code].start_ms = - json_object_get_int(json_object_array_get_idx(val, 0)); - g_sound_pack.key_mappings[key_code].duration_ms = - json_object_get_int(json_object_array_get_idx(val, 1)); - } + pack->key_mappings[key_code].start_ms = json_object_get_int(json_object_array_get_idx(val, 0)); + pack->key_mappings[key_code].duration_ms = json_object_get_int(json_object_array_get_idx(val, 1)); } else if (json_object_is_type(val, json_type_object)) { - json_object *timing_array; - if (json_object_object_get_ex(val, "timing", &timing_array) && - json_object_is_type(timing_array, json_type_array) && - json_object_array_length(timing_array) > 0) { - json_object *first_timing = - json_object_array_get_idx(timing_array, 0); - if (json_object_is_type(first_timing, json_type_array) && - json_object_array_length(first_timing) >= 2) { - g_sound_pack.key_mappings[key_code].start_ms = - json_object_get_int( - json_object_array_get_idx(first_timing, 0)); - g_sound_pack.key_mappings[key_code].duration_ms = - json_object_get_int( - json_object_array_get_idx(first_timing, 1)); + json_object *timings; + if (json_object_object_get_ex(val, "timing", &timings) && json_object_array_length(timings) > 0) { + json_object *t = json_object_array_get_idx(timings, 0); + pack->key_mappings[key_code].start_ms = json_object_get_int(json_object_array_get_idx(t, 0)); + pack->key_mappings[key_code].duration_ms = json_object_get_int(json_object_array_get_idx(t, 1)); + } + } + if (pack->key_mappings[key_code].duration_ms > 0) { + uint32_t sr = pack->sf_info.samplerate; + uint32_t ch = pack->sf_info.channels; + uint32_t start_frame = (pack->key_mappings[key_code].start_ms * sr) / 1000; + uint32_t duration_frames = (pack->key_mappings[key_code].duration_ms * sr) / 1000; + SNDFILE *sf = sf_open(pack->sound_file, SFM_READ, &pack->sf_info); + if (sf) { + sf_seek(sf, start_frame, SEEK_SET); + pack->key_mappings[key_code].num_samples = duration_frames * ch; + pack->key_mappings[key_code].pcm_data = malloc(pack->key_mappings[key_code].num_samples * sizeof(short)); + if (pack->key_mappings[key_code].pcm_data) { + sf_readf_short(sf, pack->key_mappings[key_code].pcm_data, duration_frames); } + sf_close(sf); } } } diff --git a/src/audio/main.c b/src/audio/main.c index 1e34349..9b12fc2 100644 --- a/src/audio/main.c +++ b/src/audio/main.c @@ -1,4 +1,5 @@ #define _XOPEN_SOURCE 500 +#include "audio/config.h" #include "audio/playback.h" #include "audio/types.h" #include "common/utils.h" @@ -18,8 +19,6 @@ int g_mouse_enabled = 1; int g_system_volume_following = 0; float g_system_volume_multiplier = 1.0f; -int load_sound_config(const char *config_path); - // Generic function to read runtime state files static int read_runtime_state(const char *filename_suffix, int default_value) { char state_file[1024]; @@ -93,98 +92,86 @@ void *system_volume_poller_thread(void *arg) { } else { g_system_volume_multiplier = 1.0f; } - usleep(500000); // 500ms + struct timespec ts = {0, 500000000L}; + nanosleep(&ts, NULL); // 500ms } return NULL; } int main(int argc, char *argv[]) { if (argc < 2 || argc > 12) { - safe_fprintf(stderr, - "Usage: %s [volume] [verbose] [mute] [mouse_config] " - "[mouse_volume] [keyboard_mute] [mouse_mute] [keyboard_enabled] " - "[mouse_enabled] [system_volume_following]\n", - argv[0]); - safe_fprintf(stderr, " volume: 0-100 (default: 50)\n"); - safe_fprintf(stderr, " verbose: 1 to enable verbose output (default: 0)\n"); - safe_fprintf(stderr, " mute: 1 to mute all sound (default: 0)\n"); - safe_fprintf(stderr, " mouse_config: path to mouse config.json (optional)\n"); - safe_fprintf(stderr, " mouse_volume: 0-100 for mouse volume (optional)\n"); - safe_fprintf(stderr, " keyboard_mute: 1 to mute keyboard sounds (optional)\n"); - safe_fprintf(stderr, " mouse_mute: 1 to mute mouse sounds (optional)\n"); - safe_fprintf(stderr, - " keyboard_enabled: 1 to enable keyboard sounds (optional)\n"); - safe_fprintf(stderr, " mouse_enabled: 1 to enable mouse sounds (optional)\n"); + LOG_ERROR("Usage: %s [volume] [verbose] [mute] [mouse_config] " + "[mouse_volume] [keyboard_mute] [mouse_mute] [keyboard_enabled] " + "[mouse_enabled] [system_volume_following]", + argv[0]); + LOG_ERROR(" volume: 0-100 (default: 50)"); + LOG_ERROR(" verbose: 1 to enable verbose output (default: 0)"); + LOG_ERROR(" mute: 1 to mute all sound (default: 0)"); + LOG_ERROR(" mouse_config: path to mouse config.json (optional)"); + LOG_ERROR(" mouse_volume: 0-100 for mouse volume (optional)"); + LOG_ERROR(" keyboard_mute: 1 to mute keyboard sounds (optional)"); + LOG_ERROR(" mouse_mute: 1 to mute mouse sounds (optional)"); + LOG_ERROR(" keyboard_enabled: 1 to enable keyboard sounds (optional)"); + LOG_ERROR(" mouse_enabled: 1 to enable mouse sounds (optional)"); return 1; } if (argc >= 3) { int volume_percent = validate_volume(atoi(argv[2])); g_volume = volume_percent / 100.0f; - if (g_verbose) - printf("Volume set to: %d%%\n", volume_percent); + LOG_DEBUG("Volume set to: %d%%", volume_percent); } else { - if (g_verbose) - printf("Volume set to: 50%% (default)\n"); + LOG_DEBUG("Volume set to: 50%% (default)"); } if (argc >= 4) { g_verbose = atoi(argv[3]); if (g_verbose) { - printf("Verbose mode enabled\n"); + LOG_INFO("Verbose mode enabled"); } } if (argc >= 5) { g_mute = atoi(argv[4]); if (g_mute) { - printf("Sound muted\n"); + LOG_INFO("Sound muted"); } } if (argc >= 6) { - if (load_sound_config(argv[5]) != 0) { - safe_fprintf(stderr, "Failed to load mouse sound configuration\n"); + if (load_sound_config(argv[5], &g_mouse_sound_pack) != 0) { + LOG_ERROR("Failed to load mouse sound configuration"); return 1; } - g_mouse_sound_pack = g_sound_pack; - if (g_verbose) { - printf("Mouse sound pack loaded from: %s\n", argv[5]); - } + LOG_DEBUG("Mouse sound pack loaded from: %s", argv[5]); } if (argc >= 7) { int mouse_volume_percent = validate_volume(atoi(argv[6])); g_mouse_volume = mouse_volume_percent / 100.0f; - if (g_verbose) - printf("Mouse volume set to: %d%%\n", mouse_volume_percent); + LOG_DEBUG("Mouse volume set to: %d%%", mouse_volume_percent); } if (argc >= 8) { g_keyboard_mute = atoi(argv[7]); - if (g_verbose) - printf("Keyboard mute: %s\n", g_keyboard_mute ? "enabled" : "disabled"); + LOG_DEBUG("Keyboard mute: %s", g_keyboard_mute ? "enabled" : "disabled"); } if (argc >= 9) { g_mouse_mute = atoi(argv[8]); - if (g_verbose) - printf("Mouse mute: %s\n", g_mouse_mute ? "enabled" : "disabled"); + LOG_DEBUG("Mouse mute: %s", g_mouse_mute ? "enabled" : "disabled"); } if (argc >= 10) { g_keyboard_enabled = atoi(argv[9]); - if (g_verbose) - printf("Keyboard enabled: %s\n", g_keyboard_enabled ? "yes" : "no"); + LOG_DEBUG("Keyboard enabled: %s", g_keyboard_enabled ? "yes" : "no"); } if (argc >= 11) { g_mouse_enabled = atoi(argv[10]); - if (g_verbose) - printf("Mouse enabled: %s\n", g_mouse_enabled ? "yes" : "no"); + LOG_DEBUG("Mouse enabled: %s", g_mouse_enabled ? "yes" : "no"); } if (argc >= 12) { g_system_volume_following = atoi(argv[11]); - if (g_verbose) - printf("System volume following: %s\n", g_system_volume_following ? "yes" : "no"); + LOG_DEBUG("System volume following: %s", g_system_volume_following ? "yes" : "no"); } - if (load_sound_config(argv[1]) != 0) { - safe_fprintf(stderr, "Failed to load keyboard sound configuration\n"); + if (load_sound_config(argv[1], &g_sound_pack) != 0) { + LOG_ERROR("Failed to load keyboard sound configuration"); return 1; } if (init_audio() != 0) { - safe_fprintf(stderr, "Failed to initialize audio\n"); + LOG_ERROR("Failed to initialize audio"); return 1; } @@ -212,12 +199,9 @@ int main(int argc, char *argv[]) { if (errno == EINTR) { continue; } - perror("select"); + LOG_PERROR("select"); break; } else if (ready == 0) { - if (g_verbose) { - printf("Waiting for input...\n"); - } continue; } if (FD_ISSET(STDIN_FILENO, &readfds)) { @@ -226,7 +210,7 @@ int main(int argc, char *argv[]) { if (feof(stdin)) { LOG_DEBUG("EOF reached on stdin"); } else { - perror("fread"); + LOG_PERROR("fread"); } break; } diff --git a/src/audio/playback.c b/src/audio/playback.c index 4872916..99ab36f 100644 --- a/src/audio/playback.c +++ b/src/audio/playback.c @@ -1,3 +1,4 @@ +#define _DEFAULT_SOURCE #include "audio/playback.h" #include "audio/types.h" #include "common/utils.h" @@ -10,10 +11,13 @@ #include #include #include +#include -pthread_t sound_threads[MAX_CONCURRENT_SOUNDS]; -volatile int thread_active[MAX_CONCURRENT_SOUNDS] = {0}; -pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; +static pa_simple *g_pa_handle = NULL; +static AudioVoice g_mixer_voices[MAX_MIXER_VOICES] = {0}; +static pthread_mutex_t g_mixer_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_t g_mixer_thread; +static volatile int g_mixer_running = 0; static inline float get_boosted_system_volume(float vol_multiplier) { if (vol_multiplier >= 1.0f) return vol_multiplier; @@ -22,236 +26,145 @@ static inline float get_boosted_system_volume(float vol_multiplier) { return 1.0f - (inv * inv * inv); } -int init_audio() { - if (g_sound_pack.is_multi) - return 0; - if (strlen(g_sound_pack.sound_file) == 0) { - LOG_ERROR("No sound file specified in sound pack config"); - LOG_ERROR("Check that your sound pack has a valid config.json file."); - return -1; - } - if (access(g_sound_pack.sound_file, R_OK) != 0) { - LOG_ERROR("Sound file not accessible: %s", g_sound_pack.sound_file); - perror("access"); - return -1; - } - SNDFILE *test_sf = - sf_open(g_sound_pack.sound_file, SFM_READ, &g_sound_pack.sf_info); - if (!test_sf) { - LOG_ERROR("Could not open sound file: %s", g_sound_pack.sound_file); - LOG_ERROR("libsndfile error: %s", sf_strerror(NULL)); - return -1; - } - sf_close(test_sf); - LOG_DEBUG("Sound file info: %ld frames, %d channels, %d Hz", - (long)g_sound_pack.sf_info.frames, g_sound_pack.sf_info.channels, - g_sound_pack.sf_info.samplerate); - return 0; -} - -void *play_sound_thread(void *arg) { - PlaybackData *data = (PlaybackData *)arg; - int key_code = data->key_code; - int thread_id = data->thread_id; - int is_pressed = data->is_pressed; - const char *file_to_play = NULL; - - int is_mouse_event = (key_code == 272 || key_code == 273 || key_code == 274); - SoundPack *sound_pack = is_mouse_event ? &g_mouse_sound_pack : &g_sound_pack; - float volume = is_mouse_event ? g_mouse_volume : g_volume; - int mute_state = is_mouse_event ? g_mouse_mute : g_keyboard_mute; - - LOG_DEBUG("Thread %d: Playing %s sound for key %d (%s)", thread_id, - is_mouse_event ? "mouse" : "keyboard", key_code, - is_pressed ? "press" : "release"); - - if (g_mute || mute_state) { - LOG_DEBUG("Thread %d: %s sound is muted", thread_id, - is_mouse_event ? "Mouse" : "Keyboard"); - goto exit_cleanup; - } - if (sound_pack->is_multi) { - if (is_pressed && sound_pack->multi_key_mappings[key_code].press) - file_to_play = sound_pack->multi_key_mappings[key_code].press; - else if (!is_pressed && sound_pack->multi_key_mappings[key_code].release) - file_to_play = sound_pack->multi_key_mappings[key_code].release; - else if (is_pressed && sound_pack->num_generic_press_files > 0) { - int idx = rand() % sound_pack->num_generic_press_files; - file_to_play = sound_pack->generic_press_files[idx]; - } else if (!is_pressed && strlen(sound_pack->release_file) > 0) - file_to_play = sound_pack->release_file; - if (!file_to_play) { - LOG_DEBUG("Thread %d: No sound file found for key %d (%s)", thread_id, - key_code, is_pressed ? "press" : "release"); - goto exit_cleanup; - } - LOG_DEBUG("Thread %d: Using sound file: %s", thread_id, file_to_play); - SF_INFO sf_info = {0}; - SNDFILE *sf = sf_open(file_to_play, SFM_READ, &sf_info); - if (!sf) { - LOG_ERROR("Could not open sound file: %s", file_to_play); - LOG_ERROR("Details: %s", sf_strerror(NULL)); - LOG_ERROR("Check that the audio file exists and is readable."); - goto exit_cleanup; - } - pa_sample_spec ss = {.format = PA_SAMPLE_S16LE, - .rate = sf_info.samplerate, - .channels = sf_info.channels}; - int pa_error; - pa_simple *pa_handle = - pa_simple_new(NULL, "KeyboardSounds", PA_STREAM_PLAYBACK, NULL, - "playback", &ss, NULL, NULL, &pa_error); - if (!pa_handle) { - LOG_ERROR("Could not initialize PulseAudio: %s", pa_strerror(pa_error)); - sf_close(sf); - goto exit_cleanup; - } - int frames = 2048; - short *buffer = malloc(frames * sf_info.channels * sizeof(short)); - if (!buffer) { - pa_simple_free(pa_handle); - sf_close(sf); - goto exit_cleanup; - } - sf_count_t read; - while ((read = sf_readf_short(sf, buffer, frames)) > 0) { - float vol_mult = volume * get_boosted_system_volume(g_system_volume_multiplier); - for (sf_count_t i = 0; i < read * sf_info.channels; i++) { - buffer[i] = (short)(buffer[i] * vol_mult); +void *mixer_thread_func(void *arg) { + (void)arg; + const int chunk_frames = 512; + const int channels = g_sound_pack.sf_info.channels ? g_sound_pack.sf_info.channels : 2; + short *mix_buffer = malloc(chunk_frames * channels * sizeof(short)); + + while (g_mixer_running) { + memset(mix_buffer, 0, chunk_frames * channels * sizeof(short)); + int any_active = 0; + + pthread_mutex_lock(&g_mixer_mutex); + float sys_vol = get_boosted_system_volume(g_system_volume_multiplier); + + for (int i = 0; i < MAX_MIXER_VOICES; i++) { + if (!g_mixer_voices[i].active) continue; + any_active = 1; + + uint32_t samples_to_copy = chunk_frames * channels; + if (g_mixer_voices[i].current_pos + samples_to_copy > g_mixer_voices[i].total_samples) { + samples_to_copy = g_mixer_voices[i].total_samples - g_mixer_voices[i].current_pos; } - int pa_write_error; - if (pa_simple_write(pa_handle, buffer, - read * sf_info.channels * sizeof(short), - &pa_write_error) < 0) { - LOG_ERROR("PulseAudio write error: %s", pa_strerror(pa_write_error)); - break; + + float vol = g_mixer_voices[i].volume * sys_vol; + for (uint32_t s = 0; s < samples_to_copy; s++) { + int32_t mixed = mix_buffer[s] + (int32_t)(g_mixer_voices[i].data[g_mixer_voices[i].current_pos + s] * vol); + // Clip + if (mixed > 32767) mixed = 32767; + else if (mixed < -32768) mixed = -32768; + mix_buffer[s] = (short)mixed; + } + + g_mixer_voices[i].current_pos += samples_to_copy; + if (g_mixer_voices[i].current_pos >= g_mixer_voices[i].total_samples) { + g_mixer_voices[i].active = 0; } } - int pa_drain_error; - pa_simple_drain(pa_handle, &pa_drain_error); - pa_simple_free(pa_handle); - sf_close(sf); - free(buffer); - } else { - if (key_code >= 512 || - sound_pack->key_mappings[key_code].duration_ms == 0) { - LOG_DEBUG("Thread %d: No mapping for key %d", thread_id, key_code); - goto exit_cleanup; + pthread_mutex_unlock(&g_mixer_mutex); + + if (any_active) { + int pa_error; + if (pa_simple_write(g_pa_handle, mix_buffer, chunk_frames * channels * sizeof(short), &pa_error) < 0) { + LOG_ERROR("PulseAudio write error: %s", pa_strerror(pa_error)); + } + } else { + // Nothing playing, sleep a bit to avoid CPU spin + struct timespec ts = {0, 10000000L}; + nanosleep(&ts, NULL); // 10ms } - SoundMapping *mapping = &sound_pack->key_mappings[key_code]; - SF_INFO sf_info = sound_pack->sf_info; - SNDFILE *sf = sf_open(sound_pack->sound_file, SFM_READ, &sf_info); - if (!sf) { - LOG_ERROR("Thread: Could not open sound file"); - goto exit_cleanup; - } - pa_sample_spec ss = {.format = PA_SAMPLE_S16LE, - .rate = sf_info.samplerate, - .channels = sf_info.channels}; - int pa_error; - pa_simple *pa_handle = - pa_simple_new(NULL, "KeyboardSounds", PA_STREAM_PLAYBACK, NULL, - "playback", &ss, NULL, NULL, &pa_error); - if (!pa_handle) { - sf_close(sf); - LOG_ERROR("Thread: Could not initialize PulseAudio: %s", pa_strerror(pa_error)); - goto exit_cleanup; - } - sf_count_t start_frame = (mapping->start_ms * sf_info.samplerate) / 1000; - sf_count_t duration_frames = - (mapping->duration_ms * sf_info.samplerate) / 1000; - sf_seek(sf, start_frame, SEEK_SET); - short *buffer = malloc(duration_frames * sf_info.channels * sizeof(short)); - if (!buffer) { - pa_simple_free(pa_handle); - sf_close(sf); - goto exit_cleanup; - } - sf_count_t frames_read = sf_readf_short(sf, buffer, duration_frames); - float vol_mult = volume * get_boosted_system_volume(g_system_volume_multiplier); - for (sf_count_t i = 0; i < frames_read * sf_info.channels; i++) { - buffer[i] = (short)(buffer[i] * vol_mult); - } - int pa_write_error, pa_drain_error; - pa_simple_write(pa_handle, buffer, - frames_read * sf_info.channels * sizeof(short), - &pa_write_error); - pa_simple_drain(pa_handle, &pa_drain_error); - free(buffer); - pa_simple_free(pa_handle); - sf_close(sf); } -exit_cleanup: - pthread_mutex_lock(&thread_mutex); - thread_active[thread_id] = 0; - pthread_mutex_unlock(&thread_mutex); - free(data); + + free(mix_buffer); return NULL; } -int find_available_thread_slot() { - pthread_mutex_lock(&thread_mutex); - for (int i = 0; i < MAX_CONCURRENT_SOUNDS; i++) { - if (!thread_active[i]) { - pthread_mutex_unlock(&thread_mutex); - return i; - } +int init_audio() { + // Use keyboard pack as reference for samplerate/channels + pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = g_sound_pack.sf_info.samplerate ? g_sound_pack.sf_info.samplerate : 44100, + .channels = g_sound_pack.sf_info.channels ? g_sound_pack.sf_info.channels : 2 + }; + + int pa_error; + g_pa_handle = pa_simple_new(NULL, "vbx", PA_STREAM_PLAYBACK, NULL, "clicks", &ss, NULL, NULL, &pa_error); + if (!g_pa_handle) { + LOG_ERROR("Could not initialize PulseAudio stream: %s", pa_strerror(pa_error)); + return -1; } - pthread_mutex_unlock(&thread_mutex); - return -1; + + g_mixer_running = 1; + if (pthread_create(&g_mixer_thread, NULL, mixer_thread_func, NULL) != 0) { + LOG_ERROR("Failed to create mixer thread"); + return -1; + } + + return 0; } void play_sound_segment(int key_code, int is_pressed) { - if (g_mute) { - LOG_DEBUG("Sound muted - ignoring key %d (%s)", key_code, - is_pressed ? "press" : "release"); - return; - } + if (g_mute) return; + + int is_mouse = (key_code == 272 || key_code == 273 || key_code == 274); + int device_enabled = is_mouse ? g_mouse_enabled : g_keyboard_enabled; + if (!device_enabled) return; - // Check if this is a mouse event and if mouse is disabled - int is_mouse_event = (key_code == 272 || key_code == 273 || key_code == 274); - if (is_mouse_event) { - // For mouse events, we need to check if mouse is enabled - // This will be handled by the main loop passing enabled state - // For now, we'll add a simple check here - extern int g_mouse_enabled; - if (!g_mouse_enabled) { - LOG_DEBUG("Mouse sounds disabled - ignoring mouse event %d", key_code); - return; + SoundPack *pack = is_mouse ? &g_mouse_sound_pack : &g_sound_pack; + float volume = is_mouse ? g_mouse_volume : g_volume; + int device_mute = is_mouse ? g_mouse_mute : g_keyboard_mute; + + if (device_mute) return; + + short *pcm_data = NULL; + uint32_t num_samples = 0; + + if (pack->is_multi) { + if (is_pressed) { + if (pack->multi_key_mappings[key_code].press_data) { + pcm_data = pack->multi_key_mappings[key_code].press_data; + num_samples = pack->multi_key_mappings[key_code].press_samples; + } else if (pack->num_generic_press_files > 0) { + int idx = rand() % pack->num_generic_press_files; + pcm_data = pack->generic_press_data[idx]; + num_samples = pack->generic_press_samples[idx]; + } + } else { + if (pack->multi_key_mappings[key_code].release_data) { + pcm_data = pack->multi_key_mappings[key_code].release_data; + num_samples = pack->multi_key_mappings[key_code].release_samples; + } else if (pack->release_data) { + pcm_data = pack->release_data; + num_samples = pack->release_samples; + } } } else { - // For keyboard events, check if keyboard is enabled - extern int g_keyboard_enabled; - if (!g_keyboard_enabled) { - LOG_DEBUG("Keyboard sounds disabled - ignoring key %d", key_code); - return; + if (is_pressed && key_code < 512) { + pcm_data = pack->key_mappings[key_code].pcm_data; + num_samples = pack->key_mappings[key_code].num_samples; } } - if (!g_sound_pack.is_multi && !is_pressed) { - LOG_DEBUG("Single mode: Ignoring key release for key %d", key_code); - return; + + if (!pcm_data || num_samples == 0) return; + + // Find a slot in the mixer + pthread_mutex_lock(&g_mixer_mutex); + int found = 0; + for (int i = 0; i < MAX_MIXER_VOICES; i++) { + if (!g_mixer_voices[i].active) { + g_mixer_voices[i].data = pcm_data; + g_mixer_voices[i].total_samples = num_samples; + g_mixer_voices[i].current_pos = 0; + g_mixer_voices[i].volume = volume; + g_mixer_voices[i].active = 1; + found = 1; + break; + } } - int slot = find_available_thread_slot(); - if (slot == -1) { - LOG_WARN("No available thread slots"); - return; + pthread_mutex_unlock(&g_mixer_mutex); + + if (!found) { + LOG_WARN("Mixer full, dropping sound"); } - PlaybackData *data = malloc(sizeof(PlaybackData)); - if (!data) - return; - data->key_code = key_code; - data->thread_id = slot; - data->is_pressed = is_pressed; - pthread_mutex_lock(&thread_mutex); - thread_active[slot] = 1; - if (pthread_create(&sound_threads[slot], NULL, play_sound_thread, data) != - 0) { - thread_active[slot] = 0; - free(data); - LOG_ERROR("Failed to create sound thread"); - } else { - pthread_detach(sound_threads[slot]); - } - pthread_mutex_unlock(&thread_mutex); } - diff --git a/src/cli.c b/src/cli.c index 5a3ed6d..e4e2ab0 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1,4 +1,5 @@ #include "app/cli.h" +#include "common/log.h" #include "common/utils.h" #include "config.h" #include @@ -18,8 +19,8 @@ static int parse_device_argument(const char *optarg, const char *action, } else if (strcmp(optarg, "mouse") == 0) { *mouse_value = value; } else { - safe_fprintf(stderr, "Error: Invalid device '%s' for %s\n", optarg, action); - safe_fprintf(stderr, "Valid options: keyboard, mouse, or both\n"); + LOG_ERROR("Error: Invalid device '%s' for %s", optarg, action); + LOG_ERROR("Valid options: keyboard, mouse, or both"); return 1; } return 0; @@ -138,9 +139,8 @@ int parse_cli(int argc, char **argv, CliOptions *out) { (n == 7 && strncmp(a, "disable", 7) == 0) || (n == 7 && strncmp(a, "verbose", 7) == 0) || (n == 23 && strncmp(a, "system-volume-following", 23) == 0))) { - safe_fprintf(stderr, "Error: Unknown option '%s'\n", argv[i]); - safe_fprintf(stderr, "Run '%s --help' to see available options.\n", - argv[0]); + LOG_ERROR("Error: Unknown option '%s'", argv[i]); + LOG_ERROR("Run '%s --help' to see available options.", argv[0]); return 1; } } diff --git a/src/input.c b/src/input.c index 2a6b7d3..e01d41c 100644 --- a/src/input.c +++ b/src/input.c @@ -1,6 +1,8 @@ +#define _POSIX_C_SOURCE 200809L #include "common/utils.h" #include "common/ipc.h" #include "common/log.h" +#include #include #include #include @@ -51,7 +53,7 @@ static int open_restricted(const char *path, int flags, void *user_data) { (void)user_data; int fd = open(path, flags); if (fd < 0) - errorf("Failed to open %s because of %s.\n", path, strerror(errno)); + LOG_PERROR("Failed to open path"); return fd < 0 ? -errno : fd; } @@ -121,15 +123,17 @@ static int run_mainloop(struct libinput *libinput) { fd.fd = libinput_get_fd(libinput); fd.events = POLLIN; fd.revents = 0; - if (handle_events(libinput) != 0) - return errorf("Expected device added events on startup but got none. Maybe " - "you don't have the right permissions?\n"); + if (handle_events(libinput) != 0) { + LOG_ERROR("Expected device added events on startup but got none. Maybe you don't have the right permissions?"); + return -1; + } while (1) { - int pr = poll(&fd, 1, -1); + int pr = poll(&fd, 1, 10); if (pr < 0) { if (errno == EINTR) continue; - return errorf("poll failed: %s\n", strerror(errno)); + LOG_PERROR("poll failed"); + return -1; } handle_events(libinput); } @@ -148,7 +152,6 @@ void print_help(char *program_name) { "will run this.\n"); } -int g_verbose = 0; int is_daemon = 0; int main(int argc, char *argv[]) { @@ -172,19 +175,23 @@ int main(int argc, char *argv[]) { case '?': break; default: - errorf("%s: Invalid option `-%c`.\n", argv[0], opt); + LOG_ERROR("Invalid option `-%c`.", opt); break; } } struct udev *udev = udev_new(); - if (udev == NULL) - return errorf("Failed to initialize udev.\n"); + if (udev == NULL) { + LOG_ERROR("Failed to initialize udev."); + return 1; + } struct libinput *libinput = libinput_udev_create_context(&interface, NULL, udev); - if (!libinput) - return errorf("Failed to initialize libinput from udev.\n"); + if (!libinput) { + LOG_ERROR("Failed to initialize libinput from udev."); + return 1; + } if (libinput_udev_assign_seat(libinput, "seat0") != 0) { - errorf("Failed to set seat.\n"); + LOG_ERROR("Failed to set seat."); libinput_unref(libinput); udev_unref(udev); return SEAT_FAILED; @@ -193,7 +200,7 @@ int main(int argc, char *argv[]) { struct input_handler_data input_handler_data = {udev, libinput}; if (pthread_create(&input_handler, NULL, handle_input, &input_handler_data) != 0) { - errorf("Failed to create input handler thread.\n"); + LOG_ERROR("Failed to create input handler thread."); } else { pthread_detach(input_handler); } diff --git a/src/main.c b/src/main.c index 62ffd51..590f080 100644 --- a/src/main.c +++ b/src/main.c @@ -71,9 +71,7 @@ int main(int argc, char *argv[]) { char user_cfg_path[MAX_PATH_LENGTH]; if (get_user_config_path(user_cfg_path, sizeof(user_cfg_path))) { if (access(user_cfg_path, R_OK) == 0) { - if (verbose) { - LOG_INFO("Loading configuration from: %s", user_cfg_path); - } + LOG_DEBUG("Loading configuration from: %s", user_cfg_path); char *cfg_keyboard_sound = NULL; char *cfg_mouse_sound = NULL; int cfg_keyboard_volume = current_keyboard_volume; @@ -144,10 +142,9 @@ int main(int argc, char *argv[]) { // Show welcome message for first-time users if (access(user_cfg_path, F_OK) != 0 && !flag_daemon) { - printf("\nWelcome to VBX!\n"); - printf("This appears to be your first time running VBX.\n"); - printf("A default configuration will be created at: %s\n", user_cfg_path); - printf("\n"); + LOG_INFO("Welcome to VBX!"); + LOG_INFO("This appears to be your first time running VBX."); + LOG_INFO("A default configuration will be created at: %s", user_cfg_path); } build_pidfile_path(pidfile_path, 1024); if (flag_stop) { @@ -168,7 +165,8 @@ int main(int argc, char *argv[]) { if (mouse_sound_name_owned) { free(mouse_sound_name); } - return (perror("kill"), 1); + LOG_PERROR("kill"); + return 1; } for (int i = 0; i < 30; i++) { if (!process_is_running(running_pid)) { @@ -193,8 +191,8 @@ int main(int argc, char *argv[]) { if (mouse_sound_name_owned) { free(mouse_sound_name); } - return errorf( - "VBX: daemon did not stop in time. Try running 'vbx --stop' again.\n"); + LOG_ERROR("VBX: daemon did not stop in time. Try running 'vbx --stop' again."); + return 1; } current_mute = read_runtime_mute_file(); @@ -232,36 +230,36 @@ int main(int argc, char *argv[]) { current_keyboard_mute = cli_opts.keyboard_mute; config_updated = 1; if (current_keyboard_mute) { - printf("Keyboard sounds muted.\n"); + LOG_INFO("Keyboard sounds muted."); } else { - printf("Keyboard sounds unmuted.\n"); + LOG_INFO("Keyboard sounds unmuted."); } } if (cli_opts.mouse_mute >= 0) { current_mouse_mute = cli_opts.mouse_mute; config_updated = 1; if (current_mouse_mute) { - printf("Mouse sounds muted.\n"); + LOG_INFO("Mouse sounds muted."); } else { - printf("Mouse sounds unmuted.\n"); + LOG_INFO("Mouse sounds unmuted."); } } if (cli_opts.keyboard_enabled >= 0) { current_keyboard_enabled = cli_opts.keyboard_enabled; config_updated = 1; if (current_keyboard_enabled) { - printf("Keyboard sounds enabled.\n"); + LOG_INFO("Keyboard sounds enabled."); } else { - printf("Keyboard sounds disabled.\n"); + LOG_INFO("Keyboard sounds disabled."); } } if (cli_opts.mouse_enabled >= 0) { current_mouse_enabled = cli_opts.mouse_enabled; config_updated = 1; if (current_mouse_enabled) { - printf("Mouse sounds enabled.\n"); + LOG_INFO("Mouse sounds enabled."); } else { - printf("Mouse sounds disabled.\n"); + LOG_INFO("Mouse sounds disabled."); } } @@ -280,8 +278,8 @@ int main(int argc, char *argv[]) { current_system_volume_following)) { LOG_WARN("Failed to update config file %s", user_cfg_path); LOG_WARN("Your settings will not be saved for next time."); - } else if (verbose) { - LOG_INFO("Updated config file %s", user_cfg_path); + } else { + LOG_DEBUG("Updated config file %s", user_cfg_path); } } @@ -340,8 +338,8 @@ int main(int argc, char *argv[]) { if (mouse_sound_name_owned) { free(mouse_sound_name); } - return errorf("Error: Cannot find or execute required binaries in %s\n", - VBX_BIN_DIR); + LOG_ERROR("Error: Cannot find or execute required binaries in %s", VBX_BIN_DIR); + return 1; } signal(SIGINT, cleanup_processes); signal(SIGTERM, cleanup_processes); @@ -405,17 +403,15 @@ int main(int argc, char *argv[]) { LOG_INFO("Mouse config file: %s", mouse_config_path); LOG_INFO("Keyboard working directory: %s", sound_dir); LOG_INFO("Mouse working directory: %s", mouse_sound_dir); - LOG_INFO("Press Ctrl+C to exit."); + LOG_DEBUG("Press Ctrl+C to exit."); } else { if (!is_daemon) { - printf("VBX daemon started successfully!\n"); - printf(" Keyboard: %s (volume: %d%%)\n", sound_name, - current_keyboard_volume); - printf(" Mouse: %s (volume: %d%%)\n", mouse_sound_name, - current_mouse_volume); - printf(" Config: ~/.vbx.json (auto-reload enabled)\n"); - printf("\nUse 'vbx --stop' to stop the daemon.\n"); - printf("Press Ctrl+C to exit.\n"); + LOG_INFO("VBX daemon started successfully!"); + LOG_INFO(" Keyboard: %s (volume: %d%%)", sound_name, current_keyboard_volume); + LOG_INFO(" Mouse: %s (volume: %d%%)", mouse_sound_name, current_mouse_volume); + LOG_INFO(" Config: ~/.vbx.json (auto-reload enabled)"); + LOG_INFO("Use 'vbx --stop' to stop the daemon."); + LOG_INFO("Press Ctrl+C to exit."); } } if (!start_children(sound_dir, config_path, current_keyboard_volume, verbose, current_mute, diff --git a/src/soundpacks.c b/src/soundpacks.c index fab5fde..c7df90d 100644 --- a/src/soundpacks.c +++ b/src/soundpacks.c @@ -1,4 +1,5 @@ #include "soundpacks.h" +#include "common/log.h" #include "common/utils.h" #include "config.h" #include @@ -129,24 +130,21 @@ int build_paths_for_mouse_sound(const char *sound_name, char *out_config_path, int validate_keyboard_sound_pack(const char *sound_name) { char basedir[1024]; if (!resolve_keyboard_sound_base_dir(sound_name, basedir, sizeof(basedir))) { - fprintf( - stderr, - "Error: Keyboard sound pack '%s' not found in user or system dirs.\n", - sound_name); - fprintf(stderr, "Use --list to see available sound packs.\n"); + LOG_ERROR("Error: Keyboard sound pack '%s' not found in user or system dirs.", + sound_name); + LOG_ERROR("Use --list to see available sound packs."); return 0; } char config_path[1024]; if ((size_t)snprintf(config_path, sizeof(config_path), "%s/%s/config.json", basedir, sound_name) >= sizeof(config_path)) { - fprintf(stderr, "Error: Sound pack path too long: %s/%s\n", basedir, - sound_name); - fprintf(stderr, "Try using a shorter sound pack name.\n"); + LOG_ERROR("Error: Sound pack path too long: %s/%s", basedir, sound_name); + LOG_ERROR("Try using a shorter sound pack name."); return 0; } if (access(config_path, R_OK) != 0) { - fprintf(stderr, "Error: Sound pack config not found: %s\n", config_path); - fprintf(stderr, "Make sure the sound pack directory contains a valid config.json file.\n"); + LOG_ERROR("Error: Sound pack config not found: %s", config_path); + LOG_ERROR("Make sure the sound pack directory contains a valid config.json file."); return 0; } return 1; @@ -155,23 +153,21 @@ int validate_keyboard_sound_pack(const char *sound_name) { int validate_mouse_sound_pack(const char *sound_name) { char basedir[1024]; if (!resolve_mouse_sound_base_dir(sound_name, basedir, sizeof(basedir))) { - fprintf(stderr, - "Error: Mouse sound pack '%s' not found in user or system dirs.\n", - sound_name); - fprintf(stderr, "Use --list to see available sound packs.\n"); + LOG_ERROR("Error: Mouse sound pack '%s' not found in user or system dirs.", + sound_name); + LOG_ERROR("Use --list to see available sound packs."); return 0; } char config_path[1024]; if ((size_t)snprintf(config_path, sizeof(config_path), "%s/%s/config.json", basedir, sound_name) >= sizeof(config_path)) { - fprintf(stderr, "Error: Sound pack path too long: %s/%s\n", basedir, - sound_name); - fprintf(stderr, "Try using a shorter sound pack name.\n"); + LOG_ERROR("Error: Sound pack path too long: %s/%s", basedir, sound_name); + LOG_ERROR("Try using a shorter sound pack name."); return 0; } if (access(config_path, R_OK) != 0) { - fprintf(stderr, "Error: Sound pack config not found: %s\n", config_path); - fprintf(stderr, "Make sure the sound pack directory contains a valid config.json file.\n"); + LOG_ERROR("Error: Sound pack config not found: %s", config_path); + LOG_ERROR("Make sure the sound pack directory contains a valid config.json file."); return 0; } return 1; @@ -198,24 +194,25 @@ int list_sound_packs(void) { USER_MOUSE_AUDIO_SUBPATH); } - printf("Available Sound Packs\n"); - printf("=====================\n\n"); - printf("\nKEYBOARD SOUND PACKS:\n"); - printf("======================\n"); - printf("%-30s %-15s\n", "Pack Name", "Source"); - printf("%-30s %-15s\n", "---------", "------"); + LOG_INFO("Available Sound Packs"); + LOG_INFO("====================="); + LOG_INFO(" "); + LOG_INFO("KEYBOARD SOUND PACKS:"); + LOG_INFO("======================"); + LOG_INFO("%-30s %-15s", "Pack Name", "Source"); + LOG_INFO("%-30s %-15s", "---------", "------"); if (user_keyboard_dir[0] && (dir = opendir(user_keyboard_dir)) != NULL) { while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; if ((size_t)snprintf(path, sizeof(path), "%s/%s", user_keyboard_dir, entry->d_name) >= sizeof(path)) { - fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n", + LOG_WARN("Warning: Path too long, skipping: %s/%s", user_keyboard_dir, entry->d_name); continue; } if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { - printf("%-30s %-15s\n", entry->d_name, "user"); + LOG_INFO("%-30s %-15s", entry->d_name, "user"); } } closedir(dir); @@ -227,32 +224,33 @@ int list_sound_packs(void) { continue; if ((size_t)snprintf(path, sizeof(path), "%s/%s", KEYBOARD_AUDIO_DIR, entry->d_name) >= sizeof(path)) { - fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n", + LOG_WARN("Warning: Path too long, skipping: %s/%s", KEYBOARD_AUDIO_DIR, entry->d_name); continue; } if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { - printf("%-30s %-15s\n", entry->d_name, "system"); + LOG_INFO("%-30s %-15s", entry->d_name, "system"); } } closedir(dir); } - printf("\nMOUSE SOUND PACKS:\n"); - printf("==================\n"); - printf("%-30s %-15s\n", "Pack Name", "Source"); - printf("%-30s %-15s\n", "---------", "------"); + LOG_INFO(" "); + LOG_INFO("MOUSE SOUND PACKS:"); + LOG_INFO("=================="); + LOG_INFO("%-30s %-15s", "Pack Name", "Source"); + LOG_INFO("%-30s %-15s", "---------", "------"); if (user_mouse_dir[0] && (dir = opendir(user_mouse_dir)) != NULL) { while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; if ((size_t)snprintf(path, sizeof(path), "%s/%s", user_mouse_dir, entry->d_name) >= sizeof(path)) { - fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n", + LOG_WARN("Warning: Path too long, skipping: %s/%s", user_mouse_dir, entry->d_name); continue; } if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { - printf("%-30s %-15s\n", entry->d_name, "user"); + LOG_INFO("%-30s %-15s", entry->d_name, "user"); } } closedir(dir); @@ -264,16 +262,17 @@ int list_sound_packs(void) { continue; if ((size_t)snprintf(path, sizeof(path), "%s/%s", MOUSE_AUDIO_DIR, entry->d_name) >= sizeof(path)) { - fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n", + LOG_WARN("Warning: Path too long, skipping: %s/%s", MOUSE_AUDIO_DIR, entry->d_name); continue; } if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { - printf("%-30s %-15s\n", entry->d_name, "system"); + LOG_INFO("%-30s %-15s", entry->d_name, "system"); } } closedir(dir); } - printf("\nUsage: vbx -S for keyboard or vbx -M for mouse\n"); + LOG_INFO(" "); + LOG_INFO("Usage: vbx -S for keyboard or vbx -M for mouse"); return 0; }