git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3529 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
@@ -18,50 +18,71 @@ Fernando Lopez-Lezcano | |||||
Romain Moret | Romain Moret | ||||
Florian Faber | Florian Faber | ||||
Michael Voigt | Michael Voigt | ||||
Torben Hohn | |||||
Torben Hohn | |||||
Paul Davis | Paul Davis | ||||
--------------------------- | --------------------------- | ||||
Jackdmp changes log | Jackdmp changes log | ||||
--------------------------- | |||||
2009-04-08 Stephane Letz <letz@grame.fr> | |||||
--------------------------- | |||||
* Native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver) in progress. | |||||
2009-05-06 Stephane Letz <letz@grame.fr> | |||||
* Fix transport callback (timebase master, sync) issue when used after jack_activate (RT thread was not running). | |||||
2009-04-03 Stephane Letz <letz@grame.fr> | |||||
2009-05-05 Stephane Letz <letz@grame.fr> | |||||
* First working version of native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver). | |||||
* Simplify JackClient RT code, jack_thread_wait API marked deprecated." | |||||
2009-04-22 Stephane Letz <letz@grame.fr> | |||||
* jackctl_server_load_master renamed to jackctl_server_switch_master, jackctl_server_unload_master is removed. | |||||
2009-04-21 Stephane Letz <letz@grame.fr> | |||||
* Add jackctl_server_load_master/jackctl_server_unload_master API. | |||||
2009-04-20 Stephane Letz <letz@grame.fr> | |||||
* In ALSA audio card reservation code, tries to open the card even if reservation fails. | |||||
* Clock source setting on Linux. | |||||
2009-04-08 Stephane Letz <letz@grame.fr> | |||||
* Native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver) in progress. | |||||
2009-04-03 Stephane Letz <letz@grame.fr> | |||||
* Simplify JackClient RT code, jack_thread_wait API marked deprecated." | |||||
2009-03-29 Stephane Letz <letz@grame.fr> | 2009-03-29 Stephane Letz <letz@grame.fr> | ||||
* Cleanup JackInternalClient code. | |||||
* Cleanup JackInternalClient code. | |||||
2009-03-27 Stephane Letz <letz@grame.fr> | 2009-03-27 Stephane Letz <letz@grame.fr> | ||||
* Add a buffer size callback for netmaster that just remove the client (it will be recreated with the new parameters). | |||||
* Add a buffer size callback for netmaster that just remove the client (it will be recreated with the new parameters). | |||||
2009-03-26 Stephane Letz <letz@grame.fr> | 2009-03-26 Stephane Letz <letz@grame.fr> | ||||
* First working JackBoomerDriver two threads version. | |||||
* First working JackBoomerDriver two threads version. | |||||
2009-03-24 Stephane Letz <letz@grame.fr> | 2009-03-24 Stephane Letz <letz@grame.fr> | ||||
* New JackBoomerDriver class for Boomer driver on Solaris. | |||||
* New JackBoomerDriver class for Boomer driver on Solaris. | |||||
* Add mixed 32/64 bits mode (off by default). | * Add mixed 32/64 bits mode (off by default). | ||||
2009-03-23 Stephane Letz <letz@grame.fr> | 2009-03-23 Stephane Letz <letz@grame.fr> | ||||
* Version 1.9.3 started. | * Version 1.9.3 started. | ||||
2009-03-19 Stephane Letz <letz@grame.fr> | 2009-03-19 Stephane Letz <letz@grame.fr> | ||||
* Tim Blechmann optimization patch (inlining some heavy used methods). | * Tim Blechmann optimization patch (inlining some heavy used methods). | ||||
2009-03-12 Stephane Letz <letz@grame.fr> | 2009-03-12 Stephane Letz <letz@grame.fr> | ||||
* Virtualize and allow overriding of thread creation function, to allow Wine support (from JACK1). | * Virtualize and allow overriding of thread creation function, to allow Wine support (from JACK1). | ||||
2009-03-12 Stephane Letz <letz@grame.fr> | 2009-03-12 Stephane Letz <letz@grame.fr> | ||||
* Try automatic adaptative mode in adapters. | * Try automatic adaptative mode in adapters. | ||||
@@ -843,7 +843,7 @@ EXPORT jack_nframes_t jack_thread_wait(jack_client_t* ext_client, int status) | |||||
return 0; | return 0; | ||||
} else { | } else { | ||||
jack_error("jack_thread_wait: deprecated, use jack_cycle_wait/jack_cycle_signal"); | jack_error("jack_thread_wait: deprecated, use jack_cycle_wait/jack_cycle_signal"); | ||||
return -1; | |||||
return 0; | |||||
} | } | ||||
} | } | ||||
@@ -118,14 +118,13 @@ void JackClient::SetupDriverSync(bool freewheel) | |||||
{ | { | ||||
if (!freewheel && !GetEngineControl()->fSyncMode) { | if (!freewheel && !GetEngineControl()->fSyncMode) { | ||||
jack_log("JackClient::SetupDriverSync driver sem in flush mode"); | jack_log("JackClient::SetupDriverSync driver sem in flush mode"); | ||||
fSynchroTable[AUDIO_DRIVER_REFNUM].SetFlush(true); | |||||
fSynchroTable[FREEWHEEL_DRIVER_REFNUM].SetFlush(true); | |||||
fSynchroTable[MIDI_DRIVER_REFNUM].SetFlush(true); | |||||
for (int i = 0; i < GetEngineControl()->fDriverNum; i++) { | |||||
fSynchroTable[i].SetFlush(true); | |||||
} | |||||
} else { | } else { | ||||
jack_log("JackClient::SetupDriverSync driver sem in normal mode"); | jack_log("JackClient::SetupDriverSync driver sem in normal mode"); | ||||
fSynchroTable[AUDIO_DRIVER_REFNUM].SetFlush(false); | |||||
fSynchroTable[FREEWHEEL_DRIVER_REFNUM].SetFlush(false); | |||||
fSynchroTable[MIDI_DRIVER_REFNUM].SetFlush(false); | |||||
for (int i = 0; i < GetEngineControl()->fDriverNum; i++) | |||||
fSynchroTable[i].SetFlush(false); | |||||
} | } | ||||
} | } | ||||
@@ -338,7 +337,7 @@ int JackClient::StartThread() | |||||
// Will do "something" on OSX only... | // Will do "something" on OSX only... | ||||
fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); | fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); | ||||
if (fThread.Start() < 0) { | |||||
if (fThread.StartSync() < 0) { | |||||
jack_error("Start thread error"); | jack_error("Start thread error"); | ||||
return -1; | return -1; | ||||
} | } | ||||
@@ -593,6 +592,27 @@ void JackClient::ShutDown() | |||||
// Transport management | // Transport management | ||||
//---------------------- | //---------------------- | ||||
inline int JackClient::ActivateAux() | |||||
{ | |||||
// If activated without RT thread... | |||||
if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { | |||||
jack_log("ActivateAux"); | |||||
// RT thread is started | |||||
if (StartThread() < 0) | |||||
return -1; | |||||
int result = -1; | |||||
GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); | |||||
fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); | |||||
return result; | |||||
} else { | |||||
return 0; | |||||
} | |||||
} | |||||
int JackClient::ReleaseTimebase() | int JackClient::ReleaseTimebase() | ||||
{ | { | ||||
int result = -1; | int result = -1; | ||||
@@ -611,29 +631,30 @@ int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg) | |||||
GetClientControl()->fTransportSync = (fSync != NULL); | GetClientControl()->fTransportSync = (fSync != NULL); | ||||
fSyncArg = arg; | fSyncArg = arg; | ||||
fSync = sync_callback; | fSync = sync_callback; | ||||
return 0; | |||||
} | |||||
int JackClient::SetSyncTimeout(jack_time_t timeout) | |||||
{ | |||||
GetEngineControl()->fTransport.SetSyncTimeout(timeout); | |||||
return 0; | |||||
return ActivateAux(); | |||||
} | } | ||||
int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) | int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) | ||||
{ | { | ||||
int result = -1; | int result = -1; | ||||
fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | ||||
jack_log("SetTimebaseCallback result = %ld", result); | |||||
if (result == 0) { | if (result == 0) { | ||||
GetClientControl()->fTransportTimebase = true; | GetClientControl()->fTransportTimebase = true; | ||||
fTimebase = timebase_callback; | fTimebase = timebase_callback; | ||||
fTimebaseArg = arg; | fTimebaseArg = arg; | ||||
return ActivateAux(); | |||||
} else { | } else { | ||||
fTimebase = NULL; | fTimebase = NULL; | ||||
fTimebaseArg = NULL; | fTimebaseArg = NULL; | ||||
return -1; | |||||
} | } | ||||
return result; | |||||
} | |||||
int JackClient::SetSyncTimeout(jack_time_t timeout) | |||||
{ | |||||
GetEngineControl()->fTransport.SetSyncTimeout(timeout); | |||||
return 0; | |||||
} | } | ||||
// Must be RT safe | // Must be RT safe | ||||
@@ -108,6 +108,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||||
inline void CycleSignalAux(int status); | inline void CycleSignalAux(int status); | ||||
inline void CallSyncCallbackAux(); | inline void CallSyncCallbackAux(); | ||||
inline void CallTimebaseCallbackAux(); | inline void CallTimebaseCallbackAux(); | ||||
inline int ActivateAux(); | |||||
public: | public: | ||||
@@ -17,11 +17,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
*/ | */ | ||||
#include <iostream> | |||||
#include <assert.h> | |||||
#include "JackConnectionManager.h" | #include "JackConnectionManager.h" | ||||
#include "JackClientControl.h" | #include "JackClientControl.h" | ||||
#include "JackEngineControl.h" | |||||
#include "JackGlobals.h" | |||||
#include "JackError.h" | #include "JackError.h" | ||||
#include <iostream> | |||||
#include <assert.h> | |||||
namespace Jack | namespace Jack | ||||
{ | { | ||||
@@ -54,12 +56,7 @@ bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const | |||||
{ | { | ||||
jack_log("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld", ref1, ref2); | jack_log("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld", ref1, ref2); | ||||
if (ref1 == AUDIO_DRIVER_REFNUM // Driver is reached | |||||
|| ref2 == AUDIO_DRIVER_REFNUM | |||||
|| ref1 == FREEWHEEL_DRIVER_REFNUM | |||||
|| ref2 == FREEWHEEL_DRIVER_REFNUM | |||||
|| ref1 == MIDI_DRIVER_REFNUM | |||||
|| ref2 == MIDI_DRIVER_REFNUM) { | |||||
if (ref1 < GetEngineControl()->fDriverNum || ref2 < GetEngineControl()->fDriverNum) { | |||||
return false; | return false; | ||||
} else if (ref1 == ref2) { // Same refnum | } else if (ref1 == ref2) { // Same refnum | ||||
return true; | return true; | ||||
@@ -49,8 +49,6 @@ | |||||
#define AUDIO_DRIVER_REFNUM 0 // Audio driver is initialized first, it will get the refnum 0 | #define AUDIO_DRIVER_REFNUM 0 // Audio driver is initialized first, it will get the refnum 0 | ||||
#define FREEWHEEL_DRIVER_REFNUM 1 // Freewheel driver is initialized second, it will get the refnum 1 | #define FREEWHEEL_DRIVER_REFNUM 1 // Freewheel driver is initialized second, it will get the refnum 1 | ||||
#define MIDI_DRIVER_REFNUM 2 // Loopback driver is initialized third, it will get the refnum 2 | |||||
#define REAL_REFNUM MIDI_DRIVER_REFNUM + 1 // Real clients start at MIDI_DRIVER_REFNUM + 1 | |||||
#define JACK_DEFAULT_SERVER_NAME "default" | #define JACK_DEFAULT_SERVER_NAME "default" | ||||
@@ -81,6 +81,10 @@ struct jackctl_server | |||||
/* uint32_t, ports of the loopback driver */ | /* uint32_t, ports of the loopback driver */ | ||||
union jackctl_parameter_value loopback_ports; | union jackctl_parameter_value loopback_ports; | ||||
union jackctl_parameter_value default_loopback_ports; | union jackctl_parameter_value default_loopback_ports; | ||||
/* uint32_t, clock source type */ | |||||
union jackctl_parameter_value clock_source; | |||||
union jackctl_parameter_value default_clock_source; | |||||
/* bool */ | /* bool */ | ||||
union jackctl_parameter_value replace_registry; | union jackctl_parameter_value replace_registry; | ||||
@@ -733,6 +737,20 @@ EXPORT jackctl_server_t * jackctl_server_create() | |||||
{ | { | ||||
goto fail_free_parameters; | goto fail_free_parameters; | ||||
} | } | ||||
value.ui = 0; | |||||
if (jackctl_add_parameter( | |||||
&server_ptr->parameters, | |||||
"clock-source", | |||||
"Clocksource type : c(ycle) | h(pet) | s(ystem)", | |||||
"", | |||||
JackParamUInt, | |||||
&server_ptr->clock_source, | |||||
&server_ptr->default_clock_source, | |||||
value) == NULL) | |||||
{ | |||||
goto fail_free_parameters; | |||||
} | |||||
value.b = false; | value.b = false; | ||||
if (jackctl_add_parameter( | if (jackctl_add_parameter( | ||||
@@ -864,6 +882,7 @@ jackctl_server_start( | |||||
server_ptr->realtime_priority.i, | server_ptr->realtime_priority.i, | ||||
server_ptr->loopback_ports.ui, | server_ptr->loopback_ports.ui, | ||||
server_ptr->verbose.b, | server_ptr->verbose.b, | ||||
(jack_timer_type_t)server_ptr->clock_source.ui, | |||||
server_ptr->name.str); | server_ptr->name.str); | ||||
if (server_ptr->engine == NULL) | if (server_ptr->engine == NULL) | ||||
{ | { | ||||
@@ -1163,7 +1182,7 @@ EXPORT bool jackctl_server_unload_internal( | |||||
} | } | ||||
} | } | ||||
EXPORT bool jackctl_server_load_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) | |||||
EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) | |||||
{ | { | ||||
if (server_ptr->engine != NULL) { | if (server_ptr->engine != NULL) { | ||||
driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); | driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); | ||||
@@ -1173,13 +1192,23 @@ EXPORT bool jackctl_server_load_slave(jackctl_server * server_ptr, jackctl_drive | |||||
} | } | ||||
} | } | ||||
EXPORT bool jackctl_server_unload_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) | |||||
EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) | |||||
{ | { | ||||
if (server_ptr->engine != NULL) { | if (server_ptr->engine != NULL) { | ||||
server_ptr->engine->RemoveSlave(driver_ptr->info); | server_ptr->engine->RemoveSlave(driver_ptr->info); | ||||
delete driver_ptr->info; | |||||
return true; | return true; | ||||
} else { | } else { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr) | |||||
{ | |||||
if (server_ptr->engine != NULL) { | |||||
return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0); | |||||
} else { | |||||
return false; | |||||
} | |||||
} | |||||
@@ -220,12 +220,15 @@ EXPORT bool jackctl_server_unload_internal( | |||||
jackctl_server * server, | jackctl_server * server, | ||||
jackctl_internal * internal); | jackctl_internal * internal); | ||||
EXPORT bool jackctl_server_load_slave(jackctl_server_t * server, | |||||
EXPORT bool jackctl_server_add_slave(jackctl_server_t * server, | |||||
jackctl_driver_t * driver); | jackctl_driver_t * driver); | ||||
EXPORT bool jackctl_server_unload_slave(jackctl_server_t * server, | |||||
EXPORT bool jackctl_server_remove_slave(jackctl_server_t * server, | |||||
jackctl_driver_t * driver); | jackctl_driver_t * driver); | ||||
EXPORT bool | |||||
jackctl_server_switch_master(jackctl_server_t * server, | |||||
jackctl_driver_t * driver); | |||||
#if 0 | #if 0 | ||||
{ /* Adjust editor indent */ | { /* Adjust editor indent */ | ||||
@@ -47,7 +47,7 @@ JackDriver::JackDriver(const char* name, const char* alias, JackLockedEngine* en | |||||
fBeginDateUst = 0; | fBeginDateUst = 0; | ||||
fDelayedUsecs = 0.f; | fDelayedUsecs = 0.f; | ||||
fIsMaster = true; | fIsMaster = true; | ||||
} | |||||
} | |||||
JackDriver::JackDriver() | JackDriver::JackDriver() | ||||
{ | { | ||||
@@ -74,6 +74,7 @@ int JackDriver::Open() | |||||
fClientControl.fRefNum = refnum; | fClientControl.fRefNum = refnum; | ||||
fClientControl.fActive = true; | fClientControl.fActive = true; | ||||
fEngineControl->fDriverNum++; | |||||
fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode | fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode | ||||
SetupDriverSync(fClientControl.fRefNum, false); | SetupDriverSync(fClientControl.fRefNum, false); | ||||
return 0; | return 0; | ||||
@@ -100,6 +101,7 @@ int JackDriver::Open (bool capturing, | |||||
fClientControl.fRefNum = refnum; | fClientControl.fRefNum = refnum; | ||||
fClientControl.fActive = true; | fClientControl.fActive = true; | ||||
fEngineControl->fDriverNum++; | |||||
fCaptureLatency = capture_latency; | fCaptureLatency = capture_latency; | ||||
fPlaybackLatency = playback_latency; | fPlaybackLatency = playback_latency; | ||||
@@ -113,7 +115,6 @@ int JackDriver::Open (bool capturing, | |||||
if (!fEngineControl->fTimeOut) | if (!fEngineControl->fTimeOut) | ||||
fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs); | fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs); | ||||
//fGraphManager->SetBufferSize(fEngineControl->fBufferSize); | |||||
fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode | fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode | ||||
SetupDriverSync(fClientControl.fRefNum, false); | SetupDriverSync(fClientControl.fRefNum, false); | ||||
return 0; | return 0; | ||||
@@ -142,6 +143,7 @@ int JackDriver::Open(jack_nframes_t buffer_size, | |||||
fClientControl.fRefNum = refnum; | fClientControl.fRefNum = refnum; | ||||
fClientControl.fActive = true; | fClientControl.fActive = true; | ||||
fEngineControl->fDriverNum++; | |||||
fEngineControl->fBufferSize = buffer_size; | fEngineControl->fBufferSize = buffer_size; | ||||
fEngineControl->fSampleRate = samplerate; | fEngineControl->fSampleRate = samplerate; | ||||
fCaptureLatency = capture_latency; | fCaptureLatency = capture_latency; | ||||
@@ -168,6 +170,7 @@ int JackDriver::Close() | |||||
jack_log("JackDriver::Close"); | jack_log("JackDriver::Close"); | ||||
fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync | fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync | ||||
fClientControl.fActive = false; | fClientControl.fActive = false; | ||||
fEngineControl->fDriverNum--; | |||||
return fEngine->ClientInternalClose(fClientControl.fRefNum, false); | return fEngine->ClientInternalClose(fClientControl.fRefNum, false); | ||||
} | } | ||||
@@ -93,6 +93,7 @@ class SERVER_EXPORT JackDriverInterface | |||||
virtual bool GetMaster() = 0; | virtual bool GetMaster() = 0; | ||||
virtual void AddSlave(JackDriverInterface* slave) = 0; | virtual void AddSlave(JackDriverInterface* slave) = 0; | ||||
virtual void RemoveSlave(JackDriverInterface* slave) = 0; | virtual void RemoveSlave(JackDriverInterface* slave) = 0; | ||||
virtual std::list<JackDriverInterface*> GetSlaves() = 0; | |||||
virtual int ProcessSlaves() = 0; | virtual int ProcessSlaves() = 0; | ||||
virtual bool IsRealTime() const = 0; | virtual bool IsRealTime() const = 0; | ||||
@@ -148,8 +149,13 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||||
void SetMaster(bool onoff); | void SetMaster(bool onoff); | ||||
bool GetMaster(); | bool GetMaster(); | ||||
void AddSlave(JackDriverInterface* slave); | void AddSlave(JackDriverInterface* slave); | ||||
void RemoveSlave(JackDriverInterface* slave); | void RemoveSlave(JackDriverInterface* slave); | ||||
std::list<JackDriverInterface*> GetSlaves() | |||||
{ | |||||
return fSlaveList; | |||||
} | |||||
int ProcessSlaves(); | int ProcessSlaves(); | ||||
virtual int Open(); | virtual int Open(); | ||||
@@ -27,6 +27,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
#include "JackInternalClient.h" | #include "JackInternalClient.h" | ||||
#include "JackEngineControl.h" | #include "JackEngineControl.h" | ||||
#include "JackClientControl.h" | #include "JackClientControl.h" | ||||
#include "JackServerGlobals.h" | |||||
#include "JackGlobals.h" | #include "JackGlobals.h" | ||||
#include "JackChannel.h" | #include "JackChannel.h" | ||||
#include "JackError.h" | #include "JackError.h" | ||||
@@ -71,7 +72,7 @@ int JackEngine::Close() | |||||
fChannel.Close(); | fChannel.Close(); | ||||
// Close remaining clients (RT is stopped) | // Close remaining clients (RT is stopped) | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { | |||||
if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) { | if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) { | ||||
jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName); | jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName); | ||||
loadable_client->Close(); | loadable_client->Close(); | ||||
@@ -110,7 +111,7 @@ void JackEngine::ReleaseRefnum(int ref) | |||||
if (fEngineControl->fTemporary) { | if (fEngineControl->fTemporary) { | ||||
int i; | int i; | ||||
for (i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { | |||||
if (fClientTable[i]) | if (fClientTable[i]) | ||||
break; | break; | ||||
} | } | ||||
@@ -180,7 +181,7 @@ correctly mixed in the time window: callbackUsecs <==> Read <==> Write. | |||||
void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions de fin | void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions de fin | ||||
{ | { | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { | |||||
JackClientInterface* client = fClientTable[i]; | JackClientInterface* client = fClientTable[i]; | ||||
if (client && client->GetClientControl()->fActive) { | if (client && client->GetClientControl()->fActive) { | ||||
JackClientTiming* timing = fGraphManager->GetClientTiming(i); | JackClientTiming* timing = fGraphManager->GetClientTiming(i); | ||||
@@ -236,6 +237,7 @@ void JackEngine::NotifyClients(int event, int sync, int value1, int value2) | |||||
int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum) | int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum) | ||||
{ | { | ||||
jack_log("JackEngine::NotifyAddClient: name = %s", name); | |||||
// Notify existing clients of the new client and new client of existing clients. | // Notify existing clients of the new client and new client of existing clients. | ||||
for (int i = 0; i < CLIENT_NUM; i++) { | for (int i = 0; i < CLIENT_NUM; i++) { | ||||
JackClientInterface* old_client = fClientTable[i]; | JackClientInterface* old_client = fClientTable[i]; | ||||
@@ -44,7 +44,7 @@ void JackEngineControl::CalcCPULoad(JackClientInterface** table, | |||||
// In Asynchronous mode, last cycle end is the max of client end dates | // In Asynchronous mode, last cycle end is the max of client end dates | ||||
if (!fSyncMode) { | if (!fSyncMode) { | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = fDriverNum; i < CLIENT_NUM; i++) { | |||||
JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
JackClientTiming* timing = manager->GetClientTiming(i); | JackClientTiming* timing = manager->GetClientTiming(i); | ||||
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) | if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) | ||||
@@ -63,6 +63,8 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem | |||||
int fMaxClientPriority; | int fMaxClientPriority; | ||||
char fServerName[64]; | char fServerName[64]; | ||||
JackTransportEngine fTransport; | JackTransportEngine fTransport; | ||||
jack_timer_type_t fClockSource; | |||||
int fDriverNum; | |||||
bool fVerbose; | bool fVerbose; | ||||
// CPU Load | // CPU Load | ||||
@@ -88,7 +90,7 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem | |||||
JackEngineProfiling fProfiler; | JackEngineProfiling fProfiler; | ||||
#endif | #endif | ||||
JackEngineControl(bool sync, bool temporary, long timeout, bool rt, long priority, bool verbose, const char* server_name) | |||||
JackEngineControl(bool sync, bool temporary, long timeout, bool rt, long priority, bool verbose, jack_timer_type_t clock, const char* server_name) | |||||
{ | { | ||||
fBufferSize = 512; | fBufferSize = 512; | ||||
fSampleRate = 48000; | fSampleRate = 48000; | ||||
@@ -113,7 +115,9 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem | |||||
fConstraint = 0; | fConstraint = 0; | ||||
fMaxDelayedUsecs = 0.f; | fMaxDelayedUsecs = 0.f; | ||||
fXrunDelayedUsecs = 0.f; | fXrunDelayedUsecs = 0.f; | ||||
} | |||||
fClockSource = clock; | |||||
fDriverNum = 0; | |||||
} | |||||
~JackEngineControl() | ~JackEngineControl() | ||||
{} | {} | ||||
@@ -20,7 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
#include "JackEngineProfiling.h" | #include "JackEngineProfiling.h" | ||||
#include "JackGraphManager.h" | #include "JackGraphManager.h" | ||||
#include "JackClientControl.h" | #include "JackClientControl.h" | ||||
#include "JackEngineControl.h" | |||||
#include "JackClientInterface.h" | #include "JackClientInterface.h" | ||||
#include "JackGlobals.h" | |||||
#include "JackTime.h" | #include "JackTime.h" | ||||
namespace Jack | namespace Jack | ||||
@@ -312,7 +314,7 @@ void JackEngineProfiling::Profile(JackClientInterface** table, | |||||
fProfileTable[fAudioCycle].fPrevCycleEnd = prev_cycle_end; | fProfileTable[fAudioCycle].fPrevCycleEnd = prev_cycle_end; | ||||
fProfileTable[fAudioCycle].fAudioCycle = fAudioCycle; | fProfileTable[fAudioCycle].fAudioCycle = fAudioCycle; | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) { | |||||
JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
JackClientTiming* timing = manager->GetClientTiming(i); | JackClientTiming* timing = manager->GetClientTiming(i); | ||||
if (client && client->GetClientControl()->fActive && client->GetClientControl()->fCallback[kRealTimeCallback]) { | if (client && client->GetClientControl()->fActive && client->GetClientControl()->fCallback[kRealTimeCallback]) { | ||||
@@ -115,6 +115,7 @@ int JackLibClient::Open(const char* server_name, const char* name, jack_options_ | |||||
JackGlobals::fClientTable[GetClientControl()->fRefNum] = this; | JackGlobals::fClientTable[GetClientControl()->fRefNum] = this; | ||||
JackGlobals::fServerRunning = true; | JackGlobals::fServerRunning = true; | ||||
SetClockSource(GetEngineControl()->fClockSource); | |||||
jack_log("JackLibClient::Open name = %s refnum = %ld", name_res, GetClientControl()->fRefNum); | jack_log("JackLibClient::Open name = %s refnum = %ld", name_res, GetClientControl()->fRefNum); | ||||
return 0; | return 0; | ||||
@@ -22,6 +22,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
#include "JackServerGlobals.h" | #include "JackServerGlobals.h" | ||||
#include "JackTime.h" | #include "JackTime.h" | ||||
#include "JackFreewheelDriver.h" | #include "JackFreewheelDriver.h" | ||||
#include "JackLoopbackDriver.h" | |||||
#include "JackDummyDriver.h" | |||||
#include "JackThreadedDriver.h" | #include "JackThreadedDriver.h" | ||||
#include "JackGlobals.h" | #include "JackGlobals.h" | ||||
#include "JackLockedEngine.h" | #include "JackLockedEngine.h" | ||||
@@ -37,7 +39,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
namespace Jack | namespace Jack | ||||
{ | { | ||||
JackServer::JackServer(bool sync, bool temporary, long timeout, bool rt, long priority, long loopback, bool verbose, const char* server_name) | |||||
JackServer::JackServer(bool sync, bool temporary, long timeout, bool rt, long priority, long loopback, bool verbose, jack_timer_type_t clock, const char* server_name) | |||||
{ | { | ||||
if (rt) { | if (rt) { | ||||
jack_info("JACK server starting in realtime mode with priority %ld", priority); | jack_info("JACK server starting in realtime mode with priority %ld", priority); | ||||
@@ -46,11 +48,13 @@ JackServer::JackServer(bool sync, bool temporary, long timeout, bool rt, long pr | |||||
} | } | ||||
fGraphManager = new JackGraphManager(); | fGraphManager = new JackGraphManager(); | ||||
fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, server_name); | |||||
fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); | |||||
fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); | fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); | ||||
fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver(fEngine, GetSynchroTable())); | fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver(fEngine, GetSynchroTable())); | ||||
fDriverInfo = new JackDriverInfo(); | |||||
fAudioDriver = NULL; | fAudioDriver = NULL; | ||||
fFreewheel = false; | fFreewheel = false; | ||||
fLoopback = loopback; | |||||
JackServerGlobals::fInstance = this; // Unique instance | JackServerGlobals::fInstance = this; // Unique instance | ||||
JackServerGlobals::fUserCount = 1; // One user | JackServerGlobals::fUserCount = 1; // One user | ||||
jack_verbose = verbose; | jack_verbose = verbose; | ||||
@@ -60,6 +64,7 @@ JackServer::~JackServer() | |||||
{ | { | ||||
delete fGraphManager; | delete fGraphManager; | ||||
delete fAudioDriver; | delete fAudioDriver; | ||||
delete fDriverInfo; | |||||
delete fFreewheelDriver; | delete fFreewheelDriver; | ||||
delete fEngine; | delete fEngine; | ||||
delete fEngineControl; | delete fEngineControl; | ||||
@@ -80,7 +85,7 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||||
goto fail_close2; | goto fail_close2; | ||||
} | } | ||||
if ((fAudioDriver = fDriverInfo.Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { | |||||
if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { | |||||
jack_error("Cannot initialize driver"); | jack_error("Cannot initialize driver"); | ||||
goto fail_close3; | goto fail_close3; | ||||
} | } | ||||
@@ -89,18 +94,19 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||||
jack_error("Cannot open driver"); | jack_error("Cannot open driver"); | ||||
goto fail_close4; | goto fail_close4; | ||||
} | } | ||||
if (fAudioDriver->Attach() != 0) { | if (fAudioDriver->Attach() != 0) { | ||||
jack_error("Cannot attach audio driver"); | jack_error("Cannot attach audio driver"); | ||||
goto fail_close5; | goto fail_close5; | ||||
} | } | ||||
fFreewheelDriver->SetMaster(false); | fFreewheelDriver->SetMaster(false); | ||||
fAudioDriver->SetMaster(true); | fAudioDriver->SetMaster(true); | ||||
fAudioDriver->AddSlave(fFreewheelDriver); // After ??? | fAudioDriver->AddSlave(fFreewheelDriver); // After ??? | ||||
InitTime(); | InitTime(); | ||||
SetClockSource(fEngineControl->fClockSource); | |||||
return 0; | return 0; | ||||
fail_close5: | fail_close5: | ||||
fFreewheelDriver->Close(); | fFreewheelDriver->Close(); | ||||
@@ -287,23 +293,64 @@ void JackServer::ClientKill(int refnum) | |||||
JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params) | JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params) | ||||
{ | { | ||||
JackDriverInfo* info = new JackDriverInfo(); | JackDriverInfo* info = new JackDriverInfo(); | ||||
JackDriverClientInterface* backend = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); | |||||
if (backend == NULL) { | |||||
JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); | |||||
if (slave == NULL) { | |||||
delete info; | delete info; | ||||
return NULL; | return NULL; | ||||
} else { | } else { | ||||
backend->Attach(); | |||||
fAudioDriver->AddSlave(backend); | |||||
slave->Attach(); | |||||
fAudioDriver->AddSlave(slave); | |||||
return info; | return info; | ||||
} | } | ||||
} | } | ||||
void JackServer::RemoveSlave(JackDriverInfo* info) | void JackServer::RemoveSlave(JackDriverInfo* info) | ||||
{ | { | ||||
JackDriverClientInterface* backend = info->GetBackend(); | |||||
fAudioDriver->RemoveSlave(info->GetBackend()); | |||||
backend->Detach(); | |||||
backend->Close(); | |||||
JackDriverClientInterface* slave = info->GetBackend(); | |||||
fAudioDriver->RemoveSlave(slave); | |||||
slave->Detach(); | |||||
slave->Close(); | |||||
} | |||||
int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||||
{ | |||||
/// Remove current master | |||||
fAudioDriver->Stop(); | |||||
fAudioDriver->Detach(); | |||||
fAudioDriver->Close(); | |||||
// Open new master | |||||
JackDriverInfo* info = new JackDriverInfo(); | |||||
JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); | |||||
if (master == NULL || info == NULL) { | |||||
delete info; | |||||
delete master; | |||||
return -1; | |||||
} else { | |||||
// Get slaves list | |||||
std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves(); | |||||
std::list<JackDriverInterface*>::const_iterator it; | |||||
// Move slaves in new master | |||||
for (it = slave_list.begin(); it != slave_list.end(); it++) { | |||||
JackDriverInterface* slave = *it; | |||||
master->AddSlave(slave); | |||||
} | |||||
// Delete old master | |||||
delete fAudioDriver; | |||||
delete fDriverInfo; | |||||
// Activate master | |||||
fAudioDriver = master; | |||||
fDriverInfo = info; | |||||
fEngineControl->InitFrameTime(); | |||||
fAudioDriver->Attach(); | |||||
fAudioDriver->SetMaster(true); | |||||
return fAudioDriver->Start(); | |||||
} | |||||
} | } | ||||
//---------------------- | //---------------------- | ||||
@@ -47,7 +47,7 @@ class SERVER_EXPORT JackServer | |||||
private: | private: | ||||
JackDriverInfo fDriverInfo; | |||||
JackDriverInfo* fDriverInfo; | |||||
JackDriverClientInterface* fAudioDriver; | JackDriverClientInterface* fAudioDriver; | ||||
JackDriverClientInterface* fFreewheelDriver; | JackDriverClientInterface* fFreewheelDriver; | ||||
JackLockedEngine* fEngine; | JackLockedEngine* fEngine; | ||||
@@ -57,12 +57,13 @@ class SERVER_EXPORT JackServer | |||||
JackConnectionManager fConnectionState; | JackConnectionManager fConnectionState; | ||||
JackSynchro fSynchroTable[CLIENT_NUM]; | JackSynchro fSynchroTable[CLIENT_NUM]; | ||||
bool fFreewheel; | bool fFreewheel; | ||||
long fLoopback; | |||||
int InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int* status); | int InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int* status); | ||||
public: | public: | ||||
JackServer(bool sync, bool temporary, long timeout, bool rt, long priority, long loopback, bool verbose, const char* server_name); | |||||
JackServer(bool sync, bool temporary, long timeout, bool rt, long priority, long loopback, bool verbose, jack_timer_type_t clock, const char* server_name); | |||||
~JackServer(); | ~JackServer(); | ||||
int Open(jack_driver_desc_t* driver_desc, JSList* driver_params); | int Open(jack_driver_desc_t* driver_desc, JSList* driver_params); | ||||
@@ -88,7 +89,8 @@ class SERVER_EXPORT JackServer | |||||
// Backend management | // Backend management | ||||
JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params); | JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params); | ||||
void RemoveSlave(JackDriverInfo* info); | void RemoveSlave(JackDriverInfo* info); | ||||
int SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params); | |||||
// Object access | // Object access | ||||
JackLockedEngine* GetEngine(); | JackLockedEngine* GetEngine(); | ||||
JackEngineControl* GetEngineControl(); | JackEngineControl* GetEngineControl(); | ||||
@@ -40,10 +40,11 @@ int JackServerGlobals::Start(const char* server_name, | |||||
int rt, | int rt, | ||||
int priority, | int priority, | ||||
int loopback, | int loopback, | ||||
int verbose) | |||||
int verbose, | |||||
jack_timer_type_t clock) | |||||
{ | { | ||||
jack_log("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld ", sync, time_out_ms, rt, priority, verbose); | jack_log("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld ", sync, time_out_ms, rt, priority, verbose); | ||||
new JackServer(sync, temporary, time_out_ms, rt, priority, loopback, verbose, server_name); // Will setup fInstance and fUserCount globals | |||||
new JackServer(sync, temporary, time_out_ms, rt, priority, loopback, verbose, clock, server_name); // Will setup fInstance and fUserCount globals | |||||
int res = fInstance->Open(driver_desc, driver_params); | int res = fInstance->Open(driver_desc, driver_params); | ||||
return (res < 0) ? res : fInstance->Start(); | return (res < 0) ? res : fInstance->Start(); | ||||
} | } | ||||
@@ -92,6 +93,7 @@ bool JackServerGlobals::Init() | |||||
char buffer[255]; | char buffer[255]; | ||||
int argc = 0; | int argc = 0; | ||||
char* argv[32]; | char* argv[32]; | ||||
jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; | |||||
// First user starts the server | // First user starts the server | ||||
if (fUserCount++ == 0) { | if (fUserCount++ == 0) { | ||||
@@ -99,8 +101,9 @@ bool JackServerGlobals::Init() | |||||
jack_log("JackServerGlobals Init"); | jack_log("JackServerGlobals Init"); | ||||
jack_driver_desc_t* driver_desc; | jack_driver_desc_t* driver_desc; | ||||
const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:"; | |||||
const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:c:"; | |||||
static struct option long_options[] = { | static struct option long_options[] = { | ||||
{ "clock-source", 1, 0, 'c' }, | |||||
{ "driver", 1, 0, 'd' }, | { "driver", 1, 0, 'd' }, | ||||
{ "verbose", 0, 0, 'v' }, | { "verbose", 0, 0, 'v' }, | ||||
{ "help", 0, 0, 'h' }, | { "help", 0, 0, 'h' }, | ||||
@@ -155,6 +158,18 @@ bool JackServerGlobals::Init() | |||||
(opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { | (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { | ||||
switch (opt) { | switch (opt) { | ||||
case 'c': | |||||
if (tolower (optarg[0]) == 'h') { | |||||
clock_source = JACK_TIMER_HPET; | |||||
} else if (tolower (optarg[0]) == 'c') { | |||||
clock_source = JACK_TIMER_CYCLE_COUNTER; | |||||
} else if (tolower (optarg[0]) == 's') { | |||||
clock_source = JACK_TIMER_SYSTEM_CLOCK; | |||||
} else { | |||||
jack_error("unknown option character %c", optopt); | |||||
} | |||||
break; | |||||
case 'd': | case 'd': | ||||
seen_driver = 1; | seen_driver = 1; | ||||
@@ -281,7 +296,7 @@ bool JackServerGlobals::Init() | |||||
free(argv[i]); | free(argv[i]); | ||||
} | } | ||||
int res = Start(server_name, driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, loopback, verbose_aux); | |||||
int res = Start(server_name, driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, loopback, verbose_aux, clock_source); | |||||
if (res < 0) { | if (res < 0) { | ||||
jack_error("Cannot start server... exit"); | jack_error("Cannot start server... exit"); | ||||
Delete(); | Delete(); | ||||
@@ -22,8 +22,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
#include "driver_interface.h" | #include "driver_interface.h" | ||||
#include "JackDriverLoader.h" | #include "JackDriverLoader.h" | ||||
#include "JackCompilerDeps.h" | |||||
#include "JackServer.h" | #include "JackServer.h" | ||||
#include <assert.h> | |||||
namespace Jack | namespace Jack | ||||
{ | { | ||||
@@ -44,7 +44,7 @@ struct SERVER_EXPORT JackServerGlobals | |||||
static bool Init(); | static bool Init(); | ||||
static void Destroy(); | static void Destroy(); | ||||
static int Start(const char* server_name, | |||||
static int Start (const char* server_name, | |||||
jack_driver_desc_t* driver_desc, | jack_driver_desc_t* driver_desc, | ||||
JSList* driver_params, | JSList* driver_params, | ||||
int sync, | int sync, | ||||
@@ -53,7 +53,8 @@ struct SERVER_EXPORT JackServerGlobals | |||||
int rt, | int rt, | ||||
int priority, | int priority, | ||||
int loopback, | int loopback, | ||||
int verbose); | |||||
int verbose, | |||||
jack_timer_type_t clock); | |||||
static void Stop(); | static void Stop(); | ||||
static void Delete(); | static void Delete(); | ||||
}; | }; | ||||
@@ -132,6 +132,11 @@ int JackThreadedDriver::ProcessSlaves() | |||||
return fDriver->ProcessSlaves(); | return fDriver->ProcessSlaves(); | ||||
} | } | ||||
std::list<JackDriverInterface*> JackThreadedDriver::GetSlaves() | |||||
{ | |||||
return fDriver->GetSlaves(); | |||||
} | |||||
int JackThreadedDriver::ClientNotify(int refnum, const char* name, int notify, int sync, int value1, int value2) | int JackThreadedDriver::ClientNotify(int refnum, const char* name, int notify, int sync, int value1, int value2) | ||||
{ | { | ||||
return fDriver->ClientNotify(refnum, name, notify, sync, value1, value2); | return fDriver->ClientNotify(refnum, name, notify, sync, value1, value2); | ||||
@@ -91,6 +91,7 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi | |||||
virtual bool GetMaster(); | virtual bool GetMaster(); | ||||
virtual void AddSlave(JackDriverInterface* slave); | virtual void AddSlave(JackDriverInterface* slave); | ||||
virtual void RemoveSlave(JackDriverInterface* slave); | virtual void RemoveSlave(JackDriverInterface* slave); | ||||
virtual std::list<JackDriverInterface*> GetSlaves(); | |||||
virtual int ProcessSlaves(); | virtual int ProcessSlaves(); | ||||
virtual int ClientNotify(int refnum, const char* name, int notify, int sync, int value1, int value2); | virtual int ClientNotify(int refnum, const char* name, int notify, int sync, int value1, int value2); | ||||
@@ -23,15 +23,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
#include "types.h" | #include "types.h" | ||||
#include "JackCompilerDeps.h" | #include "JackCompilerDeps.h" | ||||
#include "JackTypes.h" | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
extern "C" | extern "C" | ||||
{ | { | ||||
#endif | #endif | ||||
SERVER_EXPORT void InitTime(); | |||||
SERVER_EXPORT jack_time_t GetMicroSeconds(); | |||||
SERVER_EXPORT void JackSleep(long usec); | |||||
SERVER_EXPORT void InitTime(); | |||||
SERVER_EXPORT jack_time_t GetMicroSeconds(void); | |||||
SERVER_EXPORT void JackSleep(long usec); | |||||
SERVER_EXPORT void SetClockSource(jack_timer_type_t source); | |||||
SERVER_EXPORT const char* ClockSourceName(jack_timer_type_t source); | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||
@@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
#include "JackTransportEngine.h" | #include "JackTransportEngine.h" | ||||
#include "JackClientInterface.h" | #include "JackClientInterface.h" | ||||
#include "JackClientControl.h" | #include "JackClientControl.h" | ||||
#include "JackEngineControl.h" | |||||
#include "JackGlobals.h" | |||||
#include "JackError.h" | #include "JackError.h" | ||||
#include "JackTime.h" | #include "JackTime.h" | ||||
#include <assert.h> | #include <assert.h> | ||||
@@ -89,7 +91,7 @@ int JackTransportEngine::SetTimebaseMaster(int refnum, bool conditionnal) | |||||
// RT | // RT | ||||
bool JackTransportEngine::CheckAllRolling(JackClientInterface** table) | bool JackTransportEngine::CheckAllRolling(JackClientInterface** table) | ||||
{ | { | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) { | |||||
JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
if (client && client->GetClientControl()->fTransportState != JackTransportRolling) { | if (client && client->GetClientControl()->fTransportState != JackTransportRolling) { | ||||
jack_log("CheckAllRolling ref = %ld is not rolling", i); | jack_log("CheckAllRolling ref = %ld is not rolling", i); | ||||
@@ -103,7 +105,7 @@ bool JackTransportEngine::CheckAllRolling(JackClientInterface** table) | |||||
// RT | // RT | ||||
void JackTransportEngine::MakeAllStartingLocating(JackClientInterface** table) | void JackTransportEngine::MakeAllStartingLocating(JackClientInterface** table) | ||||
{ | { | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) { | |||||
JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
if (client) { | if (client) { | ||||
JackClientControl* control = client->GetClientControl(); | JackClientControl* control = client->GetClientControl(); | ||||
@@ -119,7 +121,7 @@ void JackTransportEngine::MakeAllStartingLocating(JackClientInterface** table) | |||||
// RT | // RT | ||||
void JackTransportEngine::MakeAllStopping(JackClientInterface** table) | void JackTransportEngine::MakeAllStopping(JackClientInterface** table) | ||||
{ | { | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) { | |||||
JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
if (client) { | if (client) { | ||||
JackClientControl* control = client->GetClientControl(); | JackClientControl* control = client->GetClientControl(); | ||||
@@ -134,7 +136,7 @@ void JackTransportEngine::MakeAllStopping(JackClientInterface** table) | |||||
// RT | // RT | ||||
void JackTransportEngine::MakeAllLocating(JackClientInterface** table) | void JackTransportEngine::MakeAllLocating(JackClientInterface** table) | ||||
{ | { | ||||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||||
for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) { | |||||
JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
if (client) { | if (client) { | ||||
JackClientControl* control = client->GetClientControl(); | JackClientControl* control = client->GetClientControl(); | ||||
@@ -21,6 +21,8 @@ | |||||
#ifndef __JackTypes__ | #ifndef __JackTypes__ | ||||
#define __JackTypes__ | #define __JackTypes__ | ||||
#include "JackCompilerDeps.h" | |||||
typedef unsigned short UInt16; | typedef unsigned short UInt16; | ||||
#if __LP64__ | #if __LP64__ | ||||
typedef unsigned int UInt32; | typedef unsigned int UInt32; | ||||
@@ -34,8 +36,11 @@ typedef signed long SInt32; | |||||
typedef uint16_t jack_int_t; // Internal type for ports and refnum | typedef uint16_t jack_int_t; // Internal type for ports and refnum | ||||
namespace Jack | |||||
{ | |||||
typedef enum { | |||||
JACK_TIMER_SYSTEM_CLOCK, | |||||
JACK_TIMER_CYCLE_COUNTER, | |||||
JACK_TIMER_HPET, | |||||
} jack_timer_type_t; | |||||
typedef enum { | typedef enum { | ||||
NotTriggered, | NotTriggered, | ||||
@@ -44,6 +49,4 @@ typedef enum { | |||||
Finished, | Finished, | ||||
} jack_client_state_t; | } jack_client_state_t; | ||||
} | |||||
#endif | #endif |
@@ -97,6 +97,9 @@ static void usage(FILE* file) | |||||
" [ --timeout OR -t client-timeout-in-msecs ]\n" | " [ --timeout OR -t client-timeout-in-msecs ]\n" | ||||
" [ --midi OR -X midi-driver ]\n" | " [ --midi OR -X midi-driver ]\n" | ||||
" [ --verbose OR -v ]\n" | " [ --verbose OR -v ]\n" | ||||
#ifdef __linux__ | |||||
" [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" | |||||
#endif | |||||
" [ --replace-registry OR -r ]\n" | " [ --replace-registry OR -r ]\n" | ||||
" [ --silent OR -s ]\n" | " [ --silent OR -s ]\n" | ||||
" [ --sync OR -S ]\n" | " [ --sync OR -S ]\n" | ||||
@@ -156,8 +159,17 @@ int main(int argc, char* argv[]) | |||||
const char* server_name = "default"; | const char* server_name = "default"; | ||||
jackctl_driver_t * audio_driver_ctl; | jackctl_driver_t * audio_driver_ctl; | ||||
jackctl_driver_t * midi_driver_ctl; | jackctl_driver_t * midi_driver_ctl; | ||||
#ifdef __linux__ | |||||
const char *options = "-ad:X:P:uvrshVRL:STFl:t:mn:p:c:"; | |||||
#else | |||||
const char *options = "-ad:X:P:uvrshVRL:STFl:t:mn:p:"; | const char *options = "-ad:X:P:uvrshVRL:STFl:t:mn:p:"; | ||||
#endif | |||||
struct option long_options[] = { | struct option long_options[] = { | ||||
#ifdef __linux__ | |||||
{ "clock-source", 1, 0, 'c' }, | |||||
#endif | |||||
{ "audio-driver", 1, 0, 'd' }, | { "audio-driver", 1, 0, 'd' }, | ||||
{ "midi-driver", 1, 0, 'X' }, | { "midi-driver", 1, 0, 'X' }, | ||||
{ "verbose", 0, 0, 'v' }, | { "verbose", 0, 0, 'v' }, | ||||
@@ -177,6 +189,7 @@ int main(int argc, char* argv[]) | |||||
{ "sync", 0, 0, 'S' }, | { "sync", 0, 0, 'S' }, | ||||
{ 0, 0, 0, 0 } | { 0, 0, 0, 0 } | ||||
}; | }; | ||||
int i,opt = 0; | int i,opt = 0; | ||||
int option_index = 0; | int option_index = 0; | ||||
bool seen_audio_driver = false; | bool seen_audio_driver = false; | ||||
@@ -204,13 +217,33 @@ int main(int argc, char* argv[]) | |||||
} | } | ||||
server_parameters = jackctl_server_get_parameters(server_ctl); | server_parameters = jackctl_server_get_parameters(server_ctl); | ||||
opterr = 0; | opterr = 0; | ||||
while (!seen_audio_driver && | while (!seen_audio_driver && | ||||
(opt = getopt_long(argc, argv, options, | (opt = getopt_long(argc, argv, options, | ||||
long_options, &option_index)) != EOF) { | long_options, &option_index)) != EOF) { | ||||
switch (opt) { | switch (opt) { | ||||
#ifdef __linux__ | |||||
case 'c': | |||||
param = jackctl_get_parameter(server_parameters, "clock-source"); | |||||
if (param != NULL) { | |||||
if (tolower (optarg[0]) == 'h') { | |||||
value.ui = JACK_TIMER_HPET; | |||||
jackctl_parameter_set_value(param, &value); | |||||
} else if (tolower (optarg[0]) == 'c') { | |||||
value.ui = JACK_TIMER_CYCLE_COUNTER; | |||||
jackctl_parameter_set_value(param, &value); | |||||
} else if (tolower (optarg[0]) == 's') { | |||||
value.ui = JACK_TIMER_SYSTEM_CLOCK; | |||||
jackctl_parameter_set_value(param, &value); | |||||
} else { | |||||
usage(stdout); | |||||
goto fail_free; | |||||
} | |||||
} | |||||
break; | |||||
#endif | |||||
case 'd': | case 'd': | ||||
seen_audio_driver = true; | seen_audio_driver = true; | ||||
audio_driver_name = optarg; | audio_driver_name = optarg; | ||||
@@ -382,7 +415,7 @@ int main(int argc, char* argv[]) | |||||
goto fail_free; | goto fail_free; | ||||
} | } | ||||
jackctl_server_load_slave(server_ctl, midi_driver_ctl); | |||||
jackctl_server_add_slave(server_ctl, midi_driver_ctl); | |||||
} | } | ||||
notify_server_start(server_name); | notify_server_start(server_name); | ||||
@@ -510,13 +510,42 @@ jack_log( | |||||
/* @} */ | /* @} */ | ||||
/** | |||||
* Call this function to add a slave in the driver slave list. | |||||
* | |||||
* @param server server object handle | |||||
* @param driver driver to add in the driver slave list. | |||||
* | |||||
* @return success status: true - success, false - fail | |||||
*/ | |||||
bool | |||||
jackctl_server_add_slave(jackctl_server_t * server, | |||||
jackctl_driver_t * driver); | |||||
/** | |||||
* Call this function to remove a slave from the driver slave list. | |||||
* | |||||
* @param server server object handle | |||||
* @param driver driver to remove from the driver slave list. | |||||
* | |||||
* @return success status: true - success, false - fail | |||||
*/ | |||||
bool | bool | ||||
jackctl_server_load_slave(jackctl_server_t * server, | |||||
jackctl_server_remove_slave(jackctl_server_t * server, | |||||
jackctl_driver_t * driver); | jackctl_driver_t * driver); | ||||
/** | |||||
* Call this function to switch master driver. | |||||
* | |||||
* @param server server object handle | |||||
* @param driver driver to switch to | |||||
* | |||||
* @return success status: true - success, false - fail | |||||
*/ | |||||
bool | bool | ||||
jackctl_server_unload_slave(jackctl_server_t * server, | |||||
jackctl_server_switch_master(jackctl_server_t * server, | |||||
jackctl_driver_t * driver); | jackctl_driver_t * driver); | ||||
#if 0 | #if 0 | ||||
{ /* Adjust editor indent */ | { /* Adjust editor indent */ | ||||
@@ -131,6 +131,7 @@ def build(bld): | |||||
'JackNetTool.cpp', | 'JackNetTool.cpp', | ||||
'JackNetInterface.cpp', | 'JackNetInterface.cpp', | ||||
'JackArgParser.cpp', | 'JackArgParser.cpp', | ||||
'JackDummyDriver.cpp', | |||||
] | ] | ||||
if bld.env['IS_LINUX']: | if bld.env['IS_LINUX']: | ||||
@@ -67,7 +67,7 @@ SERVER_EXPORT void* audio_acquire(int num) | |||||
NULL, | NULL, | ||||
&error)) < 0) { | &error)) < 0) { | ||||
jack_error ("Failed to acquire device: %s\n", error.message ? error.message : strerror(-e)); | |||||
jack_error("Failed to acquire device name : %s error : %s", audio_name, (error.message ? error.message : strerror(-e))); | |||||
return NULL; | return NULL; | ||||
} | } | ||||
@@ -89,5 +89,7 @@ SERVER_EXPORT void audio_release(void* dev) | |||||
if (device) { | if (device) { | ||||
jack_info("Release audio card"); | jack_info("Release audio card"); | ||||
rd_release(device); | rd_release(device); | ||||
} else { | |||||
jack_info("No audio card to release..."); | |||||
} | } | ||||
} | } |
@@ -263,6 +263,22 @@ jack_controller_stop_server( | |||||
return TRUE; | return TRUE; | ||||
} | } | ||||
bool | |||||
jack_controller_switch_master( | |||||
struct jack_controller * controller_ptr, | |||||
void *dbus_call_context_ptr) | |||||
{ | |||||
if (!jackctl_server_switch_master( | |||||
controller_ptr->server, | |||||
controller_ptr->driver)) | |||||
{ | |||||
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to switch master"); | |||||
return FALSE; | |||||
} | |||||
return TRUE; | |||||
} | |||||
void * | void * | ||||
jack_controller_create( | jack_controller_create( | ||||
DBusConnection *connection) | DBusConnection *connection) | ||||
@@ -105,6 +105,17 @@ jack_control_run_method( | |||||
jack_controller_control_send_signal_server_stopped(); | jack_controller_control_send_signal_server_stopped(); | ||||
} | } | ||||
} | } | ||||
else if (strcmp (call->method_name, "SwitchMaster") == 0) | |||||
{ | |||||
if (!jack_controller_switch_master(controller_ptr, call)) | |||||
{ | |||||
jack_error ("Failed to switch master"); | |||||
} | |||||
else | |||||
{ | |||||
jack_controller_control_send_signal_server_stopped(); | |||||
} | |||||
} | |||||
else if (strcmp (call->method_name, "GetLoad") == 0) | else if (strcmp (call->method_name, "GetLoad") == 0) | ||||
{ | { | ||||
if (!controller_ptr->started) | if (!controller_ptr->started) | ||||
@@ -252,6 +263,9 @@ JACK_DBUS_METHOD_ARGUMENTS_END | |||||
JACK_DBUS_METHOD_ARGUMENTS_BEGIN(StopServer) | JACK_DBUS_METHOD_ARGUMENTS_BEGIN(StopServer) | ||||
JACK_DBUS_METHOD_ARGUMENTS_END | JACK_DBUS_METHOD_ARGUMENTS_END | ||||
JACK_DBUS_METHOD_ARGUMENTS_BEGIN(SwitchMaster) | |||||
JACK_DBUS_METHOD_ARGUMENTS_END | |||||
JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetLoad) | JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetLoad) | ||||
JACK_DBUS_METHOD_ARGUMENT("load", "d", true) | JACK_DBUS_METHOD_ARGUMENT("load", "d", true) | ||||
JACK_DBUS_METHOD_ARGUMENTS_END | JACK_DBUS_METHOD_ARGUMENTS_END | ||||
@@ -295,6 +309,7 @@ JACK_DBUS_METHODS_BEGIN | |||||
JACK_DBUS_METHOD_DESCRIBE(IsStarted, NULL) | JACK_DBUS_METHOD_DESCRIBE(IsStarted, NULL) | ||||
JACK_DBUS_METHOD_DESCRIBE(StartServer, NULL) | JACK_DBUS_METHOD_DESCRIBE(StartServer, NULL) | ||||
JACK_DBUS_METHOD_DESCRIBE(StopServer, NULL) | JACK_DBUS_METHOD_DESCRIBE(StopServer, NULL) | ||||
JACK_DBUS_METHOD_DESCRIBE(SwitchMaster, NULL) | |||||
JACK_DBUS_METHOD_DESCRIBE(GetLoad, NULL) | JACK_DBUS_METHOD_DESCRIBE(GetLoad, NULL) | ||||
JACK_DBUS_METHOD_DESCRIBE(GetXruns, NULL) | JACK_DBUS_METHOD_DESCRIBE(GetXruns, NULL) | ||||
JACK_DBUS_METHOD_DESCRIBE(GetSampleRate, NULL) | JACK_DBUS_METHOD_DESCRIBE(GetSampleRate, NULL) | ||||
@@ -81,6 +81,11 @@ jack_controller_stop_server( | |||||
struct jack_controller *controller_ptr, | struct jack_controller *controller_ptr, | ||||
void *dbus_call_context_ptr); | void *dbus_call_context_ptr); | ||||
bool | |||||
jack_controller_switch_master( | |||||
struct jack_controller *controller_ptr, | |||||
void *dbus_call_context_ptr); | |||||
bool | bool | ||||
jack_controller_select_driver( | jack_controller_select_driver( | ||||
struct jack_controller *controller_ptr, | struct jack_controller *controller_ptr, | ||||
@@ -109,6 +109,7 @@ def main(): | |||||
print " status - check whether jack server is started, return value is 0 if runing and 1 otherwise" | print " status - check whether jack server is started, return value is 0 if runing and 1 otherwise" | ||||
print " start - start jack server if not currently started" | print " start - start jack server if not currently started" | ||||
print " stop - stop jack server if currenly started" | print " stop - stop jack server if currenly started" | ||||
print " sm - switch master to currently selected driver" | |||||
print " dl - get list of available drivers" | print " dl - get list of available drivers" | ||||
print " dg - get currently selected driver" | print " dg - get currently selected driver" | ||||
print " ds <driver> - select driver" | print " ds <driver> - select driver" | ||||
@@ -155,6 +156,9 @@ def main(): | |||||
elif arg == 'stop': | elif arg == 'stop': | ||||
print "--- stop" | print "--- stop" | ||||
control_iface.StopServer() | control_iface.StopServer() | ||||
elif arg == 'sm': | |||||
print "--- switch master driver" | |||||
control_iface.SwitchMaster() | |||||
elif arg == 'ism': | elif arg == 'ism': | ||||
if control_iface.IsManuallyActivated(): | if control_iface.IsManuallyActivated(): | ||||
print "Manually activated" | print "Manually activated" | ||||
@@ -53,6 +53,24 @@ static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server | |||||
return NULL; | return NULL; | ||||
} | } | ||||
static jackctl_parameter_t * | |||||
jackctl_get_parameter( | |||||
const JSList * parameters_list, | |||||
const char * parameter_name) | |||||
{ | |||||
while (parameters_list) | |||||
{ | |||||
if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) | |||||
{ | |||||
return (jackctl_parameter_t *)parameters_list->data; | |||||
} | |||||
parameters_list = jack_slist_next(parameters_list); | |||||
} | |||||
return NULL; | |||||
} | |||||
static void print_value(union jackctl_parameter_value value, jackctl_param_type_t type) | static void print_value(union jackctl_parameter_value value, jackctl_param_type_t type) | ||||
{ | { | ||||
switch (type) { | switch (type) { | ||||
@@ -152,6 +170,16 @@ int main(int argc, char *argv[]) | |||||
server = jackctl_server_create(); | server = jackctl_server_create(); | ||||
parameters = jackctl_server_get_parameters(server); | parameters = jackctl_server_get_parameters(server); | ||||
/* | |||||
jackctl_parameter_t* param; | |||||
union jackctl_parameter_value value; | |||||
param = jackctl_get_parameter(parameters, "verbose"); | |||||
if (param != NULL) { | |||||
value.b = true; | |||||
jackctl_parameter_set_value(param, &value); | |||||
} | |||||
*/ | |||||
printf("\n========================== \n"); | printf("\n========================== \n"); | ||||
printf("List of server parameters \n"); | printf("List of server parameters \n"); | ||||
printf("========================== \n"); | printf("========================== \n"); | ||||
@@ -182,7 +210,24 @@ int main(int argc, char *argv[]) | |||||
jackctl_server_start(server, jackctl_server_get_driver(server, driver_name)); | jackctl_server_start(server, jackctl_server_get_driver(server, driver_name)); | ||||
jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name)); | jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name)); | ||||
/* | |||||
// Switch master test | |||||
jackctl_driver_t* master; | |||||
usleep(5000000); | |||||
printf("jackctl_server_load_master\n"); | |||||
master = jackctl_server_get_driver(server, "coreaudio"); | |||||
jackctl_server_switch_master(server, master); | |||||
usleep(5000000); | |||||
printf("jackctl_server_load_master\n"); | |||||
master = jackctl_server_get_driver(server, "dummy"); | |||||
jackctl_server_switch_master(server, master); | |||||
*/ | |||||
signals = jackctl_setup_signals(0); | signals = jackctl_setup_signals(0); | ||||
jackctl_wait_signals(signals); | jackctl_wait_signals(signals); | ||||
@@ -18,84 +18,249 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
*/ | */ | ||||
#if defined(HAVE_CONFIG_H) | |||||
#include "config.h" | |||||
#endif | |||||
#include "JackConstants.h" | |||||
#include "JackTime.h" | #include "JackTime.h" | ||||
#include "JackTypes.h" | |||||
#include "JackError.h" | |||||
#include "cycles.h" | |||||
#include <stdint.h> | |||||
#include <stdio.h> | |||||
#include <sys/mman.h> | |||||
#include <sys/time.h> | |||||
#include <sys/types.h> | |||||
#include <sys/stat.h> | |||||
#include <fcntl.h> | |||||
#include <errno.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <stdlib.h> | |||||
SERVER_EXPORT void JackSleep(long usec) | |||||
static jack_time_t __jack_cpu_mhz = 0; | |||||
jack_time_t (*_jack_get_microseconds)(void) = 0; | |||||
#if defined(__gnu_linux__) && (defined(__i386__) || defined(__x86_64__)) | |||||
#define HPET_SUPPORT | |||||
#define HPET_MMAP_SIZE 1024 | |||||
#define HPET_CAPS 0x000 | |||||
#define HPET_PERIOD 0x004 | |||||
#define HPET_COUNTER 0x0f0 | |||||
#define HPET_CAPS_COUNTER_64BIT (1 << 13) | |||||
#if defined(__x86_64__) | |||||
typedef uint64_t hpet_counter_t; | |||||
#else | |||||
typedef uint32_t hpet_counter_t; | |||||
#endif | |||||
static int hpet_fd; | |||||
static unsigned char *hpet_ptr; | |||||
static uint32_t hpet_period; /* period length in femto secs */ | |||||
static uint64_t hpet_offset = 0; | |||||
static uint64_t hpet_wrap; | |||||
static hpet_counter_t hpet_previous = 0; | |||||
#endif /* defined(__gnu_linux__) && (__i386__ || __x86_64__) */ | |||||
#ifdef HPET_SUPPORT | |||||
static int jack_hpet_init () | |||||
{ | { | ||||
usleep(usec); | |||||
uint32_t hpet_caps; | |||||
hpet_fd = open("/dev/hpet", O_RDONLY); | |||||
if (hpet_fd < 0) { | |||||
jack_error ("This system has no accessible HPET device (%s)", strerror (errno)); | |||||
return -1; | |||||
} | |||||
hpet_ptr = (unsigned char *) mmap(NULL, HPET_MMAP_SIZE, | |||||
PROT_READ, MAP_SHARED, hpet_fd, 0); | |||||
if (hpet_ptr == MAP_FAILED) { | |||||
jack_error ("This system has no mappable HPET device (%s)", strerror (errno)); | |||||
close (hpet_fd); | |||||
return -1; | |||||
} | |||||
/* this assumes period to be constant. if needed, | |||||
it can be moved to the clock access function | |||||
*/ | |||||
hpet_period = *((uint32_t *) (hpet_ptr + HPET_PERIOD)); | |||||
hpet_caps = *((uint32_t *) (hpet_ptr + HPET_CAPS)); | |||||
hpet_wrap = ((hpet_caps & HPET_CAPS_COUNTER_64BIT) && | |||||
(sizeof(hpet_counter_t) == sizeof(uint64_t))) ? | |||||
0 : ((uint64_t) 1 << 32); | |||||
return 0; | |||||
} | |||||
static jack_time_t jack_get_microseconds_from_hpet (void) | |||||
{ | |||||
hpet_counter_t hpet_counter; | |||||
long double hpet_time; | |||||
hpet_counter = *((hpet_counter_t *) (hpet_ptr + HPET_COUNTER)); | |||||
if (hpet_counter < hpet_previous) | |||||
hpet_offset += hpet_wrap; | |||||
hpet_previous = hpet_counter; | |||||
hpet_time = (long double) (hpet_offset + hpet_counter) * | |||||
(long double) hpet_period * (long double) 1e-9; | |||||
return ((jack_time_t) (hpet_time + 0.5)); | |||||
} | } | ||||
#ifdef GETCYCLE_TIME | |||||
#else | |||||
static int jack_hpet_init () | |||||
{ | |||||
jack_error ("This version of JACK or this computer does not have HPET support.\n" | |||||
"Please choose a different clock source."); | |||||
return -1; | |||||
} | |||||
static jack_time_t jack_get_microseconds_from_hpet (void) | |||||
{ | |||||
/* never called */ | |||||
return 0; | |||||
} | |||||
#endif /* HPET_SUPPORT */ | |||||
static jack_time_t jack_get_microseconds_from_cycles (void) { | |||||
return get_cycles() / __jack_cpu_mhz; | |||||
} | |||||
#include <stdio.h> | |||||
#include "cycles.h" | |||||
/* | |||||
* This is another kludge. It looks CPU-dependent, but actually it | |||||
* reflects the lack of standards for the Linux kernel formatting of | |||||
* /proc/cpuinfo. | |||||
*/ | |||||
static jack_time_t __jack_cpu_mhz; | |||||
static jack_time_t jack_get_mhz (void) | |||||
{ | |||||
FILE *f = fopen("/proc/cpuinfo", "r"); | |||||
if (f == 0) | |||||
{ | |||||
perror("can't open /proc/cpuinfo\n"); | |||||
exit(1); | |||||
} | |||||
static inline jack_time_t GetMhz(void) | |||||
for ( ; ; ) | |||||
{ | { | ||||
FILE *f = fopen("/proc/cpuinfo", "r"); | |||||
if (f == 0) { | |||||
perror("can't open /proc/cpuinfo\n"); | |||||
jack_time_t mhz; | |||||
int ret; | |||||
char buf[1000]; | |||||
if (fgets(buf, sizeof(buf), f) == NULL) { | |||||
jack_error ("FATAL: cannot locate cpu MHz in " | |||||
"/proc/cpuinfo\n"); | |||||
exit(1); | exit(1); | ||||
} | } | ||||
for (;;) { | |||||
jack_time_t mhz; | |||||
int ret; | |||||
char buf[1000]; | |||||
if (fgets(buf, sizeof(buf), f) == NULL) { | |||||
jack_error("FATAL: cannot locate cpu MHz in /proc/cpuinfo\n"); | |||||
exit(1); | |||||
} | |||||
#if defined(__powerpc__) | |||||
ret = sscanf(buf, "clock\t: %" SCNu64 "MHz", &mhz); | |||||
#elif defined( __i386__ ) || defined (__hppa__) || defined (__ia64__) || \ | |||||
defined(__x86_64__) | |||||
ret = sscanf(buf, "cpu MHz : %" SCNu64, &mhz); | |||||
#elif defined( __sparc__ ) | |||||
ret = sscanf(buf, "Cpu0Bogo : %" SCNu64, &mhz); | |||||
#elif defined( __mc68000__ ) | |||||
ret = sscanf(buf, "Clocking: %" SCNu64, &mhz); | |||||
#elif defined( __s390__ ) | |||||
ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz); | |||||
#else /* MIPS, ARM, alpha */ | |||||
ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz); | |||||
#endif | |||||
if (ret == 1) { | |||||
fclose(f); | |||||
return (jack_time_t)mhz; | |||||
} | |||||
#if defined(__powerpc__) | |||||
ret = sscanf(buf, "clock\t: %" SCNu64 "MHz", &mhz); | |||||
#elif defined( __i386__ ) || defined (__hppa__) || defined (__ia64__) || \ | |||||
defined(__x86_64__) | |||||
ret = sscanf(buf, "cpu MHz : %" SCNu64, &mhz); | |||||
#elif defined( __sparc__ ) | |||||
ret = sscanf(buf, "Cpu0Bogo : %" SCNu64, &mhz); | |||||
#elif defined( __mc68000__ ) | |||||
ret = sscanf(buf, "Clocking: %" SCNu64, &mhz); | |||||
#elif defined( __s390__ ) | |||||
ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz); | |||||
#else /* MIPS, ARM, alpha */ | |||||
ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz); | |||||
#endif | |||||
if (ret == 1) | |||||
{ | |||||
fclose(f); | |||||
return (jack_time_t)mhz; | |||||
} | } | ||||
} | } | ||||
} | |||||
#define HAVE_CLOCK_GETTIME 1 | |||||
#ifndef HAVE_CLOCK_GETTIME | |||||
static jack_time_t jack_get_microseconds_from_system (void) | |||||
{ | |||||
jack_time_t jackTime; | |||||
struct timeval tv; | |||||
gettimeofday (&tv, NULL); | |||||
jackTime = (jack_time_t) tv.tv_sec * 1000000 + (jack_time_t) tv.tv_usec; | |||||
return jackTime; | |||||
} | |||||
SERVER_EXPORT void InitTime() | |||||
{ | |||||
__jack_cpu_mhz = GetMhz(); | |||||
} | |||||
SERVER_EXPORT jack_time_t GetMicroSeconds(void) | |||||
{ | |||||
return get_cycles() / __jack_cpu_mhz; | |||||
} | |||||
#else | #else | ||||
#include <time.h> | |||||
SERVER_EXPORT void InitTime() | |||||
{} | |||||
SERVER_EXPORT jack_time_t GetMicroSeconds(void) | |||||
static jack_time_t jack_get_microseconds_from_system (void) | |||||
{ | |||||
jack_time_t jackTime; | |||||
struct timespec time; | |||||
clock_gettime(CLOCK_MONOTONIC, &time); | |||||
jackTime = (jack_time_t) time.tv_sec * 1e6 + | |||||
(jack_time_t) time.tv_nsec / 1e3; | |||||
return jackTime; | |||||
} | |||||
#endif /* HAVE_CLOCK_GETTIME */ | |||||
SERVER_EXPORT void JackSleep(long usec) | |||||
{ | |||||
usleep(usec); | |||||
} | |||||
SERVER_EXPORT void InitTime() | |||||
{ | |||||
__jack_cpu_mhz = jack_get_mhz (); | |||||
} | |||||
SERVER_EXPORT void SetClockSource(jack_timer_type_t source) | |||||
{ | |||||
jack_log("Clock source : %s", ClockSourceName(source)); | |||||
switch (source) | |||||
{ | { | ||||
struct timespec ts; | |||||
clock_gettime(CLOCK_MONOTONIC, &ts); | |||||
return (jack_time_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; | |||||
case JACK_TIMER_CYCLE_COUNTER: | |||||
_jack_get_microseconds = jack_get_microseconds_from_cycles; | |||||
break; | |||||
case JACK_TIMER_HPET: | |||||
if (jack_hpet_init () == 0) { | |||||
_jack_get_microseconds = jack_get_microseconds_from_hpet; | |||||
} else { | |||||
_jack_get_microseconds = jack_get_microseconds_from_system; | |||||
} | |||||
break; | |||||
case JACK_TIMER_SYSTEM_CLOCK: | |||||
default: | |||||
_jack_get_microseconds = jack_get_microseconds_from_system; | |||||
break; | |||||
} | } | ||||
#endif | |||||
} | |||||
SERVER_EXPORT const char* ClockSourceName(jack_timer_type_t source) | |||||
{ | |||||
switch (source) { | |||||
case JACK_TIMER_CYCLE_COUNTER: | |||||
return "cycle counter"; | |||||
case JACK_TIMER_HPET: | |||||
return "hpet"; | |||||
case JACK_TIMER_SYSTEM_CLOCK: | |||||
#ifdef HAVE_CLOCK_GETTIME | |||||
return "system clock via clock_gettime"; | |||||
#else | |||||
return "system clock via gettimeofday"; | |||||
#endif | |||||
} | |||||
/* what is wrong with gcc ? */ | |||||
return "unknown"; | |||||
} | |||||
SERVER_EXPORT jack_time_t GetMicroSeconds() | |||||
{ | |||||
return _jack_get_microseconds(); | |||||
} |
@@ -51,6 +51,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
#include "audio_reserve.h" | #include "audio_reserve.h" | ||||
//#define DEBUG_WAKEUP 1 | |||||
namespace Jack | namespace Jack | ||||
{ | { | ||||
@@ -1346,6 +1348,9 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||||
/* if POLLIN was the only bit set, we're OK */ | /* if POLLIN was the only bit set, we're OK */ | ||||
*status = 0; | *status = 0; | ||||
if (driver->pfd[nfds-1].revents == POLLIN) { | |||||
jack_error("driver->pfd[nfds-1].revents == POLLIN"); | |||||
} | |||||
return (driver->pfd[nfds-1].revents == POLLIN) ? 0 : -1; | return (driver->pfd[nfds-1].revents == POLLIN) ? 0 : -1; | ||||
} | } | ||||
@@ -2191,21 +2196,18 @@ int JackAlsaDriver::Open(jack_nframes_t nframes, | |||||
if (audio_reservation_init() < 0) { | if (audio_reservation_init() < 0) { | ||||
jack_error("Audio device reservation service not available...."); | jack_error("Audio device reservation service not available...."); | ||||
} else if (strcmp(capture_driver_name, playback_driver_name) == 0) { // Same device for input and output | } else if (strcmp(capture_driver_name, playback_driver_name) == 0) { // Same device for input and output | ||||
fReservedCaptureDevice = audio_acquire(card_to_num(capture_driver_name)); | |||||
if (fReservedCaptureDevice == NULL) { | |||||
jack_error("Error audio device %s not available...", capture_driver_name); | |||||
return -1; | |||||
fReservedCaptureDevice = audio_acquire(card_to_num(capture_driver_name)); | |||||
if (fReservedCaptureDevice == NULL) { | |||||
jack_error("Error audio device %s cannot be acquired, trying to open it anyway...", capture_driver_name); | |||||
} | } | ||||
} else { | } else { | ||||
fReservedCaptureDevice = audio_acquire(card_to_num(capture_driver_name)); | fReservedCaptureDevice = audio_acquire(card_to_num(capture_driver_name)); | ||||
if (fReservedCaptureDevice == NULL) { | if (fReservedCaptureDevice == NULL) { | ||||
jack_error("Error capture audio device %s not available...", capture_driver_name); | |||||
return -1; | |||||
} | |||||
jack_error("Error capture audio device %s cannot be acquired, trying to open it anyway...", capture_driver_name); | |||||
} | |||||
fReservedPlaybackDevice = audio_acquire(card_to_num(playback_driver_name)); | fReservedPlaybackDevice = audio_acquire(card_to_num(playback_driver_name)); | ||||
if (fReservedPlaybackDevice == NULL) { | if (fReservedPlaybackDevice == NULL) { | ||||
jack_error("Error playback audio device %s not available...", playback_driver_name); | |||||
return -1; | |||||
jack_error("Error playback audio device %s cannot be acquired, trying to open it anyway...", playback_driver_name); | |||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
@@ -2277,7 +2279,7 @@ int JackAlsaDriver::Read() | |||||
/* we detected an xrun and restarted: notify | /* we detected an xrun and restarted: notify | ||||
* clients about the delay. | * clients about the delay. | ||||
*/ | */ | ||||
jack_log("ALSA XRun"); | |||||
jack_log("ALSA XRun wait_status = %d", wait_status); | |||||
NotifyXRun(fBeginDateUst, fDelayedUsecs); | NotifyXRun(fBeginDateUst, fDelayedUsecs); | ||||
return -1; | return -1; | ||||
} | } | ||||
@@ -39,6 +39,20 @@ | |||||
#ifdef __linux__ | #ifdef __linux__ | ||||
#ifdef __x86_64__ | |||||
typedef unsigned long cycles_t; | |||||
extern cycles_t cacheflush_time; | |||||
static inline unsigned long get_cycles(void) | |||||
{ | |||||
unsigned int hi, lo; | |||||
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); | |||||
return (((unsigned long)hi)<<32) | ((unsigned long)lo); | |||||
} | |||||
#endif | |||||
#ifdef __PPC__ | #ifdef __PPC__ | ||||
/* PowerPC */ | /* PowerPC */ | ||||
@@ -42,7 +42,7 @@ rpc_type server_rpc_jack_client_check(mach_port_t private_port, client_name_t na | |||||
rpc_type server_rpc_jack_client_open(mach_port_t server_port, client_name_t name, int pid, mach_port_t* private_port, int* shared_engine, int* shared_client, int* shared_graph, int* result) | rpc_type server_rpc_jack_client_open(mach_port_t server_port, client_name_t name, int pid, mach_port_t* private_port, int* shared_engine, int* shared_client, int* shared_graph, int* result) | ||||
{ | { | ||||
jack_log("rpc_jack_client_opne name = %s", name); | |||||
jack_log("rpc_jack_client_open name = %s", name); | |||||
JackMachServerChannel* channel = JackMachServerChannel::fPortTable[server_port]; | JackMachServerChannel* channel = JackMachServerChannel::fPortTable[server_port]; | ||||
assert(channel); | assert(channel); | ||||
channel->ClientOpen((char*)name, pid, private_port, shared_engine, shared_client, shared_graph, result); | channel->ClientOpen((char*)name, pid, private_port, shared_engine, shared_client, shared_graph, result); | ||||
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
#include "JackTime.h" | #include "JackTime.h" | ||||
#include "JackError.h" | #include "JackError.h" | ||||
#include "JackTypes.h" | |||||
#include <mach/mach_time.h> | #include <mach/mach_time.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
@@ -42,3 +43,11 @@ SERVER_EXPORT jack_time_t GetMicroSeconds(void) | |||||
{ | { | ||||
return (jack_time_t) (mach_absolute_time () * __jack_time_ratio); | return (jack_time_t) (mach_absolute_time () * __jack_time_ratio); | ||||
} | } | ||||
SERVER_EXPORT void SetClockSource(jack_timer_type_t source) | |||||
{} | |||||
SERVER_EXPORT const char* ClockSourceName(jack_timer_type_t source) | |||||
{ | |||||
return ""; | |||||
} |
@@ -577,6 +577,8 @@ | |||||
4BF284190F31B4BC00B05BE3 /* JackArgParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF284170F31B4BC00B05BE3 /* JackArgParser.h */; }; | 4BF284190F31B4BC00B05BE3 /* JackArgParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF284170F31B4BC00B05BE3 /* JackArgParser.h */; }; | ||||
4BF2841A0F31B4BC00B05BE3 /* JackArgParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF284160F31B4BC00B05BE3 /* JackArgParser.cpp */; }; | 4BF2841A0F31B4BC00B05BE3 /* JackArgParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF284160F31B4BC00B05BE3 /* JackArgParser.cpp */; }; | ||||
4BF2841B0F31B4BC00B05BE3 /* JackArgParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF284170F31B4BC00B05BE3 /* JackArgParser.h */; }; | 4BF2841B0F31B4BC00B05BE3 /* JackArgParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF284170F31B4BC00B05BE3 /* JackArgParser.h */; }; | ||||
4BF2F4210F9F4DA300B3FFAD /* JackDummyDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3988908B3CF6C00B6F371 /* JackDummyDriver.cpp */; }; | |||||
4BF2F4220F9F4DA700B3FFAD /* JackDummyDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3988908B3CF6C00B6F371 /* JackDummyDriver.cpp */; }; | |||||
4BF339160F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */; }; | 4BF339160F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */; }; | ||||
4BF339170F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF339150F8B86DC0080FB5B /* JackCoreMidiDriver.cpp */; }; | 4BF339170F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF339150F8B86DC0080FB5B /* JackCoreMidiDriver.cpp */; }; | ||||
4BF339180F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */; }; | 4BF339180F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */; }; | ||||
@@ -5475,6 +5477,7 @@ | |||||
4BECB2FB0F4451C10091B70A /* JackProcessSync.cpp in Sources */, | 4BECB2FB0F4451C10091B70A /* JackProcessSync.cpp in Sources */, | ||||
4BF339190F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */, | 4BF339190F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */, | ||||
4BF339210F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */, | 4BF339210F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */, | ||||
4BF2F4220F9F4DA700B3FFAD /* JackDummyDriver.cpp in Sources */, | |||||
); | ); | ||||
runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
}; | }; | ||||
@@ -5855,6 +5858,7 @@ | |||||
4BBAE4110F42FA6100B8BD3F /* JackEngineProfiling.cpp in Sources */, | 4BBAE4110F42FA6100B8BD3F /* JackEngineProfiling.cpp in Sources */, | ||||
4BECB2F50F4451C10091B70A /* JackProcessSync.cpp in Sources */, | 4BECB2F50F4451C10091B70A /* JackProcessSync.cpp in Sources */, | ||||
4BF339230F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */, | 4BF339230F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */, | ||||
4BF2F4210F9F4DA300B3FFAD /* JackDummyDriver.cpp in Sources */, | |||||
); | ); | ||||
runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
}; | }; | ||||
@@ -157,6 +157,14 @@ error: | |||||
return err; | return err; | ||||
} | } | ||||
static CFStringRef GetDeviceName(AudioDeviceID id) | |||||
{ | |||||
UInt32 size = sizeof(CFStringRef); | |||||
CFStringRef UIname; | |||||
OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname); | |||||
return (err == noErr) ? UIname : NULL; | |||||
} | |||||
OSStatus JackCoreAudioDriver::Render(void *inRefCon, | OSStatus JackCoreAudioDriver::Render(void *inRefCon, | ||||
AudioUnitRenderActionFlags *ioActionFlags, | AudioUnitRenderActionFlags *ioActionFlags, | ||||
const AudioTimeStamp *inTimeStamp, | const AudioTimeStamp *inTimeStamp, | ||||
@@ -434,6 +442,136 @@ JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, Ja | |||||
JackCoreAudioDriver::~JackCoreAudioDriver() | JackCoreAudioDriver::~JackCoreAudioDriver() | ||||
{} | {} | ||||
OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, AudioDeviceID* outAggregateDevice) | |||||
{ | |||||
OSStatus osErr = noErr; | |||||
UInt32 outSize; | |||||
Boolean outWritable; | |||||
//----------------------- | |||||
// Start to create a new aggregate by getting the base audio hardware plugin | |||||
//----------------------- | |||||
osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); | |||||
if (osErr != noErr) | |||||
return osErr; | |||||
AudioValueTranslation pluginAVT; | |||||
CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); | |||||
AudioObjectID pluginID; | |||||
pluginAVT.mInputData = &inBundleRef; | |||||
pluginAVT.mInputDataSize = sizeof(inBundleRef); | |||||
pluginAVT.mOutputData = &pluginID; | |||||
pluginAVT.mOutputDataSize = sizeof(pluginID); | |||||
osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); | |||||
if (osErr != noErr) | |||||
return osErr; | |||||
//----------------------- | |||||
// Create a CFDictionary for our aggregate device | |||||
//----------------------- | |||||
CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |||||
CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); | |||||
CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); | |||||
// add the name of the device to the dictionary | |||||
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); | |||||
// add our choice of UID for the aggregate device to the dictionary | |||||
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); | |||||
//------------------------------------------------- | |||||
// Create a CFMutableArray for our sub-device list | |||||
//------------------------------------------------- | |||||
CFStringRef captureDeviceUID = GetDeviceName(captureDeviceID); | |||||
CFStringRef playbackDeviceUID = GetDeviceName(playbackDeviceID); | |||||
if (captureDeviceUID == NULL || playbackDeviceUID == NULL) | |||||
return -1; | |||||
// we need to append the UID for each device to a CFMutableArray, so create one here | |||||
CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |||||
// two sub-devices in this example, so append the sub-device's UID to the CFArray | |||||
CFArrayAppendValue(subDevicesArray, captureDeviceUID); | |||||
CFArrayAppendValue(subDevicesArray, playbackDeviceUID); | |||||
//----------------------------------------------------------------------- | |||||
// Feed the dictionary to the plugin, to create a blank aggregate device | |||||
//----------------------------------------------------------------------- | |||||
AudioObjectPropertyAddress pluginAOPA; | |||||
pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; | |||||
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||||
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||||
UInt32 outDataSize; | |||||
osErr = AudioObjectGetPropertyDataSize(pluginID, &pluginAOPA, 0, NULL, &outDataSize); | |||||
if (osErr != noErr) | |||||
return osErr; | |||||
osErr = AudioObjectGetPropertyData(pluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); | |||||
if (osErr != noErr) | |||||
return osErr; | |||||
// pause for a bit to make sure that everything completed correctly | |||||
// this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created | |||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||||
//------------------------- | |||||
// Set the sub-device list | |||||
//------------------------- | |||||
pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; | |||||
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||||
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||||
outDataSize = sizeof(CFMutableArrayRef); | |||||
osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray); | |||||
if (osErr != noErr) | |||||
return osErr; | |||||
// pause again to give the changes time to take effect | |||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||||
//----------------------- | |||||
// Set the master device | |||||
//----------------------- | |||||
// set the master device manually (this is the device which will act as the master clock for the aggregate device) | |||||
// pass in the UID of the device you want to use | |||||
pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; | |||||
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||||
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||||
outDataSize = sizeof(CFStringRef); | |||||
osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID); // capture is master... | |||||
if (osErr != noErr) | |||||
return osErr; | |||||
// pause again to give the changes time to take effect | |||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||||
//---------- | |||||
// Clean up | |||||
//---------- | |||||
// release the CF objects we have created - we don't need them any more | |||||
CFRelease(aggDeviceDict); | |||||
CFRelease(subDevicesArray); | |||||
// release the device UID | |||||
CFRelease(captureDeviceUID); | |||||
CFRelease(playbackDeviceUID); | |||||
jack_log("New aggregate device %ld", *outAggregateDevice); | |||||
return noErr; | |||||
} | |||||
int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char* playback_driver_uid, char* capture_driver_name, char* playback_driver_name) | int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char* playback_driver_uid, char* capture_driver_name, char* playback_driver_name) | ||||
{ | { | ||||
capture_driver_name[0] = 0; | capture_driver_name[0] = 0; | ||||
@@ -442,16 +580,42 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char | |||||
// Duplex | // Duplex | ||||
if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { | if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { | ||||
jack_log("JackCoreAudioDriver::Open duplex"); | jack_log("JackCoreAudioDriver::Open duplex"); | ||||
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { | |||||
jack_log("Will take default in/out"); | |||||
if (GetDefaultDevice(&fDeviceID) != noErr) { | |||||
jack_error("Cannot open default device"); | |||||
/* | |||||
AudioDeviceID captureID, playbackID; | |||||
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) | |||||
return -1; | |||||
if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) | |||||
return -1; | |||||
if (CreateAggregateDevice(captureID, playbackID, &fDeviceID) != noErr) | |||||
return -1; | |||||
*/ | |||||
// Same device for capture and playback... | |||||
if (strcmp(capture_driver_uid, playback_driver_uid) == 0) { | |||||
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { | |||||
jack_log("Will take default in/out"); | |||||
if (GetDefaultDevice(&fDeviceID) != noErr) { | |||||
jack_error("Cannot open default device"); | |||||
return -1; | |||||
} | |||||
} | |||||
if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) { | |||||
jack_error("Cannot get device name from device ID"); | |||||
return -1; | return -1; | ||||
} | } | ||||
} | |||||
if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) { | |||||
jack_error("Cannot get device name from device ID"); | |||||
return -1; | |||||
} else { | |||||
// Creates agregate device | |||||
AudioDeviceID captureID, playbackID; | |||||
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) | |||||
return -1; | |||||
if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) | |||||
return -1; | |||||
if (CreateAggregateDevice(captureID, playbackID, &fDeviceID) != noErr) | |||||
return -1; | |||||
} | } | ||||
// Capture only | // Capture only | ||||
@@ -115,6 +115,7 @@ class JackCoreAudioDriver : public JackAudioDriver | |||||
OSStatus GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput); | OSStatus GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput); | ||||
// Setup | // Setup | ||||
OSStatus CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, AudioDeviceID* outAggregateDevice); | |||||
int SetupDevices(const char* capture_driver_uid, | int SetupDevices(const char* capture_driver_uid, | ||||
const char* playback_driver_uid, | const char* playback_driver_uid, | ||||
char* capture_driver_name, | char* capture_driver_name, | ||||
@@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
*/ | */ | ||||
#include "JackTime.h" | #include "JackTime.h" | ||||
#include "JackTypes.h" | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <time.h> | #include <time.h> | ||||
@@ -35,3 +36,10 @@ SERVER_EXPORT jack_time_t GetMicroSeconds(void) | |||||
return (jack_time_t)(gethrtime() / 1000); | return (jack_time_t)(gethrtime() / 1000); | ||||
} | } | ||||
SERVER_EXPORT void SetClockSource(jack_timer_type_t source) | |||||
{} | |||||
SERVER_EXPORT const char* ClockSourceName(jack_timer_type_t source) | |||||
{ | |||||
return ""; | |||||
} |
@@ -20,12 +20,12 @@ | |||||
#ifndef __JackTypes_WIN32__ | #ifndef __JackTypes_WIN32__ | ||||
#define __JackTypes_WIN32__ | #define __JackTypes_WIN32__ | ||||
#include <windows.h> | |||||
#include <windows.h> | |||||
#include "types.h" | |||||
typedef ULONGLONG UInt64; | typedef ULONGLONG UInt64; | ||||
typedef unsigned short uint16_t; | typedef unsigned short uint16_t; | ||||
typedef DWORD jack_tls_key; | |||||
typedef HANDLE pthread_t; | |||||
typedef DWORD jack_tls_key; | |||||
#endif | #endif | ||||
@@ -119,7 +119,7 @@ JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient() | |||||
fOverlap.hEvent = CreateEvent(NULL, // default security attribute | fOverlap.hEvent = CreateEvent(NULL, // default security attribute | ||||
TRUE, // manual-reset event | TRUE, // manual-reset event | ||||
TRUE, // initial state = signaled | TRUE, // initial state = signaled | ||||
NULL); // unnamed event object | |||||
NULL); // unnamed event object | |||||
} | } | ||||
JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, bool pending) | JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, bool pending) | ||||
@@ -13,18 +13,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
You should have received a copy of the GNU Lesser General Public License | You should have received a copy of the GNU Lesser General Public License | ||||
along with this program; if not, write to the Free Software | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
*/ | */ | ||||
#include <windows.h> | |||||
#include "JackTime.h" | #include "JackTime.h" | ||||
#include "JackError.h" | |||||
static LARGE_INTEGER _jack_freq; | static LARGE_INTEGER _jack_freq; | ||||
SERVER_EXPORT void JackSleep(long usec) | |||||
SERVER_EXPORT void JackSleep(long usec) | |||||
{ | { | ||||
Sleep(usec / 1000); | Sleep(usec / 1000); | ||||
} | } | ||||
@@ -35,9 +33,17 @@ SERVER_EXPORT void InitTime() | |||||
_jack_freq.QuadPart = _jack_freq.QuadPart / 1000000; // by usec | _jack_freq.QuadPart = _jack_freq.QuadPart / 1000000; // by usec | ||||
} | } | ||||
SERVER_EXPORT jack_time_t GetMicroSeconds(void) | |||||
SERVER_EXPORT jack_time_t GetMicroSeconds(void) | |||||
{ | { | ||||
LARGE_INTEGER t1; | LARGE_INTEGER t1; | ||||
QueryPerformanceCounter(&t1); | QueryPerformanceCounter(&t1); | ||||
return (jack_time_t)(((double)t1.QuadPart) / ((double)_jack_freq.QuadPart)); | |||||
return (jack_time_t)(((double)t1.QuadPart) / ((double)_jack_freq.QuadPart)); | |||||
} | |||||
SERVER_EXPORT void SetClockSource(jack_timer_type_t source) | |||||
{} | |||||
SERVER_EXPORT const char* ClockSourceName(jack_timer_type_t source) | |||||
{ | |||||
return ""; | |||||
} | } |
@@ -1,7 +1,7 @@ | |||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> | <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> | ||||
<CodeBlocks_workspace_file> | <CodeBlocks_workspace_file> | ||||
<Workspace title="jack"> | <Workspace title="jack"> | ||||
<Project filename="libjackserver.cbp" /> | |||||
<Project filename="libjackserver.cbp" active="1" /> | |||||
<Project filename="jackd.cbp"> | <Project filename="jackd.cbp"> | ||||
<Depends filename="libjackserver.cbp" /> | <Depends filename="libjackserver.cbp" /> | ||||
</Project> | </Project> | ||||
@@ -46,6 +46,6 @@ | |||||
<Project filename="multiple_metro.cbp"> | <Project filename="multiple_metro.cbp"> | ||||
<Depends filename="libjack.cbp" /> | <Depends filename="libjack.cbp" /> | ||||
</Project> | </Project> | ||||
<Project filename="jack_winmme.cbp" active="1" /> | |||||
<Project filename="jack_winmme.cbp" /> | |||||
</Workspace> | </Workspace> | ||||
</CodeBlocks_workspace_file> | </CodeBlocks_workspace_file> |