aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends/winmm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'alc/backends/winmm.cpp')
-rw-r--r--alc/backends/winmm.cpp216
1 files changed, 105 insertions, 111 deletions
diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp
index 649bb345..38e1193f 100644
--- a/alc/backends/winmm.cpp
+++ b/alc/backends/winmm.cpp
@@ -20,7 +20,7 @@
#include "config.h"
-#include "backends/winmm.h"
+#include "winmm.h"
#include <stdlib.h>
#include <stdio.h>
@@ -28,6 +28,7 @@
#include <windows.h>
#include <mmsystem.h>
+#include <mmreg.h>
#include <array>
#include <atomic>
@@ -37,13 +38,13 @@
#include <algorithm>
#include <functional>
-#include "alcmain.h"
-#include "alexcpt.h"
-#include "alu.h"
+#include "alnumeric.h"
+#include "core/device.h"
+#include "core/helpers.h"
+#include "core/logging.h"
#include "ringbuffer.h"
#include "strutils.h"
#include "threads.h"
-#include "compat.h"
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
@@ -64,9 +65,9 @@ void ProbePlaybackDevices(void)
{
PlaybackDevices.clear();
- ALuint numdevs{waveOutGetNumDevs()};
+ UINT numdevs{waveOutGetNumDevs()};
PlaybackDevices.reserve(numdevs);
- for(ALuint i{0};i < numdevs;i++)
+ for(UINT i{0};i < numdevs;++i)
{
std::string dname;
@@ -95,9 +96,9 @@ void ProbeCaptureDevices(void)
{
CaptureDevices.clear();
- ALuint numdevs{waveInGetNumDevs()};
+ UINT numdevs{waveInGetNumDevs()};
CaptureDevices.reserve(numdevs);
- for(ALuint i{0};i < numdevs;i++)
+ for(UINT i{0};i < numdevs;++i)
{
std::string dname;
@@ -124,7 +125,7 @@ void ProbeCaptureDevices(void)
struct WinMMPlayback final : public BackendBase {
- WinMMPlayback(ALCdevice *device) noexcept : BackendBase{device} { }
+ WinMMPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
~WinMMPlayback() override;
void CALLBACK waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR param1, DWORD_PTR param2) noexcept;
@@ -133,14 +134,14 @@ struct WinMMPlayback final : public BackendBase {
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;
- std::atomic<ALuint> mWritable{0u};
+ std::atomic<uint> mWritable{0u};
al::semaphore mSem;
- ALuint mIdx{0u};
+ uint mIdx{0u};
std::array<WAVEHDR,4> mWaveBuffer{};
HWAVEOUT mOutHdl{nullptr};
@@ -180,36 +181,33 @@ FORCE_ALIGN int WinMMPlayback::mixerProc()
SetRTPriority();
althrd_setname(MIXER_THREAD_NAME);
- std::unique_lock<WinMMPlayback> 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))
{
- ALsizei todo = mWritable.load(std::memory_order_acquire);
+ uint todo{mWritable.load(std::memory_order_acquire)};
if(todo < 1)
{
- dlock.unlock();
mSem.wait();
- dlock.lock();
continue;
}
size_t widx{mIdx};
do {
WAVEHDR &waveHdr = mWaveBuffer[widx];
- widx = (widx+1) % mWaveBuffer.size();
+ if(++widx == mWaveBuffer.size()) widx = 0;
- aluMixData(mDevice, waveHdr.lpData, mDevice->UpdateSize);
+ mDevice->renderSamples(waveHdr.lpData, mDevice->UpdateSize, mFormat.nChannels);
mWritable.fetch_sub(1, std::memory_order_acq_rel);
waveOutWrite(mOutHdl, &waveHdr, sizeof(WAVEHDR));
} while(--todo);
- mIdx = static_cast<ALuint>(widx);
+ mIdx = static_cast<uint>(widx);
}
return 0;
}
-void WinMMPlayback::open(const ALCchar *name)
+void WinMMPlayback::open(const char *name)
{
if(PlaybackDevices.empty())
ProbePlaybackDevices();
@@ -219,51 +217,59 @@ void WinMMPlayback::open(const ALCchar *name)
std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) :
PlaybackDevices.cbegin();
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};
auto DeviceID = static_cast<UINT>(std::distance(PlaybackDevices.cbegin(), iter));
+ DevFmtType fmttype{mDevice->FmtType};
retry_open:
- mFormat = WAVEFORMATEX{};
- if(mDevice->FmtType == DevFmtFloat)
+ WAVEFORMATEX format{};
+ if(fmttype == DevFmtFloat)
{
- mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- mFormat.wBitsPerSample = 32;
+ format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ format.wBitsPerSample = 32;
}
else
{
- mFormat.wFormatTag = WAVE_FORMAT_PCM;
- if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtByte)
- mFormat.wBitsPerSample = 8;
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ if(fmttype == DevFmtUByte || fmttype == DevFmtByte)
+ format.wBitsPerSample = 8;
else
- mFormat.wBitsPerSample = 16;
+ format.wBitsPerSample = 16;
}
- mFormat.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2);
- mFormat.nBlockAlign = static_cast<WORD>(mFormat.wBitsPerSample * mFormat.nChannels / 8);
- mFormat.nSamplesPerSec = mDevice->Frequency;
- mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign;
- mFormat.cbSize = 0;
-
- MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &mFormat,
+ 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)
{
- if(mDevice->FmtType == DevFmtFloat)
+ if(fmttype == DevFmtFloat)
{
- mDevice->FmtType = DevFmtShort;
+ fmttype = DevFmtShort;
goto retry_open;
}
- throw al::backend_exception{ALC_INVALID_VALUE, "waveOutOpen failed: %u", res};
+ throw al::backend_exception{al::backend_error::DeviceError, "waveOutOpen failed: %u", res};
}
+ if(mOutHdl)
+ waveOutClose(mOutHdl);
+ mOutHdl = outHandle;
+ mFormat = format;
+
mDevice->DeviceName = PlaybackDevices[DeviceID];
}
bool WinMMPlayback::reset()
{
- mDevice->BufferSize = static_cast<ALuint>(uint64_t{mDevice->BufferSize} *
+ mDevice->BufferSize = static_cast<uint>(uint64_t{mDevice->BufferSize} *
mFormat.nSamplesPerSec / mDevice->Frequency);
- mDevice->BufferSize = (mDevice->BufferSize+3) & ~0x3;
+ mDevice->BufferSize = (mDevice->BufferSize+3) & ~0x3u;
mDevice->UpdateSize = mDevice->BufferSize / 4;
mDevice->Frequency = mFormat.nSamplesPerSec;
@@ -295,7 +301,7 @@ bool WinMMPlayback::reset()
return false;
}
- if(mFormat.nChannels == 2)
+ if(mFormat.nChannels >= 2)
mDevice->FmtChans = DevFmtStereo;
else if(mFormat.nChannels == 1)
mDevice->FmtChans = DevFmtMono;
@@ -304,9 +310,9 @@ bool WinMMPlayback::reset()
ERR("Unhandled channel count: %d\n", mFormat.nChannels);
return false;
}
- SetDefaultWFXChannelOrder(mDevice);
+ setDefaultWFXChannelOrder();
- ALuint BufferSize{mDevice->UpdateSize * mDevice->frameSizeFromFmt()};
+ uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()};
al_free(mWaveBuffer[0].lpData);
mWaveBuffer[0] = WAVEHDR{};
@@ -323,25 +329,20 @@ bool WinMMPlayback::reset()
return true;
}
-bool WinMMPlayback::start()
+void WinMMPlayback::start()
{
try {
- std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(),
- [this](WAVEHDR &waveHdr) -> void
- { waveOutPrepareHeader(mOutHdl, &waveHdr, static_cast<UINT>(sizeof(WAVEHDR))); }
- );
- mWritable.store(static_cast<ALuint>(mWaveBuffer.size()), std::memory_order_release);
+ for(auto &waveHdr : mWaveBuffer)
+ waveOutPrepareHeader(mOutHdl, &waveHdr, sizeof(WAVEHDR));
+ mWritable.store(static_cast<uint>(mWaveBuffer.size()), std::memory_order_release);
mKillNow.store(false, std::memory_order_release);
mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), this};
- return true;
}
catch(std::exception& e) {
- ERR("Failed to start mixing 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 WinMMPlayback::stop()
@@ -352,16 +353,14 @@ void WinMMPlayback::stop()
while(mWritable.load(std::memory_order_acquire) < mWaveBuffer.size())
mSem.wait();
- std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(),
- [this](WAVEHDR &waveHdr) -> void
- { waveOutUnprepareHeader(mOutHdl, &waveHdr, sizeof(WAVEHDR)); }
- );
+ for(auto &waveHdr : mWaveBuffer)
+ waveOutUnprepareHeader(mOutHdl, &waveHdr, sizeof(WAVEHDR));
mWritable.store(0, std::memory_order_release);
}
struct WinMMCapture final : public BackendBase {
- WinMMCapture(ALCdevice *device) noexcept : BackendBase{device} { }
+ WinMMCapture(DeviceBase *device) noexcept : BackendBase{device} { }
~WinMMCapture() override;
void CALLBACK waveInProc(HWAVEIN device, UINT msg, DWORD_PTR param1, DWORD_PTR param2) noexcept;
@@ -370,15 +369,15 @@ struct WinMMCapture final : public BackendBase {
int captureProc();
- 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;
- std::atomic<ALuint> mReadable{0u};
+ std::atomic<uint> mReadable{0u};
al::semaphore mSem;
- ALuint mIdx{0};
+ uint mIdx{0};
std::array<WAVEHDR,4> mWaveBuffer{};
HWAVEIN mInHdl{nullptr};
@@ -420,16 +419,13 @@ int WinMMCapture::captureProc()
{
althrd_setname(RECORD_THREAD_NAME);
- std::unique_lock<WinMMCapture> dlock{*this};
while(!mKillNow.load(std::memory_order_acquire) &&
mDevice->Connected.load(std::memory_order_acquire))
{
- ALuint todo{mReadable.load(std::memory_order_acquire)};
+ uint todo{mReadable.load(std::memory_order_acquire)};
if(todo < 1)
{
- dlock.unlock();
mSem.wait();
- dlock.lock();
continue;
}
@@ -442,14 +438,14 @@ int WinMMCapture::captureProc()
mReadable.fetch_sub(1, std::memory_order_acq_rel);
waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR));
} while(--todo);
- mIdx = static_cast<ALuint>(widx);
+ mIdx = static_cast<uint>(widx);
}
return 0;
}
-void WinMMCapture::open(const ALCchar *name)
+void WinMMCapture::open(const char *name)
{
if(CaptureDevices.empty())
ProbeCaptureDevices();
@@ -459,7 +455,8 @@ void WinMMCapture::open(const ALCchar *name)
std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) :
CaptureDevices.cbegin();
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};
auto DeviceID = static_cast<UINT>(std::distance(CaptureDevices.cbegin(), iter));
switch(mDevice->FmtChans)
@@ -470,11 +467,12 @@ void WinMMCapture::open(const ALCchar *name)
case DevFmtQuad:
case DevFmtX51:
- case DevFmtX51Rear:
case DevFmtX61:
case DevFmtX71:
+ case DevFmtX714:
+ case DevFmtX3D71:
case DevFmtAmbi3D:
- throw al::backend_exception{ALC_INVALID_VALUE, "%s capture not supported",
+ throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported",
DevFmtChannelsString(mDevice->FmtChans)};
}
@@ -489,7 +487,7 @@ void WinMMCapture::open(const ALCchar *name)
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
- throw al::backend_exception{ALC_INVALID_VALUE, "%s samples not supported",
+ throw al::backend_exception{al::backend_error::DeviceError, "%s samples not supported",
DevFmtTypeString(mDevice->FmtType)};
}
@@ -507,7 +505,7 @@ void WinMMCapture::open(const ALCchar *name)
reinterpret_cast<DWORD_PTR>(&WinMMCapture::waveInProcC),
reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION)};
if(res != MMSYSERR_NOERROR)
- throw al::backend_exception{ALC_INVALID_VALUE, "waveInOpen failed: %u", res};
+ throw al::backend_exception{al::backend_error::DeviceError, "waveInOpen failed: %u", res};
// Ensure each buffer is 50ms each
DWORD BufferSize{mFormat.nAvgBytesPerSec / 20u};
@@ -515,14 +513,14 @@ void WinMMCapture::open(const ALCchar *name)
// Allocate circular memory buffer for the captured audio
// Make sure circular buffer is at least 100ms in size
- ALuint CapturedDataSize{mDevice->BufferSize};
- CapturedDataSize = static_cast<ALuint>(maxz(CapturedDataSize, BufferSize*mWaveBuffer.size()));
+ uint CapturedDataSize{mDevice->BufferSize};
+ CapturedDataSize = static_cast<uint>(maxz(CapturedDataSize, BufferSize*mWaveBuffer.size()));
- mRing = CreateRingBuffer(CapturedDataSize, mFormat.nBlockAlign, false);
+ mRing = RingBuffer::Create(CapturedDataSize, mFormat.nBlockAlign, false);
al_free(mWaveBuffer[0].lpData);
mWaveBuffer[0] = WAVEHDR{};
- mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize*4));
+ mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size()));
mWaveBuffer[0].dwBufferLength = BufferSize;
for(size_t i{1};i < mWaveBuffer.size();++i)
{
@@ -534,7 +532,7 @@ void WinMMCapture::open(const ALCchar *name)
mDevice->DeviceName = CaptureDevices[DeviceID];
}
-bool WinMMCapture::start()
+void WinMMCapture::start()
{
try {
for(size_t i{0};i < mWaveBuffer.size();++i)
@@ -547,14 +545,11 @@ bool WinMMCapture::start()
mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), this};
waveInStart(mInHdl);
- return true;
}
catch(std::exception& e) {
- ERR("Failed to start mixing 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 WinMMCapture::stop()
@@ -576,14 +571,11 @@ void WinMMCapture::stop()
mIdx = 0;
}
-ALCenum WinMMCapture::captureSamples(al::byte *buffer, ALCuint samples)
-{
- mRing->read(buffer, samples);
- return ALC_NO_ERROR;
-}
+void WinMMCapture::captureSamples(al::byte *buffer, uint samples)
+{ mRing->read(buffer, samples); }
-ALCuint WinMMCapture::availableSamples()
-{ return static_cast<ALCuint>(mRing->readSpace()); }
+uint WinMMCapture::availableSamples()
+{ return static_cast<uint>(mRing->readSpace()); }
} // namespace
@@ -594,31 +586,33 @@ bool WinMMBackendFactory::init()
bool WinMMBackendFactory::querySupport(BackendType type)
{ return type == BackendType::Playback || type == BackendType::Capture; }
-void WinMMBackendFactory::probe(DevProbe type, std::string *outnames)
+std::string WinMMBackendFactory::probe(BackendType type)
{
- auto add_device = [outnames](const std::string &dname) -> void
+ 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);
+ outnames.append(dname.c_str(), dname.length()+1);
};
switch(type)
{
- case DevProbe::Playback:
- ProbePlaybackDevices();
- std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
- break;
-
- case DevProbe::Capture:
- ProbeCaptureDevices();
- std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device);
- break;
+ case BackendType::Playback:
+ ProbePlaybackDevices();
+ std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
+ break;
+
+ case BackendType::Capture:
+ ProbeCaptureDevices();
+ std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device);
+ break;
}
+ return outnames;
}
-BackendPtr WinMMBackendFactory::createBackend(ALCdevice *device, BackendType type)
+BackendPtr WinMMBackendFactory::createBackend(DeviceBase *device, BackendType type)
{
if(type == BackendType::Playback)
return BackendPtr{new WinMMPlayback{device}};