mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 07:34:45 +00:00
update openal
This commit is contained in:
parent
62f3b93ff9
commit
6721a6b021
287 changed files with 33851 additions and 27325 deletions
|
|
@ -31,27 +31,26 @@
|
|||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "albyte.h"
|
||||
#include "alc/alconfig.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
#include "aloptional.h"
|
||||
#include "alstring.h"
|
||||
#include "althrd_setname.h"
|
||||
#include "core/device.h"
|
||||
#include "core/helpers.h"
|
||||
#include "core/logging.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "threads.h"
|
||||
#include "vector.h"
|
||||
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
|
|
@ -83,117 +82,148 @@
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr char DefaultName[] = "OSS Default";
|
||||
std::string DefaultPlayback{"/dev/dsp"};
|
||||
std::string DefaultCapture{"/dev/dsp"};
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
[[nodiscard]] constexpr auto GetDefaultName() noexcept { return "OSS Default"sv; }
|
||||
|
||||
std::string DefaultPlayback{"/dev/dsp"s};
|
||||
std::string DefaultCapture{"/dev/dsp"s};
|
||||
|
||||
struct DevMap {
|
||||
std::string name;
|
||||
std::string device_name;
|
||||
|
||||
template<typename T, typename U>
|
||||
DevMap(T&& name_, U&& devname_)
|
||||
: name{std::forward<T>(name_)}, device_name{std::forward<U>(devname_)}
|
||||
{ }
|
||||
};
|
||||
|
||||
al::vector<DevMap> PlaybackDevices;
|
||||
al::vector<DevMap> CaptureDevices;
|
||||
std::vector<DevMap> PlaybackDevices;
|
||||
std::vector<DevMap> CaptureDevices;
|
||||
|
||||
|
||||
#ifdef ALC_OSS_COMPAT
|
||||
|
||||
#define DSP_CAP_OUTPUT 0x00020000
|
||||
#define DSP_CAP_INPUT 0x00010000
|
||||
void ALCossListPopulate(al::vector<DevMap> &devlist, int type)
|
||||
void ALCossListPopulate(std::vector<DevMap> &devlist, int type)
|
||||
{
|
||||
devlist.emplace_back(DevMap{DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback});
|
||||
devlist.emplace_back(GetDefaultName(), (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ALCossListAppend(al::vector<DevMap> &list, al::span<const char> handle, al::span<const char> path)
|
||||
class FileHandle {
|
||||
int mFd{-1};
|
||||
|
||||
public:
|
||||
FileHandle() = default;
|
||||
FileHandle(const FileHandle&) = delete;
|
||||
FileHandle& operator=(const FileHandle&) = delete;
|
||||
~FileHandle() { if(mFd != -1) ::close(mFd); }
|
||||
|
||||
template<typename ...Args>
|
||||
[[nodiscard]] auto open(const char *fname, Args&& ...args) -> bool
|
||||
{
|
||||
close();
|
||||
mFd = ::open(fname, std::forward<Args>(args)...);
|
||||
return mFd != -1;
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if(mFd != -1)
|
||||
::close(mFd);
|
||||
mFd = -1;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto get() const noexcept -> int { return mFd; }
|
||||
};
|
||||
|
||||
void ALCossListAppend(std::vector<DevMap> &list, std::string_view handle, std::string_view path)
|
||||
{
|
||||
#ifdef ALC_OSS_DEVNODE_TRUC
|
||||
for(size_t i{0};i < path.size();++i)
|
||||
{
|
||||
if(path[i] == '.' && handle.size() + i >= path.size())
|
||||
if(path[i] == '.' && handle.size() >= path.size() - 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);
|
||||
handle = handle.substr(0, hoffset);
|
||||
path = path.substr(0, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(handle.empty())
|
||||
handle = path;
|
||||
|
||||
std::string basename{handle.data(), handle.size()};
|
||||
std::string devname{path.data(), path.size()};
|
||||
|
||||
auto match_devname = [&devname](const DevMap &entry) -> bool
|
||||
{ return entry.device_name == devname; };
|
||||
auto match_devname = [path](const DevMap &entry) -> bool
|
||||
{ return entry.device_name == path; };
|
||||
if(std::find_if(list.cbegin(), list.cend(), match_devname) != list.cend())
|
||||
return;
|
||||
|
||||
auto checkName = [&list](const std::string &name) -> bool
|
||||
auto checkName = [&list](const std::string_view name) -> bool
|
||||
{
|
||||
auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; };
|
||||
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};
|
||||
std::string newname{handle};
|
||||
while(checkName(newname))
|
||||
{
|
||||
newname = basename;
|
||||
newname = handle;
|
||||
newname += " #";
|
||||
newname += std::to_string(++count);
|
||||
}
|
||||
|
||||
list.emplace_back(DevMap{std::move(newname), std::move(devname)});
|
||||
const DevMap &entry = list.back();
|
||||
const DevMap &entry = list.emplace_back(std::move(newname), path);
|
||||
|
||||
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(std::vector<DevMap> &devlist, int type_flag)
|
||||
{
|
||||
int fd{open("/dev/mixer", O_RDONLY)};
|
||||
if(fd < 0)
|
||||
oss_sysinfo si{};
|
||||
FileHandle file;
|
||||
if(!file.open("/dev/mixer", O_RDONLY))
|
||||
{
|
||||
TRACE("Could not open /dev/mixer: %s\n", strerror(errno));
|
||||
TRACE("Could not open /dev/mixer: %s\n", std::generic_category().message(errno).c_str());
|
||||
goto done;
|
||||
}
|
||||
|
||||
oss_sysinfo si;
|
||||
if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1)
|
||||
if(ioctl(file.get(), SNDCTL_SYSINFO, &si) == -1)
|
||||
{
|
||||
TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno));
|
||||
TRACE("SNDCTL_SYSINFO failed: %s\n", std::generic_category().message(errno).c_str());
|
||||
goto done;
|
||||
}
|
||||
|
||||
for(int i{0};i < si.numaudios;i++)
|
||||
{
|
||||
oss_audioinfo ai;
|
||||
oss_audioinfo ai{};
|
||||
ai.dev = i;
|
||||
if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1)
|
||||
if(ioctl(file.get(), SNDCTL_AUDIOINFO, &ai) == -1)
|
||||
{
|
||||
ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno));
|
||||
ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i,
|
||||
std::generic_category().message(errno).c_str());
|
||||
continue;
|
||||
}
|
||||
if(!(ai.caps&type_flag) || ai.devnode[0] == '\0')
|
||||
continue;
|
||||
|
||||
al::span<const char> handle;
|
||||
std::string_view handle;
|
||||
if(ai.handle[0] != '\0')
|
||||
handle = {ai.handle, strnlen(ai.handle, sizeof(ai.handle))};
|
||||
else
|
||||
handle = {ai.name, strnlen(ai.name, sizeof(ai.name))};
|
||||
al::span<const char> devnode{ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))};
|
||||
const std::string_view devnode{ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))};
|
||||
|
||||
ALCossListAppend(devlist, handle, devnode);
|
||||
}
|
||||
|
||||
done:
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
fd = -1;
|
||||
file.close();
|
||||
|
||||
const char *defdev{((type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback).c_str()};
|
||||
auto iter = std::find_if(devlist.cbegin(), devlist.cend(),
|
||||
|
|
@ -201,7 +231,7 @@ done:
|
|||
{ return entry.device_name == defdev; }
|
||||
);
|
||||
if(iter == devlist.cend())
|
||||
devlist.insert(devlist.begin(), DevMap{DefaultName, defdev});
|
||||
devlist.insert(devlist.begin(), DevMap{GetDefaultName(), defdev});
|
||||
else
|
||||
{
|
||||
DevMap entry{std::move(*iter)};
|
||||
|
|
@ -231,19 +261,17 @@ struct OSSPlayback final : public BackendBase {
|
|||
|
||||
int mixerProc();
|
||||
|
||||
void open(const char *name) override;
|
||||
void open(std::string_view name) override;
|
||||
bool reset() override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
|
||||
int mFd{-1};
|
||||
|
||||
al::vector<al::byte> mMixData;
|
||||
std::vector<std::byte> mMixData;
|
||||
|
||||
std::atomic<bool> mKillNow{true};
|
||||
std::thread mThread;
|
||||
|
||||
DEF_NEWDEL(OSSPlayback)
|
||||
};
|
||||
|
||||
OSSPlayback::~OSSPlayback()
|
||||
|
|
@ -257,7 +285,7 @@ OSSPlayback::~OSSPlayback()
|
|||
int OSSPlayback::mixerProc()
|
||||
{
|
||||
SetRTPriority();
|
||||
althrd_setname(MIXER_THREAD_NAME);
|
||||
althrd_setname(GetMixerThreadName());
|
||||
|
||||
const size_t frame_step{mDevice->channelsFromFmt()};
|
||||
const size_t frame_size{mDevice->frameSizeFromFmt()};
|
||||
|
|
@ -269,38 +297,38 @@ int OSSPlayback::mixerProc()
|
|||
pollitem.fd = mFd;
|
||||
pollitem.events = POLLOUT;
|
||||
|
||||
int pret{poll(&pollitem, 1, 1000)};
|
||||
if(pret < 0)
|
||||
if(int pret{poll(&pollitem, 1, 1000)}; pret < 0)
|
||||
{
|
||||
if(errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
ERR("poll failed: %s\n", strerror(errno));
|
||||
mDevice->handleDisconnect("Failed waiting for playback buffer: %s", strerror(errno));
|
||||
const auto errstr = std::generic_category().message(errno);
|
||||
ERR("poll failed: %s\n", errstr.c_str());
|
||||
mDevice->handleDisconnect("Failed waiting for playback buffer: %s", errstr.c_str());
|
||||
break;
|
||||
}
|
||||
else if(pret == 0)
|
||||
else if(pret == 0) /* NOLINT(*-else-after-return) 'pret' is local to the if/else blocks */
|
||||
{
|
||||
WARN("poll timeout\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
al::byte *write_ptr{mMixData.data()};
|
||||
size_t to_write{mMixData.size()};
|
||||
mDevice->renderSamples(write_ptr, static_cast<uint>(to_write/frame_size), frame_step);
|
||||
while(to_write > 0 && !mKillNow.load(std::memory_order_acquire))
|
||||
al::span write_buf{mMixData};
|
||||
mDevice->renderSamples(write_buf.data(), static_cast<uint>(write_buf.size()/frame_size),
|
||||
frame_step);
|
||||
while(!write_buf.empty() && !mKillNow.load(std::memory_order_acquire))
|
||||
{
|
||||
ssize_t wrote{write(mFd, write_ptr, to_write)};
|
||||
ssize_t wrote{write(mFd, write_buf.data(), write_buf.size())};
|
||||
if(wrote < 0)
|
||||
{
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
||||
continue;
|
||||
ERR("write failed: %s\n", strerror(errno));
|
||||
mDevice->handleDisconnect("Failed writing playback samples: %s", strerror(errno));
|
||||
const auto errstr = std::generic_category().message(errno);
|
||||
ERR("write failed: %s\n", errstr.c_str());
|
||||
mDevice->handleDisconnect("Failed writing playback samples: %s", errstr.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
to_write -= static_cast<size_t>(wrote);
|
||||
write_ptr += wrote;
|
||||
write_buf = write_buf.subspan(static_cast<size_t>(wrote));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -308,11 +336,11 @@ int OSSPlayback::mixerProc()
|
|||
}
|
||||
|
||||
|
||||
void OSSPlayback::open(const char *name)
|
||||
void OSSPlayback::open(std::string_view name)
|
||||
{
|
||||
const char *devname{DefaultPlayback.c_str()};
|
||||
if(!name)
|
||||
name = DefaultName;
|
||||
if(name.empty())
|
||||
name = GetDefaultName();
|
||||
else
|
||||
{
|
||||
if(PlaybackDevices.empty())
|
||||
|
|
@ -324,14 +352,14 @@ void OSSPlayback::open(const char *name)
|
|||
);
|
||||
if(iter == PlaybackDevices.cend())
|
||||
throw al::backend_exception{al::backend_error::NoDevice,
|
||||
"Device name \"%s\" not found", name};
|
||||
"Device name \"%.*s\" not found", al::sizei(name), name.data()};
|
||||
devname = iter->device_name.c_str();
|
||||
}
|
||||
|
||||
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)};
|
||||
std::generic_category().message(errno).c_str()};
|
||||
|
||||
if(mFd != -1)
|
||||
::close(mFd);
|
||||
|
|
@ -367,15 +395,14 @@ bool OSSPlayback::reset()
|
|||
uint ossSpeed{mDevice->Frequency};
|
||||
uint frameSize{numChannels * mDevice->bytesFromFmt()};
|
||||
/* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */
|
||||
uint log2FragmentSize{maxu(log2i(mDevice->UpdateSize*frameSize), 4)};
|
||||
uint log2FragmentSize{std::max(log2i(mDevice->UpdateSize*frameSize), 4u)};
|
||||
uint numFragmentsLogSize{(periods << 16) | log2FragmentSize};
|
||||
|
||||
audio_buf_info info{};
|
||||
const char *err;
|
||||
#define CHECKERR(func) if((func) < 0) { \
|
||||
err = #func; \
|
||||
goto err; \
|
||||
}
|
||||
#define CHECKERR(func) if((func) < 0) \
|
||||
throw al::backend_exception{al::backend_error::DeviceError, "%s failed: %s\n", #func, \
|
||||
std::generic_category().message(errno).c_str()};
|
||||
|
||||
/* Don't fail if SETFRAGMENT fails. We can handle just about anything
|
||||
* that's reported back via GETOSPACE */
|
||||
ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
|
||||
|
|
@ -383,12 +410,6 @@ bool OSSPlayback::reset()
|
|||
CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels));
|
||||
CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed));
|
||||
CHECKERR(ioctl(mFd, SNDCTL_DSP_GETOSPACE, &info));
|
||||
if(0)
|
||||
{
|
||||
err:
|
||||
ERR("%s failed: %s\n", err, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#undef CHECKERR
|
||||
|
||||
if(mDevice->channelsFromFmt() != numChannels)
|
||||
|
|
@ -413,7 +434,7 @@ bool OSSPlayback::reset()
|
|||
|
||||
setDefaultChannelOrder();
|
||||
|
||||
mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt());
|
||||
mMixData.resize(size_t{mDevice->UpdateSize} * mDevice->frameSizeFromFmt());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -437,7 +458,7 @@ void OSSPlayback::stop()
|
|||
mThread.join();
|
||||
|
||||
if(ioctl(mFd, SNDCTL_DSP_RESET) != 0)
|
||||
ERR("Error resetting device: %s\n", strerror(errno));
|
||||
ERR("Error resetting device: %s\n", std::generic_category().message(errno).c_str());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -447,10 +468,10 @@ struct OSScapture final : public BackendBase {
|
|||
|
||||
int recordProc();
|
||||
|
||||
void open(const char *name) override;
|
||||
void open(std::string_view name) override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
void captureSamples(al::byte *buffer, uint samples) override;
|
||||
void captureSamples(std::byte *buffer, uint samples) override;
|
||||
uint availableSamples() override;
|
||||
|
||||
int mFd{-1};
|
||||
|
|
@ -459,8 +480,6 @@ struct OSScapture final : public BackendBase {
|
|||
|
||||
std::atomic<bool> mKillNow{true};
|
||||
std::thread mThread;
|
||||
|
||||
DEF_NEWDEL(OSScapture)
|
||||
};
|
||||
|
||||
OSScapture::~OSScapture()
|
||||
|
|
@ -474,7 +493,7 @@ OSScapture::~OSScapture()
|
|||
int OSScapture::recordProc()
|
||||
{
|
||||
SetRTPriority();
|
||||
althrd_setname(RECORD_THREAD_NAME);
|
||||
althrd_setname(GetRecordThreadName());
|
||||
|
||||
const size_t frame_size{mDevice->frameSizeFromFmt()};
|
||||
while(!mKillNow.load(std::memory_order_acquire))
|
||||
|
|
@ -483,16 +502,16 @@ int OSScapture::recordProc()
|
|||
pollitem.fd = mFd;
|
||||
pollitem.events = POLLIN;
|
||||
|
||||
int sret{poll(&pollitem, 1, 1000)};
|
||||
if(sret < 0)
|
||||
if(int pret{poll(&pollitem, 1, 1000)}; pret < 0)
|
||||
{
|
||||
if(errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
ERR("poll failed: %s\n", strerror(errno));
|
||||
mDevice->handleDisconnect("Failed to check capture samples: %s", strerror(errno));
|
||||
const auto errstr = std::generic_category().message(errno);
|
||||
ERR("poll failed: %s\n", errstr.c_str());
|
||||
mDevice->handleDisconnect("Failed to check capture samples: %s", errstr.c_str());
|
||||
break;
|
||||
}
|
||||
else if(sret == 0)
|
||||
else if(pret == 0) /* NOLINT(*-else-after-return) 'pret' is local to the if/else blocks */
|
||||
{
|
||||
WARN("poll timeout\n");
|
||||
continue;
|
||||
|
|
@ -504,8 +523,9 @@ int OSScapture::recordProc()
|
|||
ssize_t amt{read(mFd, vec.first.buf, vec.first.len*frame_size)};
|
||||
if(amt < 0)
|
||||
{
|
||||
ERR("read failed: %s\n", strerror(errno));
|
||||
mDevice->handleDisconnect("Failed reading capture samples: %s", strerror(errno));
|
||||
const auto errstr = std::generic_category().message(errno);
|
||||
ERR("read failed: %s\n", errstr.c_str());
|
||||
mDevice->handleDisconnect("Failed reading capture samples: %s", errstr.c_str());
|
||||
break;
|
||||
}
|
||||
mRing->writeAdvance(static_cast<size_t>(amt)/frame_size);
|
||||
|
|
@ -516,11 +536,11 @@ int OSScapture::recordProc()
|
|||
}
|
||||
|
||||
|
||||
void OSScapture::open(const char *name)
|
||||
void OSScapture::open(std::string_view name)
|
||||
{
|
||||
const char *devname{DefaultCapture.c_str()};
|
||||
if(!name)
|
||||
name = DefaultName;
|
||||
if(name.empty())
|
||||
name = GetDefaultName();
|
||||
else
|
||||
{
|
||||
if(CaptureDevices.empty())
|
||||
|
|
@ -532,14 +552,14 @@ void OSScapture::open(const char *name)
|
|||
);
|
||||
if(iter == CaptureDevices.cend())
|
||||
throw al::backend_exception{al::backend_error::NoDevice,
|
||||
"Device name \"%s\" not found", name};
|
||||
"Device name \"%.*s\" not found", al::sizei(name), name.data()};
|
||||
devname = iter->device_name.c_str();
|
||||
}
|
||||
|
||||
mFd = ::open(devname, O_RDONLY);
|
||||
if(mFd == -1)
|
||||
throw al::backend_exception{al::backend_error::NoDevice, "Could not open %s: %s", devname,
|
||||
strerror(errno)};
|
||||
std::generic_category().message(errno).c_str()};
|
||||
|
||||
int ossFormat{};
|
||||
switch(mDevice->FmtType)
|
||||
|
|
@ -566,13 +586,13 @@ void OSScapture::open(const char *name)
|
|||
uint frameSize{numChannels * mDevice->bytesFromFmt()};
|
||||
uint ossSpeed{mDevice->Frequency};
|
||||
/* according to the OSS spec, 16 bytes are the minimum */
|
||||
uint log2FragmentSize{maxu(log2i(mDevice->BufferSize * frameSize / periods), 4)};
|
||||
uint log2FragmentSize{std::max(log2i(mDevice->BufferSize * frameSize / periods), 4u)};
|
||||
uint numFragmentsLogSize{(periods << 16) | log2FragmentSize};
|
||||
|
||||
audio_buf_info info{};
|
||||
#define CHECKERR(func) if((func) < 0) { \
|
||||
throw al::backend_exception{al::backend_error::DeviceError, #func " failed: %s", \
|
||||
strerror(errno)}; \
|
||||
std::generic_category().message(errno).c_str()}; \
|
||||
}
|
||||
CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
|
||||
CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat));
|
||||
|
|
@ -617,11 +637,11 @@ void OSScapture::stop()
|
|||
mThread.join();
|
||||
|
||||
if(ioctl(mFd, SNDCTL_DSP_RESET) != 0)
|
||||
ERR("Error resetting device: %s\n", strerror(errno));
|
||||
ERR("Error resetting device: %s\n", std::generic_category().message(errno).c_str());
|
||||
}
|
||||
|
||||
void OSScapture::captureSamples(al::byte *buffer, uint samples)
|
||||
{ mRing->read(buffer, samples); }
|
||||
void OSScapture::captureSamples(std::byte *buffer, uint samples)
|
||||
{ std::ignore = mRing->read(buffer, samples); }
|
||||
|
||||
uint OSScapture::availableSamples()
|
||||
{ return static_cast<uint>(mRing->readSpace()); }
|
||||
|
|
@ -637,9 +657,9 @@ BackendFactory &OSSBackendFactory::getFactory()
|
|||
|
||||
bool OSSBackendFactory::init()
|
||||
{
|
||||
if(auto devopt = ConfigValueStr(nullptr, "oss", "device"))
|
||||
if(auto devopt = ConfigValueStr({}, "oss", "device"))
|
||||
DefaultPlayback = std::move(*devopt);
|
||||
if(auto capopt = ConfigValueStr(nullptr, "oss", "capture"))
|
||||
if(auto capopt = ConfigValueStr({}, "oss", "capture"))
|
||||
DefaultCapture = std::move(*capopt);
|
||||
|
||||
return true;
|
||||
|
|
@ -648,18 +668,13 @@ bool OSSBackendFactory::init()
|
|||
bool OSSBackendFactory::querySupport(BackendType type)
|
||||
{ return (type == BackendType::Playback || type == BackendType::Capture); }
|
||||
|
||||
std::string OSSBackendFactory::probe(BackendType type)
|
||||
auto OSSBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
|
||||
{
|
||||
std::string outnames;
|
||||
|
||||
std::vector<std::string> outnames;
|
||||
auto add_device = [&outnames](const DevMap &entry) -> void
|
||||
{
|
||||
struct stat buf;
|
||||
if(stat(entry.device_name.c_str(), &buf) == 0)
|
||||
{
|
||||
/* Includes null char. */
|
||||
outnames.append(entry.name.c_str(), entry.name.length()+1);
|
||||
}
|
||||
if(struct stat buf{}; stat(entry.device_name.c_str(), &buf) == 0)
|
||||
outnames.emplace_back(entry.name);
|
||||
};
|
||||
|
||||
switch(type)
|
||||
|
|
@ -667,12 +682,14 @@ std::string OSSBackendFactory::probe(BackendType type)
|
|||
case BackendType::Playback:
|
||||
PlaybackDevices.clear();
|
||||
ALCossListPopulate(PlaybackDevices, DSP_CAP_OUTPUT);
|
||||
outnames.reserve(PlaybackDevices.size());
|
||||
std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
|
||||
break;
|
||||
|
||||
case BackendType::Capture:
|
||||
CaptureDevices.clear();
|
||||
ALCossListPopulate(CaptureDevices, DSP_CAP_INPUT);
|
||||
outnames.reserve(CaptureDevices.size());
|
||||
std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue