From 83dec6b97535aadcbbfe2a75a7a405190786fe57 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 19:16:50 -0800 Subject: Use a C++ vector for enumerated OSS devices --- Alc/backends/oss.cpp | 301 +++++++++++++++++++++++++-------------------------- 1 file changed, 146 insertions(+), 155 deletions(-) (limited to 'Alc/backends') diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 279a2b99..24609954 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -33,6 +33,10 @@ #include #include +#include +#include +#include + #include "alMain.h" #include "alu.h" #include "alconfig.h" @@ -72,30 +76,39 @@ namespace { -struct oss_device { - const ALCchar *handle; - const char *path; - struct oss_device *next; -}; +constexpr char DefaultName[] = "OSS Default"; +const char *DefaultPlayback{"/dev/dsp"}; +const char *DefaultCapture{"/dev/dsp"}; -struct oss_device oss_playback = { - "OSS Default", - "/dev/dsp", - nullptr -}; +struct DevMap { + std::string name; + std::string device_name; -struct oss_device oss_capture = { - "OSS Default", - "/dev/dsp", - nullptr + template + DevMap(StrT0&& name_, StrT1&& devname_) + : name{std::forward(name_)}, device_name{std::forward(devname_)} + { } }; +bool checkName(const std::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + +std::vector PlaybackDevices; +std::vector CaptureDevices; + + #ifdef ALC_OSS_COMPAT #define DSP_CAP_OUTPUT 0x00020000 #define DSP_CAP_INPUT 0x00010000 -void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) +void ALCossListPopulate(std::vector *devlist, int type) { + devlist->emplace_back(DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback); } #else @@ -110,17 +123,10 @@ size_t my_strnlen(const char *str, size_t maxlen) #define strnlen my_strnlen #endif -void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) +void ALCossListAppend(std::vector *list, const char *handle, size_t hlen, const char *path, size_t plen) { - struct oss_device *next; - struct oss_device *last; - size_t i; - - /* skip the first item "OSS Default" */ - last = list; - next = list->next; #ifdef ALC_OSS_DEVNODE_TRUC - for(i = 0;i < plen;i++) + for(size_t i{0};i < plen;i++) { if(path[i] == '.') { @@ -129,8 +135,6 @@ void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, plen = i; } } -#else - (void)i; #endif if(handle[0] == '\0') { @@ -138,58 +142,63 @@ void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, hlen = plen; } - while(next != nullptr) + std::string basename{handle, hlen}; + basename.erase(std::find(basename.begin(), basename.end(), '\0'), basename.end()); + std::string devname{path, plen}; + devname.erase(std::find(devname.begin(), devname.end(), '\0'), devname.end()); + + auto iter = std::find_if(list->cbegin(), list->cend(), + [&devname](const DevMap &entry) -> bool + { return entry.device_name == devname; } + ); + if(iter != list->cend()) + return; + + int count{1}; + std::string newname{basename}; + while(checkName(PlaybackDevices, newname)) { - if(strncmp(next->path, path, plen) == 0) - return; - last = next; - next = next->next; + newname = basename; + newname += " #"; + newname += std::to_string(++count); } - next = (struct oss_device*)malloc(sizeof(struct oss_device) + hlen + plen + 2); - next->handle = (char*)(next + 1); - next->path = next->handle + hlen + 1; - next->next = nullptr; - last->next = next; + list->emplace_back(std::move(newname), std::move(devname)); + const DevMap &entry = list->back(); - strncpy((char*)next->handle, handle, hlen); - ((char*)next->handle)[hlen] = '\0'; - strncpy((char*)next->path, path, plen); - ((char*)next->path)[plen] = '\0'; - - TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } -void ALCossListPopulate(struct oss_device *devlist, int type_flag) +void ALCossListPopulate(std::vector *devlist, int type_flag) { - struct oss_sysinfo si; - struct oss_audioinfo ai; - int fd, i; - - if((fd=open("/dev/mixer", O_RDONLY)) < 0) + int fd{open("/dev/mixer", O_RDONLY)}; + if(fd < 0) { TRACE("Could not open /dev/mixer: %s\n", strerror(errno)); - return; + goto done; } + + struct oss_sysinfo si; if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) { TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); goto done; } - for(i = 0;i < si.numaudios;i++) - { - const char *handle; - size_t len; + for(int i{0};i < si.numaudios;i++) + { + struct oss_audioinfo ai; ai.dev = i; if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) { ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); continue; } - if(ai.devnode[0] == '\0') + if(!(ai.caps&type_flag) || ai.devnode[0] == '\0') continue; + const char *handle; + size_t len; if(ai.handle[0] != '\0') { len = strnlen(ai.handle, sizeof(ai.handle)); @@ -200,35 +209,34 @@ void ALCossListPopulate(struct oss_device *devlist, int type_flag) len = strnlen(ai.name, sizeof(ai.name)); handle = ai.name; } - if((ai.caps&type_flag)) - ALCossListAppend(devlist, handle, len, ai.devnode, - strnlen(ai.devnode, sizeof(ai.devnode))); + + ALCossListAppend(devlist, handle, len, ai.devnode, + strnlen(ai.devnode, sizeof(ai.devnode))); } done: - close(fd); -} - -#endif - -void ALCossListFree(struct oss_device *list) -{ - struct oss_device *cur; - if(list == nullptr) - return; - - /* skip the first item "OSS Default" */ - cur = list->next; - list->next = nullptr; - - while(cur != nullptr) + if(fd >= 0) + close(fd); + fd = -1; + + const char *defdev{(type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}; + auto iter = std::find_if(devlist->cbegin(), devlist->cend(), + [defdev](const DevMap &entry) -> bool + { return entry.device_name == defdev; } + ); + if(iter == devlist->cend()) + devlist->insert(devlist->begin(), DevMap{DefaultName, defdev}); + else { - struct oss_device *next = cur->next; - free(cur); - cur = next; + DevMap entry{std::move(*iter)}; + devlist->erase(iter); + devlist->insert(devlist->begin(), std::move(entry)); } + devlist->shrink_to_fit(); } +#endif + int log2i(ALCuint x) { int y = 0; @@ -361,35 +369,29 @@ static int ALCplaybackOSS_mixerProc(void *ptr) static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { - struct oss_device *dev = &oss_playback; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(!name || strcmp(name, dev->handle) == 0) - name = dev->handle; + const char *devname{DefaultPlayback}; + if(!name) + name = DefaultName; else { - if(!dev->next) - { - ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); - dev = &oss_playback; - } - while(dev != nullptr) - { - if (strcmp(dev->handle, name) == 0) - break; - dev = dev->next; - } - if(dev == nullptr) - { - WARN("Could not find \"%s\" in device list\n", name); + if(PlaybackDevices.empty()) + ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); + + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; - } + devname = iter->device_name.c_str(); } - self->fd = open(dev->path, O_WRONLY); + self->fd = open(devname, O_WRONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", dev->path, strerror(errno)); + ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } @@ -628,46 +630,32 @@ static int ALCcaptureOSS_recordProc(void *ptr) static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct oss_device *dev = &oss_capture; - int numFragmentsLogSize; - int log2FragmentSize; - unsigned int periods; - audio_buf_info info; - ALuint frameSize; - int numChannels; - int ossFormat; - int ossSpeed; - const char *err; - if(!name || strcmp(name, dev->handle) == 0) - name = dev->handle; + const char *devname{DefaultCapture}; + if(!name) + name = DefaultName; else { - if(!dev->next) - { - ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); - dev = &oss_capture; - } - while(dev != nullptr) - { - if (strcmp(dev->handle, name) == 0) - break; - dev = dev->next; - } - if(dev == nullptr) - { - WARN("Could not find \"%s\" in device list\n", name); + if(CaptureDevices.empty()) + ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); + + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; - } + devname = iter->device_name.c_str(); } - self->fd = open(dev->path, O_RDONLY); + self->fd = open(devname, O_RDONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", dev->path, strerror(errno)); + ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } + int ossFormat{}; switch(device->FmtType) { case DevFmtByte: @@ -687,18 +675,19 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - periods = 4; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - ossSpeed = device->Frequency; - log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * - frameSize / periods); + int periods{4}; + int numChannels{ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)}; + int frameSize{numChannels * BytesFromDevFmt(device->FmtType)}; + int ossSpeed{static_cast(device->Frequency)}; + int log2FragmentSize{log2i(device->UpdateSize * device->NumUpdates * + frameSize / periods)}; /* according to the OSS spec, 16 bytes are the minimum */ - if (log2FragmentSize < 4) - log2FragmentSize = 4; - numFragmentsLogSize = (periods << 16) | log2FragmentSize; + log2FragmentSize = std::max(log2FragmentSize, 4); + int numFragmentsLogSize{(periods << 16) | log2FragmentSize}; + audio_buf_info info; + const char *err; #define CHECKERR(func) if((func) < 0) { \ err = #func; \ goto err; \ @@ -810,16 +799,16 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void) ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) { - ConfigValueStr(nullptr, "oss", "device", &oss_playback.path); - ConfigValueStr(nullptr, "oss", "capture", &oss_capture.path); + ConfigValueStr(nullptr, "oss", "device", &DefaultPlayback); + ConfigValueStr(nullptr, "oss", "capture", &DefaultCapture); return ALC_TRUE; } -void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) +void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) { - ALCossListFree(&oss_playback); - ALCossListFree(&oss_capture); + PlaybackDevices.clear(); + CaptureDevices.clear(); } @@ -832,30 +821,32 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { - struct oss_device *cur = nullptr; + auto add_device = [outnames](const DevMap &entry) -> void + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(entry.device_name.c_str(), &buf) == 0) +#endif + { + const char *name{entry.name.c_str()}; + alstr_append_range(outnames, name, name+entry.name.length()+1); + } + }; + switch(type) { case ALL_DEVICE_PROBE: - ALCossListFree(&oss_playback); - ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); - cur = &oss_playback; + PlaybackDevices.clear(); + ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: - ALCossListFree(&oss_capture); - ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); - cur = &oss_capture; + CaptureDevices.clear(); + ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; } - while(cur != nullptr) - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(cur->path, &buf) == 0) -#endif - alstr_append_range(outnames, cur->handle, cur->handle+strlen(cur->handle)+1); - cur = cur->next; - } } ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -- cgit v1.2.3