aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends
diff options
context:
space:
mode:
Diffstat (limited to 'alc/backends')
-rw-r--r--alc/backends/alsa.cpp8
-rw-r--r--alc/backends/coreaudio.cpp12
-rw-r--r--alc/backends/dsound.cpp138
-rw-r--r--alc/backends/jack.cpp31
-rw-r--r--alc/backends/oboe.cpp3
-rw-r--r--alc/backends/opensl.cpp3
-rw-r--r--alc/backends/oss.cpp10
-rw-r--r--alc/backends/portaudio.cpp35
-rw-r--r--alc/backends/pulseaudio.cpp17
-rw-r--r--alc/backends/sdl2.cpp41
-rw-r--r--alc/backends/sndio.cpp8
-rw-r--r--alc/backends/solaris.cpp8
-rw-r--r--alc/backends/wasapi.cpp262
-rw-r--r--alc/backends/wave.cpp9
-rw-r--r--alc/backends/winmm.cpp32
15 files changed, 360 insertions, 257 deletions
diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp
index bdfdd040..6a7a1187 100644
--- a/alc/backends/alsa.cpp
+++ b/alc/backends/alsa.cpp
@@ -635,12 +635,16 @@ void AlsaPlayback::open(const char *name)
name = alsaDevice;
driver = GetConfigValue(nullptr, "alsa", "device", "default");
}
-
TRACE("Opening device \"%s\"\n", driver);
- int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)};
+
+ snd_pcm_t *pcmHandle{};
+ int err{snd_pcm_open(&pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)};
if(err < 0)
throw al::backend_exception{al::backend_error::NoDevice,
"Could not open ALSA device \"%s\"", driver};
+ if(mPcmHandle)
+ snd_pcm_close(mPcmHandle);
+ mPcmHandle = pcmHandle;
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp
index 8e38a777..977bdc78 100644
--- a/alc/backends/coreaudio.cpp
+++ b/alc/backends/coreaudio.cpp
@@ -118,10 +118,20 @@ void CoreAudioPlayback::open(const char *name)
if(comp == nullptr)
throw al::backend_exception{al::backend_error::NoDevice, "Could not find audio component"};
- OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)};
+ AudioUnit audioUnit{};
+ OSStatus err{AudioComponentInstanceNew(comp, &audioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::NoDevice,
"Could not create component instance: %u", err};
+ /* WARNING: I don't know if "valid" audio unit values are guaranteed to be
+ * non-0. If not, this logic is broken.
+ */
+ if(mAudioUnit)
+ {
+ AudioUnitUninitialize(mAudioUnit);
+ AudioComponentInstanceDispose(mAudioUnit);
+ }
+ mAudioUnit = audioUnit;
/* init and start the default audio unit... */
err = AudioUnitInitialize(mAudioUnit);
diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp
index aa3a92a0..34fe25f4 100644
--- a/alc/backends/dsound.cpp
+++ b/alc/backends/dsound.cpp
@@ -107,6 +107,69 @@ HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallbac
#endif
+template<typename T>
+class ComPtr {
+ T *mPtr{nullptr};
+
+public:
+ ComPtr() noexcept = default;
+ ComPtr(const ComPtr &rhs) : mPtr{rhs.mPtr} { if(mPtr) mPtr->AddRef(); }
+ ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; }
+ ComPtr(std::nullptr_t) noexcept { }
+ explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { }
+ ~ComPtr() { if(mPtr) mPtr->Release(); }
+
+ ComPtr& operator=(const ComPtr &rhs)
+ {
+ if(!rhs.mPtr)
+ {
+ if(mPtr)
+ mPtr->Release();
+ mPtr = nullptr;
+ }
+ else
+ {
+ rhs.mPtr->AddRef();
+ try {
+ if(mPtr)
+ mPtr->Release();
+ mPtr = rhs.mPtr;
+ }
+ catch(...) {
+ rhs.mPtr->Release();
+ throw;
+ }
+ }
+ return *this;
+ }
+ ComPtr& operator=(ComPtr&& rhs)
+ {
+ if(mPtr)
+ mPtr->Release();
+ mPtr = rhs.mPtr;
+ rhs.mPtr = nullptr;
+ return *this;
+ }
+
+ operator bool() const noexcept { return mPtr != nullptr; }
+
+ T& operator*() const noexcept { return *mPtr; }
+ T* operator->() const noexcept { return mPtr; }
+ T* get() const noexcept { return mPtr; }
+ T** getPtr() noexcept { return &mPtr; }
+
+ T* release() noexcept
+ {
+ T *ret{mPtr};
+ mPtr = nullptr;
+ return ret;
+ }
+
+ void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
+ void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
+};
+
+
#define MONO SPEAKER_FRONT_CENTER
#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
@@ -179,11 +242,11 @@ struct DSoundPlayback final : public BackendBase {
void start() override;
void stop() override;
- IDirectSound *mDS{nullptr};
- IDirectSoundBuffer *mPrimaryBuffer{nullptr};
- IDirectSoundBuffer *mBuffer{nullptr};
- IDirectSoundNotify *mNotifies{nullptr};
- HANDLE mNotifyEvent{nullptr};
+ ComPtr<IDirectSound> mDS;
+ ComPtr<IDirectSoundBuffer> mPrimaryBuffer;
+ ComPtr<IDirectSoundBuffer> mBuffer;
+ ComPtr<IDirectSoundNotify> mNotifies;
+ HANDLE mNotifyEvent{nullptr};
std::atomic<bool> mKillNow{true};
std::thread mThread;
@@ -193,19 +256,11 @@ struct DSoundPlayback final : public BackendBase {
DSoundPlayback::~DSoundPlayback()
{
- if(mNotifies)
- mNotifies->Release();
mNotifies = nullptr;
- if(mBuffer)
- mBuffer->Release();
mBuffer = nullptr;
- if(mPrimaryBuffer)
- mPrimaryBuffer->Release();
mPrimaryBuffer = nullptr;
-
- if(mDS)
- mDS->Release();
mDS = nullptr;
+
if(mNotifyEvent)
CloseHandle(mNotifyEvent);
mNotifyEvent = nullptr;
@@ -234,8 +289,8 @@ FORCE_ALIGN int DSoundPlayback::mixerProc()
bool Playing{false};
DWORD LastCursor{0u};
mBuffer->GetCurrentPosition(&LastCursor, nullptr);
- 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))
{
// Get current play cursor
DWORD PlayCursor;
@@ -344,31 +399,34 @@ void DSoundPlayback::open(const char *name)
}
hr = DS_OK;
- mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr);
- if(!mNotifyEvent) hr = E_FAIL;
+ if(!mNotifyEvent)
+ {
+ mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr);
+ if(!mNotifyEvent) hr = E_FAIL;
+ }
//DirectSound Init code
+ ComPtr<IDirectSound> ds;
if(SUCCEEDED(hr))
- hr = DirectSoundCreate(guid, &mDS, nullptr);
+ hr = DirectSoundCreate(guid, ds.getPtr(), nullptr);
if(SUCCEEDED(hr))
- hr = mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY);
+ hr = ds->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY);
if(FAILED(hr))
throw al::backend_exception{al::backend_error::DeviceError, "Device init failed: 0x%08lx",
hr};
+ mNotifies = nullptr;
+ mBuffer = nullptr;
+ mPrimaryBuffer = nullptr;
+ mDS = std::move(ds);
+
mDevice->DeviceName = name;
}
bool DSoundPlayback::reset()
{
- if(mNotifies)
- mNotifies->Release();
mNotifies = nullptr;
- if(mBuffer)
- mBuffer->Release();
mBuffer = nullptr;
- if(mPrimaryBuffer)
- mPrimaryBuffer->Release();
mPrimaryBuffer = nullptr;
switch(mDevice->FmtType)
@@ -465,7 +523,7 @@ retry_open:
DSBUFFERDESC DSBDescription{};
DSBDescription.dwSize = sizeof(DSBDescription);
DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
- hr = mDS->CreateSoundBuffer(&DSBDescription, &mPrimaryBuffer, nullptr);
+ hr = mDS->CreateSoundBuffer(&DSBDescription, mPrimaryBuffer.getPtr(), nullptr);
}
if(SUCCEEDED(hr))
hr = mPrimaryBuffer->SetFormat(&OutputType.Format);
@@ -485,7 +543,7 @@ retry_open:
DSBDescription.dwBufferBytes = mDevice->BufferSize * OutputType.Format.nBlockAlign;
DSBDescription.lpwfxFormat = &OutputType.Format;
- hr = mDS->CreateSoundBuffer(&DSBDescription, &mBuffer, nullptr);
+ hr = mDS->CreateSoundBuffer(&DSBDescription, mBuffer.getPtr(), nullptr);
if(FAILED(hr) && mDevice->FmtType == DevFmtFloat)
{
mDevice->FmtType = DevFmtShort;
@@ -499,7 +557,7 @@ retry_open:
hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr);
if(SUCCEEDED(hr))
{
- mNotifies = static_cast<IDirectSoundNotify*>(ptr);
+ mNotifies = ComPtr<IDirectSoundNotify>{static_cast<IDirectSoundNotify*>(ptr)};
uint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
assert(num_updates <= MAX_UPDATES);
@@ -517,14 +575,8 @@ retry_open:
if(FAILED(hr))
{
- if(mNotifies)
- mNotifies->Release();
mNotifies = nullptr;
- if(mBuffer)
- mBuffer->Release();
mBuffer = nullptr;
- if(mPrimaryBuffer)
- mPrimaryBuffer->Release();
mPrimaryBuffer = nullptr;
return false;
}
@@ -567,8 +619,8 @@ struct DSoundCapture final : public BackendBase {
void captureSamples(al::byte *buffer, uint samples) override;
uint availableSamples() override;
- IDirectSoundCapture *mDSC{nullptr};
- IDirectSoundCaptureBuffer *mDSCbuffer{nullptr};
+ ComPtr<IDirectSoundCapture> mDSC;
+ ComPtr<IDirectSoundCaptureBuffer> mDSCbuffer;
DWORD mBufferBytes{0u};
DWORD mCursor{0u};
@@ -582,12 +634,8 @@ DSoundCapture::~DSoundCapture()
if(mDSCbuffer)
{
mDSCbuffer->Stop();
- mDSCbuffer->Release();
mDSCbuffer = nullptr;
}
-
- if(mDSC)
- mDSC->Release();
mDSC = nullptr;
}
@@ -693,20 +741,16 @@ void DSoundCapture::open(const char *name)
DSCBDescription.lpwfxFormat = &InputType.Format;
//DirectSoundCapture Init code
- hr = DirectSoundCaptureCreate(guid, &mDSC, nullptr);
+ hr = DirectSoundCaptureCreate(guid, mDSC.getPtr(), nullptr);
if(SUCCEEDED(hr))
- mDSC->CreateCaptureBuffer(&DSCBDescription, &mDSCbuffer, nullptr);
+ mDSC->CreateCaptureBuffer(&DSCBDescription, mDSCbuffer.getPtr(), nullptr);
if(SUCCEEDED(hr))
mRing = RingBuffer::Create(mDevice->BufferSize, InputType.Format.nBlockAlign, false);
if(FAILED(hr))
{
mRing = nullptr;
- if(mDSCbuffer)
- mDSCbuffer->Release();
mDSCbuffer = nullptr;
- if(mDSC)
- mDSC->Release();
mDSC = nullptr;
throw al::backend_exception{al::backend_error::DeviceError, "Device init failed: 0x%08lx",
diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp
index 42509d77..cf52e7a4 100644
--- a/alc/backends/jack.cpp
+++ b/alc/backends/jack.cpp
@@ -384,22 +384,23 @@ int JackPlayback::mixerProc()
void JackPlayback::open(const char *name)
{
- mPortPattern.clear();
-
- const PathNamePair &binname = GetProcBinary();
- const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
-
- jack_status_t status;
- mClient = jack_client_open(client_name, ClientOptions, &status, nullptr);
- if(mClient == nullptr)
- throw al::backend_exception{al::backend_error::DeviceError,
- "Failed to open client connection: 0x%02x", status};
- if((status&JackServerStarted))
- TRACE("JACK server started\n");
- if((status&JackNameNotUnique))
+ if(!mClient)
{
- client_name = jack_get_client_name(mClient);
- TRACE("Client name not unique, got '%s' instead\n", client_name);
+ const PathNamePair &binname = GetProcBinary();
+ const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
+
+ jack_status_t status;
+ mClient = jack_client_open(client_name, ClientOptions, &status, nullptr);
+ if(mClient == nullptr)
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "Failed to open client connection: 0x%02x", status};
+ if((status&JackServerStarted))
+ TRACE("JACK server started\n");
+ if((status&JackNameNotUnique))
+ {
+ client_name = jack_get_client_name(mClient);
+ TRACE("Client name not unique, got '%s' instead\n", client_name);
+ }
}
if(PlaybackList.empty())
diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp
index d84cea8e..b94a0882 100644
--- a/alc/backends/oboe.cpp
+++ b/alc/backends/oboe.cpp
@@ -64,9 +64,10 @@ void OboePlayback::open(const char *name)
name};
/* Open a basic output stream, just to ensure it can work. */
+ oboe::ManagedStream stream;
oboe::Result result{oboe::AudioStreamBuilder{}.setDirection(oboe::Direction::Output)
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
- ->openManagedStream(mStream)};
+ ->openManagedStream(stream)};
if(result != oboe::Result::OK)
throw al::backend_exception{al::backend_error::DeviceError, "Failed to create stream: %s",
oboe::convertToText(result)};
diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp
index 917e097f..cae17ce1 100644
--- a/alc/backends/opensl.cpp
+++ b/alc/backends/opensl.cpp
@@ -316,6 +316,9 @@ void OpenSLPlayback::open(const char *name)
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
name};
+ /* There's only one device, so if it's already open, there's nothing to do. */
+ if(mEngineObj) return;
+
// create engine
SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
PRINTERR(result, "slCreateEngine");
diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp
index 4cff5959..196744b0 100644
--- a/alc/backends/oss.cpp
+++ b/alc/backends/oss.cpp
@@ -249,7 +249,7 @@ struct OSSPlayback final : public BackendBase {
OSSPlayback::~OSSPlayback()
{
if(mFd != -1)
- close(mFd);
+ ::close(mFd);
mFd = -1;
}
@@ -328,11 +328,15 @@ void OSSPlayback::open(const char *name)
devname = iter->device_name.c_str();
}
- mFd = ::open(devname, O_WRONLY);
- if(mFd == -1)
+ 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;
}
diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp
index d2e6a5a4..188f72f2 100644
--- a/alc/backends/portaudio.cpp
+++ b/alc/backends/portaudio.cpp
@@ -123,53 +123,58 @@ void PortPlayback::open(const char *name)
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
name};
- mUpdateSize = mDevice->UpdateSize;
-
+ PaStreamParameters params{};
auto devidopt = ConfigValueInt(nullptr, "port", "device");
- if(devidopt && *devidopt >= 0) mParams.device = *devidopt;
- else mParams.device = Pa_GetDefaultOutputDevice();
- mParams.suggestedLatency = mDevice->BufferSize / static_cast<double>(mDevice->Frequency);
- mParams.hostApiSpecificStreamInfo = nullptr;
+ if(devidopt && *devidopt >= 0) params.device = *devidopt;
+ else params.device = Pa_GetDefaultOutputDevice();
+ params.suggestedLatency = mDevice->BufferSize / static_cast<double>(mDevice->Frequency);
+ params.hostApiSpecificStreamInfo = nullptr;
- mParams.channelCount = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2);
+ params.channelCount = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2);
switch(mDevice->FmtType)
{
case DevFmtByte:
- mParams.sampleFormat = paInt8;
+ params.sampleFormat = paInt8;
break;
case DevFmtUByte:
- mParams.sampleFormat = paUInt8;
+ params.sampleFormat = paUInt8;
break;
case DevFmtUShort:
/* fall-through */
case DevFmtShort:
- mParams.sampleFormat = paInt16;
+ params.sampleFormat = paInt16;
break;
case DevFmtUInt:
/* fall-through */
case DevFmtInt:
- mParams.sampleFormat = paInt32;
+ params.sampleFormat = paInt32;
break;
case DevFmtFloat:
- mParams.sampleFormat = paFloat32;
+ params.sampleFormat = paFloat32;
break;
}
retry_open:
- PaError err{Pa_OpenStream(&mStream, nullptr, &mParams, mDevice->Frequency, mDevice->UpdateSize,
+ PaStream *stream{};
+ PaError err{Pa_OpenStream(&stream, nullptr, &params, mDevice->Frequency, mDevice->UpdateSize,
paNoFlag, &PortPlayback::writeCallbackC, this)};
if(err != paNoError)
{
- if(mParams.sampleFormat == paFloat32)
+ if(params.sampleFormat == paFloat32)
{
- mParams.sampleFormat = paInt16;
+ params.sampleFormat = paInt16;
goto retry_open;
}
throw al::backend_exception{al::backend_error::NoDevice, "Failed to open stream: %s",
Pa_GetErrorText(err)};
}
+ Pa_CloseStream(mStream);
+ mStream = stream;
+ mParams = params;
+ mUpdateSize = mDevice->UpdateSize;
+
mDevice->DeviceName = name;
}
diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp
index a6aa93a5..90f56968 100644
--- a/alc/backends/pulseaudio.cpp
+++ b/alc/backends/pulseaudio.cpp
@@ -846,7 +846,8 @@ void PulsePlayback::open(const char *name)
}
auto plock = mMainloop.getUniqueLock();
- mContext = mMainloop.connectContext(plock);
+ if(!mContext)
+ mContext = mMainloop.connectContext(plock);
pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
PA_STREAM_FIX_CHANNELS};
@@ -864,8 +865,18 @@ void PulsePlayback::open(const char *name)
if(defname) pulse_name = defname->c_str();
}
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
- mStream = mMainloop.connectStream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr,
- BackendType::Playback);
+ pa_stream *stream{mMainloop.connectStream(pulse_name, plock, mContext, flags, nullptr, &spec,
+ nullptr, BackendType::Playback)};
+ if(mStream)
+ {
+ pa_stream_set_state_callback(mStream, nullptr, nullptr);
+ pa_stream_set_moved_callback(mStream, nullptr, nullptr);
+ pa_stream_set_write_callback(mStream, nullptr, nullptr);
+ pa_stream_set_buffer_attr_callback(mStream, nullptr, nullptr);
+ pa_stream_disconnect(mStream);
+ pa_stream_unref(mStream);
+ }
+ mStream = stream;
pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this);
mFrameSize = static_cast<uint>(pa_frame_size(pa_stream_get_sample_spec(mStream)));
diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp
index 084b51c0..4c4c71ed 100644
--- a/alc/backends/sdl2.cpp
+++ b/alc/backends/sdl2.cpp
@@ -106,32 +106,34 @@ void Sdl2Backend::open(const char *name)
/* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't
* necessarily the first in the list.
*/
+ SDL_AudioDeviceID devid;
if(!name || strcmp(name, defaultDeviceName) == 0)
- mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have,
- SDL_AUDIO_ALLOW_ANY_CHANGE);
+ devid = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
else
{
const size_t prefix_len = strlen(DEVNAME_PREFIX);
if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0)
- mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have,
+ devid = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have,
SDL_AUDIO_ALLOW_ANY_CHANGE);
else
- mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have,
- SDL_AUDIO_ALLOW_ANY_CHANGE);
+ devid = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
}
- if(mDeviceID == 0)
+ if(!devid)
throw al::backend_exception{al::backend_error::NoDevice, "%s", SDL_GetError()};
- mDevice->Frequency = static_cast<uint>(have.freq);
-
+ DevFmtChannels devchans{};
if(have.channels == 1)
- mDevice->FmtChans = DevFmtMono;
+ devchans = DevFmtMono;
else if(have.channels == 2)
- mDevice->FmtChans = DevFmtStereo;
+ devchans = DevFmtStereo;
else
+ {
+ SDL_CloseAudioDevice(devid);
throw al::backend_exception{al::backend_error::DeviceError,
"Unhandled SDL channel count: %d", int{have.channels}};
+ }
+ DevFmtType devtype{};
switch(have.format)
{
case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break;
@@ -141,17 +143,20 @@ void Sdl2Backend::open(const char *name)
case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break;
case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break;
default:
+ SDL_CloseAudioDevice(devid);
throw al::backend_exception{al::backend_error::DeviceError, "Unhandled SDL format: 0x%04x",
have.format};
}
- mDevice->UpdateSize = have.samples;
- mDevice->BufferSize = have.samples * 2; /* SDL always (tries to) use two periods. */
- mFrameSize = mDevice->frameSizeFromFmt();
- mFrequency = mDevice->Frequency;
- mFmtChans = mDevice->FmtChans;
- mFmtType = mDevice->FmtType;
- mUpdateSize = mDevice->UpdateSize;
+ if(mDeviceID)
+ SDL_CloseAudioDevice(mDeviceID);
+ mDeviceID = devid;
+
+ mFrameSize = FrameSizeFromDevFmt(devchans, devtype, 0);
+ mFrequency = static_cast<uint>(have.freq);
+ mFmtChans = devchans;
+ mFmtType = devtype;
+ mUpdateSize = have.samples;
mDevice->DeviceName = name ? name : defaultDeviceName;
}
@@ -162,7 +167,7 @@ bool Sdl2Backend::reset()
mDevice->FmtChans = mFmtChans;
mDevice->FmtType = mFmtType;
mDevice->UpdateSize = mUpdateSize;
- mDevice->BufferSize = mUpdateSize * 2;
+ mDevice->BufferSize = mUpdateSize * 2; /* SDL always (tries to) use two periods. */
setDefaultWFXChannelOrder();
return true;
}
diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp
index 41bdb73b..a26eeaa6 100644
--- a/alc/backends/sndio.cpp
+++ b/alc/backends/sndio.cpp
@@ -122,10 +122,14 @@ void SndioPlayback::open(const char *name)
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
name};
- mSndHandle = sio_open(nullptr, SIO_PLAY, 0);
- if(mSndHandle == nullptr)
+ sio_hdl *sndHandle{sio_open(nullptr, SIO_PLAY, 0)};
+ if(!sndHandle)
throw al::backend_exception{al::backend_error::NoDevice, "Could not open backend device"};
+ if(mSndHandle)
+ sio_close(mSndHandle);
+ mSndHandle = sndHandle;
+
mDevice->DeviceName = name;
}
diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp
index a5bb45b0..68ab814c 100644
--- a/alc/backends/solaris.cpp
+++ b/alc/backends/solaris.cpp
@@ -148,11 +148,15 @@ void SolarisBackend::open(const char *name)
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
name};
- mFd = ::open(solaris_driver.c_str(), O_WRONLY);
- if(mFd == -1)
+ int fd{::open(solaris_driver.c_str(), O_WRONLY)};
+ if(fd == -1)
throw al::backend_exception{al::backend_error::NoDevice, "Could not open %s: %s",
solaris_driver.c_str(), strerror(errno)};
+ if(mFd != -1)
+ ::close(mFd);
+ mFd = fd;
+
mDevice->DeviceName = name;
}
diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp
index 0786a7d7..b594aebe 100644
--- a/alc/backends/wasapi.cpp
+++ b/alc/backends/wasapi.cpp
@@ -238,10 +238,9 @@ struct DevMap {
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();
+ auto match_name = [&name](const DevMap &entry) -> bool
+ { return entry.name == name; };
+ return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend();
}
al::vector<DevMap> PlaybackDevices;
@@ -297,26 +296,26 @@ NameGUIDPair get_device_name_and_guid(IMMDevice *device)
return std::make_pair(std::move(name), std::move(guid));
}
-void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor)
+EndpointFormFactor get_device_formfactor(IMMDevice *device)
{
ComPtr<IPropertyStore> ps;
- HRESULT hr = device->OpenPropertyStore(STGM_READ, ps.getPtr());
+ HRESULT hr{device->OpenPropertyStore(STGM_READ, ps.getPtr())};
if(FAILED(hr))
{
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
- return;
+ return UnknownFormFactor;
}
+ EndpointFormFactor formfactor{UnknownFormFactor};
PropVariant pvform;
- hr = ps->GetValue(reinterpret_cast<const PROPERTYKEY&>(PKEY_AudioEndpoint_FormFactor), pvform.get());
+ hr = ps->GetValue(PKEY_AudioEndpoint_FormFactor, pvform.get());
if(FAILED(hr))
WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr);
else if(pvform->vt == VT_UI4)
- *formfactor = static_cast<EndpointFormFactor>(pvform->ulVal);
- else if(pvform->vt == VT_EMPTY)
- *formfactor = UnknownFormFactor;
- else
+ formfactor = static_cast<EndpointFormFactor>(pvform->ulVal);
+ else if(pvform->vt != VT_EMPTY)
WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt);
+ return formfactor;
}
@@ -484,6 +483,7 @@ void TraceFormat(const char *msg, const WAVEFORMATEX *format)
enum class MsgType {
OpenDevice,
+ ReopenDevice,
ResetDevice,
StartDevice,
StopDevice,
@@ -497,6 +497,7 @@ enum class MsgType {
constexpr char MessageStr[static_cast<size_t>(MsgType::Count)][20]{
"Open Device",
+ "Reopen Device",
"Reset Device",
"Start Device",
"Stop Device",
@@ -511,7 +512,7 @@ constexpr char MessageStr[static_cast<size_t>(MsgType::Count)][20]{
struct WasapiProxy {
virtual ~WasapiProxy() = default;
- virtual HRESULT openProxy() = 0;
+ virtual HRESULT openProxy(const char *name) = 0;
virtual void closeProxy() = 0;
virtual HRESULT resetProxy() = 0;
@@ -521,19 +522,20 @@ struct WasapiProxy {
struct Msg {
MsgType mType;
WasapiProxy *mProxy;
+ const char *mParam;
std::promise<HRESULT> mPromise;
};
static std::deque<Msg> mMsgQueue;
static std::mutex mMsgQueueLock;
static std::condition_variable mMsgQueueCond;
- std::future<HRESULT> pushMessage(MsgType type)
+ std::future<HRESULT> pushMessage(MsgType type, const char *param=nullptr)
{
std::promise<HRESULT> promise;
std::future<HRESULT> future{promise.get_future()};
{
std::lock_guard<std::mutex> _{mMsgQueueLock};
- mMsgQueue.emplace_back(Msg{type, this, std::move(promise)});
+ mMsgQueue.emplace_back(Msg{type, this, param, std::move(promise)});
}
mMsgQueueCond.notify_one();
return future;
@@ -545,7 +547,7 @@ struct WasapiProxy {
std::future<HRESULT> future{promise.get_future()};
{
std::lock_guard<std::mutex> _{mMsgQueueLock};
- mMsgQueue.emplace_back(Msg{type, nullptr, std::move(promise)});
+ mMsgQueue.emplace_back(Msg{type, nullptr, nullptr, std::move(promise)});
}
mMsgQueueCond.notify_one();
return future;
@@ -600,9 +602,9 @@ int WasapiProxy::messageHandler(std::promise<HRESULT> *promise)
Msg msg;
while(popMessage(msg))
{
- TRACE("Got message \"%s\" (0x%04x, this=%p)\n",
+ TRACE("Got message \"%s\" (0x%04x, this=%p, param=%p)\n",
MessageStr[static_cast<size_t>(msg.mType)], static_cast<uint>(msg.mType),
- decltype(std::declval<void*>()){msg.mProxy});
+ static_cast<void*>(msg.mProxy), static_cast<const void*>(msg.mParam));
switch(msg.mType)
{
@@ -611,7 +613,7 @@ int WasapiProxy::messageHandler(std::promise<HRESULT> *promise)
if(++deviceCount == 1)
hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if(SUCCEEDED(hr))
- hr = msg.mProxy->openProxy();
+ hr = msg.mProxy->openProxy(msg.mParam);
msg.mPromise.set_value(hr);
if(FAILED(hr))
@@ -621,6 +623,11 @@ int WasapiProxy::messageHandler(std::promise<HRESULT> *promise)
}
continue;
+ case MsgType::ReopenDevice:
+ hr = msg.mProxy->openProxy(msg.mParam);
+ msg.mPromise.set_value(hr);
+ continue;
+
case MsgType::ResetDevice:
hr = msg.mProxy->resetProxy();
msg.mPromise.set_value(hr);
@@ -688,7 +695,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy {
int mixerProc();
void open(const char *name) override;
- HRESULT openProxy() override;
+ HRESULT openProxy(const char *name) override;
void closeProxy() override;
bool reset() override;
@@ -700,8 +707,6 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy {
ClockLatency getClockLatency() override;
- std::wstring mDevId;
-
HRESULT mOpenStatus{E_FAIL};
ComPtr<IMMDevice> mMMDev{nullptr};
ComPtr<IAudioClient> mClient{nullptr};
@@ -796,83 +801,86 @@ void WasapiPlayback::open(const char *name)
{
HRESULT hr{S_OK};
- mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr);
- if(mNotifyEvent == nullptr)
+ if(!mNotifyEvent)
{
- ERR("Failed to create notify events: %lu\n", GetLastError());
- hr = E_FAIL;
- }
-
- if(SUCCEEDED(hr))
- {
- if(name)
+ mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr);
+ if(mNotifyEvent == nullptr)
{
- if(PlaybackDevices.empty())
- pushMessage(MsgType::EnumeratePlayback).wait();
-
+ ERR("Failed to create notify events: %lu\n", GetLastError());
hr = E_FAIL;
- auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
- [name](const DevMap &entry) -> bool
- { return entry.name == name || entry.endpoint_guid == name; });
- if(iter == PlaybackDevices.cend())
- {
- const std::wstring wname{utf8_to_wstr(name)};
- iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
- [&wname](const DevMap &entry) -> bool
- { return entry.devid == wname; });
- }
- if(iter == PlaybackDevices.cend())
- WARN("Failed to find device name matching \"%s\"\n", name);
- else
- {
- mDevId = iter->devid;
- mDevice->DeviceName = iter->name;
- hr = S_OK;
- }
}
}
if(SUCCEEDED(hr))
- hr = pushMessage(MsgType::OpenDevice).get();
- mOpenStatus = hr;
-
- if(FAILED(hr))
{
- if(mNotifyEvent != nullptr)
- CloseHandle(mNotifyEvent);
- mNotifyEvent = nullptr;
+ if(name && PlaybackDevices.empty())
+ pushMessage(MsgType::EnumeratePlayback).wait();
- mDevId.clear();
+ if(SUCCEEDED(mOpenStatus))
+ hr = pushMessage(MsgType::ReopenDevice, name).get();
+ else
+ {
+ hr = pushMessage(MsgType::OpenDevice, name).get();
+ mOpenStatus = hr;
+ }
+ }
+ if(FAILED(hr))
throw al::backend_exception{al::backend_error::DeviceError, "Device init failed: 0x%08lx",
hr};
- }
}
-HRESULT WasapiPlayback::openProxy()
+HRESULT WasapiPlayback::openProxy(const char *name)
{
+ const wchar_t *devid{nullptr};
+ if(name)
+ {
+ auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
+ [name](const DevMap &entry) -> bool
+ { return entry.name == name || entry.endpoint_guid == name; });
+ if(iter == PlaybackDevices.cend())
+ {
+ const std::wstring wname{utf8_to_wstr(name)};
+ iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
+ [&wname](const DevMap &entry) -> bool
+ { return entry.devid == wname; });
+ }
+ if(iter == PlaybackDevices.cend())
+ {
+ WARN("Failed to find device name matching \"%s\"\n", name);
+ return E_FAIL;
+ }
+ name = iter->name.c_str();
+ devid = iter->devid.c_str();
+ }
+
void *ptr;
HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER,
IID_IMMDeviceEnumerator, &ptr)};
- if(SUCCEEDED(hr))
+ ComPtr<IMMDeviceEnumerator> enumerator{static_cast<IMMDeviceEnumerator*>(ptr)};
+ ComPtr<IMMDevice> mmdev;
+ if(!devid)
+ hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, mmdev.getPtr());
+ else
+ hr = enumerator->GetDevice(devid, mmdev.getPtr());
+ enumerator = nullptr;
+ if(FAILED(hr))
{
- ComPtr<IMMDeviceEnumerator> enumerator{static_cast<IMMDeviceEnumerator*>(ptr)};
- if(mDevId.empty())
- hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, mMMDev.getPtr());
- else
- hr = enumerator->GetDevice(mDevId.c_str(), mMMDev.getPtr());
+ WARN("Failed to open device \"%s\"\n", name?name:"(default)");
+ return hr;
}
- if(SUCCEEDED(hr))
- hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr);
- if(SUCCEEDED(hr))
+
+ hr = mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr);
+ if(FAILED(hr))
{
- mClient = ComPtr<IAudioClient>{static_cast<IAudioClient*>(ptr)};
- if(mDevice->DeviceName.empty())
- mDevice->DeviceName = get_device_name_and_guid(mMMDev.get()).first;
+ WARN("Failed to activate device \"%s\"\n", name?name:"(default)");
+ return hr;
}
- if(FAILED(hr))
- mMMDev = nullptr;
+ mClient = ComPtr<IAudioClient>{static_cast<IAudioClient*>(ptr)};
+ mMMDev = std::move(mmdev);
+ if(name) mDevice->DeviceName = name;
+ else mDevice->DeviceName = get_device_name_and_guid(mMMDev.get()).first;
return hr;
}
@@ -1105,8 +1113,7 @@ HRESULT WasapiPlayback::resetProxy()
}
mFrameStep = OutputType.Format.nChannels;
- EndpointFormFactor formfactor{UnknownFormFactor};
- get_device_formfactor(mMMDev.get(), &formfactor);
+ const EndpointFormFactor formfactor{get_device_formfactor(mMMDev.get())};
mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo
&& (formfactor == Headphones || formfactor == Headset));
@@ -1226,7 +1233,7 @@ struct WasapiCapture final : public BackendBase, WasapiProxy {
int recordProc();
void open(const char *name) override;
- HRESULT openProxy() override;
+ HRESULT openProxy(const char *name) override;
void closeProxy() override;
HRESULT resetProxy() override;
@@ -1238,8 +1245,6 @@ struct WasapiCapture final : public BackendBase, WasapiProxy {
void captureSamples(al::byte *buffer, uint samples) override;
uint availableSamples() override;
- std::wstring mDevId;
-
HRESULT mOpenStatus{E_FAIL};
ComPtr<IMMDevice> mMMDev{nullptr};
ComPtr<IAudioClient> mClient{nullptr};
@@ -1373,48 +1378,15 @@ void WasapiCapture::open(const char *name)
if(SUCCEEDED(hr))
{
- if(name)
- {
- if(CaptureDevices.empty())
- pushMessage(MsgType::EnumerateCapture).wait();
-
- hr = E_FAIL;
- auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
- [name](const DevMap &entry) -> bool
- { return entry.name == name || entry.endpoint_guid == name; });
- if(iter == CaptureDevices.cend())
- {
- const std::wstring wname{utf8_to_wstr(name)};
- iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
- [&wname](const DevMap &entry) -> bool
- { return entry.devid == wname; });
- }
- if(iter == CaptureDevices.cend())
- WARN("Failed to find device name matching \"%s\"\n", name);
- else
- {
- mDevId = iter->devid;
- mDevice->DeviceName = iter->name;
- hr = S_OK;
- }
- }
+ if(name && CaptureDevices.empty())
+ pushMessage(MsgType::EnumerateCapture).wait();
+ hr = pushMessage(MsgType::OpenDevice, name).get();
}
-
- if(SUCCEEDED(hr))
- hr = pushMessage(MsgType::OpenDevice).get();
mOpenStatus = hr;
if(FAILED(hr))
- {
- if(mNotifyEvent != nullptr)
- CloseHandle(mNotifyEvent);
- mNotifyEvent = nullptr;
-
- mDevId.clear();
-
throw al::backend_exception{al::backend_error::DeviceError, "Device init failed: 0x%08lx",
hr};
- }
hr = pushMessage(MsgType::ResetDevice).get();
if(FAILED(hr))
@@ -1425,30 +1397,56 @@ void WasapiCapture::open(const char *name)
}
}
-HRESULT WasapiCapture::openProxy()
+HRESULT WasapiCapture::openProxy(const char *name)
{
+ const wchar_t *devid{nullptr};
+ if(name)
+ {
+ auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
+ [name](const DevMap &entry) -> bool
+ { return entry.name == name || entry.endpoint_guid == name; });
+ if(iter == CaptureDevices.cend())
+ {
+ const std::wstring wname{utf8_to_wstr(name)};
+ iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
+ [&wname](const DevMap &entry) -> bool
+ { return entry.devid == wname; });
+ }
+ if(iter == CaptureDevices.cend())
+ {
+ WARN("Failed to find device name matching \"%s\"\n", name);
+ return E_FAIL;
+ }
+ name = iter->name.c_str();
+ devid = iter->devid.c_str();
+ }
+
void *ptr;
HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER,
IID_IMMDeviceEnumerator, &ptr)};
- if(SUCCEEDED(hr))
- {
- ComPtr<IMMDeviceEnumerator> enumerator{static_cast<IMMDeviceEnumerator*>(ptr)};
- if(mDevId.empty())
- hr = enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, mMMDev.getPtr());
- else
- hr = enumerator->GetDevice(mDevId.c_str(), mMMDev.getPtr());
- }
- if(SUCCEEDED(hr))
- hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr);
- if(SUCCEEDED(hr))
+ ComPtr<IMMDeviceEnumerator> enumerator{static_cast<IMMDeviceEnumerator*>(ptr)};
+ if(!devid)
+ hr = enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, mMMDev.getPtr());
+ else
+ hr = enumerator->GetDevice(devid, mMMDev.getPtr());
+ enumerator = nullptr;
+ if(FAILED(hr))
{
- mClient = ComPtr<IAudioClient>{static_cast<IAudioClient*>(ptr)};
- if(mDevice->DeviceName.empty())
- mDevice->DeviceName = get_device_name_and_guid(mMMDev.get()).first;
+ WARN("Failed to open device \"%s\"\n", name?name:"(default)");
+ return hr;
}
+ hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr);
if(FAILED(hr))
+ {
+ WARN("Failed to activate device \"%s\"\n", name?name:"(default)");
mMMDev = nullptr;
+ return hr;
+ }
+
+ mClient = ComPtr<IAudioClient>{static_cast<IAudioClient*>(ptr)};
+ if(name) mDevice->DeviceName = name;
+ else mDevice->DeviceName = get_device_name_and_guid(mMMDev.get()).first;
return hr;
}
diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp
index 4f738230..e80fb3ae 100644
--- a/alc/backends/wave.cpp
+++ b/alc/backends/wave.cpp
@@ -132,8 +132,8 @@ int WaveBackend::mixerProc()
int64_t done{0};
auto start = std::chrono::steady_clock::now();
- 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))
{
auto now = std::chrono::steady_clock::now();
@@ -214,9 +214,12 @@ void WaveBackend::open(const char *name)
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
name};
+ /* There's only one "device", so if it's already open, we're done. */
+ if(mFile) return;
+
#ifdef _WIN32
{
- std::wstring wname = utf8_to_wstr(fname);
+ std::wstring wname{utf8_to_wstr(fname)};
mFile = _wfopen(wname.c_str(), L"wb");
}
#else
diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp
index 9b88f12e..14fda45b 100644
--- a/alc/backends/winmm.cpp
+++ b/alc/backends/winmm.cpp
@@ -224,27 +224,28 @@ void WinMMPlayback::open(const char *name)
auto DeviceID = static_cast<UINT>(std::distance(PlaybackDevices.cbegin(), iter));
retry_open:
- mFormat = WAVEFORMATEX{};
+ WAVEFORMATEX format{};
if(mDevice->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;
+ format.wFormatTag = WAVE_FORMAT_PCM;
if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtByte)
- mFormat.wBitsPerSample = 8;
+ 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)
@@ -257,6 +258,11 @@ retry_open:
throw al::backend_exception{al::backend_error::DeviceError, "waveOutOpen failed: %u", res};
}
+ if(mOutHdl)
+ waveOutClose(mOutHdl);
+ mOutHdl = outHandle;
+ mFormat = format;
+
mDevice->DeviceName = PlaybackDevices[DeviceID];
}