Jack2 1.9.6
|
00001 /* 00002 Copyright (C) 2001 Paul Davis 00003 Copyright (C) 2004-2008 Grame 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU Lesser General Public License as published by 00007 the Free Software Foundation; either version 2.1 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 00019 */ 00020 00021 #include "JackClient.h" 00022 #include "JackGraphManager.h" 00023 #include "JackClientControl.h" 00024 #include "JackEngineControl.h" 00025 #include "JackGlobals.h" 00026 #include "JackChannel.h" 00027 #include "JackTransportEngine.h" 00028 #include "driver_interface.h" 00029 #include "JackLibGlobals.h" 00030 00031 #include <math.h> 00032 #include <string> 00033 #include <algorithm> 00034 00035 using namespace std; 00036 00037 namespace Jack 00038 { 00039 00040 #define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL)) 00041 00042 JackClient::JackClient():fThread(this) 00043 {} 00044 00045 JackClient::JackClient(JackSynchro* table):fThread(this) 00046 { 00047 fSynchroTable = table; 00048 fProcess = NULL; 00049 fGraphOrder = NULL; 00050 fXrun = NULL; 00051 fShutdown = NULL; 00052 fInfoShutdown = NULL; 00053 fInit = NULL; 00054 fBufferSize = NULL; 00055 fClientRegistration = NULL; 00056 fFreewheel = NULL; 00057 fPortRegistration = NULL; 00058 fPortConnect = NULL; 00059 fPortRename = NULL; 00060 fTimebase = NULL; 00061 fSync = NULL; 00062 fThreadFun = NULL; 00063 fProcessArg = NULL; 00064 fGraphOrderArg = NULL; 00065 fXrunArg = NULL; 00066 fShutdownArg = NULL; 00067 fInfoShutdownArg = NULL; 00068 fInitArg = NULL; 00069 fBufferSizeArg = NULL; 00070 fFreewheelArg = NULL; 00071 fClientRegistrationArg = NULL; 00072 fPortRegistrationArg = NULL; 00073 fPortConnectArg = NULL; 00074 fPortRenameArg = NULL; 00075 fSyncArg = NULL; 00076 fTimebaseArg = NULL; 00077 fThreadFunArg = NULL; 00078 } 00079 00080 JackClient::~JackClient() 00081 {} 00082 00083 int JackClient::Close() 00084 { 00085 jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); 00086 int result = 0; 00087 00088 Deactivate(); 00089 fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing 00090 00091 // Request close only if server is still running 00092 if (JackGlobals::fServerRunning) { 00093 fChannel->ClientClose(GetClientControl()->fRefNum, &result); 00094 } else { 00095 jack_log("JackClient::Close server is shutdown"); 00096 } 00097 00098 fChannel->Close(); 00099 fSynchroTable[GetClientControl()->fRefNum].Disconnect(); 00100 JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; 00101 return result; 00102 } 00103 00104 bool JackClient::IsActive() 00105 { 00106 return (GetClientControl()) ? GetClientControl()->fActive : false; 00107 } 00108 00109 pthread_t JackClient::GetThreadID() 00110 { 00111 return fThread.GetThreadID(); 00112 } 00113 00119 void JackClient::SetupDriverSync(bool freewheel) 00120 { 00121 if (!freewheel && !GetEngineControl()->fSyncMode) { 00122 jack_log("JackClient::SetupDriverSync driver sem in flush mode"); 00123 for (int i = 0; i < GetEngineControl()->fDriverNum; i++) { 00124 fSynchroTable[i].SetFlush(true); 00125 } 00126 } else { 00127 jack_log("JackClient::SetupDriverSync driver sem in normal mode"); 00128 for (int i = 0; i < GetEngineControl()->fDriverNum; i++) 00129 fSynchroTable[i].SetFlush(false); 00130 } 00131 } 00132 00137 int JackClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) 00138 { 00139 return 0; 00140 } 00141 00142 int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) 00143 { 00144 int res = 0; 00145 00146 // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient 00147 switch (notify) { 00148 00149 case kAddClient: 00150 res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2); 00151 break; 00152 00153 case kRemoveClient: 00154 res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2); 00155 break; 00156 00157 case kActivateClient: 00158 jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum); 00159 Init(); 00160 break; 00161 } 00162 00163 /* 00164 The current semantic is that notifications can only be received when the client has been activated, 00165 although is this implementation, one could imagine calling notifications as soon as the client has be opened. 00166 */ 00167 if (IsActive()) { 00168 00169 switch (notify) { 00170 00171 case kAddClient: 00172 jack_log("JackClient::kAddClient fName = %s name = %s", GetClientControl()->fName, name); 00173 if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself 00174 fClientRegistration(name, 1, fClientRegistrationArg); 00175 } 00176 break; 00177 00178 case kRemoveClient: 00179 jack_log("JackClient::kRemoveClient fName = %s name = %s", GetClientControl()->fName, name); 00180 if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself 00181 fClientRegistration(name, 0, fClientRegistrationArg); 00182 } 00183 break; 00184 00185 case kBufferSizeCallback: 00186 jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", value1); 00187 if (fBufferSize) { 00188 res = fBufferSize(value1, fBufferSizeArg); 00189 } 00190 break; 00191 00192 case kSampleRateCallback: 00193 jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1); 00194 if (fSampleRate) { 00195 res = fSampleRate(value1, fSampleRateArg); 00196 } 00197 break; 00198 00199 case kGraphOrderCallback: 00200 jack_log("JackClient::kGraphOrderCallback"); 00201 if (fGraphOrder) { 00202 res = fGraphOrder(fGraphOrderArg); 00203 } 00204 break; 00205 00206 case kStartFreewheelCallback: 00207 jack_log("JackClient::kStartFreewheel"); 00208 SetupDriverSync(true); 00209 fThread.DropRealTime(); // Always done (JACK server in RT mode or not...) 00210 if (fFreewheel) { 00211 fFreewheel(1, fFreewheelArg); 00212 } 00213 break; 00214 00215 case kStopFreewheelCallback: 00216 jack_log("JackClient::kStopFreewheel"); 00217 SetupDriverSync(false); 00218 if (fFreewheel) { 00219 fFreewheel(0, fFreewheelArg); 00220 } 00221 if (GetEngineControl()->fRealTime) { 00222 fThread.AcquireRealTime(); 00223 } 00224 break; 00225 00226 case kPortRegistrationOnCallback: 00227 jack_log("JackClient::kPortRegistrationOn port_index = %ld", value1); 00228 if (fPortRegistration) { 00229 fPortRegistration(value1, 1, fPortRegistrationArg); 00230 } 00231 break; 00232 00233 case kPortRegistrationOffCallback: 00234 jack_log("JackClient::kPortRegistrationOff port_index = %ld ", value1); 00235 if (fPortRegistration) { 00236 fPortRegistration(value1, 0, fPortRegistrationArg); 00237 } 00238 break; 00239 00240 case kPortConnectCallback: 00241 jack_log("JackClient::kPortConnectCallback src = %ld dst = %ld", value1, value2); 00242 if (fPortConnect) { 00243 fPortConnect(value1, value2, 1, fPortConnectArg); 00244 } 00245 break; 00246 00247 case kPortDisconnectCallback: 00248 jack_log("JackClient::kPortDisconnectCallback src = %ld dst = %ld", value1, value2); 00249 if (fPortConnect) { 00250 fPortConnect(value1, value2, 0, fPortConnectArg); 00251 } 00252 break; 00253 00254 case kPortRenameCallback: 00255 jack_log("JackClient::kPortRenameCallback port = %ld", value1); 00256 if (fPortRename) { 00257 fPortRename(value1, message, GetGraphManager()->GetPort(value1)->GetName(), fPortRenameArg); 00258 } 00259 break; 00260 00261 case kXRunCallback: 00262 jack_log("JackClient::kXRunCallback"); 00263 if (fXrun) { 00264 res = fXrun(fXrunArg); 00265 } 00266 break; 00267 00268 case kShutDownCallback: 00269 jack_log("JackClient::kShutDownCallback"); 00270 if (fInfoShutdown) { 00271 fInfoShutdown((jack_status_t)value1, message, fInfoShutdownArg); 00272 fInfoShutdown = NULL; 00273 } 00274 break; 00275 } 00276 } 00277 00278 return res; 00279 } 00280 00285 int JackClient::Activate() 00286 { 00287 jack_log("JackClient::Activate"); 00288 if (IsActive()) 00289 return 0; 00290 00291 // RT thread is started only when needed... 00292 if (IsRealTime()) { 00293 if (StartThread() < 0) 00294 return -1; 00295 } 00296 00297 /* 00298 Insertion of client in the graph will cause a kGraphOrderCallback notification 00299 to be delivered by the server, the client wants to receive it. 00300 */ 00301 GetClientControl()->fActive = true; 00302 00303 // Transport related callback become "active" 00304 GetClientControl()->fTransportSync = true; 00305 GetClientControl()->fTransportTimebase = true; 00306 00307 int result = -1; 00308 GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); 00309 fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); 00310 return result; 00311 } 00312 00316 int JackClient::Deactivate() 00317 { 00318 jack_log("JackClient::Deactivate"); 00319 if (!IsActive()) 00320 return 0; 00321 00322 GetClientControl()->fActive = false; 00323 00324 // Transport related callback become "unactive" 00325 GetClientControl()->fTransportSync = false; 00326 GetClientControl()->fTransportTimebase = false; 00327 00328 // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate 00329 int result = -1; 00330 fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); 00331 jack_log("JackClient::Deactivate res = %ld", result); 00332 00333 // RT thread is stopped only when needed... 00334 if (IsRealTime()) 00335 fThread.Kill(); 00336 return result; 00337 } 00338 00339 //---------------------- 00340 // RT thread management 00341 //---------------------- 00342 00346 bool JackClient::Init() 00347 { 00348 if (fInit) { 00349 jack_log("JackClient::Init calling client thread init callback"); 00350 fInit(fInitArg); 00351 } 00352 return true; 00353 } 00354 00355 int JackClient::StartThread() 00356 { 00357 jack_log("JackClient::StartThread : period = %ld computation = %ld constraint = %ld", 00358 long(int64_t(GetEngineControl()->fPeriod) / 1000.0f), 00359 long(int64_t(GetEngineControl()->fComputation) / 1000.0f), 00360 long(int64_t(GetEngineControl()->fConstraint) / 1000.0f)); 00361 00362 // Will do "something" on OSX only... 00363 fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); 00364 00365 if (fThread.StartSync() < 0) { 00366 jack_error("Start thread error"); 00367 return -1; 00368 } 00369 00370 if (GetEngineControl()->fRealTime) { 00371 if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { 00372 jack_error("AcquireRealTime error"); 00373 } 00374 } 00375 00376 return 0; 00377 } 00378 00383 bool JackClient::Execute() 00384 { 00385 if (!jack_tls_set(JackGlobals::fRealTime, this)) 00386 jack_error("failed to set thread realtime key"); 00387 00388 if (GetEngineControl()->fRealTime) 00389 set_threaded_log_function(); 00390 00391 // Execute a dummy cycle to be sure thread has the correct properties 00392 DummyCycle(); 00393 00394 if (fThreadFun) { 00395 fThreadFun(fThreadFunArg); 00396 } else { 00397 ExecuteThread(); 00398 } 00399 return false; 00400 } 00401 00402 void JackClient::DummyCycle() 00403 { 00404 WaitSync(); 00405 SignalSync(); 00406 } 00407 00408 inline void JackClient::ExecuteThread() 00409 { 00410 while (true) { 00411 CycleWaitAux(); 00412 CycleSignalAux(CallProcessCallback()); 00413 } 00414 } 00415 00416 inline jack_nframes_t JackClient::CycleWaitAux() 00417 { 00418 if (!WaitSync()) 00419 Error(); // Terminates the thread 00420 CallSyncCallbackAux(); 00421 return GetEngineControl()->fBufferSize; 00422 } 00423 00424 inline void JackClient::CycleSignalAux(int status) 00425 { 00426 if (status == 0) 00427 CallTimebaseCallbackAux(); 00428 SignalSync(); 00429 if (status != 0) 00430 End(); // Terminates the thread 00431 } 00432 00433 jack_nframes_t JackClient::CycleWait() 00434 { 00435 return CycleWaitAux(); 00436 } 00437 00438 void JackClient::CycleSignal(int status) 00439 { 00440 CycleSignalAux(status); 00441 } 00442 00443 inline int JackClient::CallProcessCallback() 00444 { 00445 return (fProcess != NULL) ? fProcess(GetEngineControl()->fBufferSize, fProcessArg) : 0; 00446 } 00447 00448 inline bool JackClient::WaitSync() 00449 { 00450 // Suspend itself: wait on the input synchro 00451 if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) { 00452 jack_error("SuspendRefNum error"); 00453 return false; 00454 } else { 00455 return true; 00456 } 00457 } 00458 00459 inline void JackClient::SignalSync() 00460 { 00461 // Resume: signal output clients connected to the running client 00462 if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) { 00463 jack_error("ResumeRefNum error"); 00464 } 00465 } 00466 00467 inline void JackClient::End() 00468 { 00469 jack_log("JackClient::Execute end name = %s", GetClientControl()->fName); 00470 // Hum... not sure about this, the following "close" code is called in the RT thread... 00471 int result; 00472 fThread.DropSelfRealTime(); 00473 GetClientControl()->fActive = false; 00474 fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); 00475 fThread.Terminate(); 00476 } 00477 00478 inline void JackClient::Error() 00479 { 00480 jack_error("JackClient::Execute error name = %s", GetClientControl()->fName); 00481 // Hum... not sure about this, the following "close" code is called in the RT thread... 00482 int result; 00483 fThread.DropSelfRealTime(); 00484 GetClientControl()->fActive = false; 00485 fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); 00486 ShutDown(); 00487 fThread.Terminate(); 00488 } 00489 00490 //----------------- 00491 // Port management 00492 //----------------- 00493 00494 int JackClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size) 00495 { 00496 // Check if port name is empty 00497 string port_name_str = string(port_name); 00498 if (port_name_str.size() == 0) { 00499 jack_error("port_name is empty"); 00500 return 0; // Means failure here... 00501 } 00502 00503 // Check port name length 00504 string name = string(GetClientControl()->fName) + string(":") + port_name_str; 00505 if (name.size() >= JACK_PORT_NAME_SIZE) { 00506 jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n" 00507 "Please use %lu characters or less", 00508 GetClientControl()->fName, 00509 port_name, 00510 JACK_PORT_NAME_SIZE - 1); 00511 return 0; // Means failure here... 00512 } 00513 00514 int result = -1; 00515 jack_port_id_t port_index = NO_PORT; 00516 fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result); 00517 00518 if (result == 0) { 00519 jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, name.c_str(), port_type, port_index); 00520 fPortList.push_back(port_index); 00521 return port_index; 00522 } else { 00523 return 0; 00524 } 00525 } 00526 00527 int JackClient::PortUnRegister(jack_port_id_t port_index) 00528 { 00529 jack_log("JackClient::PortUnRegister port_index = %ld", port_index); 00530 list<jack_port_id_t>::iterator it = find(fPortList.begin(), fPortList.end(), port_index); 00531 00532 if (it != fPortList.end()) { 00533 fPortList.erase(it); 00534 int result = -1; 00535 fChannel->PortUnRegister(GetClientControl()->fRefNum, port_index, &result); 00536 return result; 00537 } else { 00538 jack_error("unregistering a port %ld that is not own by the client", port_index); 00539 return -1; 00540 } 00541 } 00542 00543 int JackClient::PortConnect(const char* src, const char* dst) 00544 { 00545 jack_log("JackClient::Connect src = %s dst = %s", src, dst); 00546 int result = -1; 00547 fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result); 00548 return result; 00549 } 00550 00551 int JackClient::PortDisconnect(const char* src, const char* dst) 00552 { 00553 jack_log("JackClient::Disconnect src = %s dst = %s", src, dst); 00554 int result = -1; 00555 fChannel->PortDisconnect(GetClientControl()->fRefNum, src, dst, &result); 00556 return result; 00557 } 00558 00559 int JackClient::PortDisconnect(jack_port_id_t src) 00560 { 00561 jack_log("JackClient::PortDisconnect src = %ld", src); 00562 int result = -1; 00563 fChannel->PortDisconnect(GetClientControl()->fRefNum, src, ALL_PORTS, &result); 00564 return result; 00565 } 00566 00567 int JackClient::PortIsMine(jack_port_id_t port_index) 00568 { 00569 JackPort* port = GetGraphManager()->GetPort(port_index); 00570 return GetClientControl()->fRefNum == port->GetRefNum(); 00571 } 00572 00573 int JackClient::PortRename(jack_port_id_t port_index, const char* name) 00574 { 00575 int result = -1; 00576 fChannel->PortRename(GetClientControl()->fRefNum, port_index, name, &result); 00577 return result; 00578 } 00579 00580 //-------------------- 00581 // Context management 00582 //-------------------- 00583 00584 int JackClient::SetBufferSize(jack_nframes_t buffer_size) 00585 { 00586 int result = -1; 00587 fChannel->SetBufferSize(buffer_size, &result); 00588 return result; 00589 } 00590 00591 int JackClient::SetFreeWheel(int onoff) 00592 { 00593 int result = -1; 00594 fChannel->SetFreewheel(onoff, &result); 00595 return result; 00596 } 00597 00598 /* 00599 ShutDown is called: 00600 - from the RT thread when Execute method fails 00601 - possibly from a "closed" notification channel 00602 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown)) 00603 */ 00604 00605 void JackClient::ShutDown() 00606 { 00607 jack_log("ShutDown"); 00608 JackGlobals::fServerRunning = false; 00609 00610 if (fInfoShutdown) { 00611 fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); 00612 fInfoShutdown = NULL; 00613 } else if (fShutdown) { 00614 fShutdown(fShutdownArg); 00615 fShutdown = NULL; 00616 } 00617 } 00618 00619 //---------------------- 00620 // Transport management 00621 //---------------------- 00622 00623 inline int JackClient::ActivateAux() 00624 { 00625 // If activated without RT thread... 00626 if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { 00627 00628 jack_log("ActivateAux"); 00629 00630 // RT thread is started 00631 if (StartThread() < 0) 00632 return -1; 00633 00634 int result = -1; 00635 GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); 00636 fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); 00637 return result; 00638 00639 } else { 00640 return 0; 00641 } 00642 } 00643 00644 int JackClient::ReleaseTimebase() 00645 { 00646 int result = -1; 00647 fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result); 00648 if (result == 0) { 00649 GetClientControl()->fTransportTimebase = false; 00650 fTimebase = NULL; 00651 fTimebaseArg = NULL; 00652 } 00653 return result; 00654 } 00655 00656 /* Call the server if the client is active, otherwise keeps the arguments */ 00657 int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg) 00658 { 00659 GetClientControl()->fTransportSync = (fSync != NULL); 00660 fSyncArg = arg; 00661 fSync = sync_callback; 00662 return ActivateAux(); 00663 } 00664 00665 int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) 00666 { 00667 int result = -1; 00668 fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); 00669 00670 if (result == 0) { 00671 GetClientControl()->fTransportTimebase = true; 00672 fTimebase = timebase_callback; 00673 fTimebaseArg = arg; 00674 return ActivateAux(); 00675 } else { 00676 fTimebase = NULL; 00677 fTimebaseArg = NULL; 00678 return -1; 00679 } 00680 } 00681 00682 int JackClient::SetSyncTimeout(jack_time_t timeout) 00683 { 00684 GetEngineControl()->fTransport.SetSyncTimeout(timeout); 00685 return 0; 00686 } 00687 00688 // Must be RT safe 00689 00690 void JackClient::TransportLocate(jack_nframes_t frame) 00691 { 00692 jack_position_t pos; 00693 pos.frame = frame; 00694 pos.valid = (jack_position_bits_t)0; 00695 jack_log("TransportLocate pos = %ld", pos.frame); 00696 GetEngineControl()->fTransport.RequestNewPos(&pos); 00697 } 00698 00699 int JackClient::TransportReposition(jack_position_t* pos) 00700 { 00701 jack_position_t tmp = *pos; 00702 jack_log("TransportReposition pos = %ld", pos->frame); 00703 if (tmp.valid & ~JACK_POSITION_MASK) { 00704 return EINVAL; 00705 } else { 00706 GetEngineControl()->fTransport.RequestNewPos(pos); 00707 return 0; 00708 } 00709 } 00710 00711 jack_transport_state_t JackClient::TransportQuery(jack_position_t* pos) 00712 { 00713 return GetEngineControl()->fTransport.Query(pos); 00714 } 00715 00716 jack_nframes_t JackClient::GetCurrentTransportFrame() 00717 { 00718 return GetEngineControl()->fTransport.GetCurrentFrame(); 00719 } 00720 00721 // Must be RT safe: directly write in the transport shared mem 00722 void JackClient::TransportStart() 00723 { 00724 GetEngineControl()->fTransport.SetCommand(TransportCommandStart); 00725 } 00726 00727 // Must be RT safe: directly write in the transport shared mem 00728 void JackClient::TransportStop() 00729 { 00730 GetEngineControl()->fTransport.SetCommand(TransportCommandStop); 00731 } 00732 00733 // Never called concurently with the server 00734 // TODO check concurrency with SetSyncCallback 00735 00736 void JackClient::CallSyncCallback() 00737 { 00738 CallSyncCallbackAux(); 00739 } 00740 00741 inline void JackClient::CallSyncCallbackAux() 00742 { 00743 if (GetClientControl()->fTransportSync) { 00744 00745 JackTransportEngine& transport = GetEngineControl()->fTransport; 00746 jack_position_t* cur_pos = transport.ReadCurrentState(); 00747 jack_transport_state_t transport_state = transport.GetState(); 00748 00749 if (fSync != NULL) { 00750 if (fSync(transport_state, cur_pos, fSyncArg)) { 00751 GetClientControl()->fTransportState = JackTransportRolling; 00752 GetClientControl()->fTransportSync = false; 00753 } 00754 } else { 00755 GetClientControl()->fTransportState = JackTransportRolling; 00756 GetClientControl()->fTransportSync = false; 00757 } 00758 } 00759 } 00760 00761 void JackClient::CallTimebaseCallback() 00762 { 00763 CallTimebaseCallbackAux(); 00764 } 00765 00766 inline void JackClient::CallTimebaseCallbackAux() 00767 { 00768 JackTransportEngine& transport = GetEngineControl()->fTransport; 00769 int master; 00770 bool unused; 00771 00772 transport.GetTimebaseMaster(master, unused); 00773 00774 if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... 00775 00776 jack_transport_state_t transport_state = transport.GetState(); 00777 jack_position_t* cur_pos = transport.WriteNextStateStart(1); 00778 00779 if (GetClientControl()->fTransportTimebase) { 00780 fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); 00781 GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true 00782 } else if (transport_state == JackTransportRolling) { 00783 fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); 00784 } 00785 00786 transport.WriteNextStateStop(1); 00787 } 00788 } 00789 00790 //--------------------- 00791 // Callback management 00792 //--------------------- 00793 00794 void JackClient::OnShutdown(JackShutdownCallback callback, void *arg) 00795 { 00796 if (IsActive()) { 00797 jack_error("You cannot set callbacks on an active client"); 00798 } else { 00799 fShutdownArg = arg; 00800 fShutdown = callback; 00801 } 00802 } 00803 00804 void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) 00805 { 00806 if (IsActive()) { 00807 jack_error("You cannot set callbacks on an active client"); 00808 } else { 00809 GetClientControl()->fCallback[kShutDownCallback] = (callback != NULL); 00810 fInfoShutdownArg = arg; 00811 fInfoShutdown = callback; 00812 } 00813 } 00814 00815 int JackClient::SetProcessCallback(JackProcessCallback callback, void *arg) 00816 { 00817 if (IsActive()) { 00818 jack_error("You cannot set callbacks on an active client"); 00819 return -1; 00820 } else if (fThreadFun) { 00821 jack_error ("A thread callback has already been setup, both models cannot be used at the same time!"); 00822 return -1; 00823 } else { 00824 fProcessArg = arg; 00825 fProcess = callback; 00826 return 0; 00827 } 00828 } 00829 00830 int JackClient::SetXRunCallback(JackXRunCallback callback, void *arg) 00831 { 00832 if (IsActive()) { 00833 jack_error("You cannot set callbacks on an active client"); 00834 return -1; 00835 } else { 00836 GetClientControl()->fCallback[kXRunCallback] = (callback != NULL); 00837 fXrunArg = arg; 00838 fXrun = callback; 00839 return 0; 00840 } 00841 } 00842 00843 int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg) 00844 { 00845 if (IsActive()) { 00846 jack_error("You cannot set callbacks on an active client"); 00847 return -1; 00848 } else { 00849 fInitArg = arg; 00850 fInit = callback; 00851 /* make sure that the message buffer thread is initialized too */ 00852 JackMessageBuffer::fInstance->SetInitCallback(callback, arg); 00853 return 0; 00854 } 00855 } 00856 00857 int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) 00858 { 00859 jack_log("SetGraphOrderCallback "); 00860 00861 if (IsActive()) { 00862 jack_error("You cannot set callbacks on an active client"); 00863 return -1; 00864 } else { 00865 GetClientControl()->fCallback[kGraphOrderCallback] = (callback != NULL); 00866 fGraphOrder = callback; 00867 fGraphOrderArg = arg; 00868 return 0; 00869 } 00870 } 00871 00872 int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg) 00873 { 00874 if (IsActive()) { 00875 jack_error("You cannot set callbacks on an active client"); 00876 return -1; 00877 } else { 00878 GetClientControl()->fCallback[kBufferSizeCallback] = (callback != NULL); 00879 fBufferSizeArg = arg; 00880 fBufferSize = callback; 00881 return 0; 00882 } 00883 } 00884 00885 int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg) 00886 { 00887 if (IsActive()) { 00888 jack_error("You cannot set callbacks on an active client"); 00889 return -1; 00890 } else { 00891 GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); 00892 fSampleRateArg = arg; 00893 fSampleRate = callback; 00894 // Now invoke it 00895 if (callback) 00896 callback(GetEngineControl()->fSampleRate, arg); 00897 return 0; 00898 } 00899 } 00900 00901 int JackClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback, void* arg) 00902 { 00903 if (IsActive()) { 00904 jack_error("You cannot set callbacks on an active client"); 00905 return -1; 00906 } else { 00907 // kAddClient and kRemoveClient notifications must be delivered by the server in any case 00908 fClientRegistrationArg = arg; 00909 fClientRegistration = callback; 00910 return 0; 00911 } 00912 } 00913 00914 int JackClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg) 00915 { 00916 if (IsActive()) { 00917 jack_error("You cannot set callbacks on an active client"); 00918 return -1; 00919 } else { 00920 GetClientControl()->fCallback[kStartFreewheelCallback] = (callback != NULL); 00921 GetClientControl()->fCallback[kStopFreewheelCallback] = (callback != NULL); 00922 fFreewheelArg = arg; 00923 fFreewheel = callback; 00924 return 0; 00925 } 00926 } 00927 00928 int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg) 00929 { 00930 if (IsActive()) { 00931 jack_error("You cannot set callbacks on an active client"); 00932 return -1; 00933 } else { 00934 GetClientControl()->fCallback[kPortRegistrationOnCallback] = (callback != NULL); 00935 GetClientControl()->fCallback[kPortRegistrationOffCallback] = (callback != NULL); 00936 fPortRegistrationArg = arg; 00937 fPortRegistration = callback; 00938 return 0; 00939 } 00940 } 00941 00942 int JackClient::SetPortConnectCallback(JackPortConnectCallback callback, void *arg) 00943 { 00944 if (IsActive()) { 00945 jack_error("You cannot set callbacks on an active client"); 00946 return -1; 00947 } else { 00948 GetClientControl()->fCallback[kPortConnectCallback] = (callback != NULL); 00949 GetClientControl()->fCallback[kPortDisconnectCallback] = (callback != NULL); 00950 fPortConnectArg = arg; 00951 fPortConnect = callback; 00952 return 0; 00953 } 00954 } 00955 00956 int JackClient::SetPortRenameCallback(JackPortRenameCallback callback, void *arg) 00957 { 00958 if (IsActive()) { 00959 jack_error("You cannot set callbacks on an active client"); 00960 return -1; 00961 } else { 00962 GetClientControl()->fCallback[kPortRenameCallback] = (callback != NULL); 00963 fPortRenameArg = arg; 00964 fPortRename = callback; 00965 return 0; 00966 } 00967 } 00968 00969 int JackClient::SetProcessThread(JackThreadCallback fun, void *arg) 00970 { 00971 if (IsActive()) { 00972 jack_error("You cannot set callbacks on an active client"); 00973 return -1; 00974 } else if (fProcess) { 00975 jack_error ("A process callback has already been setup, both models cannot be used at the same time!"); 00976 return -1; 00977 } else { 00978 fThreadFun = fun; 00979 fThreadFunArg = arg; 00980 return 0; 00981 } 00982 } 00983 00984 //------------------ 00985 // Internal clients 00986 //------------------ 00987 00988 char* JackClient::GetInternalClientName(int ref) 00989 { 00990 char name_res[JACK_CLIENT_NAME_SIZE + 1]; 00991 int result = -1; 00992 fChannel->GetInternalClientName(GetClientControl()->fRefNum, ref, name_res, &result); 00993 return (result < 0) ? NULL : strdup(name_res); 00994 } 00995 00996 int JackClient::InternalClientHandle(const char* client_name, jack_status_t* status) 00997 { 00998 int int_ref, result = -1; 00999 fChannel->InternalClientHandle(GetClientControl()->fRefNum, client_name, (int*)status, &int_ref, &result); 01000 return int_ref; 01001 } 01002 01003 int JackClient::InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va) 01004 { 01005 if (strlen(client_name) >= JACK_CLIENT_NAME_SIZE) { 01006 jack_error ("\"%s\" is too long for a JACK client name.\n" 01007 "Please use %lu characters or less.", 01008 client_name, JACK_CLIENT_NAME_SIZE); 01009 return 0; 01010 } 01011 01012 if (va->load_name && (strlen(va->load_name) >= JACK_PATH_MAX)) { 01013 jack_error("\"%s\" is too long for a shared object name.\n" 01014 "Please use %lu characters or less.", 01015 va->load_name, JACK_PATH_MAX); 01016 int my_status1 = *status | (JackFailure | JackInvalidOption); 01017 *status = (jack_status_t)my_status1; 01018 return 0; 01019 } 01020 01021 if (va->load_init && (strlen(va->load_init) >= JACK_LOAD_INIT_LIMIT)) { 01022 jack_error ("\"%s\" is too long for internal client init " 01023 "string.\nPlease use %lu characters or less.", 01024 va->load_init, JACK_LOAD_INIT_LIMIT); 01025 int my_status1 = *status | (JackFailure | JackInvalidOption); 01026 *status = (jack_status_t)my_status1; 01027 return 0; 01028 } 01029 01030 int int_ref = 0; 01031 int result = -1; 01032 fChannel->InternalClientLoad(GetClientControl()->fRefNum, client_name, va->load_name, va->load_init, options, (int*)status, &int_ref, &result); 01033 return int_ref; 01034 } 01035 01036 void JackClient::InternalClientUnload(int ref, jack_status_t* status) 01037 { 01038 int result = -1; 01039 fChannel->InternalClientUnload(GetClientControl()->fRefNum, ref, (int*)status, &result); 01040 } 01041 01042 01043 } // end of namespace 01044