From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- src/detection/sound/sound_sunos.c | 109 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/detection/sound/sound_sunos.c (limited to 'src/detection/sound/sound_sunos.c') diff --git a/src/detection/sound/sound_sunos.c b/src/detection/sound/sound_sunos.c new file mode 100644 index 0000000..7c84e55 --- /dev/null +++ b/src/detection/sound/sound_sunos.c @@ -0,0 +1,109 @@ +#include "sound.h" +#include "common/io.h" +#include "common/strutil.h" + +#include +#include +#if __has_include() + #include +#else + // Strangely, they don't provide this file on default installation + #include "audio_oss_sunos.h" +#endif + +const char* ffDetectSound(FFSoundOptions* options, FFlist* devices) { + int defaultDev; + { + char mixerp[12]; + ssize_t plen = readlink("/dev/audio", mixerp, ARRAY_SIZE(mixerp)); + if (plen < 6) { + return "readlink(/dev/audio) failed"; + } + defaultDev = mixerp[plen - 1] - '0'; + if (defaultDev < 0 || defaultDev > 9) { + return "Invalid mixer device"; + } + } + + char path[] = "/dev/mixer0"; + + FF_STRBUF_AUTO_DESTROY sndstat = ffStrbufCreate(); + + struct oss_sysinfo info = { .nummixers = 9 }; + + // The implementation is very different from *BSD's. They call it OSS4 + for (int idev = 0; idev < info.nummixers; ++idev) { + bool isMain = idev == defaultDev; + if ((options->soundType & FF_SOUND_TYPE_MAIN) && !isMain) { + continue; + } + + path[strlen("/dev/mixer")] = (char) ('0' + idev); + FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) { + break; + } + + if (idev == 0) { + if (ioctl(fd, SNDCTL_SYSINFO, &info) != 0) { + return "ioctl(SNDCTL_SYSINFO) failed"; + } + if (ffAppendFDBuffer(fd, &sndstat)) { + ffStrbufSubstrAfterFirstS(&sndstat, "\nMixers:"); + } + } + + struct oss_mixerinfo mi = {}; + if (ioctl(fd, SNDCTL_MIXERINFO, &mi) < 0) { + continue; + } + + if (options->soundType == FF_SOUND_TYPE_ACTIVE && !mi.enabled) { + continue; + } + + int volume = -1; + for (int iext = 0; iext < mi.nrext; ++iext) { + struct oss_mixext me = { .dev = mi.dev, .ctrl = iext }; + if (ioctl(fd, SNDCTL_MIX_EXTINFO, &me) < 0) { + continue; + } + if (me.flags & MIXF_PCMVOL) { + struct oss_mixer_value mv = { .dev = mi.dev, .ctrl = iext, .timestamp = me.timestamp }; + if (ioctl(fd, SNDCTL_MIX_READ, &mv) >= 0) { + mv.value -= me.minvalue; + me.maxvalue -= me.minvalue; + volume = (uint8_t) ((mv.value * 100 + me.maxvalue / 2) / me.maxvalue); + } + break; + } + } + if (volume == -1) { + continue; + } + + FFSoundDevice* device = FF_LIST_ADD(FFSoundDevice, *devices); + ffStrbufInitS(&device->identifier, path); + char buf[16]; + int bufLen = snprintf(buf, ARRAY_SIZE(buf), "\n%d: ", mi.dev); + assert(bufLen > 3); + const char* pLine = memmem(sndstat.chars, sndstat.length, buf, (size_t) bufLen); + if (pLine) { + pLine += bufLen; + const char* pEnd = strchr(pLine, '\n'); + if (!pEnd) { + pEnd = sndstat.chars + sndstat.length; + } + ffStrbufInitNS(&device->name, (uint32_t) (pEnd - pLine), pLine); + } else { + ffStrbufInitS(&device->name, mi.name); + } + ffStrbufTrimRightSpace(&device->name); + ffStrbufInitF(&device->platformApi, "%s %s", info.product, info.version); + device->volume = (uint8_t) volume; + device->type = (mi.enabled ? FF_SOUND_TYPE_ACTIVE : FF_SOUND_TYPE_NONE) | + (isMain ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE); + } + + return NULL; +} -- cgit v1.2.3