diff options
author | Sven Gothel <[email protected]> | 2023-05-03 16:17:49 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-05-03 16:17:49 +0200 |
commit | ec167fd05661a5b02dd406c87081f84a0f8dd77d (patch) | |
tree | 9c4669e471c9969bda59265381b18d2d416db060 /alc/backends/oss.cpp | |
parent | 0d14d30808cfe7b9e3413353e3eef8a0f201399a (diff) | |
parent | d3875f333fb6abe2f39d82caca329414871ae53b (diff) |
Merge branch 'v1.23.1'
Resolved Conflicts:
CMakeLists.txt
Diffstat (limited to 'alc/backends/oss.cpp')
-rw-r--r-- | alc/backends/oss.cpp | 284 |
1 files changed, 131 insertions, 153 deletions
diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 59cc44e4..6d4fa261 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -20,7 +20,7 @@ #include "config.h" -#include "backends/oss.h" +#include "oss.h" #include <fcntl.h> #include <poll.h> @@ -41,16 +41,14 @@ #include <thread> #include <utility> -#include "AL/al.h" - -#include "alcmain.h" -#include "alconfig.h" -#include "alexcpt.h" +#include "albyte.h" +#include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" #include "aloptional.h" -#include "alu.h" -#include "logging.h" +#include "core/device.h" +#include "core/helpers.h" +#include "core/logging.h" #include "ringbuffer.h" #include "threads.h" #include "vector.h" @@ -94,14 +92,6 @@ struct DevMap { std::string device_name; }; -bool checkName(const al::vector<DevMap> &list, const std::string &name) -{ - return std::find_if(list.cbegin(), list.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ) != list.cend(); -} - al::vector<DevMap> PlaybackDevices; al::vector<DevMap> CaptureDevices; @@ -110,60 +100,59 @@ al::vector<DevMap> CaptureDevices; #define DSP_CAP_OUTPUT 0x00020000 #define DSP_CAP_INPUT 0x00010000 -void ALCossListPopulate(al::vector<DevMap> *devlist, int type) +void ALCossListPopulate(al::vector<DevMap> &devlist, int type) { - devlist->emplace_back(DevMap{DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}); + devlist.emplace_back(DevMap{DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}); } #else -void ALCossListAppend(al::vector<DevMap> *list, const char *handle, size_t hlen, const char *path, size_t plen) +void ALCossListAppend(al::vector<DevMap> &list, al::span<const char> handle, al::span<const char> path) { #ifdef ALC_OSS_DEVNODE_TRUC - for(size_t i{0};i < plen;i++) + for(size_t i{0};i < path.size();++i) { - if(path[i] == '.') + if(path[i] == '.' && handle.size() + i >= path.size()) { - if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) - hlen = hlen + i - plen; - plen = i; + const size_t hoffset{handle.size() + i - path.size()}; + if(strncmp(path.data() + i, handle.data() + hoffset, path.size() - i) == 0) + handle = handle.first(hoffset); + path = path.first(i); } } #endif - if(handle[0] == '\0') - { + if(handle.empty()) handle = path; - hlen = plen; - } - 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()); + std::string basename{handle.data(), handle.size()}; + std::string devname{path.data(), path.size()}; - auto iter = std::find_if(list->cbegin(), list->cend(), - [&devname](const DevMap &entry) -> bool - { return entry.device_name == devname; } - ); - if(iter != list->cend()) + auto match_devname = [&devname](const DevMap &entry) -> bool + { return entry.device_name == devname; }; + if(std::find_if(list.cbegin(), list.cend(), match_devname) != list.cend()) return; + auto checkName = [&list](const std::string &name) -> bool + { + auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; }; + return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); + }; int count{1}; std::string newname{basename}; - while(checkName(PlaybackDevices, newname)) + while(checkName(newname)) { newname = basename; newname += " #"; newname += std::to_string(++count); } - list->emplace_back(DevMap{std::move(newname), std::move(devname)}); - const DevMap &entry = list->back(); + list.emplace_back(DevMap{std::move(newname), std::move(devname)}); + const DevMap &entry = list.back(); TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } -void ALCossListPopulate(al::vector<DevMap> *devlist, int type_flag) +void ALCossListPopulate(al::vector<DevMap> &devlist, int type_flag) { int fd{open("/dev/mixer", O_RDONLY)}; if(fd < 0) @@ -191,21 +180,14 @@ void ALCossListPopulate(al::vector<DevMap> *devlist, int type_flag) if(!(ai.caps&type_flag) || ai.devnode[0] == '\0') continue; - const char *handle; - size_t len; + al::span<const char> handle; if(ai.handle[0] != '\0') - { - len = strnlen(ai.handle, sizeof(ai.handle)); - handle = ai.handle; - } + handle = {ai.handle, strnlen(ai.handle, sizeof(ai.handle))}; else - { - len = strnlen(ai.name, sizeof(ai.name)); - handle = ai.name; - } + handle = {ai.name, strnlen(ai.name, sizeof(ai.name))}; + al::span<const char> devnode{ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))}; - ALCossListAppend(devlist, handle, len, ai.devnode, - strnlen(ai.devnode, sizeof(ai.devnode))); + ALCossListAppend(devlist, handle, devnode); } done: @@ -214,26 +196,26 @@ done: fd = -1; const char *defdev{((type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback).c_str()}; - auto iter = std::find_if(devlist->cbegin(), devlist->cend(), + 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}); + if(iter == devlist.cend()) + devlist.insert(devlist.begin(), DevMap{DefaultName, defdev}); else { DevMap entry{std::move(*iter)}; - devlist->erase(iter); - devlist->insert(devlist->begin(), std::move(entry)); + devlist.erase(iter); + devlist.insert(devlist.begin(), std::move(entry)); } - devlist->shrink_to_fit(); + devlist.shrink_to_fit(); } #endif -ALCuint log2i(ALCuint x) +uint log2i(uint x) { - ALCuint y{0}; + uint y{0}; while(x > 1) { x >>= 1; @@ -244,19 +226,19 @@ ALCuint log2i(ALCuint x) struct OSSPlayback final : public BackendBase { - OSSPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + OSSPlayback(DeviceBase *device) noexcept : BackendBase{device} { } ~OSSPlayback() override; int mixerProc(); - void open(const ALCchar *name) override; + void open(const char *name) override; bool reset() override; - bool start() override; + void start() override; void stop() override; int mFd{-1}; - al::vector<ALubyte> mMixData; + al::vector<al::byte> mMixData; std::atomic<bool> mKillNow{true}; std::thread mThread; @@ -267,7 +249,7 @@ struct OSSPlayback final : public BackendBase { OSSPlayback::~OSSPlayback() { if(mFd != -1) - close(mFd); + ::close(mFd); mFd = -1; } @@ -277,25 +259,23 @@ int OSSPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - const ALuint frame_size{mDevice->frameSizeFromFmt()}; + const size_t frame_step{mDevice->channelsFromFmt()}; + const size_t frame_size{mDevice->frameSizeFromFmt()}; - std::unique_lock<OSSPlayback> dlock{*this}; - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) + while(!mKillNow.load(std::memory_order_acquire) + && mDevice->Connected.load(std::memory_order_acquire)) { pollfd pollitem{}; pollitem.fd = mFd; pollitem.events = POLLOUT; - dlock.unlock(); int pret{poll(&pollitem, 1, 1000)}; - dlock.lock(); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed waiting for playback buffer: %s", strerror(errno)); + mDevice->handleDisconnect("Failed waiting for playback buffer: %s", strerror(errno)); break; } else if(pret == 0) @@ -304,9 +284,9 @@ int OSSPlayback::mixerProc() continue; } - ALubyte *write_ptr{mMixData.data()}; + al::byte *write_ptr{mMixData.data()}; size_t to_write{mMixData.size()}; - aluMixData(mDevice, write_ptr, static_cast<ALuint>(to_write/frame_size)); + mDevice->renderSamples(write_ptr, static_cast<uint>(to_write/frame_size), frame_step); while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) { ssize_t wrote{write(mFd, write_ptr, to_write)}; @@ -315,8 +295,7 @@ int OSSPlayback::mixerProc() if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed writing playback samples: %s", - strerror(errno)); + mDevice->handleDisconnect("Failed writing playback samples: %s", strerror(errno)); break; } @@ -329,7 +308,7 @@ int OSSPlayback::mixerProc() } -void OSSPlayback::open(const ALCchar *name) +void OSSPlayback::open(const char *name) { const char *devname{DefaultPlayback.c_str()}; if(!name) @@ -337,22 +316,27 @@ void OSSPlayback::open(const ALCchar *name) else { if(PlaybackDevices.empty()) - ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); + 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()) - throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; + throw al::backend_exception{al::backend_error::NoDevice, + "Device name \"%s\" not found", name}; devname = iter->device_name.c_str(); } - mFd = ::open(devname, O_WRONLY); - if(mFd == -1) - throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", devname, + int fd{::open(devname, O_WRONLY)}; + if(fd == -1) + throw al::backend_exception{al::backend_error::NoDevice, "Could not open %s: %s", devname, strerror(errno)}; + if(mFd != -1) + ::close(mFd); + mFd = fd; + mDevice->DeviceName = name; } @@ -378,13 +362,13 @@ bool OSSPlayback::reset() break; } - ALuint periods{mDevice->BufferSize / mDevice->UpdateSize}; - ALuint numChannels{mDevice->channelsFromFmt()}; - ALuint ossSpeed{mDevice->Frequency}; - ALuint frameSize{numChannels * mDevice->bytesFromFmt()}; + uint periods{mDevice->BufferSize / mDevice->UpdateSize}; + uint numChannels{mDevice->channelsFromFmt()}; + uint ossSpeed{mDevice->Frequency}; + uint frameSize{numChannels * mDevice->bytesFromFmt()}; /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ - ALuint log2FragmentSize{maxu(log2i(mDevice->UpdateSize*frameSize), 4)}; - ALuint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; + uint log2FragmentSize{maxu(log2i(mDevice->UpdateSize*frameSize), 4)}; + uint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; audio_buf_info info{}; const char *err; @@ -424,29 +408,26 @@ bool OSSPlayback::reset() } mDevice->Frequency = ossSpeed; - mDevice->UpdateSize = static_cast<ALuint>(info.fragsize) / frameSize; - mDevice->BufferSize = static_cast<ALuint>(info.fragments) * mDevice->UpdateSize; + mDevice->UpdateSize = static_cast<uint>(info.fragsize) / frameSize; + mDevice->BufferSize = static_cast<uint>(info.fragments) * mDevice->UpdateSize; - SetDefaultChannelOrder(mDevice); + setDefaultChannelOrder(); mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); return true; } -bool OSSPlayback::start() +void OSSPlayback::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&OSSPlayback::mixerProc), this}; - return true; } catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { + throw al::backend_exception{al::backend_error::DeviceError, + "Failed to start mixing thread: %s", e.what()}; } - return false; } void OSSPlayback::stop() @@ -461,16 +442,16 @@ void OSSPlayback::stop() struct OSScapture final : public BackendBase { - OSScapture(ALCdevice *device) noexcept : BackendBase{device} { } + OSScapture(DeviceBase *device) noexcept : BackendBase{device} { } ~OSScapture() override; int recordProc(); - void open(const ALCchar *name) override; - bool start() override; + void open(const char *name) override; + void start() override; void stop() override; - ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; - ALCuint availableSamples() override; + void captureSamples(al::byte *buffer, uint samples) override; + uint availableSamples() override; int mFd{-1}; @@ -495,7 +476,7 @@ int OSScapture::recordProc() SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - const ALuint frame_size{mDevice->frameSizeFromFmt()}; + const size_t frame_size{mDevice->frameSizeFromFmt()}; while(!mKillNow.load(std::memory_order_acquire)) { pollfd pollitem{}; @@ -508,7 +489,7 @@ int OSScapture::recordProc() if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno)); + mDevice->handleDisconnect("Failed to check capture samples: %s", strerror(errno)); break; } else if(sret == 0) @@ -524,11 +505,10 @@ int OSScapture::recordProc() if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed reading capture samples: %s", - strerror(errno)); + mDevice->handleDisconnect("Failed reading capture samples: %s", strerror(errno)); break; } - mRing->writeAdvance(static_cast<ALuint>(amt)/frame_size); + mRing->writeAdvance(static_cast<size_t>(amt)/frame_size); } } @@ -536,7 +516,7 @@ int OSScapture::recordProc() } -void OSScapture::open(const ALCchar *name) +void OSScapture::open(const char *name) { const char *devname{DefaultCapture.c_str()}; if(!name) @@ -544,20 +524,21 @@ void OSScapture::open(const ALCchar *name) else { if(CaptureDevices.empty()) - ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); + 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()) - throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; + throw al::backend_exception{al::backend_error::NoDevice, + "Device name \"%s\" not found", name}; devname = iter->device_name.c_str(); } mFd = ::open(devname, O_RDONLY); if(mFd == -1) - throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", devname, + throw al::backend_exception{al::backend_error::NoDevice, "Could not open %s: %s", devname, strerror(errno)}; int ossFormat{}; @@ -576,21 +557,22 @@ void OSScapture::open(const ALCchar *name) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", - DevFmtTypeString(mDevice->FmtType)}; + throw al::backend_exception{al::backend_error::DeviceError, + "%s capture samples not supported", DevFmtTypeString(mDevice->FmtType)}; } - ALuint periods{4}; - ALuint numChannels{mDevice->channelsFromFmt()}; - ALuint frameSize{numChannels * mDevice->bytesFromFmt()}; - ALuint ossSpeed{mDevice->Frequency}; + uint periods{4}; + uint numChannels{mDevice->channelsFromFmt()}; + uint frameSize{numChannels * mDevice->bytesFromFmt()}; + uint ossSpeed{mDevice->Frequency}; /* according to the OSS spec, 16 bytes are the minimum */ - ALuint log2FragmentSize{maxu(log2i(mDevice->BufferSize * frameSize / periods), 4)}; - ALuint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; + uint log2FragmentSize{maxu(log2i(mDevice->BufferSize * frameSize / periods), 4)}; + uint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; audio_buf_info info{}; #define CHECKERR(func) if((func) < 0) { \ - throw al::backend_exception{ALC_INVALID_VALUE, #func " failed: %s", strerror(errno)}; \ + throw al::backend_exception{al::backend_error::DeviceError, #func " failed: %s", \ + strerror(errno)}; \ } CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); @@ -600,35 +582,32 @@ void OSScapture::open(const ALCchar *name) #undef CHECKERR if(mDevice->channelsFromFmt() != numChannels) - throw al::backend_exception{ALC_INVALID_VALUE, + throw al::backend_exception{al::backend_error::DeviceError, "Failed to set %s, got %d channels instead", DevFmtChannelsString(mDevice->FmtChans), numChannels}; if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) - throw al::backend_exception{ALC_INVALID_VALUE, + throw al::backend_exception{al::backend_error::DeviceError, "Failed to set %s samples, got OSS format %#x", DevFmtTypeString(mDevice->FmtType), ossFormat}; - mRing = CreateRingBuffer(mDevice->BufferSize, frameSize, false); + mRing = RingBuffer::Create(mDevice->BufferSize, frameSize, false); mDevice->DeviceName = name; } -bool OSScapture::start() +void OSScapture::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&OSScapture::recordProc), this}; - return true; } catch(std::exception& e) { - ERR("Could not create record thread: %s\n", e.what()); + throw al::backend_exception{al::backend_error::DeviceError, + "Failed to start recording thread: %s", e.what()}; } - catch(...) { - } - return false; } void OSScapture::stop() @@ -641,14 +620,11 @@ void OSScapture::stop() ERR("Error resetting device: %s\n", strerror(errno)); } -ALCenum OSScapture::captureSamples(al::byte *buffer, ALCuint samples) -{ - mRing->read(buffer, samples); - return ALC_NO_ERROR; -} +void OSScapture::captureSamples(al::byte *buffer, uint samples) +{ mRing->read(buffer, samples); } -ALCuint OSScapture::availableSamples() -{ return static_cast<ALCuint>(mRing->readSpace()); } +uint OSScapture::availableSamples() +{ return static_cast<uint>(mRing->readSpace()); } } // namespace @@ -672,37 +648,39 @@ bool OSSBackendFactory::init() bool OSSBackendFactory::querySupport(BackendType type) { return (type == BackendType::Playback || type == BackendType::Capture); } -void OSSBackendFactory::probe(DevProbe type, std::string *outnames) +std::string OSSBackendFactory::probe(BackendType type) { - auto add_device = [outnames](const DevMap &entry) -> void + std::string outnames; + + auto add_device = [&outnames](const DevMap &entry) -> void { -#ifdef HAVE_STAT struct stat buf; if(stat(entry.device_name.c_str(), &buf) == 0) -#endif { /* Includes null char. */ - outnames->append(entry.name.c_str(), entry.name.length()+1); + outnames.append(entry.name.c_str(), entry.name.length()+1); } }; switch(type) { - case DevProbe::Playback: - PlaybackDevices.clear(); - ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; + case BackendType::Playback: + PlaybackDevices.clear(); + ALCossListPopulate(PlaybackDevices, DSP_CAP_OUTPUT); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; - case DevProbe::Capture: - CaptureDevices.clear(); - ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; + case BackendType::Capture: + CaptureDevices.clear(); + ALCossListPopulate(CaptureDevices, DSP_CAP_INPUT); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; } + + return outnames; } -BackendPtr OSSBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr OSSBackendFactory::createBackend(DeviceBase *device, BackendType type) { if(type == BackendType::Playback) return BackendPtr{new OSSPlayback{device}}; |