aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends/oss.cpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-05-03 16:17:49 +0200
committerSven Gothel <[email protected]>2023-05-03 16:17:49 +0200
commitec167fd05661a5b02dd406c87081f84a0f8dd77d (patch)
tree9c4669e471c9969bda59265381b18d2d416db060 /alc/backends/oss.cpp
parent0d14d30808cfe7b9e3413353e3eef8a0f201399a (diff)
parentd3875f333fb6abe2f39d82caca329414871ae53b (diff)
Merge branch 'v1.23.1'
Resolved Conflicts: CMakeLists.txt
Diffstat (limited to 'alc/backends/oss.cpp')
-rw-r--r--alc/backends/oss.cpp284
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}};