From 08de5eabed144e8d157b6e3a89be027ebd1b669a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 Apr 2026 14:05:36 +0800 Subject: [PATCH] Sound: merges `isMain` and `isActive` to `type` --- src/detection/sound/sound.h | 3 +- src/detection/sound/sound_apple.c | 4 +- src/detection/sound/sound_bsd.c | 3 +- src/detection/sound/sound_haiku.cpp | 3 +- src/detection/sound/sound_linux.c | 74 +++++++++++++++------------ src/detection/sound/sound_nbsd.c | 3 +- src/detection/sound/sound_obsd.c | 3 +- src/detection/sound/sound_sunos.c | 4 +- src/detection/sound/sound_windows.cpp | 4 +- src/modules/sound/sound.c | 26 +++++++--- 10 files changed, 71 insertions(+), 56 deletions(-) diff --git a/src/detection/sound/sound.h b/src/detection/sound/sound.h index f6aa80d1b..041e6a1f8 100644 --- a/src/detection/sound/sound.h +++ b/src/detection/sound/sound.h @@ -10,8 +10,7 @@ typedef struct FFSoundDevice { FFstrbuf name; FFstrbuf platformApi; uint8_t volume; // 0-100% - bool main; - bool active; + FFSoundType type; } FFSoundDevice; const char* ffDetectSound(FFSoundOptions* options, FFlist* devices /* List of FFSoundDevice */); diff --git a/src/detection/sound/sound_apple.c b/src/detection/sound/sound_apple.c index 49d87b105..01daab128 100644 --- a/src/detection/sound/sound_apple.c +++ b/src/detection/sound/sound_apple.c @@ -55,8 +55,8 @@ const char* ffDetectSound(FFSoundOptions* options, FFlist* devices /* List of FF } FFSoundDevice* device = FF_LIST_ADD(FFSoundDevice, *devices); - device->main = deviceId == mainDeviceId; - device->active = !!active; + device->type = (deviceId == mainDeviceId ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE) | + (active ? FF_SOUND_TYPE_ACTIVE : FF_SOUND_TYPE_NONE); device->volume = FF_SOUND_VOLUME_UNKNOWN; ffStrbufInit(&device->identifier); ffStrbufInit(&device->name); diff --git a/src/detection/sound/sound_bsd.c b/src/detection/sound/sound_bsd.c index 1b85db319..6bb2b9d98 100644 --- a/src/detection/sound/sound_bsd.c +++ b/src/detection/sound/sound_bsd.c @@ -83,8 +83,7 @@ const char* ffDetectSound(FFSoundOptions* options, FFlist* devices) { mutemask & SOUND_MASK_VOLUME ? 0 : #endif ((uint8_t) volume /*left*/ + (uint8_t) (volume >> 8) /*right*/) / 2; - device->active = true; - device->main = isMain; + device->type = FF_SOUND_TYPE_ACTIVE | (isMain ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE); } return NULL; diff --git a/src/detection/sound/sound_haiku.cpp b/src/detection/sound/sound_haiku.cpp index 717977a55..8cb3814c3 100644 --- a/src/detection/sound/sound_haiku.cpp +++ b/src/detection/sound/sound_haiku.cpp @@ -30,8 +30,7 @@ const char* ffDetectSound(FF_A_UNUSED FFSoundOptions* options, FFlist* devices / ffStrbufInitStatic(&device->platformApi, "MediaKit"); // We'll check the Mixer actually device->volume = 0; - device->active = true; - device->main = true; + device->type = (FFSoundType) (FF_SOUND_TYPE_ACTIVE | FF_SOUND_TYPE_MAIN); roster->ReleaseNode(mediaNode); diff --git a/src/detection/sound/sound_linux.c b/src/detection/sound/sound_linux.c index 3e4833446..af9a22dbd 100644 --- a/src/detection/sound/sound_linux.c +++ b/src/detection/sound/sound_linux.c @@ -36,8 +36,7 @@ static void paSinkInfoCallback(FF_A_UNUSED pa_context* c, const pa_sink_info* i, ffStrbufTrimRightSpace(&device->name); ffStrbufTrimLeft(&device->name, ' '); device->volume = i->mute ? 0 : (uint8_t) ((i->volume.values[0] * 100 + PA_VOLUME_NORM / 2 /*round*/) / PA_VOLUME_NORM); - device->active = isActive; - device->main = isMain; + device->type = (isMain ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE) | (isActive ? FF_SOUND_TYPE_ACTIVE : FF_SOUND_TYPE_NONE); } static void paServerInfoCallback(FF_A_UNUSED pa_context* c, const pa_server_info* i, void* userdata) { @@ -70,6 +69,7 @@ static const char* detectSound(FFSoundOptions* options, FFlist* devices) { FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_get_sink_info_list) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_get_server_info) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_unref) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_operation_cancel) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_operation_get_state) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_operation_unref) @@ -90,32 +90,35 @@ static const char* detectSound(FFSoundOptions* options, FFlist* devices) { return "Failed to create pulseaudio context"; } - if (ffpa_context_connect(context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) { - ffpa_context_unref(context); - ffpa_mainloop_free(mainloop); - return "Failed to connect to pulseaudio context"; - } - - pa_context_state_t state; - while ((state = ffpa_context_get_state(context)) != PA_CONTEXT_READY) { - if (!PA_CONTEXT_IS_GOOD(state)) { - ffpa_context_unref(context); - ffpa_mainloop_free(mainloop); - return "Failed to get pulseaudio context state"; - } - - ffpa_mainloop_iterate(mainloop, 1, NULL); - } - struct DetectionInfoBundle bundle = { .serverName = ffStrbufCreate(), .defaultDeviceId = ffStrbufCreate(), .result = devices, .options = options, }; + const char* error = NULL; + + if (ffpa_context_connect(context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) { + error = "Failed to connect to pulseaudio context"; + goto exit; + } + + pa_context_state_t state; + while ((state = ffpa_context_get_state(context)) != PA_CONTEXT_READY) { + if (!PA_CONTEXT_IS_GOOD(state)) { + error = "Failed to get pulseaudio context state"; + goto exit; + } + + ffpa_mainloop_iterate(mainloop, 1, NULL); + } { pa_operation* operation = ffpa_context_get_server_info(context, paServerInfoCallback, &bundle); + if (!operation) { + error = "Failed to get pulseaudio server info"; + goto exit; + } while (ffpa_operation_get_state(operation) == PA_OPERATION_RUNNING) { ffpa_mainloop_iterate(mainloop, 1, NULL); } @@ -123,23 +126,30 @@ static const char* detectSound(FFSoundOptions* options, FFlist* devices) { ffpa_operation_unref(operation); } - pa_operation* operation = ffpa_context_get_sink_info_list(context, paSinkInfoCallback, &bundle); - if (!operation) { - ffpa_context_unref(context); - ffpa_mainloop_free(mainloop); - return "Failed to get pulseaudio sink info list"; + { + pa_operation* operation = ffpa_context_get_sink_info_list(context, paSinkInfoCallback, &bundle); + if (!operation) { + error = "Failed to get pulseaudio sink info list"; + goto exit; + } + + while (ffpa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + if (options->soundType & FF_SOUND_TYPE_MAIN && devices->length > 0) { + ffpa_operation_cancel(operation); + } + + ffpa_mainloop_iterate(mainloop, 1, NULL); + } + + ffpa_operation_unref(operation); } - while (ffpa_operation_get_state(operation) == PA_OPERATION_RUNNING) { - ffpa_mainloop_iterate(mainloop, 1, NULL); - } - - ffpa_operation_unref(operation); - - +exit: + ffStrbufDestroy(&bundle.serverName); + ffStrbufDestroy(&bundle.defaultDeviceId); ffpa_context_unref(context); ffpa_mainloop_free(mainloop); - return NULL; + return error; } #endif // FF_HAVE_PULSE diff --git a/src/detection/sound/sound_nbsd.c b/src/detection/sound/sound_nbsd.c index 592dce9f5..efd276eac 100644 --- a/src/detection/sound/sound_nbsd.c +++ b/src/detection/sound/sound_nbsd.c @@ -51,8 +51,7 @@ const char* ffDetectSound(FFSoundOptions* options, FFlist* devices) { ffStrbufTrimRightSpace(&device->name); ffStrbufInitF(&device->platformApi, "%s", "SunAudio"); device->volume = (uint8_t) ((ai.play.gain * 100 + AUDIO_MAX_GAIN / 2) / AUDIO_MAX_GAIN); - device->active = true; - device->main = isMain; + device->type = FF_SOUND_TYPE_ACTIVE | (isMain ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE); } return NULL; diff --git a/src/detection/sound/sound_obsd.c b/src/detection/sound/sound_obsd.c index b66985ba6..0d9d7fea4 100644 --- a/src/detection/sound/sound_obsd.c +++ b/src/detection/sound/sound_obsd.c @@ -75,9 +75,8 @@ const char* ffDetectSound(FFSoundOptions* options, FFlist* devices) { ffStrbufInitS(&device->name, bundle.name); ffStrbufInitS(&device->identifier, SIO_DEVANY); ffStrbufInitStatic(&device->platformApi, "sndio"); - device->active = true; - device->main = true; device->volume = 0; + device->type = FF_SOUND_TYPE_ACTIVE | FF_SOUND_TYPE_MAIN; double totalLevel = 0; for (uint8_t i = 0; i < bundle.iLevel; ++i) { diff --git a/src/detection/sound/sound_sunos.c b/src/detection/sound/sound_sunos.c index 85362e50d..bba147821 100644 --- a/src/detection/sound/sound_sunos.c +++ b/src/detection/sound/sound_sunos.c @@ -101,8 +101,8 @@ const char* ffDetectSound(FFSoundOptions* options, FFlist* devices) { ffStrbufTrimRightSpace(&device->name); ffStrbufInitF(&device->platformApi, "%s %s", info.product, info.version); device->volume = (uint8_t) volume; - device->active = !!mi.enabled; - device->main = isMain; + device->type = (mi.enabled ? FF_SOUND_TYPE_ACTIVE : FF_SOUND_TYPE_NONE) | + (isMain ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE); } return NULL; diff --git a/src/detection/sound/sound_windows.cpp b/src/detection/sound/sound_windows.cpp index 116581daa..c770f5c97 100644 --- a/src/detection/sound/sound_windows.cpp +++ b/src/detection/sound/sound_windows.cpp @@ -36,8 +36,8 @@ static const char* detectSoundDevice(FFlist* devices /* List of FFSoundDevice */ } FFSoundDevice* device = FF_LIST_ADD(FFSoundDevice, *devices); - device->main = !mainDeviceId || wcscmp(immDeviceId, mainDeviceId) == 0; - device->active = !!(immState & DEVICE_STATE_ACTIVE); + device->type = (FFSoundType) ((!mainDeviceId || wcscmp(immDeviceId, mainDeviceId) == 0 ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE) | + ((immState & DEVICE_STATE_ACTIVE) ? FF_SOUND_TYPE_ACTIVE : FF_SOUND_TYPE_NONE)); device->volume = FF_SOUND_VOLUME_UNKNOWN; ffStrbufInitWS(&device->identifier, immDeviceId); ffStrbufInit(&device->name); diff --git a/src/modules/sound/sound.c b/src/modules/sound/sound.c index 34286baf1..d0f611397 100644 --- a/src/modules/sound/sound.c +++ b/src/modules/sound/sound.c @@ -34,7 +34,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui } if (!(percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) { - if (device->main && index > 0) { + if ((device->type & FF_SOUND_TYPE_MAIN) && index > 0) { ffStrbufAppendS(&str, " (*)"); } } @@ -52,8 +52,11 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui } } + bool isMain = !!(device->type & FF_SOUND_TYPE_MAIN); + bool isActive = !!(device->type & FF_SOUND_TYPE_ACTIVE); FF_PRINT_FORMAT_CHECKED(FF_SOUND_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { - FF_ARG(device->main, "is-main"), + FF_ARG(isMain, "is-main"), + FF_ARG(isActive, "is-active"), FF_ARG(device->name, "name"), FF_ARG(percentageNum, "volume-percentage"), FF_ARG(device->identifier, "identifier"), @@ -155,18 +158,24 @@ bool ffGenerateSoundJsonResult(FFSoundOptions* options, yyjson_mut_doc* doc, yyj yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result"); FF_LIST_FOR_EACH (FFSoundDevice, item, result) { yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); - yyjson_mut_obj_add_bool(doc, obj, "active", item->active); - yyjson_mut_obj_add_bool(doc, obj, "main", item->main); + + yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name); + yyjson_mut_obj_add_strbuf(doc, obj, "identifier", &item->identifier); + yyjson_mut_obj_add_strbuf(doc, obj, "platformApi", &item->platformApi); + + yyjson_mut_val* type = yyjson_mut_obj_add_arr(doc, obj, "type"); + if (item->type & FF_SOUND_TYPE_MAIN) { + yyjson_mut_arr_add_str(doc, type, "main"); + } + if (item->type & FF_SOUND_TYPE_ACTIVE) { + yyjson_mut_arr_add_str(doc, type, "active"); + } if (item->volume != FF_SOUND_VOLUME_UNKNOWN) { yyjson_mut_obj_add_uint(doc, obj, "volume", item->volume); } else { yyjson_mut_obj_add_null(doc, obj, "volume"); } - - yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name); - yyjson_mut_obj_add_strbuf(doc, obj, "identifier", &item->identifier); - yyjson_mut_obj_add_strbuf(doc, obj, "platformApi", &item->platformApi); } FF_LIST_FOR_EACH (FFSoundDevice, device, result) { @@ -200,6 +209,7 @@ FFModuleBaseInfo ffSoundModuleInfo = { .generateJsonConfig = (void*) ffGenerateSoundJsonConfig, .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) { { "Is main sound device", "is-main" }, + { "Is active sound device", "is-active" }, { "Device name", "name" }, { "Volume (in percentage num)", "volume-percentage" }, { "Identifier", "identifier" },