2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "JackClient.h"
22 #include "JackGraphManager.h"
23 #include "JackClientControl.h"
24 #include "JackEngineControl.h"
25 #include "JackGlobals.h"
26 #include "JackChannel.h"
27 #include "JackTransportEngine.h"
28 #include "driver_interface.h"
29 #include "JackLibGlobals.h"
40 #define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL))
42 JackClient::JackClient():fThread(this)
45 JackClient::JackClient(JackSynchro
* table
):fThread(this)
47 fSynchroTable
= table
;
55 fClientRegistration
= NULL
;
57 fPortRegistration
= NULL
;
64 fGraphOrderArg
= NULL
;
67 fInfoShutdownArg
= NULL
;
69 fBufferSizeArg
= NULL
;
71 fClientRegistrationArg
= NULL
;
72 fPortRegistrationArg
= NULL
;
73 fPortConnectArg
= NULL
;
74 fPortRenameArg
= NULL
;
80 JackClient::~JackClient()
83 int JackClient::Close()
85 jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum
);
89 fChannel
->Stop(); // Channels is stopped first to avoid receiving notifications while closing
91 // Request close only if server is still running
92 if (JackGlobals::fServerRunning
) {
93 fChannel
->ClientClose(GetClientControl()->fRefNum
, &result
);
95 jack_log("JackClient::Close server is shutdown");
99 fSynchroTable
[GetClientControl()->fRefNum
].Disconnect();
100 JackGlobals::fClientTable
[GetClientControl()->fRefNum
] = NULL
;
104 bool JackClient::IsActive()
106 return (GetClientControl()) ? GetClientControl()->fActive
: false;
109 pthread_t
JackClient::GetThreadID()
111 return fThread
.GetThreadID();
115 In "async" mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
116 The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
117 Drivers synchro are setup in "flush" mode if server is "async" and NOT freewheel.
119 void JackClient::SetupDriverSync(bool freewheel
)
121 if (!freewheel
&& !GetEngineControl()->fSyncMode
) {
122 jack_log("JackClient::SetupDriverSync driver sem in flush mode");
123 for (int i
= 0; i
< GetEngineControl()->fDriverNum
; i
++) {
124 fSynchroTable
[i
].SetFlush(true);
127 jack_log("JackClient::SetupDriverSync driver sem in normal mode");
128 for (int i
= 0; i
< GetEngineControl()->fDriverNum
; i
++)
129 fSynchroTable
[i
].SetFlush(false);
134 \brief Notification received from the server.
137 int JackClient::ClientNotifyImp(int refnum
, const char* name
, int notify
, int sync
, const char* message
, int value1
, int value2
)
142 int JackClient::ClientNotify(int refnum
, const char* name
, int notify
, int sync
, const char* message
, int value1
, int value2
)
146 // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient
150 res
= ClientNotifyImp(refnum
, name
, notify
, sync
, message
, value1
, value2
);
154 res
= ClientNotifyImp(refnum
, name
, notify
, sync
, message
, value1
, value2
);
157 case kActivateClient
:
158 jack_log("JackClient::kActivateClient name = %s ref = %ld ", name
, refnum
);
164 The current semantic is that notifications can only be received when the client has been activated,
165 although is this implementation, one could imagine calling notifications as soon as the client has be opened.
172 jack_log("JackClient::kAddClient fName = %s name = %s", GetClientControl()->fName
, name
);
173 if (fClientRegistration
&& strcmp(GetClientControl()->fName
, name
) != 0) { // Don't call the callback for the registering client itself
174 fClientRegistration(name
, 1, fClientRegistrationArg
);
179 jack_log("JackClient::kRemoveClient fName = %s name = %s", GetClientControl()->fName
, name
);
180 if (fClientRegistration
&& strcmp(GetClientControl()->fName
, name
) != 0) { // Don't call the callback for the registering client itself
181 fClientRegistration(name
, 0, fClientRegistrationArg
);
185 case kBufferSizeCallback
:
186 jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", value1
);
188 res
= fBufferSize(value1
, fBufferSizeArg
);
192 case kSampleRateCallback
:
193 jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1
);
195 res
= fSampleRate(value1
, fSampleRateArg
);
199 case kGraphOrderCallback
:
200 jack_log("JackClient::kGraphOrderCallback");
202 res
= fGraphOrder(fGraphOrderArg
);
206 case kStartFreewheelCallback
:
207 jack_log("JackClient::kStartFreewheel");
208 SetupDriverSync(true);
209 fThread
.DropRealTime(); // Always done (JACK server in RT mode or not...)
211 fFreewheel(1, fFreewheelArg
);
215 case kStopFreewheelCallback
:
216 jack_log("JackClient::kStopFreewheel");
217 SetupDriverSync(false);
219 fFreewheel(0, fFreewheelArg
);
221 if (GetEngineControl()->fRealTime
) {
222 fThread
.AcquireRealTime();
226 case kPortRegistrationOnCallback
:
227 jack_log("JackClient::kPortRegistrationOn port_index = %ld", value1
);
228 if (fPortRegistration
) {
229 fPortRegistration(value1
, 1, fPortRegistrationArg
);
233 case kPortRegistrationOffCallback
:
234 jack_log("JackClient::kPortRegistrationOff port_index = %ld ", value1
);
235 if (fPortRegistration
) {
236 fPortRegistration(value1
, 0, fPortRegistrationArg
);
240 case kPortConnectCallback
:
241 jack_log("JackClient::kPortConnectCallback src = %ld dst = %ld", value1
, value2
);
243 fPortConnect(value1
, value2
, 1, fPortConnectArg
);
247 case kPortDisconnectCallback
:
248 jack_log("JackClient::kPortDisconnectCallback src = %ld dst = %ld", value1
, value2
);
250 fPortConnect(value1
, value2
, 0, fPortConnectArg
);
254 case kPortRenameCallback
:
255 jack_log("JackClient::kPortRenameCallback port = %ld");
257 fPortRename(value1
, GetGraphManager()->GetPort(value1
)->GetName(), fPortRenameArg
);
262 jack_log("JackClient::kXRunCallback");
264 res
= fXrun(fXrunArg
);
268 case kShutDownCallback
:
269 jack_log("JackClient::kShutDownCallback");
271 fInfoShutdown((jack_status_t
)value1
, message
, fInfoShutdownArg
);
272 fInfoShutdown
= NULL
;
282 \brief We need to start thread before activating in the server, otherwise the FW driver
283 connected to the client may not be activated.
285 int JackClient::Activate()
287 jack_log("JackClient::Activate");
291 // RT thread is started only when needed...
293 if (StartThread() < 0)
298 Insertion of client in the graph will cause a kGraphOrderCallback notification
299 to be delivered by the server, the client wants to receive it.
301 GetClientControl()->fActive
= true;
303 // Transport related callback become "active"
304 GetClientControl()->fTransportSync
= true;
305 GetClientControl()->fTransportTimebase
= true;
308 GetClientControl()->fCallback
[kRealTimeCallback
] = IsRealTime();
309 fChannel
->ClientActivate(GetClientControl()->fRefNum
, IsRealTime(), &result
);
314 \brief Need to stop thread after deactivating in the server.
316 int JackClient::Deactivate()
318 jack_log("JackClient::Deactivate");
322 GetClientControl()->fActive
= false;
324 // Transport related callback become "unactive"
325 GetClientControl()->fTransportSync
= false;
326 GetClientControl()->fTransportTimebase
= false;
328 // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
330 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
331 jack_log("JackClient::Deactivate res = %ld", result
);
333 // RT thread is stopped only when needed...
339 //----------------------
340 // RT thread management
341 //----------------------
344 \brief Called once when the thread starts.
346 bool JackClient::Init()
349 jack_log("JackClient::Init calling client thread init callback");
355 int JackClient::StartThread()
357 jack_log("JackClient::StartThread : period = %ld computation = %ld constraint = %ld",
358 long(int64_t(GetEngineControl()->fPeriod
) / 1000.0f
),
359 long(int64_t(GetEngineControl()->fComputation
) / 1000.0f
),
360 long(int64_t(GetEngineControl()->fConstraint
) / 1000.0f
));
362 // Will do "something" on OSX only...
363 fThread
.SetParams(GetEngineControl()->fPeriod
, GetEngineControl()->fComputation
, GetEngineControl()->fConstraint
);
365 if (fThread
.StartSync() < 0) {
366 jack_error("Start thread error");
370 if (GetEngineControl()->fRealTime
) {
371 if (fThread
.AcquireRealTime(GetEngineControl()->fClientPriority
) < 0) {
372 jack_error("AcquireRealTime error");
383 bool JackClient::Execute()
385 if (!jack_tls_set(JackGlobals::fRealTime
, this))
386 jack_error("failed to set thread realtime key");
388 if (GetEngineControl()->fRealTime
)
389 set_threaded_log_function();
391 // Execute a dummy cycle to be sure thread has the correct properties
395 fThreadFun(fThreadFunArg
);
402 void JackClient::DummyCycle()
408 inline void JackClient::ExecuteThread()
412 CycleSignalAux(CallProcessCallback());
416 inline jack_nframes_t
JackClient::CycleWaitAux()
419 Error(); // Terminates the thread
420 CallSyncCallbackAux();
421 return GetEngineControl()->fBufferSize
;
424 inline void JackClient::CycleSignalAux(int status
)
427 CallTimebaseCallbackAux();
430 End(); // Terminates the thread
433 jack_nframes_t
JackClient::CycleWait()
435 return CycleWaitAux();
438 void JackClient::CycleSignal(int status
)
440 CycleSignalAux(status
);
443 inline int JackClient::CallProcessCallback()
445 return (fProcess
!= NULL
) ? fProcess(GetEngineControl()->fBufferSize
, fProcessArg
) : 0;
448 inline bool JackClient::WaitSync()
450 // Suspend itself: wait on the input synchro
451 if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable
, 0x7FFFFFFF) < 0) {
452 jack_error("SuspendRefNum error");
459 inline void JackClient::SignalSync()
461 // Resume: signal output clients connected to the running client
462 if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable
) < 0) {
463 jack_error("ResumeRefNum error");
467 inline void JackClient::End()
469 jack_log("JackClient::Execute end name = %s", GetClientControl()->fName
);
470 // Hum... not sure about this, the following "close" code is called in the RT thread...
472 fThread
.DropSelfRealTime();
473 GetClientControl()->fActive
= false;
474 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
478 inline void JackClient::Error()
480 jack_error("JackClient::Execute error name = %s", GetClientControl()->fName
);
481 // Hum... not sure about this, the following "close" code is called in the RT thread...
483 fThread
.DropSelfRealTime();
484 GetClientControl()->fActive
= false;
485 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
494 int JackClient::PortRegister(const char* port_name
, const char* port_type
, unsigned long flags
, unsigned long buffer_size
)
496 // Check if port name is empty
497 string port_name_str
= string(port_name
);
498 if (port_name_str
.size() == 0) {
499 jack_error("port_name is empty");
500 return 0; // Means failure here...
503 // Check port name length
504 string name
= string(GetClientControl()->fName
) + string(":") + port_name_str
;
505 if (name
.size() >= JACK_PORT_NAME_SIZE
) {
506 jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n"
507 "Please use %lu characters or less",
508 GetClientControl()->fName
,
510 JACK_PORT_NAME_SIZE
- 1);
511 return 0; // Means failure here...
515 jack_port_id_t port_index
= NO_PORT
;
516 fChannel
->PortRegister(GetClientControl()->fRefNum
, name
.c_str(), port_type
, flags
, buffer_size
, &port_index
, &result
);
519 jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum
, name
.c_str(), port_type
, port_index
);
520 fPortList
.push_back(port_index
);
527 int JackClient::PortUnRegister(jack_port_id_t port_index
)
529 jack_log("JackClient::PortUnRegister port_index = %ld", port_index
);
530 list
<jack_port_id_t
>::iterator it
= find(fPortList
.begin(), fPortList
.end(), port_index
);
532 if (it
!= fPortList
.end()) {
535 fChannel
->PortUnRegister(GetClientControl()->fRefNum
, port_index
, &result
);
538 jack_error("unregistering a port %ld that is not own by the client", port_index
);
543 int JackClient::PortConnect(const char* src
, const char* dst
)
545 jack_log("JackClient::Connect src = %s dst = %s", src
, dst
);
547 fChannel
->PortConnect(GetClientControl()->fRefNum
, src
, dst
, &result
);
551 int JackClient::PortDisconnect(const char* src
, const char* dst
)
553 jack_log("JackClient::Disconnect src = %s dst = %s", src
, dst
);
555 fChannel
->PortDisconnect(GetClientControl()->fRefNum
, src
, dst
, &result
);
559 int JackClient::PortDisconnect(jack_port_id_t src
)
561 jack_log("JackClient::PortDisconnect src = %ld", src
);
563 fChannel
->PortDisconnect(GetClientControl()->fRefNum
, src
, ALL_PORTS
, &result
);
567 int JackClient::PortIsMine(jack_port_id_t port_index
)
569 JackPort
* port
= GetGraphManager()->GetPort(port_index
);
570 return GetClientControl()->fRefNum
== port
->GetRefNum();
573 int JackClient::PortRename(jack_port_id_t port_index
, const char* name
)
576 fChannel
->PortRename(GetClientControl()->fRefNum
, port_index
, name
, &result
);
580 //--------------------
581 // Context management
582 //--------------------
584 int JackClient::SetBufferSize(jack_nframes_t buffer_size
)
587 fChannel
->SetBufferSize(buffer_size
, &result
);
591 int JackClient::SetFreeWheel(int onoff
)
594 fChannel
->SetFreewheel(onoff
, &result
);
600 - from the RT thread when Execute method fails
601 - possibly from a "closed" notification channel
602 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
605 void JackClient::ShutDown()
607 jack_log("ShutDown");
608 JackGlobals::fServerRunning
= false;
611 fInfoShutdown(JackFailure
, "JACK server has been closed", fInfoShutdownArg
);
612 fInfoShutdown
= NULL
;
613 } else if (fShutdown
) {
614 fShutdown(fShutdownArg
);
619 //----------------------
620 // Transport management
621 //----------------------
623 inline int JackClient::ActivateAux()
625 // If activated without RT thread...
626 if (IsActive() && fThread
.GetStatus() != JackThread::kRunning
) {
628 jack_log("ActivateAux");
630 // RT thread is started
631 if (StartThread() < 0)
635 GetClientControl()->fCallback
[kRealTimeCallback
] = IsRealTime();
636 fChannel
->ClientActivate(GetClientControl()->fRefNum
, IsRealTime(), &result
);
644 int JackClient::ReleaseTimebase()
647 fChannel
->ReleaseTimebase(GetClientControl()->fRefNum
, &result
);
649 GetClientControl()->fTransportTimebase
= false;
656 /* Call the server if the client is active, otherwise keeps the arguments */
657 int JackClient::SetSyncCallback(JackSyncCallback sync_callback
, void* arg
)
659 GetClientControl()->fTransportSync
= (fSync
!= NULL
);
661 fSync
= sync_callback
;
662 return ActivateAux();
665 int JackClient::SetTimebaseCallback(int conditional
, JackTimebaseCallback timebase_callback
, void* arg
)
668 fChannel
->SetTimebaseCallback(GetClientControl()->fRefNum
, conditional
, &result
);
671 GetClientControl()->fTransportTimebase
= true;
672 fTimebase
= timebase_callback
;
674 return ActivateAux();
682 int JackClient::SetSyncTimeout(jack_time_t timeout
)
684 GetEngineControl()->fTransport
.SetSyncTimeout(timeout
);
690 void JackClient::TransportLocate(jack_nframes_t frame
)
694 pos
.valid
= (jack_position_bits_t
)0;
695 jack_log("TransportLocate pos = %ld", pos
.frame
);
696 GetEngineControl()->fTransport
.RequestNewPos(&pos
);
699 int JackClient::TransportReposition(jack_position_t
* pos
)
701 jack_position_t tmp
= *pos
;
702 jack_log("TransportReposition pos = %ld", pos
->frame
);
703 if (tmp
.valid
& ~JACK_POSITION_MASK
) {
706 GetEngineControl()->fTransport
.RequestNewPos(pos
);
711 jack_transport_state_t
JackClient::TransportQuery(jack_position_t
* pos
)
713 return GetEngineControl()->fTransport
.Query(pos
);
716 jack_nframes_t
JackClient::GetCurrentTransportFrame()
718 return GetEngineControl()->fTransport
.GetCurrentFrame();
721 // Must be RT safe: directly write in the transport shared mem
722 void JackClient::TransportStart()
724 GetEngineControl()->fTransport
.SetCommand(TransportCommandStart
);
727 // Must be RT safe: directly write in the transport shared mem
728 void JackClient::TransportStop()
730 GetEngineControl()->fTransport
.SetCommand(TransportCommandStop
);
733 // Never called concurently with the server
734 // TODO check concurrency with SetSyncCallback
736 void JackClient::CallSyncCallback()
738 CallSyncCallbackAux();
741 inline void JackClient::CallSyncCallbackAux()
743 if (GetClientControl()->fTransportSync
) {
745 JackTransportEngine
& transport
= GetEngineControl()->fTransport
;
746 jack_position_t
* cur_pos
= transport
.ReadCurrentState();
747 jack_transport_state_t transport_state
= transport
.GetState();
750 if (fSync(transport_state
, cur_pos
, fSyncArg
)) {
751 GetClientControl()->fTransportState
= JackTransportRolling
;
752 GetClientControl()->fTransportSync
= false;
755 GetClientControl()->fTransportState
= JackTransportRolling
;
756 GetClientControl()->fTransportSync
= false;
761 void JackClient::CallTimebaseCallback()
763 CallTimebaseCallbackAux();
766 inline void JackClient::CallTimebaseCallbackAux()
768 JackTransportEngine
& transport
= GetEngineControl()->fTransport
;
772 transport
.GetTimebaseMaster(master
, unused
);
774 if (GetClientControl()->fRefNum
== master
&& fTimebase
) { // Client *is* timebase...
776 jack_transport_state_t transport_state
= transport
.GetState();
777 jack_position_t
* cur_pos
= transport
.WriteNextStateStart(1);
779 if (GetClientControl()->fTransportTimebase
) {
780 fTimebase(transport_state
, GetEngineControl()->fBufferSize
, cur_pos
, true, fTimebaseArg
);
781 GetClientControl()->fTransportTimebase
= false; // Callback is called only once with "new_pos" = true
782 } else if (transport_state
== JackTransportRolling
) {
783 fTimebase(transport_state
, GetEngineControl()->fBufferSize
, cur_pos
, false, fTimebaseArg
);
786 transport
.WriteNextStateStop(1);
790 //---------------------
791 // Callback management
792 //---------------------
794 void JackClient::OnShutdown(JackShutdownCallback callback
, void *arg
)
797 jack_error("You cannot set callbacks on an active client");
800 fShutdown
= callback
;
804 void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback
, void *arg
)
807 jack_error("You cannot set callbacks on an active client");
809 GetClientControl()->fCallback
[kShutDownCallback
] = (callback
!= NULL
);
810 fInfoShutdownArg
= arg
;
811 fInfoShutdown
= callback
;
815 int JackClient::SetProcessCallback(JackProcessCallback callback
, void *arg
)
818 jack_error("You cannot set callbacks on an active client");
820 } else if (fThreadFun
) {
821 jack_error ("A thread callback has already been setup, both models cannot be used at the same time!");
830 int JackClient::SetXRunCallback(JackXRunCallback callback
, void *arg
)
833 jack_error("You cannot set callbacks on an active client");
836 GetClientControl()->fCallback
[kXRunCallback
] = (callback
!= NULL
);
843 int JackClient::SetInitCallback(JackThreadInitCallback callback
, void *arg
)
846 jack_error("You cannot set callbacks on an active client");
855 int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback
, void *arg
)
857 jack_log("SetGraphOrderCallback ");
860 jack_error("You cannot set callbacks on an active client");
863 GetClientControl()->fCallback
[kGraphOrderCallback
] = (callback
!= NULL
);
864 fGraphOrder
= callback
;
865 fGraphOrderArg
= arg
;
870 int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback
, void *arg
)
873 jack_error("You cannot set callbacks on an active client");
876 GetClientControl()->fCallback
[kBufferSizeCallback
] = (callback
!= NULL
);
877 fBufferSizeArg
= arg
;
878 fBufferSize
= callback
;
883 int JackClient::SetSampleRateCallback(JackSampleRateCallback callback
, void *arg
)
886 jack_error("You cannot set callbacks on an active client");
889 GetClientControl()->fCallback
[kSampleRateCallback
] = (callback
!= NULL
);
890 fSampleRateArg
= arg
;
891 fSampleRate
= callback
;
894 callback(GetEngineControl()->fSampleRate
, arg
);
899 int JackClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback
, void* arg
)
902 jack_error("You cannot set callbacks on an active client");
905 // kAddClient and kRemoveClient notifications must be delivered by the server in any case
906 fClientRegistrationArg
= arg
;
907 fClientRegistration
= callback
;
912 int JackClient::SetFreewheelCallback(JackFreewheelCallback callback
, void *arg
)
915 jack_error("You cannot set callbacks on an active client");
918 GetClientControl()->fCallback
[kStartFreewheelCallback
] = (callback
!= NULL
);
919 GetClientControl()->fCallback
[kStopFreewheelCallback
] = (callback
!= NULL
);
921 fFreewheel
= callback
;
926 int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback
, void *arg
)
929 jack_error("You cannot set callbacks on an active client");
932 GetClientControl()->fCallback
[kPortRegistrationOnCallback
] = (callback
!= NULL
);
933 GetClientControl()->fCallback
[kPortRegistrationOffCallback
] = (callback
!= NULL
);
934 fPortRegistrationArg
= arg
;
935 fPortRegistration
= callback
;
940 int JackClient::SetPortConnectCallback(JackPortConnectCallback callback
, void *arg
)
943 jack_error("You cannot set callbacks on an active client");
946 GetClientControl()->fCallback
[kPortConnectCallback
] = (callback
!= NULL
);
947 GetClientControl()->fCallback
[kPortDisconnectCallback
] = (callback
!= NULL
);
948 fPortConnectArg
= arg
;
949 fPortConnect
= callback
;
954 int JackClient::SetPortRenameCallback(JackPortRenameCallback callback
, void *arg
)
957 jack_error("You cannot set callbacks on an active client");
960 GetClientControl()->fCallback
[kPortRenameCallback
] = (callback
!= NULL
);
961 fPortRenameArg
= arg
;
962 fPortRename
= callback
;
967 int JackClient::SetProcessThread(JackThreadCallback fun
, void *arg
)
970 jack_error("You cannot set callbacks on an active client");
972 } else if (fProcess
) {
973 jack_error ("A process callback has already been setup, both models cannot be used at the same time!");
986 char* JackClient::GetInternalClientName(int ref
)
988 char name_res
[JACK_CLIENT_NAME_SIZE
+ 1];
990 fChannel
->GetInternalClientName(GetClientControl()->fRefNum
, ref
, name_res
, &result
);
991 return (result
< 0) ? NULL
: strdup(name_res
);
994 int JackClient::InternalClientHandle(const char* client_name
, jack_status_t
* status
)
996 int int_ref
, result
= -1;
997 fChannel
->InternalClientHandle(GetClientControl()->fRefNum
, client_name
, (int*)status
, &int_ref
, &result
);
1001 int JackClient::InternalClientLoad(const char* client_name
, jack_options_t options
, jack_status_t
* status
, jack_varargs_t
* va
)
1003 if (strlen(client_name
) >= JACK_CLIENT_NAME_SIZE
) {
1004 jack_error ("\"%s\" is too long for a JACK client name.\n"
1005 "Please use %lu characters or less.",
1006 client_name
, JACK_CLIENT_NAME_SIZE
);
1010 if (va
->load_name
&& (strlen(va
->load_name
) >= JACK_PATH_MAX
)) {
1011 jack_error("\"%s\" is too long for a shared object name.\n"
1012 "Please use %lu characters or less.",
1013 va
->load_name
, PATH_MAX
);
1014 int my_status1
= *status
| (JackFailure
| JackInvalidOption
);
1015 *status
= (jack_status_t
)my_status1
;
1019 if (va
->load_init
&& (strlen(va
->load_init
) >= JACK_LOAD_INIT_LIMIT
)) {
1020 jack_error ("\"%s\" is too long for internal client init "
1021 "string.\nPlease use %lu characters or less.",
1022 va
->load_init
, JACK_LOAD_INIT_LIMIT
);
1023 int my_status1
= *status
| (JackFailure
| JackInvalidOption
);
1024 *status
= (jack_status_t
)my_status1
;
1028 int int_ref
, result
= -1;
1029 fChannel
->InternalClientLoad(GetClientControl()->fRefNum
, client_name
, va
->load_name
, va
->load_init
, options
, (int*)status
, &int_ref
, &result
);
1033 void JackClient::InternalClientUnload(int ref
, jack_status_t
* status
)
1036 fChannel
->InternalClientUnload(GetClientControl()->fRefNum
, ref
, (int*)status
, &result
);
1040 } // end of namespace