mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 15:44:36 +00:00
update openal
This commit is contained in:
parent
62f3b93ff9
commit
6721a6b021
287 changed files with 33851 additions and 27325 deletions
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
#include "winmm.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <memory.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
|
@ -38,13 +38,15 @@
|
|||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "alnumeric.h"
|
||||
#include "alsem.h"
|
||||
#include "alstring.h"
|
||||
#include "althrd_setname.h"
|
||||
#include "core/device.h"
|
||||
#include "core/helpers.h"
|
||||
#include "core/logging.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "strutils.h"
|
||||
#include "threads.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
|
||||
|
|
@ -55,13 +57,13 @@ namespace {
|
|||
#define DEVNAME_HEAD "OpenAL Soft on "
|
||||
|
||||
|
||||
al::vector<std::string> PlaybackDevices;
|
||||
al::vector<std::string> CaptureDevices;
|
||||
std::vector<std::string> PlaybackDevices;
|
||||
std::vector<std::string> CaptureDevices;
|
||||
|
||||
bool checkName(const al::vector<std::string> &list, const std::string &name)
|
||||
bool checkName(const std::vector<std::string> &list, const std::string &name)
|
||||
{ return std::find(list.cbegin(), list.cend(), name) != list.cend(); }
|
||||
|
||||
void ProbePlaybackDevices(void)
|
||||
void ProbePlaybackDevices()
|
||||
{
|
||||
PlaybackDevices.clear();
|
||||
|
||||
|
|
@ -74,7 +76,7 @@ void ProbePlaybackDevices(void)
|
|||
WAVEOUTCAPSW WaveCaps{};
|
||||
if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
|
||||
{
|
||||
const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)};
|
||||
const std::string basename{DEVNAME_HEAD + wstr_to_utf8(std::data(WaveCaps.szPname))};
|
||||
|
||||
int count{1};
|
||||
std::string newname{basename};
|
||||
|
|
@ -92,7 +94,7 @@ void ProbePlaybackDevices(void)
|
|||
}
|
||||
}
|
||||
|
||||
void ProbeCaptureDevices(void)
|
||||
void ProbeCaptureDevices()
|
||||
{
|
||||
CaptureDevices.clear();
|
||||
|
||||
|
|
@ -105,7 +107,7 @@ void ProbeCaptureDevices(void)
|
|||
WAVEINCAPSW WaveCaps{};
|
||||
if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
|
||||
{
|
||||
const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)};
|
||||
const std::string basename{DEVNAME_HEAD + wstr_to_utf8(std::data(WaveCaps.szPname))};
|
||||
|
||||
int count{1};
|
||||
std::string newname{basename};
|
||||
|
|
@ -134,7 +136,7 @@ struct WinMMPlayback 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;
|
||||
|
|
@ -143,6 +145,7 @@ struct WinMMPlayback final : public BackendBase {
|
|||
al::semaphore mSem;
|
||||
uint mIdx{0u};
|
||||
std::array<WAVEHDR,4> mWaveBuffer{};
|
||||
al::vector<char,16> mBuffer;
|
||||
|
||||
HWAVEOUT mOutHdl{nullptr};
|
||||
|
||||
|
|
@ -150,8 +153,6 @@ struct WinMMPlayback final : public BackendBase {
|
|||
|
||||
std::atomic<bool> mKillNow{true};
|
||||
std::thread mThread;
|
||||
|
||||
DEF_NEWDEL(WinMMPlayback)
|
||||
};
|
||||
|
||||
WinMMPlayback::~WinMMPlayback()
|
||||
|
|
@ -159,14 +160,11 @@ WinMMPlayback::~WinMMPlayback()
|
|||
if(mOutHdl)
|
||||
waveOutClose(mOutHdl);
|
||||
mOutHdl = nullptr;
|
||||
|
||||
al_free(mWaveBuffer[0].lpData);
|
||||
std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{});
|
||||
}
|
||||
|
||||
/* WinMMPlayback::waveOutProc
|
||||
*
|
||||
* Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is
|
||||
* Posts a message to 'WinMMPlayback::mixerProc' every time a WaveOut Buffer is
|
||||
* completed and returns to the application (for more data)
|
||||
*/
|
||||
void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PTR) noexcept
|
||||
|
|
@ -179,7 +177,7 @@ void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PT
|
|||
FORCE_ALIGN int WinMMPlayback::mixerProc()
|
||||
{
|
||||
SetRTPriority();
|
||||
althrd_setname(MIXER_THREAD_NAME);
|
||||
althrd_setname(GetMixerThreadName());
|
||||
|
||||
while(!mKillNow.load(std::memory_order_acquire)
|
||||
&& mDevice->Connected.load(std::memory_order_acquire))
|
||||
|
|
@ -207,59 +205,55 @@ FORCE_ALIGN int WinMMPlayback::mixerProc()
|
|||
}
|
||||
|
||||
|
||||
void WinMMPlayback::open(const char *name)
|
||||
void WinMMPlayback::open(std::string_view name)
|
||||
{
|
||||
if(PlaybackDevices.empty())
|
||||
ProbePlaybackDevices();
|
||||
|
||||
// Find the Device ID matching the deviceName if valid
|
||||
auto iter = name ?
|
||||
auto iter = !name.empty() ?
|
||||
std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) :
|
||||
PlaybackDevices.cbegin();
|
||||
if(iter == PlaybackDevices.cend())
|
||||
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
|
||||
name};
|
||||
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
|
||||
al::sizei(name), name.data()};
|
||||
auto DeviceID = static_cast<UINT>(std::distance(PlaybackDevices.cbegin(), iter));
|
||||
|
||||
DevFmtType fmttype{mDevice->FmtType};
|
||||
retry_open:
|
||||
WAVEFORMATEX format{};
|
||||
if(fmttype == DevFmtFloat)
|
||||
{
|
||||
format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
format.wBitsPerSample = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
if(fmttype == DevFmtUByte || fmttype == DevFmtByte)
|
||||
format.wBitsPerSample = 8;
|
||||
else
|
||||
format.wBitsPerSample = 16;
|
||||
}
|
||||
format.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2);
|
||||
format.nBlockAlign = static_cast<WORD>(format.wBitsPerSample * format.nChannels / 8);
|
||||
format.nSamplesPerSec = mDevice->Frequency;
|
||||
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||
format.cbSize = 0;
|
||||
|
||||
HWAVEOUT outHandle{};
|
||||
MMRESULT res{waveOutOpen(&outHandle, DeviceID, &format,
|
||||
reinterpret_cast<DWORD_PTR>(&WinMMPlayback::waveOutProcC),
|
||||
reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION)};
|
||||
if(res != MMSYSERR_NOERROR)
|
||||
{
|
||||
do {
|
||||
format = WAVEFORMATEX{};
|
||||
if(fmttype == DevFmtFloat)
|
||||
{
|
||||
fmttype = DevFmtShort;
|
||||
goto retry_open;
|
||||
format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
format.wBitsPerSample = 32;
|
||||
}
|
||||
throw al::backend_exception{al::backend_error::DeviceError, "waveOutOpen failed: %u", res};
|
||||
}
|
||||
else
|
||||
{
|
||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
if(fmttype == DevFmtUByte || fmttype == DevFmtByte)
|
||||
format.wBitsPerSample = 8;
|
||||
else
|
||||
format.wBitsPerSample = 16;
|
||||
}
|
||||
format.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2);
|
||||
format.nBlockAlign = static_cast<WORD>(format.wBitsPerSample * format.nChannels / 8);
|
||||
format.nSamplesPerSec = mDevice->Frequency;
|
||||
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||
format.cbSize = 0;
|
||||
|
||||
MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &format,
|
||||
reinterpret_cast<DWORD_PTR>(&WinMMPlayback::waveOutProcC),
|
||||
reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION)};
|
||||
if(res == MMSYSERR_NOERROR) break;
|
||||
|
||||
if(fmttype != DevFmtFloat)
|
||||
throw al::backend_exception{al::backend_error::DeviceError, "waveOutOpen failed: %u",
|
||||
res};
|
||||
|
||||
fmttype = DevFmtShort;
|
||||
} while(true);
|
||||
|
||||
if(mOutHdl)
|
||||
waveOutClose(mOutHdl);
|
||||
mOutHdl = outHandle;
|
||||
mFormat = format;
|
||||
|
||||
mDevice->DeviceName = PlaybackDevices[DeviceID];
|
||||
|
|
@ -312,11 +306,11 @@ bool WinMMPlayback::reset()
|
|||
}
|
||||
setDefaultWFXChannelOrder();
|
||||
|
||||
uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()};
|
||||
const uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()};
|
||||
|
||||
al_free(mWaveBuffer[0].lpData);
|
||||
decltype(mBuffer)(BufferSize*mWaveBuffer.size()).swap(mBuffer);
|
||||
mWaveBuffer[0] = WAVEHDR{};
|
||||
mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size()));
|
||||
mWaveBuffer[0].lpData = mBuffer.data();
|
||||
mWaveBuffer[0].dwBufferLength = BufferSize;
|
||||
for(size_t i{1};i < mWaveBuffer.size();i++)
|
||||
{
|
||||
|
|
@ -369,16 +363,17 @@ struct WinMMCapture final : public BackendBase {
|
|||
|
||||
int captureProc();
|
||||
|
||||
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;
|
||||
|
||||
std::atomic<uint> mReadable{0u};
|
||||
al::semaphore mSem;
|
||||
uint mIdx{0};
|
||||
std::array<WAVEHDR,4> mWaveBuffer{};
|
||||
al::vector<char,16> mBuffer;
|
||||
|
||||
HWAVEIN mInHdl{nullptr};
|
||||
|
||||
|
|
@ -388,8 +383,6 @@ struct WinMMCapture final : public BackendBase {
|
|||
|
||||
std::atomic<bool> mKillNow{true};
|
||||
std::thread mThread;
|
||||
|
||||
DEF_NEWDEL(WinMMCapture)
|
||||
};
|
||||
|
||||
WinMMCapture::~WinMMCapture()
|
||||
|
|
@ -398,14 +391,11 @@ WinMMCapture::~WinMMCapture()
|
|||
if(mInHdl)
|
||||
waveInClose(mInHdl);
|
||||
mInHdl = nullptr;
|
||||
|
||||
al_free(mWaveBuffer[0].lpData);
|
||||
std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{});
|
||||
}
|
||||
|
||||
/* WinMMCapture::waveInProc
|
||||
*
|
||||
* Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is
|
||||
* Posts a message to 'WinMMCapture::captureProc' every time a WaveIn Buffer is
|
||||
* completed and returns to the application (with more data).
|
||||
*/
|
||||
void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR) noexcept
|
||||
|
|
@ -417,7 +407,7 @@ void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR)
|
|||
|
||||
int WinMMCapture::captureProc()
|
||||
{
|
||||
althrd_setname(RECORD_THREAD_NAME);
|
||||
althrd_setname(GetRecordThreadName());
|
||||
|
||||
while(!mKillNow.load(std::memory_order_acquire) &&
|
||||
mDevice->Connected.load(std::memory_order_acquire))
|
||||
|
|
@ -434,7 +424,8 @@ int WinMMCapture::captureProc()
|
|||
WAVEHDR &waveHdr = mWaveBuffer[widx];
|
||||
widx = (widx+1) % mWaveBuffer.size();
|
||||
|
||||
mRing->write(waveHdr.lpData, waveHdr.dwBytesRecorded / mFormat.nBlockAlign);
|
||||
std::ignore = mRing->write(waveHdr.lpData,
|
||||
waveHdr.dwBytesRecorded / mFormat.nBlockAlign);
|
||||
mReadable.fetch_sub(1, std::memory_order_acq_rel);
|
||||
waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR));
|
||||
} while(--todo);
|
||||
|
|
@ -445,18 +436,18 @@ int WinMMCapture::captureProc()
|
|||
}
|
||||
|
||||
|
||||
void WinMMCapture::open(const char *name)
|
||||
void WinMMCapture::open(std::string_view name)
|
||||
{
|
||||
if(CaptureDevices.empty())
|
||||
ProbeCaptureDevices();
|
||||
|
||||
// Find the Device ID matching the deviceName if valid
|
||||
auto iter = name ?
|
||||
auto iter = !name.empty() ?
|
||||
std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) :
|
||||
CaptureDevices.cbegin();
|
||||
if(iter == CaptureDevices.cend())
|
||||
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
|
||||
name};
|
||||
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
|
||||
al::sizei(name), name.data()};
|
||||
auto DeviceID = static_cast<UINT>(std::distance(CaptureDevices.cbegin(), iter));
|
||||
|
||||
switch(mDevice->FmtChans)
|
||||
|
|
@ -470,6 +461,7 @@ void WinMMCapture::open(const char *name)
|
|||
case DevFmtX61:
|
||||
case DevFmtX71:
|
||||
case DevFmtX714:
|
||||
case DevFmtX7144:
|
||||
case DevFmtX3D71:
|
||||
case DevFmtAmbi3D:
|
||||
throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported",
|
||||
|
|
@ -513,14 +505,14 @@ void WinMMCapture::open(const char *name)
|
|||
|
||||
// Allocate circular memory buffer for the captured audio
|
||||
// Make sure circular buffer is at least 100ms in size
|
||||
uint CapturedDataSize{mDevice->BufferSize};
|
||||
CapturedDataSize = static_cast<uint>(maxz(CapturedDataSize, BufferSize*mWaveBuffer.size()));
|
||||
const auto CapturedDataSize = std::max<size_t>(mDevice->BufferSize,
|
||||
BufferSize*mWaveBuffer.size());
|
||||
|
||||
mRing = RingBuffer::Create(CapturedDataSize, mFormat.nBlockAlign, false);
|
||||
|
||||
al_free(mWaveBuffer[0].lpData);
|
||||
decltype(mBuffer)(BufferSize*mWaveBuffer.size()).swap(mBuffer);
|
||||
mWaveBuffer[0] = WAVEHDR{};
|
||||
mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size()));
|
||||
mWaveBuffer[0].lpData = mBuffer.data();
|
||||
mWaveBuffer[0].dwBufferLength = BufferSize;
|
||||
for(size_t i{1};i < mWaveBuffer.size();++i)
|
||||
{
|
||||
|
|
@ -571,8 +563,8 @@ void WinMMCapture::stop()
|
|||
mIdx = 0;
|
||||
}
|
||||
|
||||
void WinMMCapture::captureSamples(al::byte *buffer, uint samples)
|
||||
{ mRing->read(buffer, samples); }
|
||||
void WinMMCapture::captureSamples(std::byte *buffer, uint samples)
|
||||
{ std::ignore = mRing->read(buffer, samples); }
|
||||
|
||||
uint WinMMCapture::availableSamples()
|
||||
{ return static_cast<uint>(mRing->readSpace()); }
|
||||
|
|
@ -586,26 +578,23 @@ bool WinMMBackendFactory::init()
|
|||
bool WinMMBackendFactory::querySupport(BackendType type)
|
||||
{ return type == BackendType::Playback || type == BackendType::Capture; }
|
||||
|
||||
std::string WinMMBackendFactory::probe(BackendType type)
|
||||
auto WinMMBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
|
||||
{
|
||||
std::string outnames;
|
||||
std::vector<std::string> outnames;
|
||||
auto add_device = [&outnames](const std::string &dname) -> void
|
||||
{
|
||||
/* +1 to also append the null char (to ensure a null-separated list and
|
||||
* double-null terminated list).
|
||||
*/
|
||||
if(!dname.empty())
|
||||
outnames.append(dname.c_str(), dname.length()+1);
|
||||
};
|
||||
{ if(!dname.empty()) outnames.emplace_back(dname); };
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case BackendType::Playback:
|
||||
ProbePlaybackDevices();
|
||||
outnames.reserve(PlaybackDevices.size());
|
||||
std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
|
||||
break;
|
||||
|
||||
case BackendType::Capture:
|
||||
ProbeCaptureDevices();
|
||||
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