Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/extern
diff options
context:
space:
mode:
authorJörg Müller <nexyon@gmail.com>2021-03-27 14:22:23 +0300
committerJörg Müller <nexyon@gmail.com>2021-03-29 13:16:01 +0300
commit35cf34de6d5627e878c88ef8c8a5e89b7c72b3be (patch)
tree1b1edb78479669752ac91c78ac7ffb1a200e3422 /extern
parentae9d61e7fea25535803e92298f44b184c9190f76 (diff)
Fix T86851: PulseAudio randomly asserts in background rendering
Upstream fix from Audaspace with simplified PulseAudio code. Maniphest Tasks: T86851 Differential Revision: https://developer.blender.org/D10840
Diffstat (limited to 'extern')
-rw-r--r--extern/audaspace/CMakeLists.txt2
-rw-r--r--extern/audaspace/include/devices/SoftwareDevice.h1
-rw-r--r--extern/audaspace/include/devices/ThreadedDevice.h95
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp62
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h19
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h14
-rw-r--r--extern/audaspace/plugins/wasapi/WASAPIDevice.cpp169
-rw-r--r--extern/audaspace/plugins/wasapi/WASAPIDevice.h29
-rw-r--r--extern/audaspace/src/devices/SoftwareDevice.cpp6
-rw-r--r--extern/audaspace/src/devices/ThreadedDevice.cpp65
10 files changed, 255 insertions, 207 deletions
diff --git a/extern/audaspace/CMakeLists.txt b/extern/audaspace/CMakeLists.txt
index fe1bf5dc742..1599c03cbad 100644
--- a/extern/audaspace/CMakeLists.txt
+++ b/extern/audaspace/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRC
src/devices/NULLDevice.cpp
src/devices/ReadDevice.cpp
src/devices/SoftwareDevice.cpp
+ src/devices/ThreadedDevice.cpp
src/Exception.cpp
src/file/File.cpp
src/file/FileManager.cpp
@@ -148,6 +149,7 @@ set(PUBLIC_HDR
include/devices/NULLDevice.h
include/devices/ReadDevice.h
include/devices/SoftwareDevice.h
+ include/devices/ThreadedDevice.h
include/Exception.h
include/file/File.h
include/file/FileManager.h
diff --git a/extern/audaspace/include/devices/SoftwareDevice.h b/extern/audaspace/include/devices/SoftwareDevice.h
index a350550048b..209be9941b1 100644
--- a/extern/audaspace/include/devices/SoftwareDevice.h
+++ b/extern/audaspace/include/devices/SoftwareDevice.h
@@ -255,6 +255,7 @@ protected:
/**
* This function tells the device, to start or pause playback.
* \param playing True if device should playback.
+ * \note This method is only called when the device is locked.
*/
virtual void playing(bool playing)=0;
diff --git a/extern/audaspace/include/devices/ThreadedDevice.h b/extern/audaspace/include/devices/ThreadedDevice.h
new file mode 100644
index 00000000000..36c2e68e36f
--- /dev/null
+++ b/extern/audaspace/include/devices/ThreadedDevice.h
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+/**
+ * @file ThreadedDevice.h
+ * @ingroup plugin
+ * The ThreadedDevice class.
+ */
+
+#include "devices/SoftwareDevice.h"
+
+#include <thread>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This device extends the SoftwareDevice with code for running mixing in a separate thread.
+ */
+class AUD_PLUGIN_API ThreadedDevice : public SoftwareDevice
+{
+private:
+ /**
+ * Whether there is currently playback.
+ */
+ bool m_playing;
+
+ /**
+ * Whether the current playback should stop.
+ */
+ bool m_stop;
+
+ /**
+ * The streaming thread.
+ */
+ std::thread m_thread;
+
+ /**
+ * Starts the streaming thread.
+ */
+ AUD_LOCAL void start();
+
+ /**
+ * Streaming thread main function.
+ */
+ AUD_LOCAL virtual void runMixingThread()=0;
+
+ // delete copy constructor and operator=
+ ThreadedDevice(const ThreadedDevice&) = delete;
+ ThreadedDevice& operator=(const ThreadedDevice&) = delete;
+
+protected:
+ virtual void playing(bool playing);
+
+ /**
+ * Empty default constructor. To setup the device call the function create()
+ * and to uninitialize call destroy().
+ */
+ ThreadedDevice();
+
+ /**
+ * Indicates that the mixing thread should be stopped.
+ * \return Whether the mixing thread should be stopping.
+ * \warning For thread safety, the device needs to be locked, when this method is called.
+ */
+ inline bool shouldStop() { return m_stop; }
+
+ /**
+ * This method needs to be called when the mixing thread is stopping.
+ * \warning For thread safety, the device needs to be locked, when this method is called.
+ */
+ inline void doStop() { m_stop = m_playing = false; }
+
+ /**
+ * Stops all playback and notifies the mixing thread to stop.
+ * \warning The device has to be unlocked to not run into a deadlock.
+ */
+ void stopMixingThread();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
index 0a50d5db2c7..3ffe97661d8 100644
--- a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
@@ -27,9 +27,9 @@ void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data
{
PulseAudioDevice* device = (PulseAudioDevice*)data;
- device->m_state = AUD_pa_context_get_state(context);
+ std::lock_guard<ILockable> lock(*device);
- AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0);
+ device->m_state = AUD_pa_context_get_state(context);
}
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t num_bytes, void *data)
@@ -68,29 +68,40 @@ void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
}
}
-void PulseAudioDevice::playing(bool playing)
+void PulseAudioDevice::runMixingThread()
{
- m_playback = playing;
+ for(;;)
+ {
+ {
+ std::lock_guard<ILockable> lock(*this);
+
+ if(shouldStop())
+ {
+ AUD_pa_stream_cork(m_stream, 1, nullptr, nullptr);
+ doStop();
+ return;
+ }
+ }
+
+ if(AUD_pa_stream_is_corked(m_stream))
+ AUD_pa_stream_cork(m_stream, 0, nullptr, nullptr);
- AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
+ AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
+ }
}
PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
- m_playback(false),
m_state(PA_CONTEXT_UNCONNECTED),
m_buffersize(buffersize),
m_underflows(0)
{
- m_mainloop = AUD_pa_threaded_mainloop_new();
+ m_mainloop = AUD_pa_mainloop_new();
- AUD_pa_threaded_mainloop_lock(m_mainloop);
-
- m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str());
+ m_context = AUD_pa_context_new(AUD_pa_mainloop_get_api(m_mainloop), name.c_str());
if(!m_context)
{
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
}
@@ -99,26 +110,21 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
AUD_pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
- AUD_pa_threaded_mainloop_start(m_mainloop);
-
while(m_state != PA_CONTEXT_READY)
{
switch(m_state)
{
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_stop(m_mainloop);
-
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
break;
default:
- AUD_pa_threaded_mainloop_wait(m_mainloop);
+ AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
break;
}
}
@@ -166,13 +172,10 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
if(!m_stream)
{
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_stop(m_mainloop);
-
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not create PulseAudio stream.");
}
@@ -188,32 +191,27 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
buffer_attr.prebuf = -1U;
buffer_attr.tlength = buffersize;
- if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
+ if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
{
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_stop(m_mainloop);
-
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect PulseAudio stream.");
}
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
-
create();
}
PulseAudioDevice::~PulseAudioDevice()
{
- AUD_pa_threaded_mainloop_stop(m_mainloop);
+ stopMixingThread();
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
destroy();
}
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
index 9efae5128b1..be34cc9032b 100644
--- a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
@@ -26,7 +26,7 @@
* The PulseAudioDevice class.
*/
-#include "devices/SoftwareDevice.h"
+#include "devices/ThreadedDevice.h"
#include <pulse/pulseaudio.h>
@@ -35,15 +35,10 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through PulseAudio, the simple direct media layer.
*/
-class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice
+class AUD_PLUGIN_API PulseAudioDevice : public ThreadedDevice
{
private:
- /**
- * Whether there is currently playback.
- */
- volatile bool m_playback;
-
- pa_threaded_mainloop* m_mainloop;
+ pa_mainloop* m_mainloop;
pa_context* m_context;
pa_stream* m_stream;
pa_context_state_t m_state;
@@ -74,13 +69,15 @@ private:
*/
AUD_LOCAL static void PulseAudio_underflow(pa_stream* stream, void* data);
+ /**
+ * Streaming thread main function.
+ */
+ AUD_LOCAL void runMixingThread();
+
// delete copy constructor and operator=
PulseAudioDevice(const PulseAudioDevice&) = delete;
PulseAudioDevice& operator=(const PulseAudioDevice&) = delete;
-protected:
- virtual void playing(bool playing);
-
public:
/**
* Opens the PulseAudio audio device for playback.
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
index 9cefbc0c7e2..4b9e1ffea2b 100644
--- a/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
@@ -24,18 +24,14 @@ PULSEAUDIO_SYMBOL(pa_context_unref);
PULSEAUDIO_SYMBOL(pa_stream_begin_write);
PULSEAUDIO_SYMBOL(pa_stream_connect_playback);
PULSEAUDIO_SYMBOL(pa_stream_cork);
+PULSEAUDIO_SYMBOL(pa_stream_is_corked);
PULSEAUDIO_SYMBOL(pa_stream_new);
PULSEAUDIO_SYMBOL(pa_stream_set_buffer_attr);
PULSEAUDIO_SYMBOL(pa_stream_set_underflow_callback);
PULSEAUDIO_SYMBOL(pa_stream_set_write_callback);
PULSEAUDIO_SYMBOL(pa_stream_write);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_free);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_get_api);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_lock);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_new);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_signal);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_start);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_stop);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_unlock);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_wait);
+PULSEAUDIO_SYMBOL(pa_mainloop_free);
+PULSEAUDIO_SYMBOL(pa_mainloop_get_api);
+PULSEAUDIO_SYMBOL(pa_mainloop_new);
+PULSEAUDIO_SYMBOL(pa_mainloop_iterate);
diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
index 4f213dc8468..b4632ebb83e 100644
--- a/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
+++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
@@ -31,159 +31,83 @@ template <class T> void SafeRelease(T **ppT)
}
}
-void WASAPIDevice::start()
-{
- lock();
-
- // thread is still running, we can abort stopping it
- if(m_stop)
- m_stop = false;
- // thread is not running, let's start it
- else if(!m_playing)
- {
- if(m_thread.joinable())
- m_thread.join();
-
- m_playing = true;
-
- m_thread = std::thread(&WASAPIDevice::updateStream, this);
- }
-
- unlock();
-}
-
-void WASAPIDevice::updateStream()
+void WASAPIDevice::runMixingThread()
{
UINT32 buffer_size;
+ UINT32 padding;
+ UINT32 length;
data_t* buffer;
- lock();
+ IAudioRenderClient* render_client = nullptr;
- if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
{
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ std::lock_guard<ILockable> lock(*this);
- IAudioRenderClient* render_client = nullptr;
- const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
+ const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
- if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
- {
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
+ goto init_error;
- UINT32 padding;
+ if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
+ goto init_error;
- if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
- {
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
+ goto init_error;
- UINT32 length = buffer_size - padding;
+ length = buffer_size - padding;
- if(FAILED(render_client->GetBuffer(length, &buffer)))
- {
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(render_client->GetBuffer(length, &buffer)))
+ goto init_error;
- mix((data_t*)buffer, length);
+ mix((data_t*)buffer, length);
- if(FAILED(render_client->ReleaseBuffer(length, 0)))
- {
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
+ if(FAILED(render_client->ReleaseBuffer(length, 0)))
+ {
+ init_error:
+ SafeRelease(&render_client);
+ doStop();
+ return;
+ }
}
- unlock();
-
m_audio_client->Start();
auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
for(;;)
{
- lock();
-
- if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ std::lock_guard<ILockable> lock(*this);
- length = buffer_size - padding;
+ if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
+ goto stop_thread;
- if(FAILED(render_client->GetBuffer(length, &buffer)))
- {
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ length = buffer_size - padding;
- mix((data_t*)buffer, length);
+ if(FAILED(render_client->GetBuffer(length, &buffer)))
+ goto stop_thread;
- if(FAILED(render_client->ReleaseBuffer(length, 0)))
- {
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ mix((data_t*)buffer, length);
- // stop thread
- if(m_stop)
- {
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(render_client->ReleaseBuffer(length, 0)))
+ goto stop_thread;
- unlock();
+ // stop thread
+ if(shouldStop())
+ {
+ stop_thread:
+ m_audio_client->Stop();
+ SafeRelease(&render_client);
+ doStop();
+ return;
+ }
+ }
std::this_thread::sleep_for(sleepDuration);
}
}
-void WASAPIDevice::playing(bool playing)
-{
- if((!m_playing || m_stop) && playing)
- start();
- else
- m_stop = true;
-}
-
WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
- m_playing(false),
- m_stop(false),
-
m_imm_device_enumerator(nullptr),
m_imm_device(nullptr),
m_audio_client(nullptr),
@@ -361,14 +285,7 @@ WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
WASAPIDevice::~WASAPIDevice()
{
- lock();
-
- stopAll();
-
- unlock();
-
- if(m_thread.joinable())
- m_thread.join();
+ stopMixingThread();
SafeRelease(&m_audio_client);
SafeRelease(&m_imm_device);
diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.h b/extern/audaspace/plugins/wasapi/WASAPIDevice.h
index ae25a09c432..375f03bd255 100644
--- a/extern/audaspace/plugins/wasapi/WASAPIDevice.h
+++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.h
@@ -26,7 +26,7 @@
* The WASAPIDevice class.
*/
-#include "devices/SoftwareDevice.h"
+#include "devices/ThreadedDevice.h"
#include <thread>
@@ -40,46 +40,23 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through WASAPI, the Windows audio API.
*/
-class AUD_PLUGIN_API WASAPIDevice : public SoftwareDevice
+class AUD_PLUGIN_API WASAPIDevice : public ThreadedDevice
{
private:
- /**
- * Whether there is currently playback.
- */
- bool m_playing;
-
- /**
- * Whether the current playback should stop.
- */
- bool m_stop;
-
IMMDeviceEnumerator* m_imm_device_enumerator;
IMMDevice* m_imm_device;
IAudioClient* m_audio_client;
WAVEFORMATEXTENSIBLE m_wave_format_extensible;
/**
- * The streaming thread.
- */
- std::thread m_thread;
-
- /**
- * Starts the streaming thread.
- */
- AUD_LOCAL void start();
-
- /**
* Streaming thread main function.
*/
- AUD_LOCAL void updateStream();
+ AUD_LOCAL void runMixingThread();
// delete copy constructor and operator=
WASAPIDevice(const WASAPIDevice&) = delete;
WASAPIDevice& operator=(const WASAPIDevice&) = delete;
-protected:
- virtual void playing(bool playing);
-
public:
/**
* Opens the WASAPI audio device for playback.
diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp
index c8c1c6081c2..7a2561515f4 100644
--- a/extern/audaspace/src/devices/SoftwareDevice.cpp
+++ b/extern/audaspace/src/devices/SoftwareDevice.cpp
@@ -737,7 +737,7 @@ void SoftwareDevice::mix(data_t* buffer, int length)
{
m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
- std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ std::lock_guard<ILockable> lock(*this);
{
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound;
@@ -880,7 +880,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<IReader> reader, b
// play sound
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound = std::shared_ptr<SoftwareDevice::SoftwareHandle>(new SoftwareDevice::SoftwareHandle(this, reader, pitch, resampler, mapper, keep));
- std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ std::lock_guard<ILockable> lock(*this);
m_playingSounds.push_back(sound);
@@ -897,7 +897,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<ISound> sound, boo
void SoftwareDevice::stopAll()
{
- std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ std::lock_guard<ILockable> lock(*this);
while(!m_playingSounds.empty())
m_playingSounds.front()->stop();
diff --git a/extern/audaspace/src/devices/ThreadedDevice.cpp b/extern/audaspace/src/devices/ThreadedDevice.cpp
new file mode 100644
index 00000000000..44ceccb8a60
--- /dev/null
+++ b/extern/audaspace/src/devices/ThreadedDevice.cpp
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "devices/ThreadedDevice.h"
+
+#include <mutex>
+
+AUD_NAMESPACE_BEGIN
+
+void ThreadedDevice::start()
+{
+ std::lock_guard<ILockable> lock(*this);
+
+ // thread is still running, we can abort stopping it
+ if(m_stop)
+ m_stop = false;
+
+ // thread is not running, let's start it
+ else if(!m_playing)
+ {
+ if(m_thread.joinable())
+ m_thread.join();
+
+ m_playing = true;
+
+ m_thread = std::thread(&ThreadedDevice::runMixingThread, this);
+ }
+}
+
+void ThreadedDevice::playing(bool playing)
+{
+ if((!m_playing || m_stop) && playing)
+ start();
+ else
+ m_stop = true;
+}
+
+ThreadedDevice::ThreadedDevice() :
+ m_playing(false),
+ m_stop(false)
+{
+}
+
+void aud::ThreadedDevice::stopMixingThread()
+{
+ stopAll();
+
+ if(m_thread.joinable())
+ m_thread.join();
+}
+
+AUD_NAMESPACE_END