update openal

This commit is contained in:
AzaezelX 2024-06-30 14:35:57 -05:00
parent 62f3b93ff9
commit 6721a6b021
287 changed files with 33851 additions and 27325 deletions

View file

@ -25,10 +25,6 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <cguid.h>
#include <mmreg.h>
#ifndef _WAVEFORMATEXTENSIBLE_
@ -36,15 +32,21 @@
#include <ksmedia.h>
#endif
#include <algorithm>
#include <atomic>
#include <cassert>
#include <thread>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <memory.h>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include "alnumeric.h"
#include "alspan.h"
#include "alstring.h"
#include "althrd_setname.h"
#include "comptr.h"
#include "core/device.h"
#include "core/helpers.h"
@ -52,7 +54,6 @@
#include "dynload.h"
#include "ringbuffer.h"
#include "strutils.h"
#include "threads.h"
/* MinGW-w64 needs this for some unknown reason now. */
using LPCWAVEFORMATEX = const WAVEFORMATEX*;
@ -129,10 +130,10 @@ struct DevMap {
{ }
};
al::vector<DevMap> PlaybackDevices;
al::vector<DevMap> CaptureDevices;
std::vector<DevMap> PlaybackDevices;
std::vector<DevMap> CaptureDevices;
bool checkName(const al::vector<DevMap> &list, const std::string &name)
bool checkName(const al::span<DevMap> list, const std::string &name)
{
auto match_name = [&name](const DevMap &entry) -> bool
{ return entry.name == name; };
@ -144,7 +145,7 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, voi
if(!guid)
return TRUE;
auto& devices = *static_cast<al::vector<DevMap>*>(data);
auto& devices = *static_cast<std::vector<DevMap>*>(data);
const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)};
int count{1};
@ -176,7 +177,7 @@ struct DSoundPlayback 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;
@ -189,8 +190,6 @@ struct DSoundPlayback final : public BackendBase {
std::atomic<bool> mKillNow{true};
std::thread mThread;
DEF_NEWDEL(DSoundPlayback)
};
DSoundPlayback::~DSoundPlayback()
@ -209,7 +208,7 @@ DSoundPlayback::~DSoundPlayback()
FORCE_ALIGN int DSoundPlayback::mixerProc()
{
SetRTPriority();
althrd_setname(MIXER_THREAD_NAME);
althrd_setname(GetMixerThreadName());
DSBCAPS DSBCaps{};
DSBCaps.dwSize = sizeof(DSBCaps);
@ -299,24 +298,22 @@ FORCE_ALIGN int DSoundPlayback::mixerProc()
return 0;
}
void DSoundPlayback::open(const char *name)
void DSoundPlayback::open(std::string_view name)
{
HRESULT hr;
if(PlaybackDevices.empty())
{
/* Initialize COM to prevent name truncation */
HRESULT hrcom{CoInitialize(nullptr)};
ComWrapper com{};
hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices);
if(FAILED(hr))
ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr);
if(SUCCEEDED(hrcom))
CoUninitialize();
}
const GUID *guid{nullptr};
if(!name && !PlaybackDevices.empty())
if(name.empty() && !PlaybackDevices.empty())
{
name = PlaybackDevices[0].name.c_str();
name = PlaybackDevices[0].name;
guid = &PlaybackDevices[0].guid;
}
else
@ -332,7 +329,7 @@ void DSoundPlayback::open(const char *name)
[&id](const DevMap &entry) -> bool { return entry.guid == id; });
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()};
}
guid = &iter->guid;
}
@ -347,7 +344,7 @@ void DSoundPlayback::open(const char *name)
//DirectSound Init code
ComPtr<IDirectSound> ds;
if(SUCCEEDED(hr))
hr = DirectSoundCreate(guid, ds.getPtr(), nullptr);
hr = DirectSoundCreate(guid, al::out_ptr(ds), nullptr);
if(SUCCEEDED(hr))
hr = ds->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY);
if(FAILED(hr))
@ -425,49 +422,53 @@ bool DSoundPlayback::reset()
case DevFmtX51: OutputType.dwChannelMask = isRear51 ? X5DOT1REAR : X5DOT1; break;
case DevFmtX61: OutputType.dwChannelMask = X6DOT1; break;
case DevFmtX71: OutputType.dwChannelMask = X7DOT1; break;
case DevFmtX7144: mDevice->FmtChans = DevFmtX714;
/* fall-through */
case DevFmtX714: OutputType.dwChannelMask = X7DOT1DOT4; break;
case DevFmtX3D71: OutputType.dwChannelMask = X7DOT1; break;
}
retry_open:
hr = S_OK;
OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
OutputType.Format.nChannels = static_cast<WORD>(mDevice->channelsFromFmt());
OutputType.Format.wBitsPerSample = static_cast<WORD>(mDevice->bytesFromFmt() * 8);
OutputType.Format.nBlockAlign = static_cast<WORD>(OutputType.Format.nChannels *
OutputType.Format.wBitsPerSample / 8);
OutputType.Format.nSamplesPerSec = mDevice->Frequency;
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
OutputType.Format.nBlockAlign;
OutputType.Format.cbSize = 0;
do {
hr = S_OK;
OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
OutputType.Format.nChannels = static_cast<WORD>(mDevice->channelsFromFmt());
OutputType.Format.wBitsPerSample = static_cast<WORD>(mDevice->bytesFromFmt() * 8);
OutputType.Format.nBlockAlign = static_cast<WORD>(OutputType.Format.nChannels *
OutputType.Format.wBitsPerSample / 8);
OutputType.Format.nSamplesPerSec = mDevice->Frequency;
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
OutputType.Format.nBlockAlign;
OutputType.Format.cbSize = 0;
if(OutputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat)
{
OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
if(mDevice->FmtType == DevFmtFloat)
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
else
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
mPrimaryBuffer = nullptr;
}
else
{
if(SUCCEEDED(hr) && !mPrimaryBuffer)
if(OutputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat)
{
DSBUFFERDESC DSBDescription{};
DSBDescription.dwSize = sizeof(DSBDescription);
DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
hr = mDS->CreateSoundBuffer(&DSBDescription, mPrimaryBuffer.getPtr(), nullptr);
}
if(SUCCEEDED(hr))
hr = mPrimaryBuffer->SetFormat(&OutputType.Format);
}
OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
/* NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) */
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
if(mDevice->FmtType == DevFmtFloat)
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
else
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
mPrimaryBuffer = nullptr;
}
else
{
if(SUCCEEDED(hr) && !mPrimaryBuffer)
{
DSBUFFERDESC DSBDescription{};
DSBDescription.dwSize = sizeof(DSBDescription);
DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
hr = mDS->CreateSoundBuffer(&DSBDescription, al::out_ptr(mPrimaryBuffer), nullptr);
}
if(SUCCEEDED(hr))
hr = mPrimaryBuffer->SetFormat(&OutputType.Format);
}
if(FAILED(hr))
break;
if(SUCCEEDED(hr))
{
uint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
if(num_updates > MAX_UPDATES)
num_updates = MAX_UPDATES;
@ -480,26 +481,21 @@ retry_open:
DSBDescription.dwBufferBytes = mDevice->BufferSize * OutputType.Format.nBlockAlign;
DSBDescription.lpwfxFormat = &OutputType.Format;
hr = mDS->CreateSoundBuffer(&DSBDescription, mBuffer.getPtr(), nullptr);
if(FAILED(hr) && mDevice->FmtType == DevFmtFloat)
{
mDevice->FmtType = DevFmtShort;
goto retry_open;
}
}
hr = mDS->CreateSoundBuffer(&DSBDescription, al::out_ptr(mBuffer), nullptr);
if(SUCCEEDED(hr) || mDevice->FmtType != DevFmtFloat)
break;
mDevice->FmtType = DevFmtShort;
} while(FAILED(hr));
if(SUCCEEDED(hr))
{
void *ptr;
hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr);
hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, al::out_ptr(mNotifies));
if(SUCCEEDED(hr))
{
mNotifies = ComPtr<IDirectSoundNotify>{static_cast<IDirectSoundNotify*>(ptr)};
uint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
assert(num_updates <= MAX_UPDATES);
std::array<DSBPOSITIONNOTIFY,MAX_UPDATES> nots;
std::array<DSBPOSITIONNOTIFY,MAX_UPDATES> nots{};
for(uint i{0};i < num_updates;++i)
{
nots[i].dwOffset = i * mDevice->UpdateSize * OutputType.Format.nBlockAlign;
@ -550,10 +546,10 @@ struct DSoundCapture final : public BackendBase {
DSoundCapture(DeviceBase *device) noexcept : BackendBase{device} { }
~DSoundCapture() override;
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;
ComPtr<IDirectSoundCapture> mDSC;
@ -562,8 +558,6 @@ struct DSoundCapture final : public BackendBase {
DWORD mCursor{0u};
RingBufferPtr mRing;
DEF_NEWDEL(DSoundCapture)
};
DSoundCapture::~DSoundCapture()
@ -577,24 +571,22 @@ DSoundCapture::~DSoundCapture()
}
void DSoundCapture::open(const char *name)
void DSoundCapture::open(std::string_view name)
{
HRESULT hr;
if(CaptureDevices.empty())
{
/* Initialize COM to prevent name truncation */
HRESULT hrcom{CoInitialize(nullptr)};
ComWrapper com{};
hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices);
if(FAILED(hr))
ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr);
if(SUCCEEDED(hrcom))
CoUninitialize();
}
const GUID *guid{nullptr};
if(!name && !CaptureDevices.empty())
if(name.empty() && !CaptureDevices.empty())
{
name = CaptureDevices[0].name.c_str();
name = CaptureDevices[0].name;
guid = &CaptureDevices[0].guid;
}
else
@ -610,7 +602,7 @@ void DSoundCapture::open(const char *name)
[&id](const DevMap &entry) -> bool { return entry.guid == id; });
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()};
}
guid = &iter->guid;
}
@ -641,6 +633,7 @@ void DSoundCapture::open(const char *name)
case DevFmtX61: InputType.dwChannelMask = X6DOT1; break;
case DevFmtX71: InputType.dwChannelMask = X7DOT1; break;
case DevFmtX714: InputType.dwChannelMask = X7DOT1DOT4; break;
case DevFmtX7144:
case DevFmtX3D71:
case DevFmtAmbi3D:
WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans));
@ -657,6 +650,7 @@ void DSoundCapture::open(const char *name)
InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec *
InputType.Format.nBlockAlign;
InputType.Format.cbSize = 0;
/* NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) */
InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
if(mDevice->FmtType == DevFmtFloat)
InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
@ -669,8 +663,7 @@ void DSoundCapture::open(const char *name)
InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
}
uint samples{mDevice->BufferSize};
samples = maxu(samples, 100 * mDevice->Frequency / 1000);
const uint samples{std::max(mDevice->BufferSize, mDevice->Frequency/10u)};
DSCBUFFERDESC DSCBDescription{};
DSCBDescription.dwSize = sizeof(DSCBDescription);
@ -679,9 +672,9 @@ void DSoundCapture::open(const char *name)
DSCBDescription.lpwfxFormat = &InputType.Format;
//DirectSoundCapture Init code
hr = DirectSoundCaptureCreate(guid, mDSC.getPtr(), nullptr);
hr = DirectSoundCaptureCreate(guid, al::out_ptr(mDSC), nullptr);
if(SUCCEEDED(hr))
mDSC->CreateCaptureBuffer(&DSCBDescription, mDSCbuffer.getPtr(), nullptr);
mDSC->CreateCaptureBuffer(&DSCBDescription, al::out_ptr(mDSCbuffer), nullptr);
if(SUCCEEDED(hr))
mRing = RingBuffer::Create(mDevice->BufferSize, InputType.Format.nBlockAlign, false);
@ -719,8 +712,8 @@ void DSoundCapture::stop()
}
}
void DSoundCapture::captureSamples(al::byte *buffer, uint samples)
{ mRing->read(buffer, samples); }
void DSoundCapture::captureSamples(std::byte *buffer, uint samples)
{ std::ignore = mRing->read(buffer, samples); }
uint DSoundCapture::availableSamples()
{
@ -743,9 +736,9 @@ uint DSoundCapture::availableSamples()
}
if(SUCCEEDED(hr))
{
mRing->write(ReadPtr1, ReadCnt1/FrameSize);
std::ignore = mRing->write(ReadPtr1, ReadCnt1/FrameSize);
if(ReadPtr2 != nullptr && ReadCnt2 > 0)
mRing->write(ReadPtr2, ReadCnt2/FrameSize);
std::ignore = mRing->write(ReadPtr2, ReadCnt2/FrameSize);
hr = mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2);
mCursor = ReadCursor;
}
@ -802,40 +795,32 @@ bool DSoundBackendFactory::init()
bool DSoundBackendFactory::querySupport(BackendType type)
{ return (type == BackendType::Playback || type == BackendType::Capture); }
std::string DSoundBackendFactory::probe(BackendType type)
auto DSoundBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
{
std::string outnames;
std::vector<std::string> outnames;
auto add_device = [&outnames](const DevMap &entry) -> void
{
/* +1 to also append the null char (to ensure a null-separated list and
* double-null terminated list).
*/
outnames.append(entry.name.c_str(), entry.name.length()+1);
};
{ outnames.emplace_back(entry.name); };
/* Initialize COM to prevent name truncation */
HRESULT hr;
HRESULT hrcom{CoInitialize(nullptr)};
ComWrapper com{};
switch(type)
{
case BackendType::Playback:
PlaybackDevices.clear();
hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices);
if(FAILED(hr))
if(HRESULT hr{DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices)}; FAILED(hr))
ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr);
outnames.reserve(PlaybackDevices.size());
std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
break;
case BackendType::Capture:
CaptureDevices.clear();
hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices);
if(FAILED(hr))
if(HRESULT hr{DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices)};FAILED(hr))
ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr);
outnames.reserve(CaptureDevices.size());
std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device);
break;
}
if(SUCCEEDED(hrcom))
CoUninitialize();
return outnames;
}