mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-17 20:26:30 +01:00
Add AudioBackendThread class to support different thread type on windows
This commit is contained in:
parent
82f0f3a9a7
commit
df363a4fb3
9 changed files with 115 additions and 43 deletions
|
|
@ -399,13 +399,17 @@ class AudioBackend : public PortEngine {
|
||||||
* stacksize. The thread will begin executing @param func, and will exit
|
* stacksize. The thread will begin executing @param func, and will exit
|
||||||
* when that function returns.
|
* when that function returns.
|
||||||
*/
|
*/
|
||||||
virtual int create_process_thread (boost::function<void()> func, AudioBackendNativeThread*, size_t stacksize) = 0;
|
virtual int create_process_thread (boost::function<void()> func, AudioBackendThread*, size_t stacksize) = 0;
|
||||||
|
|
||||||
/** Wait for the thread specified by @param thread to exit.
|
/** Wait for the thread specified by @param thread to exit.
|
||||||
*
|
*
|
||||||
* Return zero on success, non-zero on failure.
|
* Return zero on success, non-zero on failure.
|
||||||
*/
|
*/
|
||||||
virtual int wait_for_process_thread_exit (AudioBackendNativeThread thread) = 0;
|
virtual int join_process_thread (AudioBackendThread* thread) = 0;
|
||||||
|
|
||||||
|
/** Return true if execution context is in a backend thread
|
||||||
|
*/
|
||||||
|
virtual bool in_process_thread () = 0;
|
||||||
|
|
||||||
virtual void update_latencies () = 0;
|
virtual void update_latencies () = 0;
|
||||||
|
|
||||||
|
|
|
||||||
32
libs/ardour/ardour/audio_backend_thread.h
Normal file
32
libs/ardour/ardour/audio_backend_thread.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2013 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
class AudioBackendThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
AudioBackendThread () { }
|
||||||
|
|
||||||
|
virtual ~AudioBackendThread () { }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ARDOUR
|
||||||
|
|
@ -58,6 +58,7 @@ class Session;
|
||||||
class ProcessThread;
|
class ProcessThread;
|
||||||
class AudioBackend;
|
class AudioBackend;
|
||||||
class AudioBackendInfo;
|
class AudioBackendInfo;
|
||||||
|
class AudioBackendThread;
|
||||||
|
|
||||||
class AudioEngine : public SessionHandlePtr, public PortManager
|
class AudioEngine : public SessionHandlePtr, public PortManager
|
||||||
{
|
{
|
||||||
|
|
@ -100,8 +101,12 @@ public:
|
||||||
pframes_t sample_time_at_cycle_start ();
|
pframes_t sample_time_at_cycle_start ();
|
||||||
pframes_t samples_since_cycle_start ();
|
pframes_t samples_since_cycle_start ();
|
||||||
bool get_sync_offset (pframes_t& offset) const;
|
bool get_sync_offset (pframes_t& offset) const;
|
||||||
int create_process_thread (boost::function<void()> func, AudioBackendNativeThread*, size_t stacksize);
|
|
||||||
int wait_for_process_thread_exit (AudioBackendNativeThread);
|
int create_process_thread (boost::function<void()> func, AudioBackendThread*, size_t stacksize);
|
||||||
|
int join_process_thread (AudioBackendThread*);
|
||||||
|
|
||||||
|
bool in_process_thread ();
|
||||||
|
|
||||||
bool is_realtime() const;
|
bool is_realtime() const;
|
||||||
bool connected() const;
|
bool connected() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,6 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "pbd/semutils.h"
|
#include "pbd/semutils.h"
|
||||||
|
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
|
@ -49,6 +47,8 @@ class Route;
|
||||||
class Session;
|
class Session;
|
||||||
class GraphEdges;
|
class GraphEdges;
|
||||||
|
|
||||||
|
class AudioBackendThread;
|
||||||
|
|
||||||
typedef boost::shared_ptr<GraphNode> node_ptr_t;
|
typedef boost::shared_ptr<GraphNode> node_ptr_t;
|
||||||
|
|
||||||
typedef std::list< node_ptr_t > node_list_t;
|
typedef std::list< node_ptr_t > node_list_t;
|
||||||
|
|
@ -93,7 +93,7 @@ protected:
|
||||||
virtual void session_going_away ();
|
virtual void session_going_away ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<AudioBackendNativeThread> _thread_list;
|
std::list<AudioBackendThread*> _thread_list;
|
||||||
volatile bool _quit_threads;
|
volatile bool _quit_threads;
|
||||||
|
|
||||||
void reset_thread_list ();
|
void reset_thread_list ();
|
||||||
|
|
|
||||||
|
|
@ -615,16 +615,6 @@ namespace ARDOUR {
|
||||||
uint32_t max; //< samples
|
uint32_t max; //< samples
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PLATFORM SPECIFIC #ifdef's here */
|
|
||||||
|
|
||||||
/** Define the native thread type used on the platform */
|
|
||||||
typedef pthread_t AudioBackendNativeThread;
|
|
||||||
static inline bool self_thread_equal (AudioBackendNativeThread thr) {
|
|
||||||
return pthread_equal (thr, pthread_self());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PLATFORM SPECIFIC #endif's here */
|
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -826,21 +826,30 @@ AudioEngine::get_sync_offset (pframes_t& offset) const
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
AudioEngine::create_process_thread (boost::function<void()> func, AudioBackendNativeThread* thr, size_t stacksize)
|
AudioEngine::create_process_thread (boost::function<void()> func, AudioBackendThread* thread, size_t stacksize)
|
||||||
{
|
{
|
||||||
if (!_backend) {
|
if (!_backend) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return _backend->create_process_thread (func, thr, stacksize);
|
return _backend->create_process_thread (func, thread, stacksize);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
AudioEngine::wait_for_process_thread_exit (AudioBackendNativeThread thr)
|
AudioEngine::join_process_thread (AudioBackendThread* thr)
|
||||||
{
|
{
|
||||||
if (!_backend) {
|
if (!_backend) {
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
return _backend->wait_for_process_thread_exit (thr);
|
return _backend->join_process_thread (thr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AudioEngine::in_process_thread ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _backend->in_process_thread ();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -101,24 +101,24 @@ Graph::reset_thread_list ()
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::Threads::Mutex::Lock lm (_session.engine().process_lock());
|
Glib::Threads::Mutex::Lock lm (_session.engine().process_lock());
|
||||||
AudioBackendNativeThread a_thread;
|
AudioBackendThread* backend_thread;
|
||||||
|
|
||||||
if (!_thread_list.empty()) {
|
if (!_thread_list.empty()) {
|
||||||
drop_threads ();
|
drop_threads ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), &a_thread, 100000) != 0) {
|
if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), backend_thread, 100000) != 0) {
|
||||||
throw failed_constructor ();
|
throw failed_constructor ();
|
||||||
}
|
}
|
||||||
|
|
||||||
_thread_list.push_back (a_thread);
|
_thread_list.push_back (backend_thread);
|
||||||
|
|
||||||
for (uint32_t i = 1; i < num_threads; ++i) {
|
for (uint32_t i = 1; i < num_threads; ++i) {
|
||||||
if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), &a_thread, 100000) != 0) {
|
if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), backend_thread, 100000) != 0) {
|
||||||
throw failed_constructor ();
|
throw failed_constructor ();
|
||||||
}
|
}
|
||||||
|
|
||||||
_thread_list.push_back (a_thread);
|
_thread_list.push_back (backend_thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,8 +146,8 @@ Graph::drop_threads ()
|
||||||
|
|
||||||
_callback_start_sem.signal ();
|
_callback_start_sem.signal ();
|
||||||
|
|
||||||
for (list<AudioBackendNativeThread>::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) {
|
for (list<AudioBackendThread*>::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) {
|
||||||
AudioEngine::instance()->wait_for_process_thread_exit (*i);
|
AudioEngine::instance()->join_process_thread (*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
_thread_list.clear ();
|
_thread_list.clear ();
|
||||||
|
|
@ -583,10 +583,5 @@ Graph::process_one_route (Route* route)
|
||||||
bool
|
bool
|
||||||
Graph::in_process_thread () const
|
Graph::in_process_thread () const
|
||||||
{
|
{
|
||||||
for (list<AudioBackendNativeThread>::const_iterator i = _thread_list.begin (); i != _thread_list.end(); ++i) {
|
return AudioEngine::instance()->in_process_thread ();
|
||||||
if (self_thread_equal (*i)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include "ardour/audioengine.h"
|
#include "ardour/audioengine.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
#include "ardour/audio_backend_thread.h"
|
||||||
|
|
||||||
#include "jack_audiobackend.h"
|
#include "jack_audiobackend.h"
|
||||||
#include "jack_connection.h"
|
#include "jack_connection.h"
|
||||||
|
|
@ -45,6 +46,17 @@ using namespace PBD;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
|
class JACKAudioBackendThread : public AudioBackendThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
JACKAudioBackendThread (jack_native_thread_t id)
|
||||||
|
: thread_id(id) { }
|
||||||
|
|
||||||
|
jack_native_thread_t thread_id;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; }
|
#define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; }
|
||||||
#define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; }
|
#define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; }
|
||||||
|
|
||||||
|
|
@ -825,25 +837,49 @@ JACKAudioBackend::_latency_callback (jack_latency_callback_mode_t mode, void* ar
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
JACKAudioBackend::create_process_thread (boost::function<void()> f, pthread_t* thread, size_t stacksize)
|
JACKAudioBackend::create_process_thread (boost::function<void()> f, AudioBackendThread* backend_thread, size_t stacksize)
|
||||||
{
|
{
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
|
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
|
||||||
|
|
||||||
|
jack_native_thread_t thread_id;
|
||||||
ThreadData* td = new ThreadData (this, f, stacksize);
|
ThreadData* td = new ThreadData (this, f, stacksize);
|
||||||
|
|
||||||
if (jack_client_create_thread (_priv_jack, thread, jack_client_real_time_priority (_priv_jack),
|
if (jack_client_create_thread (_priv_jack, &thread_id, jack_client_real_time_priority (_priv_jack),
|
||||||
jack_is_realtime (_priv_jack), _start_process_thread, td)) {
|
jack_is_realtime (_priv_jack), _start_process_thread, td)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
backend_thread = new JACKAudioBackendThread(thread_id);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
JACKAudioBackend::wait_for_process_thread_exit (AudioBackendNativeThread thr)
|
JACKAudioBackend::join_process_thread (AudioBackendThread* backend_thread)
|
||||||
{
|
{
|
||||||
|
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
|
||||||
|
|
||||||
|
JACKAudioBackendThread * jack_thread = dynamic_cast<JACKAudioBackendThread*>(backend_thread);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
#if defined(USING_JACK2_EXPANSION_OF_JACK_API) || defined(PLATFORM_WINDOWS)
|
||||||
|
if (jack_client_stop_thread (_priv_jack, jack_thread->thread_id) != 0) {
|
||||||
|
error << "AudioEngine: cannot stop process thread" << endmsg;
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
void* status;
|
void* status;
|
||||||
/* this doesn't actively try to stop the thread, it just waits till it exits */
|
ret = pthread_join (jack_thread->thread_id, &status);
|
||||||
return pthread_join (thr, &status);
|
#endif
|
||||||
|
delete jack_thread;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
JACKAudioBackend::in_process_thread ()
|
||||||
|
{
|
||||||
|
// XXX TODO
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,9 @@ class JACKAudioBackend : public AudioBackend {
|
||||||
|
|
||||||
size_t raw_buffer_size (DataType t);
|
size_t raw_buffer_size (DataType t);
|
||||||
|
|
||||||
int create_process_thread (boost::function<void()> func, AudioBackendNativeThread*, size_t stacksize);
|
int create_process_thread (boost::function<void()> func, AudioBackendThread*, size_t stacksize);
|
||||||
int wait_for_process_thread_exit (AudioBackendNativeThread);
|
int join_process_thread (AudioBackendThread*);
|
||||||
|
bool in_process_thread ();
|
||||||
|
|
||||||
void transport_start ();
|
void transport_start ();
|
||||||
void transport_stop ();
|
void transport_stop ();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue