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", value1
);
257 fPortRename(value1
, message
, 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
;
276 case kSessionCallback
:
277 jack_log("JackClient::kSessionCallback");
279 jack_session_event_t
*event
= (jack_session_event_t
*) malloc( sizeof(jack_session_event_t
) );
280 char uuid_buf
[JACK_UUID_SIZE
];
281 event
->type
= (jack_session_event_type_t
) value1
;
282 event
->session_dir
= strdup( message
);
283 event
->command_line
= NULL
;
284 event
->flags
= (jack_session_flags_t
) 0;
285 snprintf( uuid_buf
, sizeof(uuid_buf
), "%d", GetClientControl()->fSessionID
);
286 event
->client_uuid
= strdup( uuid_buf
);
287 fImmediateSessionReply
= false;
288 fSession(event
, fSessionArg
);
289 res
= (fImmediateSessionReply
) ? 1 : 2;
299 \brief We need to start thread before activating in the server, otherwise the FW driver
300 connected to the client may not be activated.
302 int JackClient::Activate()
304 jack_log("JackClient::Activate");
308 // RT thread is started only when needed...
310 if (StartThread() < 0)
315 Insertion of client in the graph will cause a kGraphOrderCallback notification
316 to be delivered by the server, the client wants to receive it.
318 GetClientControl()->fActive
= true;
320 // Transport related callback become "active"
321 GetClientControl()->fTransportSync
= true;
322 GetClientControl()->fTransportTimebase
= true;
325 GetClientControl()->fCallback
[kRealTimeCallback
] = IsRealTime();
326 fChannel
->ClientActivate(GetClientControl()->fRefNum
, IsRealTime(), &result
);
331 \brief Need to stop thread after deactivating in the server.
333 int JackClient::Deactivate()
335 jack_log("JackClient::Deactivate");
339 GetClientControl()->fActive
= false;
341 // Transport related callback become "unactive"
342 GetClientControl()->fTransportSync
= false;
343 GetClientControl()->fTransportTimebase
= false;
345 // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
347 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
348 jack_log("JackClient::Deactivate res = %ld", result
);
350 // RT thread is stopped only when needed...
356 //----------------------
357 // RT thread management
358 //----------------------
361 \brief Called once when the thread starts.
363 bool JackClient::Init()
366 jack_log("JackClient::Init calling client thread init callback");
372 int JackClient::StartThread()
374 jack_log("JackClient::StartThread : period = %ld computation = %ld constraint = %ld",
375 long(int64_t(GetEngineControl()->fPeriod
) / 1000.0f
),
376 long(int64_t(GetEngineControl()->fComputation
) / 1000.0f
),
377 long(int64_t(GetEngineControl()->fConstraint
) / 1000.0f
));
379 // Will do "something" on OSX only...
380 fThread
.SetParams(GetEngineControl()->fPeriod
, GetEngineControl()->fComputation
, GetEngineControl()->fConstraint
);
382 if (fThread
.StartSync() < 0) {
383 jack_error("Start thread error");
387 if (GetEngineControl()->fRealTime
) {
388 if (fThread
.AcquireRealTime(GetEngineControl()->fClientPriority
) < 0) {
389 jack_error("AcquireRealTime error");
400 bool JackClient::Execute()
402 if (!jack_tls_set(JackGlobals::fRealTime
, this))
403 jack_error("failed to set thread realtime key");
405 if (GetEngineControl()->fRealTime
)
406 set_threaded_log_function();
408 // Execute a dummy cycle to be sure thread has the correct properties
412 fThreadFun(fThreadFunArg
);
419 void JackClient::DummyCycle()
425 inline void JackClient::ExecuteThread()
429 CycleSignalAux(CallProcessCallback());
433 inline jack_nframes_t
JackClient::CycleWaitAux()
436 Error(); // Terminates the thread
437 CallSyncCallbackAux();
438 return GetEngineControl()->fBufferSize
;
441 inline void JackClient::CycleSignalAux(int status
)
444 CallTimebaseCallbackAux();
447 End(); // Terminates the thread
450 jack_nframes_t
JackClient::CycleWait()
452 return CycleWaitAux();
455 void JackClient::CycleSignal(int status
)
457 CycleSignalAux(status
);
460 inline int JackClient::CallProcessCallback()
462 return (fProcess
!= NULL
) ? fProcess(GetEngineControl()->fBufferSize
, fProcessArg
) : 0;
465 inline bool JackClient::WaitSync()
467 // Suspend itself: wait on the input synchro
468 if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable
, 0x7FFFFFFF) < 0) {
469 jack_error("SuspendRefNum error");
476 inline void JackClient::SignalSync()
478 // Resume: signal output clients connected to the running client
479 if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable
) < 0) {
480 jack_error("ResumeRefNum error");
484 inline void JackClient::End()
486 jack_log("JackClient::Execute end name = %s", GetClientControl()->fName
);
487 // Hum... not sure about this, the following "close" code is called in the RT thread...
489 fThread
.DropSelfRealTime();
490 GetClientControl()->fActive
= false;
491 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
495 inline void JackClient::Error()
497 jack_error("JackClient::Execute error name = %s", GetClientControl()->fName
);
498 // Hum... not sure about this, the following "close" code is called in the RT thread...
500 fThread
.DropSelfRealTime();
501 GetClientControl()->fActive
= false;
502 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
511 int JackClient::PortRegister(const char* port_name
, const char* port_type
, unsigned long flags
, unsigned long buffer_size
)
513 // Check if port name is empty
514 string port_name_str
= string(port_name
);
515 if (port_name_str
.size() == 0) {
516 jack_error("port_name is empty");
517 return 0; // Means failure here...
520 // Check port name length
521 string name
= string(GetClientControl()->fName
) + string(":") + port_name_str
;
522 if (name
.size() >= JACK_PORT_NAME_SIZE
) {
523 jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n"
524 "Please use %lu characters or less",
525 GetClientControl()->fName
,
527 JACK_PORT_NAME_SIZE
- 1);
528 return 0; // Means failure here...
532 jack_port_id_t port_index
= NO_PORT
;
533 fChannel
->PortRegister(GetClientControl()->fRefNum
, name
.c_str(), port_type
, flags
, buffer_size
, &port_index
, &result
);
536 jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum
, name
.c_str(), port_type
, port_index
);
537 fPortList
.push_back(port_index
);
544 int JackClient::PortUnRegister(jack_port_id_t port_index
)
546 jack_log("JackClient::PortUnRegister port_index = %ld", port_index
);
547 list
<jack_port_id_t
>::iterator it
= find(fPortList
.begin(), fPortList
.end(), port_index
);
549 if (it
!= fPortList
.end()) {
552 fChannel
->PortUnRegister(GetClientControl()->fRefNum
, port_index
, &result
);
555 jack_error("unregistering a port %ld that is not own by the client", port_index
);
560 int JackClient::PortConnect(const char* src
, const char* dst
)
562 jack_log("JackClient::Connect src = %s dst = %s", src
, dst
);
564 fChannel
->PortConnect(GetClientControl()->fRefNum
, src
, dst
, &result
);
568 int JackClient::PortDisconnect(const char* src
, const char* dst
)
570 jack_log("JackClient::Disconnect src = %s dst = %s", src
, dst
);
572 fChannel
->PortDisconnect(GetClientControl()->fRefNum
, src
, dst
, &result
);
576 int JackClient::PortDisconnect(jack_port_id_t src
)
578 jack_log("JackClient::PortDisconnect src = %ld", src
);
580 fChannel
->PortDisconnect(GetClientControl()->fRefNum
, src
, ALL_PORTS
, &result
);
584 int JackClient::PortIsMine(jack_port_id_t port_index
)
586 JackPort
* port
= GetGraphManager()->GetPort(port_index
);
587 return GetClientControl()->fRefNum
== port
->GetRefNum();
590 int JackClient::PortRename(jack_port_id_t port_index
, const char* name
)
593 fChannel
->PortRename(GetClientControl()->fRefNum
, port_index
, name
, &result
);
597 //--------------------
598 // Context management
599 //--------------------
601 int JackClient::SetBufferSize(jack_nframes_t buffer_size
)
604 fChannel
->SetBufferSize(buffer_size
, &result
);
608 int JackClient::SetFreeWheel(int onoff
)
611 fChannel
->SetFreewheel(onoff
, &result
);
617 - from the RT thread when Execute method fails
618 - possibly from a "closed" notification channel
619 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
622 void JackClient::ShutDown()
624 jack_log("ShutDown");
625 JackGlobals::fServerRunning
= false;
628 fInfoShutdown(JackFailure
, "JACK server has been closed", fInfoShutdownArg
);
629 fInfoShutdown
= NULL
;
630 } else if (fShutdown
) {
631 fShutdown(fShutdownArg
);
636 //----------------------
637 // Transport management
638 //----------------------
640 inline int JackClient::ActivateAux()
642 // If activated without RT thread...
643 if (IsActive() && fThread
.GetStatus() != JackThread::kRunning
) {
645 jack_log("ActivateAux");
647 // RT thread is started
648 if (StartThread() < 0)
652 GetClientControl()->fCallback
[kRealTimeCallback
] = IsRealTime();
653 fChannel
->ClientActivate(GetClientControl()->fRefNum
, IsRealTime(), &result
);
661 int JackClient::ReleaseTimebase()
664 fChannel
->ReleaseTimebase(GetClientControl()->fRefNum
, &result
);
666 GetClientControl()->fTransportTimebase
= false;
673 /* Call the server if the client is active, otherwise keeps the arguments */
674 int JackClient::SetSyncCallback(JackSyncCallback sync_callback
, void* arg
)
676 GetClientControl()->fTransportSync
= (fSync
!= NULL
);
678 fSync
= sync_callback
;
679 return ActivateAux();
682 int JackClient::SetTimebaseCallback(int conditional
, JackTimebaseCallback timebase_callback
, void* arg
)
685 fChannel
->SetTimebaseCallback(GetClientControl()->fRefNum
, conditional
, &result
);
688 GetClientControl()->fTransportTimebase
= true;
689 fTimebase
= timebase_callback
;
691 return ActivateAux();
699 int JackClient::SetSyncTimeout(jack_time_t timeout
)
701 GetEngineControl()->fTransport
.SetSyncTimeout(timeout
);
707 void JackClient::TransportLocate(jack_nframes_t frame
)
711 pos
.valid
= (jack_position_bits_t
)0;
712 jack_log("TransportLocate pos = %ld", pos
.frame
);
713 GetEngineControl()->fTransport
.RequestNewPos(&pos
);
716 int JackClient::TransportReposition(jack_position_t
* pos
)
718 jack_position_t tmp
= *pos
;
719 jack_log("TransportReposition pos = %ld", pos
->frame
);
720 if (tmp
.valid
& ~JACK_POSITION_MASK
) {
723 GetEngineControl()->fTransport
.RequestNewPos(pos
);
728 jack_transport_state_t
JackClient::TransportQuery(jack_position_t
* pos
)
730 return GetEngineControl()->fTransport
.Query(pos
);
733 jack_nframes_t
JackClient::GetCurrentTransportFrame()
735 return GetEngineControl()->fTransport
.GetCurrentFrame();
738 // Must be RT safe: directly write in the transport shared mem
739 void JackClient::TransportStart()
741 GetEngineControl()->fTransport
.SetCommand(TransportCommandStart
);
744 // Must be RT safe: directly write in the transport shared mem
745 void JackClient::TransportStop()
747 GetEngineControl()->fTransport
.SetCommand(TransportCommandStop
);
750 // Never called concurently with the server
751 // TODO check concurrency with SetSyncCallback
753 void JackClient::CallSyncCallback()
755 CallSyncCallbackAux();
758 inline void JackClient::CallSyncCallbackAux()
760 if (GetClientControl()->fTransportSync
) {
762 JackTransportEngine
& transport
= GetEngineControl()->fTransport
;
763 jack_position_t
* cur_pos
= transport
.ReadCurrentState();
764 jack_transport_state_t transport_state
= transport
.GetState();
767 if (fSync(transport_state
, cur_pos
, fSyncArg
)) {
768 GetClientControl()->fTransportState
= JackTransportRolling
;
769 GetClientControl()->fTransportSync
= false;
772 GetClientControl()->fTransportState
= JackTransportRolling
;
773 GetClientControl()->fTransportSync
= false;
778 void JackClient::CallTimebaseCallback()
780 CallTimebaseCallbackAux();
783 inline void JackClient::CallTimebaseCallbackAux()
785 JackTransportEngine
& transport
= GetEngineControl()->fTransport
;
789 transport
.GetTimebaseMaster(master
, unused
);
791 if (GetClientControl()->fRefNum
== master
&& fTimebase
) { // Client *is* timebase...
793 jack_transport_state_t transport_state
= transport
.GetState();
794 jack_position_t
* cur_pos
= transport
.WriteNextStateStart(1);
796 if (GetClientControl()->fTransportTimebase
) {
797 fTimebase(transport_state
, GetEngineControl()->fBufferSize
, cur_pos
, true, fTimebaseArg
);
798 GetClientControl()->fTransportTimebase
= false; // Callback is called only once with "new_pos" = true
799 } else if (transport_state
== JackTransportRolling
) {
800 fTimebase(transport_state
, GetEngineControl()->fBufferSize
, cur_pos
, false, fTimebaseArg
);
803 transport
.WriteNextStateStop(1);
807 //---------------------
808 // Callback management
809 //---------------------
811 void JackClient::OnShutdown(JackShutdownCallback callback
, void *arg
)
814 jack_error("You cannot set callbacks on an active client");
817 fShutdown
= callback
;
821 void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback
, void *arg
)
824 jack_error("You cannot set callbacks on an active client");
826 GetClientControl()->fCallback
[kShutDownCallback
] = (callback
!= NULL
);
827 fInfoShutdownArg
= arg
;
828 fInfoShutdown
= callback
;
832 int JackClient::SetProcessCallback(JackProcessCallback callback
, void *arg
)
835 jack_error("You cannot set callbacks on an active client");
837 } else if (fThreadFun
) {
838 jack_error ("A thread callback has already been setup, both models cannot be used at the same time!");
847 int JackClient::SetXRunCallback(JackXRunCallback callback
, void *arg
)
850 jack_error("You cannot set callbacks on an active client");
853 GetClientControl()->fCallback
[kXRunCallback
] = (callback
!= NULL
);
860 int JackClient::SetInitCallback(JackThreadInitCallback callback
, void *arg
)
863 jack_error("You cannot set callbacks on an active client");
868 /* make sure that the message buffer thread is initialized too */
869 JackMessageBuffer::fInstance
->SetInitCallback(callback
, arg
);
874 int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback
, void *arg
)
876 jack_log("SetGraphOrderCallback ");
879 jack_error("You cannot set callbacks on an active client");
882 GetClientControl()->fCallback
[kGraphOrderCallback
] = (callback
!= NULL
);
883 fGraphOrder
= callback
;
884 fGraphOrderArg
= arg
;
889 int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback
, void *arg
)
892 jack_error("You cannot set callbacks on an active client");
895 GetClientControl()->fCallback
[kBufferSizeCallback
] = (callback
!= NULL
);
896 fBufferSizeArg
= arg
;
897 fBufferSize
= callback
;
902 int JackClient::SetSampleRateCallback(JackSampleRateCallback callback
, void *arg
)
905 jack_error("You cannot set callbacks on an active client");
908 GetClientControl()->fCallback
[kSampleRateCallback
] = (callback
!= NULL
);
909 fSampleRateArg
= arg
;
910 fSampleRate
= callback
;
913 callback(GetEngineControl()->fSampleRate
, arg
);
918 int JackClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback
, void* arg
)
921 jack_error("You cannot set callbacks on an active client");
924 // kAddClient and kRemoveClient notifications must be delivered by the server in any case
925 fClientRegistrationArg
= arg
;
926 fClientRegistration
= callback
;
931 int JackClient::SetFreewheelCallback(JackFreewheelCallback callback
, void *arg
)
934 jack_error("You cannot set callbacks on an active client");
937 GetClientControl()->fCallback
[kStartFreewheelCallback
] = (callback
!= NULL
);
938 GetClientControl()->fCallback
[kStopFreewheelCallback
] = (callback
!= NULL
);
940 fFreewheel
= callback
;
945 int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback
, void *arg
)
948 jack_error("You cannot set callbacks on an active client");
951 GetClientControl()->fCallback
[kPortRegistrationOnCallback
] = (callback
!= NULL
);
952 GetClientControl()->fCallback
[kPortRegistrationOffCallback
] = (callback
!= NULL
);
953 fPortRegistrationArg
= arg
;
954 fPortRegistration
= callback
;
959 int JackClient::SetPortConnectCallback(JackPortConnectCallback callback
, void *arg
)
962 jack_error("You cannot set callbacks on an active client");
965 GetClientControl()->fCallback
[kPortConnectCallback
] = (callback
!= NULL
);
966 GetClientControl()->fCallback
[kPortDisconnectCallback
] = (callback
!= NULL
);
967 fPortConnectArg
= arg
;
968 fPortConnect
= callback
;
973 int JackClient::SetPortRenameCallback(JackPortRenameCallback callback
, void *arg
)
976 jack_error("You cannot set callbacks on an active client");
979 GetClientControl()->fCallback
[kPortRenameCallback
] = (callback
!= NULL
);
980 fPortRenameArg
= arg
;
981 fPortRename
= callback
;
986 int JackClient::SetProcessThread(JackThreadCallback fun
, void *arg
)
989 jack_error("You cannot set callbacks on an active client");
991 } else if (fProcess
) {
992 jack_error ("A process callback has already been setup, both models cannot be used at the same time!");
1001 int JackClient::SetSessionCallback(JackSessionCallback callback
, void *arg
)
1004 jack_error("You cannot set callbacks on an active client");
1007 GetClientControl()->fCallback
[kSessionCallback
] = (callback
!= NULL
);
1009 fSession
= callback
;
1014 //------------------
1016 //------------------
1018 char* JackClient::GetInternalClientName(int ref
)
1020 char name_res
[JACK_CLIENT_NAME_SIZE
+ 1];
1022 fChannel
->GetInternalClientName(GetClientControl()->fRefNum
, ref
, name_res
, &result
);
1023 return (result
< 0) ? NULL
: strdup(name_res
);
1026 int JackClient::InternalClientHandle(const char* client_name
, jack_status_t
* status
)
1028 int int_ref
, result
= -1;
1029 fChannel
->InternalClientHandle(GetClientControl()->fRefNum
, client_name
, (int*)status
, &int_ref
, &result
);
1033 int JackClient::InternalClientLoad(const char* client_name
, jack_options_t options
, jack_status_t
* status
, jack_varargs_t
* va
)
1035 if (strlen(client_name
) >= JACK_CLIENT_NAME_SIZE
) {
1036 jack_error ("\"%s\" is too long for a JACK client name.\n"
1037 "Please use %lu characters or less.",
1038 client_name
, JACK_CLIENT_NAME_SIZE
);
1042 if (va
->load_name
&& (strlen(va
->load_name
) >= JACK_PATH_MAX
)) {
1043 jack_error("\"%s\" is too long for a shared object name.\n"
1044 "Please use %lu characters or less.",
1045 va
->load_name
, PATH_MAX
);
1046 int my_status1
= *status
| (JackFailure
| JackInvalidOption
);
1047 *status
= (jack_status_t
)my_status1
;
1051 if (va
->load_init
&& (strlen(va
->load_init
) >= JACK_LOAD_INIT_LIMIT
)) {
1052 jack_error ("\"%s\" is too long for internal client init "
1053 "string.\nPlease use %lu characters or less.",
1054 va
->load_init
, JACK_LOAD_INIT_LIMIT
);
1055 int my_status1
= *status
| (JackFailure
| JackInvalidOption
);
1056 *status
= (jack_status_t
)my_status1
;
1060 int int_ref
, result
= -1;
1062 fChannel
->InternalClientLoad(GetClientControl()->fRefNum
, client_name
, va
->load_name
, va
->load_init
, options
, (int*)status
, &int_ref
, -1, &result
);
1066 void JackClient::InternalClientUnload(int ref
, jack_status_t
* status
)
1069 fChannel
->InternalClientUnload(GetClientControl()->fRefNum
, ref
, (int*)status
, &result
);
1072 //------------------
1074 //------------------
1076 jack_session_command_t
*JackClient::SessionNotify( const char* target
, jack_session_event_type_t type
, const char* path
)
1078 jack_session_command_t
*res
;
1079 fChannel
->SessionNotify( GetClientControl()->fRefNum
, target
, type
, path
, &res
);
1083 int JackClient::SessionReply( jack_session_event_t
*ev
)
1085 if (ev
->command_line
) {
1086 strncpy( GetClientControl()->fSessionCommand
, ev
->command_line
, sizeof(GetClientControl()->fSessionCommand
) );
1088 GetClientControl()->fSessionCommand
[0] = '\0';
1091 GetClientControl()->fSessionFlags
= ev
->flags
;
1093 jack_log( "JackClient::SessionReply... we are here" );
1094 if (fChannel
->IsChannelThread()) {
1095 jack_log( "JackClient::SessionReply... in callback reply" );
1096 fImmediateSessionReply
= true;
1100 jack_log( "JackClient::SessionReply... out of cb" );
1103 fChannel
->SessionReply( GetClientControl()->fRefNum
, &res
);
1107 char* JackClient::GetUUIDForClientName(const char* client_name
)
1109 char uuid_res
[JACK_UUID_SIZE
];
1111 fChannel
->GetUUIDForClientName( GetClientControl()->fRefNum
, client_name
, uuid_res
, &result
);
1116 return strdup(uuid_res
);
1119 char* JackClient::GetClientNameForUUID(const char* uuid
)
1121 char name_res
[JACK_CLIENT_NAME_SIZE
+ 1];
1123 fChannel
->GetClientNameForUUID(GetClientControl()->fRefNum
, uuid
, name_res
, &result
);
1128 return strdup(name_res
);
1131 int JackClient::ReserveClientName(const char *name
, const char* uuid
)
1134 fChannel
->ReserveClientName( GetClientControl()->fRefNum
, name
, uuid
, &result
);
1138 } // end of namespace