diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/sound/sound_obsd.c | |
Add the files
Diffstat (limited to 'src/detection/sound/sound_obsd.c')
| -rw-r--r-- | src/detection/sound/sound_obsd.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/detection/sound/sound_obsd.c b/src/detection/sound/sound_obsd.c new file mode 100644 index 0000000..a6dd6df --- /dev/null +++ b/src/detection/sound/sound_obsd.c @@ -0,0 +1,90 @@ +#include "sound.h" +#include "common/strutil.h" + +#include <fcntl.h> +#include <sndio.h> + +static void close_hdl(struct sioctl_hdl** phdl) { + assert(phdl); + if (*phdl) { + sioctl_close(*phdl); + } +} + +enum { MAX_CHANNEL_NUM = 8 }; + +typedef struct FFSoundDeviceBundle { + char name[SIOCTL_DISPLAYMAX]; + double level[MAX_CHANNEL_NUM]; + uint8_t iLevel; + bool mute[MAX_CHANNEL_NUM]; + uint8_t iMute; +} FFSoundDeviceBundle; + +static void enumerate_props(FFSoundDeviceBundle* bundle, struct sioctl_desc* desc, int val) { + if (!desc) { + return; + } + + if (desc->type == SIOCTL_SEL) { + if (desc->display[0] != '\0' && ffStrEquals(desc->node0.name, "server")) { + ffStrCopy(bundle->name, desc->display, SIOCTL_DISPLAYMAX); + } + return; + } + + if (desc->type != SIOCTL_NUM && desc->type != SIOCTL_SW) { + return; + } + + if (!ffStrEquals(desc->node0.name, "output")) { + return; + } + + if (ffStrEquals(desc->func, "level")) { + if (__builtin_expect(bundle->iLevel == MAX_CHANNEL_NUM, false)) { + return; + } + bundle->level[bundle->iLevel] = (double) val / (double) desc->maxval; + ++bundle->iLevel; + } else if (ffStrEquals(desc->func, "mute")) { + if (__builtin_expect(bundle->iMute == MAX_CHANNEL_NUM, false)) { + return; + } + bundle->mute[bundle->iMute] = !!val; + ++bundle->iMute; + } +} + +const char* ffDetectSound(FFSoundOptions* options, FFlist* devices) { + FF_A_CLEANUP(close_hdl) struct sioctl_hdl* hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0); + if (!hdl) { + return "sio_open() failed"; + } + + FFSoundDeviceBundle bundle = {}; + if (sioctl_ondesc(hdl, (void*) enumerate_props, &bundle) == 0) { + return "sioctl_ondesc() failed"; + } + + if (bundle.iLevel != bundle.iMute || bundle.iLevel == 0) { + return "Unexpected sioctl_ondesc() result"; + } + + FFSoundDevice* device = FF_LIST_ADD(FFSoundDevice, *devices); + ffStrbufInitS(&device->name, bundle.name); + ffStrbufInitS(&device->identifier, SIO_DEVANY); + ffStrbufInitStatic(&device->platformApi, "sndio"); + 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) { + if (!bundle.mute[i]) { + totalLevel += bundle.level[i]; + } + } + device->volume = (uint8_t) ((totalLevel * 100 + bundle.iLevel / 2) / bundle.iLevel); + + return NULL; +} |