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 "JackSystemDeps.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(JackSynchro
* table
):fThread(this)
44 fSynchroTable
= table
;
52 fClientRegistration
= NULL
;
54 fPortRegistration
= NULL
;
62 fPropertyChange
= NULL
;
65 fGraphOrderArg
= NULL
;
68 fInfoShutdownArg
= NULL
;
70 fBufferSizeArg
= NULL
;
72 fClientRegistrationArg
= NULL
;
73 fPortRegistrationArg
= NULL
;
74 fPortConnectArg
= NULL
;
75 fPortRenameArg
= NULL
;
81 fPropertyChangeArg
= NULL
;
83 fSessionReply
= kPendingSessionReply
;
86 JackClient::~JackClient()
89 void JackClient::ShutDown(jack_status_t code
, const char* message
)
91 jack_log("JackClient::ShutDown");
93 // If "fInfoShutdown" callback, then call it
95 fInfoShutdown(code
, message
, fInfoShutdownArg
);
97 // Otherwise possibly call the normal "fShutdown"
98 } else if (fShutdown
) {
99 fShutdown(fShutdownArg
);
104 int JackClient::Close()
106 jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum
);
111 // Channels is stopped first to avoid receiving notifications while closing
114 fChannel
->ClientClose(GetClientControl()->fRefNum
, &result
);
117 assert(JackGlobals::fSynchroMutex
);
118 JackGlobals::fSynchroMutex
->Lock();
119 fSynchroTable
[GetClientControl()->fRefNum
].Disconnect();
120 JackGlobals::fSynchroMutex
->Unlock();
121 JackGlobals::fClientTable
[GetClientControl()->fRefNum
] = NULL
;
125 bool JackClient::IsActive()
127 return (GetClientControl()) ? GetClientControl()->fActive
: false;
130 jack_native_thread_t
JackClient::GetThreadID()
132 return fThread
.GetThreadID();
136 In "async" mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
137 The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
138 Drivers synchro are setup in "flush" mode if server is "async" and NOT freewheel.
140 void JackClient::SetupDriverSync(bool freewheel
)
142 if (!freewheel
&& !GetEngineControl()->fSyncMode
) {
143 jack_log("JackClient::SetupDriverSync driver sem in flush mode");
144 for (int i
= 0; i
< GetEngineControl()->fDriverNum
; i
++) {
145 fSynchroTable
[i
].SetFlush(true);
148 jack_log("JackClient::SetupDriverSync driver sem in normal mode");
149 for (int i
= 0; i
< GetEngineControl()->fDriverNum
; i
++) {
150 fSynchroTable
[i
].SetFlush(false);
156 \brief Notification received from the server.
159 int JackClient::ClientNotifyImp(int refnum
, const char* name
, int notify
, int sync
, const char* message
, int value1
, int value2
)
164 int JackClient::ClientNotify(int refnum
, const char* name
, int notify
, int sync
, const char* message
, int value1
, int value2
)
168 jack_log("JackClient::ClientNotify ref = %ld name = %s notify = %ld", refnum
, name
, notify
);
170 // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient
174 res
= ClientNotifyImp(refnum
, name
, notify
, sync
, message
, value1
, value2
);
178 res
= ClientNotifyImp(refnum
, name
, notify
, sync
, message
, value1
, value2
);
181 case kActivateClient
:
182 jack_log("JackClient::kActivateClient name = %s ref = %ld ", name
, refnum
);
188 The current semantic is that notifications can only be received when the client has been activated,
189 although is this implementation, one could imagine calling notifications as soon as the client has be opened.
196 jack_log("JackClient::kAddClient fName = %s name = %s", GetClientControl()->fName
, name
);
197 if (fClientRegistration
&& strcmp(GetClientControl()->fName
, name
) != 0) { // Don't call the callback for the registering client itself
198 fClientRegistration(name
, 1, fClientRegistrationArg
);
203 jack_log("JackClient::kRemoveClient fName = %s name = %s", GetClientControl()->fName
, name
);
204 if (fClientRegistration
&& strcmp(GetClientControl()->fName
, name
) != 0) { // Don't call the callback for the registering client itself
205 fClientRegistration(name
, 0, fClientRegistrationArg
);
209 case kBufferSizeCallback
:
210 jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", value1
);
212 res
= fBufferSize(value1
, fBufferSizeArg
);
216 case kSampleRateCallback
:
217 jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1
);
219 res
= fSampleRate(value1
, fSampleRateArg
);
223 case kGraphOrderCallback
:
224 jack_log("JackClient::kGraphOrderCallback");
226 res
= fGraphOrder(fGraphOrderArg
);
230 case kStartFreewheelCallback
:
231 jack_log("JackClient::kStartFreewheel");
232 SetupDriverSync(true);
233 // Drop RT only when the RT thread is actually running
234 if (fThread
.GetStatus() == JackThread::kRunning
) {
235 fThread
.DropRealTime();
238 fFreewheel(1, fFreewheelArg
);
242 case kStopFreewheelCallback
:
243 jack_log("JackClient::kStopFreewheel");
244 SetupDriverSync(false);
246 fFreewheel(0, fFreewheelArg
);
248 // Acquire RT only when the RT thread is actually running
249 if (GetEngineControl()->fRealTime
&& fThread
.GetStatus() == JackThread::kRunning
) {
250 if (fThread
.AcquireRealTime(GetEngineControl()->fClientPriority
) < 0) {
251 jack_error("JackClient::AcquireRealTime error");
256 case kPortRegistrationOnCallback
:
257 jack_log("JackClient::kPortRegistrationOn port_index = %ld", value1
);
258 if (fPortRegistration
) {
259 fPortRegistration(value1
, 1, fPortRegistrationArg
);
263 case kPortRegistrationOffCallback
:
264 jack_log("JackClient::kPortRegistrationOff port_index = %ld ", value1
);
265 if (fPortRegistration
) {
266 fPortRegistration(value1
, 0, fPortRegistrationArg
);
270 case kPortConnectCallback
:
271 jack_log("JackClient::kPortConnectCallback src = %ld dst = %ld", value1
, value2
);
273 fPortConnect(value1
, value2
, 1, fPortConnectArg
);
277 case kPortDisconnectCallback
:
278 jack_log("JackClient::kPortDisconnectCallback src = %ld dst = %ld", value1
, value2
);
280 fPortConnect(value1
, value2
, 0, fPortConnectArg
);
284 case kPortRenameCallback
:
285 jack_log("JackClient::kPortRenameCallback port = %ld", value1
);
287 fPortRename(value1
, message
, GetGraphManager()->GetPort(value1
)->GetName(), fPortRenameArg
);
292 jack_log("JackClient::kXRunCallback");
294 res
= fXrun(fXrunArg
);
298 case kShutDownCallback
:
299 jack_log("JackClient::kShutDownCallback");
300 ShutDown(jack_status_t(value1
), message
);
303 case kSessionCallback
:
304 jack_log("JackClient::kSessionCallback");
306 jack_session_event_t
* event
= (jack_session_event_t
*)malloc( sizeof(jack_session_event_t
));
307 char uuid_buf
[JACK_UUID_STRING_SIZE
];
308 event
->type
= (jack_session_event_type_t
)value1
;
309 event
->session_dir
= strdup(message
);
310 event
->command_line
= NULL
;
311 event
->flags
= (jack_session_flags_t
)0;
312 jack_uuid_unparse(GetClientControl()->fSessionID
, uuid_buf
);
313 event
->client_uuid
= strdup(uuid_buf
);
314 fSessionReply
= kPendingSessionReply
;
315 // Session callback may change fSessionReply by directly using jack_session_reply
316 fSession(event
, fSessionArg
);
321 case kLatencyCallback
:
322 res
= HandleLatencyCallback(value1
);
325 case kPropertyChangeCallback
: {
327 jack_uuid_parse(name
, &subject
);
328 const char* key
= message
;
329 jack_property_change_t change
= (jack_property_change_t
)value1
;
330 jack_log("JackClient::kPropertyChangeCallback subject = %x key = %s change = %x", subject
, key
, change
);
332 fPropertyChange(subject
, key
, change
, fPropertyChangeArg
);
341 int JackClient::HandleLatencyCallback(int status
)
343 jack_latency_callback_mode_t mode
= (status
== 0) ? JackCaptureLatency
: JackPlaybackLatency
;
344 jack_latency_range_t latency
= { UINT32_MAX
, 0 };
346 /* first setup all latency values of the ports.
347 * this is based on the connections of the ports.
349 list
<jack_port_id_t
>::iterator it
;
351 for (it
= fPortList
.begin(); it
!= fPortList
.end(); it
++) {
352 JackPort
* port
= GetGraphManager()->GetPort(*it
);
353 if ((port
->GetFlags() & JackPortIsOutput
) && (mode
== JackPlaybackLatency
)) {
354 GetGraphManager()->RecalculateLatency(*it
, mode
);
356 if ((port
->GetFlags() & JackPortIsInput
) && (mode
== JackCaptureLatency
)) {
357 GetGraphManager()->RecalculateLatency(*it
, mode
);
363 * default action is to assume all ports depend on each other.
364 * then always take the maximum latency.
367 if (mode
== JackPlaybackLatency
) {
368 /* iterate over all OutputPorts, to find maximum playback latency
370 for (it
= fPortList
.begin(); it
!= fPortList
.end(); it
++) {
371 JackPort
* port
= GetGraphManager()->GetPort(*it
);
372 if (port
->GetFlags() & JackPortIsOutput
) {
373 jack_latency_range_t other_latency
;
374 port
->GetLatencyRange(mode
, &other_latency
);
375 if (other_latency
.max
> latency
.max
) {
376 latency
.max
= other_latency
.max
;
378 if (other_latency
.min
< latency
.min
) {
379 latency
.min
= other_latency
.min
;
384 if (latency
.min
== UINT32_MAX
) {
388 /* now set the found latency on all input ports
390 for (it
= fPortList
.begin(); it
!= fPortList
.end(); it
++) {
391 JackPort
* port
= GetGraphManager()->GetPort(*it
);
392 if (port
->GetFlags() & JackPortIsInput
) {
393 port
->SetLatencyRange(mode
, &latency
);
397 if (mode
== JackCaptureLatency
) {
398 /* iterate over all InputPorts, to find maximum playback latency
400 for (it
= fPortList
.begin(); it
!= fPortList
.end(); it
++) {
401 JackPort
* port
= GetGraphManager()->GetPort(*it
);
402 if (port
->GetFlags() & JackPortIsInput
) {
403 jack_latency_range_t other_latency
;
404 port
->GetLatencyRange(mode
, &other_latency
);
405 if (other_latency
.max
> latency
.max
) {
406 latency
.max
= other_latency
.max
;
408 if (other_latency
.min
< latency
.min
) {
409 latency
.min
= other_latency
.min
;
414 if (latency
.min
== UINT32_MAX
) {
418 /* now set the found latency on all output ports
420 for (it
= fPortList
.begin(); it
!= fPortList
.end(); it
++) {
421 JackPort
* port
= GetGraphManager()->GetPort(*it
);
422 if (port
->GetFlags() & JackPortIsOutput
) {
423 port
->SetLatencyRange(mode
, &latency
);
430 /* we have a latency callback setup by the client,
433 fLatency(mode
, fLatencyArg
);
438 \brief We need to start thread before activating in the server, otherwise the FW driver
439 connected to the client may not be activated.
441 int JackClient::Activate()
443 jack_log("JackClient::Activate");
448 // RT thread is started only when needed...
450 if (StartThread() < 0) {
456 Insertion of client in the graph will cause a kGraphOrderCallback notification
457 to be delivered by the server, the client wants to receive it.
459 GetClientControl()->fActive
= true;
461 // Transport related callback become "active"
462 GetClientControl()->fTransportSync
= true;
463 GetClientControl()->fTransportTimebase
= true;
466 GetClientControl()->fCallback
[kRealTimeCallback
] = IsRealTime();
467 fChannel
->ClientActivate(GetClientControl()->fRefNum
, IsRealTime(), &result
);
472 \brief Need to stop thread after deactivating in the server.
474 int JackClient::Deactivate()
476 jack_log("JackClient::Deactivate");
481 GetClientControl()->fActive
= false;
483 // Transport related callback become "unactive"
484 GetClientControl()->fTransportSync
= false;
485 GetClientControl()->fTransportTimebase
= false;
487 // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
489 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
490 jack_log("JackClient::Deactivate res = %ld", result
);
492 // RT thread is stopped only when needed...
499 //----------------------
500 // RT thread management
501 //----------------------
503 void JackClient::InitAux()
506 jack_log("JackClient::Init calling client thread init callback");
512 \brief Called once when the thread starts.
514 bool JackClient::Init()
517 Execute buffer_size callback.
519 Since StartThread uses fThread.StartSync, we are sure that buffer_size callback
520 is executed before StartThread returns (and then IsActive will be true).
521 So no RT callback can be called at the same time.
523 jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", GetEngineControl()->fBufferSize
);
525 fBufferSize(GetEngineControl()->fBufferSize
, fBufferSizeArg
);
532 if (!jack_tls_set(JackGlobals::fRealTimeThread
, this)) {
533 jack_error("Failed to set thread realtime key");
537 if (GetEngineControl()->fRealTime
) {
538 set_threaded_log_function();
545 void JackClient::SetupRealTime()
547 jack_log("JackClient::Init : period = %ld computation = %ld constraint = %ld",
548 long(int64_t(GetEngineControl()->fPeriod
) / 1000.0f
),
549 long(int64_t(GetEngineControl()->fComputation
) / 1000.0f
),
550 long(int64_t(GetEngineControl()->fConstraint
) / 1000.0f
));
552 // Will do "something" on OSX only...
553 fThread
.SetParams(GetEngineControl()->fPeriod
, GetEngineControl()->fComputation
, GetEngineControl()->fConstraint
);
555 if (fThread
.AcquireSelfRealTime(GetEngineControl()->fClientPriority
) < 0) {
556 jack_error("JackClient::AcquireSelfRealTime error");
560 int JackClient::StartThread()
562 if (fThread
.StartSync() < 0) {
563 jack_error("Start thread error");
574 bool JackClient::Execute()
576 // Execute a dummy cycle to be sure thread has the correct properties
580 fThreadFun(fThreadFunArg
);
587 void JackClient::DummyCycle()
593 inline void JackClient::ExecuteThread()
597 CycleSignalAux(CallProcessCallback());
601 inline jack_nframes_t
JackClient::CycleWaitAux()
604 Error(); // Terminates the thread
606 CallSyncCallbackAux();
607 return GetEngineControl()->fBufferSize
;
610 inline void JackClient::CycleSignalAux(int status
)
613 CallTimebaseCallbackAux();
617 End(); // Terminates the thread
621 jack_nframes_t
JackClient::CycleWait()
623 return CycleWaitAux();
626 void JackClient::CycleSignal(int status
)
628 CycleSignalAux(status
);
631 inline int JackClient::CallProcessCallback()
633 return (fProcess
!= NULL
) ? fProcess(GetEngineControl()->fBufferSize
, fProcessArg
) : 0;
636 inline bool JackClient::WaitSync()
638 // Suspend itself: wait on the input synchro
639 if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable
, 0x7FFFFFFF) < 0) {
640 jack_error("SuspendRefNum error");
647 inline void JackClient::SignalSync()
649 // Resume: signal output clients connected to the running client
650 if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable
) < 0) {
651 jack_error("ResumeRefNum error");
655 inline void JackClient::End()
657 jack_log("JackClient::Execute end name = %s", GetClientControl()->fName
);
658 // Hum... not sure about this, the following "close" code is called in the RT thread...
660 fThread
.DropSelfRealTime();
661 GetClientControl()->fActive
= false;
662 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
666 inline void JackClient::Error()
668 jack_error("JackClient::Execute error name = %s", GetClientControl()->fName
);
669 // Hum... not sure about this, the following "close" code is called in the RT thread...
671 fThread
.DropSelfRealTime();
672 GetClientControl()->fActive
= false;
673 fChannel
->ClientDeactivate(GetClientControl()->fRefNum
, &result
);
674 ShutDown(jack_status_t(JackFailure
| JackServerError
), JACK_SERVER_FAILURE
);
682 int JackClient::PortRegister(const char* port_name
, const char* port_type
, unsigned long flags
, unsigned long buffer_size
)
684 // Check if port name is empty
685 string port_short_name_str
= string(port_name
);
686 if (port_short_name_str
.size() == 0) {
687 jack_error("port_name is empty");
688 return 0; // Means failure here...
691 // Check port name length
692 string port_full_name_str
= string(GetClientControl()->fName
) + string(":") + port_short_name_str
;
693 if (port_full_name_str
.size() >= REAL_JACK_PORT_NAME_SIZE
) {
694 jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n"
695 "Please use %lu characters or less",
696 GetClientControl()->fName
,
698 JACK_PORT_NAME_SIZE
- 1);
699 return 0; // Means failure here...
703 jack_port_id_t port_index
= NO_PORT
;
704 fChannel
->PortRegister(GetClientControl()->fRefNum
, port_full_name_str
.c_str(), port_type
, flags
, buffer_size
, &port_index
, &result
);
707 jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum
, port_full_name_str
.c_str(), port_type
, port_index
);
708 fPortList
.push_back(port_index
);
715 int JackClient::PortUnRegister(jack_port_id_t port_index
)
717 jack_log("JackClient::PortUnRegister port_index = %ld", port_index
);
718 list
<jack_port_id_t
>::iterator it
= find(fPortList
.begin(), fPortList
.end(), port_index
);
720 if (it
!= fPortList
.end()) {
723 fChannel
->PortUnRegister(GetClientControl()->fRefNum
, port_index
, &result
);
726 jack_error("unregistering a port %ld that is not own by the client", port_index
);
731 int JackClient::PortConnect(const char* src
, const char* dst
)
733 jack_log("JackClient::Connect src = %s dst = %s", src
, dst
);
734 if (strlen(src
) >= REAL_JACK_PORT_NAME_SIZE
) {
735 jack_error("\"%s\" is too long to be used as a JACK port name.\n", src
);
738 if (strlen(dst
) >= REAL_JACK_PORT_NAME_SIZE
) {
739 jack_error("\"%s\" is too long to be used as a JACK port name.\n", dst
);
743 fChannel
->PortConnect(GetClientControl()->fRefNum
, src
, dst
, &result
);
747 int JackClient::PortDisconnect(const char* src
, const char* dst
)
749 jack_log("JackClient::Disconnect src = %s dst = %s", src
, dst
);
750 if (strlen(src
) >= REAL_JACK_PORT_NAME_SIZE
) {
751 jack_error("\"%s\" is too long to be used as a JACK port name.\n", src
);
754 if (strlen(dst
) >= REAL_JACK_PORT_NAME_SIZE
) {
755 jack_error("\"%s\" is too long to be used as a JACK port name.\n", dst
);
759 fChannel
->PortDisconnect(GetClientControl()->fRefNum
, src
, dst
, &result
);
763 int JackClient::PortDisconnect(jack_port_id_t src
)
765 jack_log("JackClient::PortDisconnect src = %ld", src
);
767 fChannel
->PortDisconnect(GetClientControl()->fRefNum
, src
, ALL_PORTS
, &result
);
771 int JackClient::PortIsMine(jack_port_id_t port_index
)
773 JackPort
* port
= GetGraphManager()->GetPort(port_index
);
774 return GetClientControl()->fRefNum
== port
->GetRefNum();
777 int JackClient::PortRename(jack_port_id_t port_index
, const char* name
)
780 fChannel
->PortRename(GetClientControl()->fRefNum
, port_index
, name
, &result
);
784 //--------------------
785 // Context management
786 //--------------------
788 int JackClient::SetBufferSize(jack_nframes_t buffer_size
)
791 fChannel
->SetBufferSize(buffer_size
, &result
);
795 int JackClient::SetFreeWheel(int onoff
)
798 fChannel
->SetFreewheel(onoff
, &result
);
802 int JackClient::ComputeTotalLatencies()
805 fChannel
->ComputeTotalLatencies(&result
);
809 //----------------------
810 // Transport management
811 //----------------------
813 inline int JackClient::ActivateAux()
815 // If activated without RT thread...
816 if (IsActive() && fThread
.GetStatus() != JackThread::kRunning
) {
818 jack_log("JackClient::ActivateAux");
820 // RT thread is started
821 if (StartThread() < 0) {
826 GetClientControl()->fCallback
[kRealTimeCallback
] = IsRealTime();
827 fChannel
->ClientActivate(GetClientControl()->fRefNum
, IsRealTime(), &result
);
835 int JackClient::ReleaseTimebase()
838 fChannel
->ReleaseTimebase(GetClientControl()->fRefNum
, &result
);
840 GetClientControl()->fTransportTimebase
= false;
847 /* Call the server if the client is active, otherwise keeps the arguments */
848 int JackClient::SetSyncCallback(JackSyncCallback sync_callback
, void* arg
)
850 GetClientControl()->fTransportSync
= (fSync
!= NULL
);
852 fSync
= sync_callback
;
853 return ActivateAux();
856 int JackClient::SetTimebaseCallback(int conditional
, JackTimebaseCallback timebase_callback
, void* arg
)
859 fChannel
->SetTimebaseCallback(GetClientControl()->fRefNum
, conditional
, &result
);
862 GetClientControl()->fTransportTimebase
= true;
863 fTimebase
= timebase_callback
;
865 return ActivateAux();
873 int JackClient::SetSyncTimeout(jack_time_t timeout
)
875 GetEngineControl()->fTransport
.SetSyncTimeout(timeout
);
881 void JackClient::TransportLocate(jack_nframes_t frame
)
885 pos
.valid
= (jack_position_bits_t
)0;
886 jack_log("JackClient::TransportLocate pos = %ld", pos
.frame
);
887 GetEngineControl()->fTransport
.RequestNewPos(&pos
);
890 int JackClient::TransportReposition(const jack_position_t
* pos
)
892 jack_position_t tmp
= *pos
;
893 jack_log("JackClient::TransportReposition pos = %ld", pos
->frame
);
894 if (tmp
.valid
& ~JACK_POSITION_MASK
) {
897 GetEngineControl()->fTransport
.RequestNewPos(&tmp
);
902 jack_transport_state_t
JackClient::TransportQuery(jack_position_t
* pos
)
904 return GetEngineControl()->fTransport
.Query(pos
);
907 jack_nframes_t
JackClient::GetCurrentTransportFrame()
909 return GetEngineControl()->fTransport
.GetCurrentFrame();
912 // Must be RT safe: directly write in the transport shared mem
913 void JackClient::TransportStart()
915 GetEngineControl()->fTransport
.SetCommand(TransportCommandStart
);
918 // Must be RT safe: directly write in the transport shared mem
919 void JackClient::TransportStop()
921 GetEngineControl()->fTransport
.SetCommand(TransportCommandStop
);
924 // Never called concurrently with the server
925 // TODO check concurrency with SetSyncCallback
927 void JackClient::CallSyncCallback()
929 CallSyncCallbackAux();
932 inline void JackClient::CallSyncCallbackAux()
934 if (GetClientControl()->fTransportSync
) {
936 JackTransportEngine
& transport
= GetEngineControl()->fTransport
;
937 jack_position_t
* cur_pos
= transport
.ReadCurrentState();
938 jack_transport_state_t transport_state
= transport
.GetState();
941 if (fSync(transport_state
, cur_pos
, fSyncArg
)) {
942 GetClientControl()->fTransportState
= JackTransportRolling
;
943 GetClientControl()->fTransportSync
= false;
946 GetClientControl()->fTransportState
= JackTransportRolling
;
947 GetClientControl()->fTransportSync
= false;
952 void JackClient::CallTimebaseCallback()
954 CallTimebaseCallbackAux();
957 inline void JackClient::CallTimebaseCallbackAux()
959 JackTransportEngine
& transport
= GetEngineControl()->fTransport
;
963 transport
.GetTimebaseMaster(master
, unused
);
965 if (GetClientControl()->fRefNum
== master
&& fTimebase
) { // Client *is* timebase...
967 jack_transport_state_t transport_state
= transport
.GetState();
968 jack_position_t
* cur_pos
= transport
.WriteNextStateStart(1);
970 if (GetClientControl()->fTransportTimebase
) {
971 fTimebase(transport_state
, GetEngineControl()->fBufferSize
, cur_pos
, true, fTimebaseArg
);
972 GetClientControl()->fTransportTimebase
= false; // Callback is called only once with "new_pos" = true
973 } else if (transport_state
== JackTransportRolling
) {
974 fTimebase(transport_state
, GetEngineControl()->fBufferSize
, cur_pos
, false, fTimebaseArg
);
977 transport
.WriteNextStateStop(1);
981 //---------------------
982 // Callback management
983 //---------------------
985 void JackClient::OnShutdown(JackShutdownCallback callback
, void *arg
)
988 jack_error("You cannot set callbacks on an active client");
990 // Shutdown callback will either be an old API version or the new version (with info)
991 GetClientControl()->fCallback
[kShutDownCallback
] = (callback
!= NULL
);
993 fShutdown
= callback
;
997 void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback
, void *arg
)
1000 jack_error("You cannot set callbacks on an active client");
1002 // Shutdown callback will either be an old API version or the new version (with info)
1003 GetClientControl()->fCallback
[kShutDownCallback
] = (callback
!= NULL
);
1004 fInfoShutdownArg
= arg
;
1005 fInfoShutdown
= callback
;
1009 int JackClient::SetProcessCallback(JackProcessCallback callback
, void *arg
)
1012 jack_error("You cannot set callbacks on an active client");
1014 } else if (fThreadFun
) {
1015 jack_error ("A thread callback has already been setup, both models cannot be used at the same time!");
1019 fProcess
= callback
;
1024 int JackClient::SetXRunCallback(JackXRunCallback callback
, void *arg
)
1027 jack_error("You cannot set callbacks on an active client");
1030 GetClientControl()->fCallback
[kXRunCallback
] = (callback
!= NULL
);
1037 int JackClient::SetInitCallback(JackThreadInitCallback callback
, void *arg
)
1040 jack_error("You cannot set callbacks on an active client");
1045 /* make sure that the message buffer thread is initialized too */
1046 return JackMessageBuffer::fInstance
->SetInitCallback(callback
, arg
);
1050 int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback
, void *arg
)
1053 jack_error("You cannot set callbacks on an active client");
1056 GetClientControl()->fCallback
[kGraphOrderCallback
] = (callback
!= NULL
);
1057 fGraphOrder
= callback
;
1058 fGraphOrderArg
= arg
;
1063 int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback
, void *arg
)
1066 jack_error("You cannot set callbacks on an active client");
1069 GetClientControl()->fCallback
[kBufferSizeCallback
] = (callback
!= NULL
);
1070 fBufferSizeArg
= arg
;
1071 fBufferSize
= callback
;
1076 int JackClient::SetSampleRateCallback(JackSampleRateCallback callback
, void *arg
)
1079 jack_error("You cannot set callbacks on an active client");
1082 GetClientControl()->fCallback
[kSampleRateCallback
] = (callback
!= NULL
);
1083 fSampleRateArg
= arg
;
1084 fSampleRate
= callback
;
1087 callback(GetEngineControl()->fSampleRate
, arg
);
1093 int JackClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback
, void* arg
)
1096 jack_error("You cannot set callbacks on an active client");
1099 // kAddClient and kRemoveClient notifications must be delivered by the server in any case
1100 fClientRegistrationArg
= arg
;
1101 fClientRegistration
= callback
;
1106 int JackClient::SetFreewheelCallback(JackFreewheelCallback callback
, void *arg
)
1109 jack_error("You cannot set callbacks on an active client");
1112 GetClientControl()->fCallback
[kStartFreewheelCallback
] = (callback
!= NULL
);
1113 GetClientControl()->fCallback
[kStopFreewheelCallback
] = (callback
!= NULL
);
1114 fFreewheelArg
= arg
;
1115 fFreewheel
= callback
;
1120 int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback
, void *arg
)
1123 jack_error("You cannot set callbacks on an active client");
1126 GetClientControl()->fCallback
[kPortRegistrationOnCallback
] = (callback
!= NULL
);
1127 GetClientControl()->fCallback
[kPortRegistrationOffCallback
] = (callback
!= NULL
);
1128 fPortRegistrationArg
= arg
;
1129 fPortRegistration
= callback
;
1134 int JackClient::SetPortConnectCallback(JackPortConnectCallback callback
, void *arg
)
1137 jack_error("You cannot set callbacks on an active client");
1140 GetClientControl()->fCallback
[kPortConnectCallback
] = (callback
!= NULL
);
1141 GetClientControl()->fCallback
[kPortDisconnectCallback
] = (callback
!= NULL
);
1142 fPortConnectArg
= arg
;
1143 fPortConnect
= callback
;
1148 int JackClient::SetPortRenameCallback(JackPortRenameCallback callback
, void *arg
)
1151 jack_error("You cannot set callbacks on an active client");
1154 GetClientControl()->fCallback
[kPortRenameCallback
] = (callback
!= NULL
);
1155 fPortRenameArg
= arg
;
1156 fPortRename
= callback
;
1161 int JackClient::SetProcessThread(JackThreadCallback fun
, void *arg
)
1164 jack_error("You cannot set callbacks on an active client");
1166 } else if (fProcess
) {
1167 jack_error("A process callback has already been setup, both models cannot be used at the same time!");
1171 fThreadFunArg
= arg
;
1176 int JackClient::SetSessionCallback(JackSessionCallback callback
, void *arg
)
1179 jack_error("You cannot set callbacks on an active client");
1182 GetClientControl()->fCallback
[kSessionCallback
] = (callback
!= NULL
);
1184 fSession
= callback
;
1189 int JackClient::SetLatencyCallback(JackLatencyCallback callback
, void *arg
)
1192 jack_error("You cannot set callbacks on an active client");
1195 // fCallback[kLatencyCallback] must always be 'true'
1197 fLatency
= callback
;
1202 int JackClient::SetPropertyChangeCallback(JackPropertyChangeCallback callback
, void *arg
)
1205 jack_error("You cannot set callbacks on an active client");
1208 fPropertyChangeArg
= arg
;
1209 fPropertyChange
= callback
;
1214 //------------------
1216 //------------------
1218 char* JackClient::GetInternalClientName(int ref
)
1220 char name_res
[JACK_CLIENT_NAME_SIZE
+1];
1222 fChannel
->GetInternalClientName(GetClientControl()->fRefNum
, ref
, name_res
, &result
);
1223 return (result
< 0) ? NULL
: strdup(name_res
);
1226 int JackClient::InternalClientHandle(const char* client_name
, jack_status_t
* status
)
1228 int int_ref
, result
= -1;
1229 fChannel
->InternalClientHandle(GetClientControl()->fRefNum
, client_name
, (int*)status
, &int_ref
, &result
);
1233 int JackClient::InternalClientLoad(const char* client_name
, jack_options_t options
, jack_status_t
* status
, jack_varargs_t
* va
)
1235 if (strlen(client_name
) >= JACK_CLIENT_NAME_SIZE
) {
1236 jack_error ("\"%s\" is too long for a JACK client name.\n"
1237 "Please use %lu characters or less.",
1238 client_name
, JACK_CLIENT_NAME_SIZE
);
1242 if (va
->load_name
&& (strlen(va
->load_name
) >= JACK_PATH_MAX
)) {
1243 jack_error("\"%s\" is too long for a shared object name.\n"
1244 "Please use %lu characters or less.",
1245 va
->load_name
, JACK_PATH_MAX
);
1246 int my_status1
= *status
| (JackFailure
| JackInvalidOption
);
1247 *status
= (jack_status_t
)my_status1
;
1251 if (va
->load_init
&& (strlen(va
->load_init
) >= JACK_LOAD_INIT_LIMIT
)) {
1252 jack_error ("\"%s\" is too long for internal client init "
1253 "string.\nPlease use %lu characters or less.",
1254 va
->load_init
, JACK_LOAD_INIT_LIMIT
);
1255 int my_status1
= *status
| (JackFailure
| JackInvalidOption
);
1256 *status
= (jack_status_t
)my_status1
;
1260 int int_ref
, result
= -1;
1261 fChannel
->InternalClientLoad(GetClientControl()->fRefNum
, client_name
, va
->load_name
, va
->load_init
, options
, (int*)status
, &int_ref
, -1, &result
);
1265 void JackClient::InternalClientUnload(int ref
, jack_status_t
* status
)
1268 fChannel
->InternalClientUnload(GetClientControl()->fRefNum
, ref
, (int*)status
, &result
);
1271 //------------------
1273 //------------------
1275 jack_session_command_t
* JackClient::SessionNotify(const char* target
, jack_session_event_type_t type
, const char* path
)
1277 jack_session_command_t
* res
;
1278 fChannel
->SessionNotify(GetClientControl()->fRefNum
, target
, type
, path
, &res
);
1282 int JackClient::SessionReply(jack_session_event_t
* ev
)
1284 if (ev
->command_line
) {
1285 strncpy(GetClientControl()->fSessionCommand
, ev
->command_line
, sizeof(GetClientControl()->fSessionCommand
));
1287 GetClientControl()->fSessionCommand
[0] = '\0';
1290 GetClientControl()->fSessionFlags
= ev
->flags
;
1292 jack_log("JackClient::SessionReply... we are here");
1293 if (fChannel
->IsChannelThread()) {
1294 jack_log("JackClient::SessionReply... in callback reply");
1295 // OK, immediate reply...
1296 fSessionReply
= kImmediateSessionReply
;
1300 jack_log("JackClient::SessionReply... out of cb");
1303 fChannel
->SessionReply(GetClientControl()->fRefNum
, &result
);
1307 char* JackClient::GetUUIDForClientName(const char* client_name
)
1309 char uuid_res
[JACK_UUID_STRING_SIZE
];
1311 fChannel
->GetUUIDForClientName(GetClientControl()->fRefNum
, client_name
, uuid_res
, &result
);
1312 return (result
) ? NULL
: strdup(uuid_res
);
1315 char* JackClient::GetClientNameByUUID(const char* uuid
)
1317 char name_res
[JACK_CLIENT_NAME_SIZE
+ 1];
1319 fChannel
->GetClientNameForUUID(GetClientControl()->fRefNum
, uuid
, name_res
, &result
);
1320 return (result
) ? NULL
: strdup(name_res
);
1323 int JackClient::ReserveClientName(const char* client_name
, const char* uuid
)
1326 fChannel
->ReserveClientName( GetClientControl()->fRefNum
, client_name
, uuid
, &result
);
1330 int JackClient::ClientHasSessionCallback(const char* client_name
)
1333 fChannel
->ClientHasSessionCallback(client_name
, &result
);
1337 //------------------
1339 //------------------
1341 int JackClient::PropertyChangeNotify(jack_uuid_t subject
, const char* key
, jack_property_change_t change
)
1344 fChannel
->PropertyChangeNotify(subject
, key
, change
, &result
);
1349 } // end of namespace