Jack2
1.9.8
|
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 "JackSystemDeps.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 00032 #include <math.h> 00033 #include <string> 00034 #include <algorithm> 00035 00036 using namespace std; 00037 00038 namespace Jack 00039 { 00040 00041 #define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL)) 00042 00043 JackClient::JackClient():fThread(this) 00044 {} 00045 00046 JackClient::JackClient(JackSynchro* table):fThread(this) 00047 { 00048 fSynchroTable = table; 00049 fProcess = NULL; 00050 fGraphOrder = NULL; 00051 fXrun = NULL; 00052 fShutdown = NULL; 00053 fInfoShutdown = NULL; 00054 fInit = NULL; 00055 fBufferSize = NULL; 00056 fClientRegistration = NULL; 00057 fFreewheel = NULL; 00058 fPortRegistration = NULL; 00059 fPortConnect = NULL; 00060 fPortRename = NULL; 00061 fTimebase = NULL; 00062 fSync = NULL; 00063 fThreadFun = NULL; 00064 fSession = NULL; 00065 fLatency = NULL; 00066 00067 fProcessArg = NULL; 00068 fGraphOrderArg = NULL; 00069 fXrunArg = NULL; 00070 fShutdownArg = NULL; 00071 fInfoShutdownArg = NULL; 00072 fInitArg = NULL; 00073 fBufferSizeArg = NULL; 00074 fFreewheelArg = NULL; 00075 fClientRegistrationArg = NULL; 00076 fPortRegistrationArg = NULL; 00077 fPortConnectArg = NULL; 00078 fPortRenameArg = NULL; 00079 fSyncArg = NULL; 00080 fTimebaseArg = NULL; 00081 fThreadFunArg = NULL; 00082 fSessionArg = NULL; 00083 fLatencyArg = NULL; 00084 00085 fSessionReply = kPendingSessionReply; 00086 } 00087 00088 JackClient::~JackClient() 00089 {} 00090 00091 int JackClient::Close() 00092 { 00093 jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); 00094 int result = 0; 00095 00096 Deactivate(); 00097 fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing 00098 00099 // Request close only if server is still running 00100 if (JackGlobals::fServerRunning) { 00101 fChannel->ClientClose(GetClientControl()->fRefNum, &result); 00102 } else { 00103 jack_log("JackClient::Close server is shutdown"); 00104 } 00105 00106 fChannel->Close(); 00107 fSynchroTable[GetClientControl()->fRefNum].Disconnect(); 00108 JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; 00109 return result; 00110 } 00111 00112 bool JackClient::IsActive() 00113 { 00114 return (GetClientControl()) ? GetClientControl()->fActive : false; 00115 } 00116 00117 jack_native_thread_t JackClient::GetThreadID() 00118 { 00119 return fThread.GetThreadID(); 00120 } 00121 00127 void JackClient::SetupDriverSync(bool freewheel) 00128 { 00129 if (!freewheel && !GetEngineControl()->fSyncMode) { 00130 jack_log("JackClient::SetupDriverSync driver sem in flush mode"); 00131 for (int i = 0; i < GetEngineControl()->fDriverNum; i++) { 00132 fSynchroTable[i].SetFlush(true); 00133 } 00134 } else { 00135 jack_log("JackClient::SetupDriverSync driver sem in normal mode"); 00136 for (int i = 0; i < GetEngineControl()->fDriverNum; i++) 00137 fSynchroTable[i].SetFlush(false); 00138 } 00139 } 00140 00145 int JackClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) 00146 { 00147 return 0; 00148 } 00149 00150 int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) 00151 { 00152 int res = 0; 00153 00154 jack_log("JackClient::ClientNotify ref = %ld name = %s notify = %ld", refnum, name, notify); 00155 00156 // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient 00157 switch (notify) { 00158 00159 case kAddClient: 00160 res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2); 00161 break; 00162 00163 case kRemoveClient: 00164 res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2); 00165 break; 00166 00167 case kActivateClient: 00168 jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum); 00169 InitAux(); 00170 break; 00171 } 00172 00173 /* 00174 The current semantic is that notifications can only be received when the client has been activated, 00175 although is this implementation, one could imagine calling notifications as soon as the client has be opened. 00176 */ 00177 if (IsActive()) { 00178 00179 switch (notify) { 00180 00181 case kAddClient: 00182 jack_log("JackClient::kAddClient fName = %s name = %s", GetClientControl()->fName, name); 00183 if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself 00184 fClientRegistration(name, 1, fClientRegistrationArg); 00185 } 00186 break; 00187 00188 case kRemoveClient: 00189 jack_log("JackClient::kRemoveClient fName = %s name = %s", GetClientControl()->fName, name); 00190 if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself 00191 fClientRegistration(name, 0, fClientRegistrationArg); 00192 } 00193 break; 00194 00195 case kBufferSizeCallback: 00196 jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", value1); 00197 if (fBufferSize) { 00198 res = fBufferSize(value1, fBufferSizeArg); 00199 } 00200 break; 00201 00202 case kSampleRateCallback: 00203 jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1); 00204 if (fSampleRate) { 00205 res = fSampleRate(value1, fSampleRateArg); 00206 } 00207 break; 00208 00209 case kGraphOrderCallback: 00210 jack_log("JackClient::kGraphOrderCallback"); 00211 if (fGraphOrder) { 00212 res = fGraphOrder(fGraphOrderArg); 00213 } 00214 break; 00215 00216 case kStartFreewheelCallback: 00217 jack_log("JackClient::kStartFreewheel"); 00218 SetupDriverSync(true); 00219 fThread.DropRealTime(); // Always done (JACK server in RT mode or not...) 00220 if (fFreewheel) { 00221 fFreewheel(1, fFreewheelArg); 00222 } 00223 break; 00224 00225 case kStopFreewheelCallback: 00226 jack_log("JackClient::kStopFreewheel"); 00227 SetupDriverSync(false); 00228 if (fFreewheel) { 00229 fFreewheel(0, fFreewheelArg); 00230 } 00231 if (GetEngineControl()->fRealTime) { 00232 if (fThread.AcquireRealTime() < 0) { 00233 jack_error("JackClient::AcquireRealTime error"); 00234 } 00235 } 00236 break; 00237 00238 case kPortRegistrationOnCallback: 00239 jack_log("JackClient::kPortRegistrationOn port_index = %ld", value1); 00240 if (fPortRegistration) { 00241 fPortRegistration(value1, 1, fPortRegistrationArg); 00242 } 00243 break; 00244 00245 case kPortRegistrationOffCallback: 00246 jack_log("JackClient::kPortRegistrationOff port_index = %ld ", value1); 00247 if (fPortRegistration) { 00248 fPortRegistration(value1, 0, fPortRegistrationArg); 00249 } 00250 break; 00251 00252 case kPortConnectCallback: 00253 jack_log("JackClient::kPortConnectCallback src = %ld dst = %ld", value1, value2); 00254 if (fPortConnect) { 00255 fPortConnect(value1, value2, 1, fPortConnectArg); 00256 } 00257 break; 00258 00259 case kPortDisconnectCallback: 00260 jack_log("JackClient::kPortDisconnectCallback src = %ld dst = %ld", value1, value2); 00261 if (fPortConnect) { 00262 fPortConnect(value1, value2, 0, fPortConnectArg); 00263 } 00264 break; 00265 00266 case kPortRenameCallback: 00267 jack_log("JackClient::kPortRenameCallback port = %ld", value1); 00268 if (fPortRename) { 00269 fPortRename(value1, message, GetGraphManager()->GetPort(value1)->GetName(), fPortRenameArg); 00270 } 00271 break; 00272 00273 case kXRunCallback: 00274 jack_log("JackClient::kXRunCallback"); 00275 if (fXrun) { 00276 res = fXrun(fXrunArg); 00277 } 00278 break; 00279 00280 case kShutDownCallback: 00281 jack_log("JackClient::kShutDownCallback"); 00282 if (fInfoShutdown) { 00283 fInfoShutdown((jack_status_t)value1, message, fInfoShutdownArg); 00284 fInfoShutdown = NULL; 00285 } 00286 break; 00287 00288 case kSessionCallback: 00289 jack_log("JackClient::kSessionCallback"); 00290 if (fSession) { 00291 jack_session_event_t* event = (jack_session_event_t*)malloc( sizeof(jack_session_event_t)); 00292 char uuid_buf[JACK_UUID_SIZE]; 00293 event->type = (jack_session_event_type_t)value1; 00294 event->session_dir = strdup(message); 00295 event->command_line = NULL; 00296 event->flags = (jack_session_flags_t)0; 00297 snprintf(uuid_buf, sizeof(uuid_buf), "%d", GetClientControl()->fSessionID); 00298 event->client_uuid = strdup(uuid_buf); 00299 fSessionReply = kPendingSessionReply; 00300 // Session callback may change fSessionReply by directly using jack_session_reply 00301 fSession(event, fSessionArg); 00302 res = fSessionReply; 00303 } 00304 break; 00305 00306 case kLatencyCallback: 00307 res = HandleLatencyCallback(value1); 00308 break; 00309 } 00310 } 00311 00312 return res; 00313 } 00314 00315 int JackClient::HandleLatencyCallback(int status) 00316 { 00317 jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency; 00318 jack_latency_range_t latency = { UINT32_MAX, 0 }; 00319 00320 /* first setup all latency values of the ports. 00321 * this is based on the connections of the ports. 00322 */ 00323 list<jack_port_id_t>::iterator it; 00324 00325 for (it = fPortList.begin(); it != fPortList.end(); it++) { 00326 JackPort* port = GetGraphManager()->GetPort(*it); 00327 if ((port->GetFlags() & JackPortIsOutput) && (mode == JackPlaybackLatency)) { 00328 GetGraphManager()->RecalculateLatency(*it, mode); 00329 } 00330 if ((port->GetFlags() & JackPortIsInput) && (mode == JackCaptureLatency)) { 00331 GetGraphManager()->RecalculateLatency(*it, mode); 00332 } 00333 } 00334 00335 if (!fLatency) { 00336 /* 00337 * default action is to assume all ports depend on each other. 00338 * then always take the maximum latency. 00339 */ 00340 00341 if (mode == JackPlaybackLatency) { 00342 /* iterate over all OutputPorts, to find maximum playback latency 00343 */ 00344 for (it = fPortList.begin(); it != fPortList.end(); it++) { 00345 JackPort* port = GetGraphManager()->GetPort(*it); 00346 if (port->GetFlags() & JackPortIsOutput) { 00347 jack_latency_range_t other_latency; 00348 port->GetLatencyRange(mode, &other_latency); 00349 if (other_latency.max > latency.max) 00350 latency.max = other_latency.max; 00351 if (other_latency.min < latency.min) 00352 latency.min = other_latency.min; 00353 } 00354 } 00355 00356 if (latency.min == UINT32_MAX) 00357 latency.min = 0; 00358 00359 /* now set the found latency on all input ports 00360 */ 00361 for (it = fPortList.begin(); it != fPortList.end(); it++) { 00362 JackPort* port = GetGraphManager()->GetPort(*it); 00363 if (port->GetFlags() & JackPortIsInput) { 00364 port->SetLatencyRange(mode, &latency); 00365 } 00366 } 00367 } 00368 if (mode == JackCaptureLatency) { 00369 /* iterate over all InputPorts, to find maximum playback latency 00370 */ 00371 for (it = fPortList.begin(); it != fPortList.end(); it++) { 00372 JackPort* port = GetGraphManager()->GetPort(*it); 00373 if (port->GetFlags() & JackPortIsInput) { 00374 jack_latency_range_t other_latency; 00375 port->GetLatencyRange(mode, &other_latency); 00376 if (other_latency.max > latency.max) 00377 latency.max = other_latency.max; 00378 if (other_latency.min < latency.min) 00379 latency.min = other_latency.min; 00380 } 00381 } 00382 00383 if (latency.min == UINT32_MAX) 00384 latency.min = 0; 00385 00386 /* now set the found latency on all output ports 00387 */ 00388 for (it = fPortList.begin(); it != fPortList.end(); it++) { 00389 JackPort* port = GetGraphManager()->GetPort(*it); 00390 if (port->GetFlags() & JackPortIsOutput) { 00391 port->SetLatencyRange(mode, &latency); 00392 } 00393 } 00394 } 00395 return 0; 00396 } 00397 00398 /* we have a latency callback setup by the client, 00399 * lets use it... 00400 */ 00401 fLatency(mode, fLatencyArg); 00402 return 0; 00403 } 00404 00409 int JackClient::Activate() 00410 { 00411 jack_log("JackClient::Activate"); 00412 if (IsActive()) 00413 return 0; 00414 00415 // RT thread is started only when needed... 00416 if (IsRealTime()) { 00417 if (StartThread() < 0) 00418 return -1; 00419 } 00420 00421 /* 00422 Insertion of client in the graph will cause a kGraphOrderCallback notification 00423 to be delivered by the server, the client wants to receive it. 00424 */ 00425 GetClientControl()->fActive = true; 00426 00427 // Transport related callback become "active" 00428 GetClientControl()->fTransportSync = true; 00429 GetClientControl()->fTransportTimebase = true; 00430 00431 int result = -1; 00432 GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); 00433 fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); 00434 return result; 00435 } 00436 00440 int JackClient::Deactivate() 00441 { 00442 jack_log("JackClient::Deactivate"); 00443 if (!IsActive()) 00444 return 0; 00445 00446 GetClientControl()->fActive = false; 00447 00448 // Transport related callback become "unactive" 00449 GetClientControl()->fTransportSync = false; 00450 GetClientControl()->fTransportTimebase = false; 00451 00452 // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate 00453 int result = -1; 00454 fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); 00455 jack_log("JackClient::Deactivate res = %ld", result); 00456 00457 // RT thread is stopped only when needed... 00458 if (IsRealTime()) 00459 fThread.Kill(); 00460 return result; 00461 } 00462 00463 //---------------------- 00464 // RT thread management 00465 //---------------------- 00466 00467 void JackClient::InitAux() 00468 { 00469 if (fInit) { 00470 jack_log("JackClient::Init calling client thread init callback"); 00471 fInit(fInitArg); 00472 } 00473 } 00474 00478 bool JackClient::Init() 00479 { 00480 /* 00481 Execute buffer_size callback. 00482 00483 Since StartThread uses fThread.StartSync, we are sure that buffer_size callback 00484 is executed before StartThread returns (and then IsActive will be true). 00485 So no RT callback can be called at the same time. 00486 */ 00487 jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", GetEngineControl()->fBufferSize); 00488 if (fBufferSize) { 00489 fBufferSize(GetEngineControl()->fBufferSize, fBufferSizeArg); 00490 } 00491 00492 // Init callback 00493 InitAux(); 00494 00495 // Setup context 00496 if (!jack_tls_set(JackGlobals::fRealTime, this)) 00497 jack_error("failed to set thread realtime key"); 00498 00499 if (GetEngineControl()->fRealTime) 00500 set_threaded_log_function(); 00501 00502 // Setup RT 00503 if (GetEngineControl()->fRealTime) { 00504 if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) { 00505 jack_error("JackClient::AcquireSelfRealTime error"); 00506 } 00507 } 00508 00509 return true; 00510 } 00511 00512 int JackClient::StartThread() 00513 { 00514 jack_log("JackClient::StartThread : period = %ld computation = %ld constraint = %ld", 00515 long(int64_t(GetEngineControl()->fPeriod) / 1000.0f), 00516 long(int64_t(GetEngineControl()->fComputation) / 1000.0f), 00517 long(int64_t(GetEngineControl()->fConstraint) / 1000.0f)); 00518 00519 // Will do "something" on OSX only... 00520 fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); 00521 00522 if (fThread.StartSync() < 0) { 00523 jack_error("Start thread error"); 00524 return -1; 00525 } 00526 00527 return 0; 00528 } 00529 00534 bool JackClient::Execute() 00535 { 00536 // Execute a dummy cycle to be sure thread has the correct properties 00537 DummyCycle(); 00538 00539 if (fThreadFun) { 00540 fThreadFun(fThreadFunArg); 00541 } else { 00542 ExecuteThread(); 00543 } 00544 return false; 00545 } 00546 00547 void JackClient::DummyCycle() 00548 { 00549 WaitSync(); 00550 SignalSync(); 00551 } 00552 00553 inline void JackClient::ExecuteThread() 00554 { 00555 while (true) { 00556 CycleWaitAux(); 00557 CycleSignalAux(CallProcessCallback()); 00558 } 00559 } 00560 00561 inline jack_nframes_t JackClient::CycleWaitAux() 00562 { 00563 if (!WaitSync()) 00564 Error(); // Terminates the thread 00565 CallSyncCallbackAux(); 00566 return GetEngineControl()->fBufferSize; 00567 } 00568 00569 inline void JackClient::CycleSignalAux(int status) 00570 { 00571 if (status == 0) 00572 CallTimebaseCallbackAux(); 00573 SignalSync(); 00574 if (status != 0) 00575 End(); // Terminates the thread 00576 } 00577 00578 jack_nframes_t JackClient::CycleWait() 00579 { 00580 return CycleWaitAux(); 00581 } 00582 00583 void JackClient::CycleSignal(int status) 00584 { 00585 CycleSignalAux(status); 00586 } 00587 00588 inline int JackClient::CallProcessCallback() 00589 { 00590 return (fProcess != NULL) ? fProcess(GetEngineControl()->fBufferSize, fProcessArg) : 0; 00591 } 00592 00593 inline bool JackClient::WaitSync() 00594 { 00595 // Suspend itself: wait on the input synchro 00596 if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) { 00597 jack_error("SuspendRefNum error"); 00598 return false; 00599 } else { 00600 return true; 00601 } 00602 } 00603 00604 inline void JackClient::SignalSync() 00605 { 00606 // Resume: signal output clients connected to the running client 00607 if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) { 00608 jack_error("ResumeRefNum error"); 00609 } 00610 } 00611 00612 inline void JackClient::End() 00613 { 00614 jack_log("JackClient::Execute end name = %s", GetClientControl()->fName); 00615 // Hum... not sure about this, the following "close" code is called in the RT thread... 00616 int result; 00617 fThread.DropSelfRealTime(); 00618 GetClientControl()->fActive = false; 00619 fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); 00620 fThread.Terminate(); 00621 } 00622 00623 inline void JackClient::Error() 00624 { 00625 jack_error("JackClient::Execute error name = %s", GetClientControl()->fName); 00626 // Hum... not sure about this, the following "close" code is called in the RT thread... 00627 int result; 00628 fThread.DropSelfRealTime(); 00629 GetClientControl()->fActive = false; 00630 fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); 00631 ShutDown(); 00632 fThread.Terminate(); 00633 } 00634 00635 //----------------- 00636 // Port management 00637 //----------------- 00638 00639 int JackClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size) 00640 { 00641 // Check if port name is empty 00642 string port_name_str = string(port_name); 00643 if (port_name_str.size() == 0) { 00644 jack_error("port_name is empty"); 00645 return 0; // Means failure here... 00646 } 00647 00648 // Check port name length 00649 string name = string(GetClientControl()->fName) + string(":") + port_name_str; 00650 if (name.size() >= REAL_JACK_PORT_NAME_SIZE) { 00651 jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n" 00652 "Please use %lu characters or less", 00653 GetClientControl()->fName, 00654 port_name, 00655 JACK_PORT_NAME_SIZE - 1); 00656 return 0; // Means failure here... 00657 } 00658 00659 int result = -1; 00660 jack_port_id_t port_index = NO_PORT; 00661 fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result); 00662 00663 if (result == 0) { 00664 jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, name.c_str(), port_type, port_index); 00665 fPortList.push_back(port_index); 00666 return port_index; 00667 } else { 00668 return 0; 00669 } 00670 } 00671 00672 int JackClient::PortUnRegister(jack_port_id_t port_index) 00673 { 00674 jack_log("JackClient::PortUnRegister port_index = %ld", port_index); 00675 list<jack_port_id_t>::iterator it = find(fPortList.begin(), fPortList.end(), port_index); 00676 00677 if (it != fPortList.end()) { 00678 fPortList.erase(it); 00679 int result = -1; 00680 fChannel->PortUnRegister(GetClientControl()->fRefNum, port_index, &result); 00681 return result; 00682 } else { 00683 jack_error("unregistering a port %ld that is not own by the client", port_index); 00684 return -1; 00685 } 00686 } 00687 00688 int JackClient::PortConnect(const char* src, const char* dst) 00689 { 00690 jack_log("JackClient::Connect src = %s dst = %s", src, dst); 00691 int result = -1; 00692 fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result); 00693 return result; 00694 } 00695 00696 int JackClient::PortDisconnect(const char* src, const char* dst) 00697 { 00698 jack_log("JackClient::Disconnect src = %s dst = %s", src, dst); 00699 int result = -1; 00700 fChannel->PortDisconnect(GetClientControl()->fRefNum, src, dst, &result); 00701 return result; 00702 } 00703 00704 int JackClient::PortDisconnect(jack_port_id_t src) 00705 { 00706 jack_log("JackClient::PortDisconnect src = %ld", src); 00707 int result = -1; 00708 fChannel->PortDisconnect(GetClientControl()->fRefNum, src, ALL_PORTS, &result); 00709 return result; 00710 } 00711 00712 int JackClient::PortIsMine(jack_port_id_t port_index) 00713 { 00714 JackPort* port = GetGraphManager()->GetPort(port_index); 00715 return GetClientControl()->fRefNum == port->GetRefNum(); 00716 } 00717 00718 int JackClient::PortRename(jack_port_id_t port_index, const char* name) 00719 { 00720 int result = -1; 00721 fChannel->PortRename(GetClientControl()->fRefNum, port_index, name, &result); 00722 return result; 00723 } 00724 00725 //-------------------- 00726 // Context management 00727 //-------------------- 00728 00729 int JackClient::SetBufferSize(jack_nframes_t buffer_size) 00730 { 00731 int result = -1; 00732 fChannel->SetBufferSize(buffer_size, &result); 00733 return result; 00734 } 00735 00736 int JackClient::SetFreeWheel(int onoff) 00737 { 00738 int result = -1; 00739 fChannel->SetFreewheel(onoff, &result); 00740 return result; 00741 } 00742 00743 int JackClient::ComputeTotalLatencies() 00744 { 00745 int result = -1; 00746 fChannel->ComputeTotalLatencies(&result); 00747 return result; 00748 } 00749 00750 /* 00751 ShutDown is called: 00752 - from the RT thread when Execute method fails 00753 - possibly from a "closed" notification channel 00754 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown)) 00755 */ 00756 00757 void JackClient::ShutDown() 00758 { 00759 jack_log("JackClient::ShutDown"); 00760 JackGlobals::fServerRunning = false; 00761 00762 if (fInfoShutdown) { 00763 fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); 00764 fInfoShutdown = NULL; 00765 } else if (fShutdown) { 00766 fShutdown(fShutdownArg); 00767 fShutdown = NULL; 00768 } 00769 } 00770 00771 //---------------------- 00772 // Transport management 00773 //---------------------- 00774 00775 inline int JackClient::ActivateAux() 00776 { 00777 // If activated without RT thread... 00778 if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { 00779 00780 jack_log("JackClient::ActivateAux"); 00781 00782 // RT thread is started 00783 if (StartThread() < 0) 00784 return -1; 00785 00786 int result = -1; 00787 GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); 00788 fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); 00789 return result; 00790 00791 } else { 00792 return 0; 00793 } 00794 } 00795 00796 int JackClient::ReleaseTimebase() 00797 { 00798 int result = -1; 00799 fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result); 00800 if (result == 0) { 00801 GetClientControl()->fTransportTimebase = false; 00802 fTimebase = NULL; 00803 fTimebaseArg = NULL; 00804 } 00805 return result; 00806 } 00807 00808 /* Call the server if the client is active, otherwise keeps the arguments */ 00809 int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg) 00810 { 00811 GetClientControl()->fTransportSync = (fSync != NULL); 00812 fSyncArg = arg; 00813 fSync = sync_callback; 00814 return ActivateAux(); 00815 } 00816 00817 int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) 00818 { 00819 int result = -1; 00820 fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); 00821 00822 if (result == 0) { 00823 GetClientControl()->fTransportTimebase = true; 00824 fTimebase = timebase_callback; 00825 fTimebaseArg = arg; 00826 return ActivateAux(); 00827 } else { 00828 fTimebase = NULL; 00829 fTimebaseArg = NULL; 00830 return -1; 00831 } 00832 } 00833 00834 int JackClient::SetSyncTimeout(jack_time_t timeout) 00835 { 00836 GetEngineControl()->fTransport.SetSyncTimeout(timeout); 00837 return 0; 00838 } 00839 00840 // Must be RT safe 00841 00842 void JackClient::TransportLocate(jack_nframes_t frame) 00843 { 00844 jack_position_t pos; 00845 pos.frame = frame; 00846 pos.valid = (jack_position_bits_t)0; 00847 jack_log("JackClient::TransportLocate pos = %ld", pos.frame); 00848 GetEngineControl()->fTransport.RequestNewPos(&pos); 00849 } 00850 00851 int JackClient::TransportReposition(const jack_position_t* pos) 00852 { 00853 jack_position_t tmp = *pos; 00854 jack_log("JackClient::TransportReposition pos = %ld", pos->frame); 00855 if (tmp.valid & ~JACK_POSITION_MASK) { 00856 return EINVAL; 00857 } else { 00858 GetEngineControl()->fTransport.RequestNewPos(&tmp); 00859 return 0; 00860 } 00861 } 00862 00863 jack_transport_state_t JackClient::TransportQuery(jack_position_t* pos) 00864 { 00865 return GetEngineControl()->fTransport.Query(pos); 00866 } 00867 00868 jack_nframes_t JackClient::GetCurrentTransportFrame() 00869 { 00870 return GetEngineControl()->fTransport.GetCurrentFrame(); 00871 } 00872 00873 // Must be RT safe: directly write in the transport shared mem 00874 void JackClient::TransportStart() 00875 { 00876 GetEngineControl()->fTransport.SetCommand(TransportCommandStart); 00877 } 00878 00879 // Must be RT safe: directly write in the transport shared mem 00880 void JackClient::TransportStop() 00881 { 00882 GetEngineControl()->fTransport.SetCommand(TransportCommandStop); 00883 } 00884 00885 // Never called concurently with the server 00886 // TODO check concurrency with SetSyncCallback 00887 00888 void JackClient::CallSyncCallback() 00889 { 00890 CallSyncCallbackAux(); 00891 } 00892 00893 inline void JackClient::CallSyncCallbackAux() 00894 { 00895 if (GetClientControl()->fTransportSync) { 00896 00897 JackTransportEngine& transport = GetEngineControl()->fTransport; 00898 jack_position_t* cur_pos = transport.ReadCurrentState(); 00899 jack_transport_state_t transport_state = transport.GetState(); 00900 00901 if (fSync != NULL) { 00902 if (fSync(transport_state, cur_pos, fSyncArg)) { 00903 GetClientControl()->fTransportState = JackTransportRolling; 00904 GetClientControl()->fTransportSync = false; 00905 } 00906 } else { 00907 GetClientControl()->fTransportState = JackTransportRolling; 00908 GetClientControl()->fTransportSync = false; 00909 } 00910 } 00911 } 00912 00913 void JackClient::CallTimebaseCallback() 00914 { 00915 CallTimebaseCallbackAux(); 00916 } 00917 00918 inline void JackClient::CallTimebaseCallbackAux() 00919 { 00920 JackTransportEngine& transport = GetEngineControl()->fTransport; 00921 int master; 00922 bool unused; 00923 00924 transport.GetTimebaseMaster(master, unused); 00925 00926 if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... 00927 00928 jack_transport_state_t transport_state = transport.GetState(); 00929 jack_position_t* cur_pos = transport.WriteNextStateStart(1); 00930 00931 if (GetClientControl()->fTransportTimebase) { 00932 fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); 00933 GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true 00934 } else if (transport_state == JackTransportRolling) { 00935 fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); 00936 } 00937 00938 transport.WriteNextStateStop(1); 00939 } 00940 } 00941 00942 //--------------------- 00943 // Callback management 00944 //--------------------- 00945 00946 void JackClient::OnShutdown(JackShutdownCallback callback, void *arg) 00947 { 00948 if (IsActive()) { 00949 jack_error("You cannot set callbacks on an active client"); 00950 } else { 00951 fShutdownArg = arg; 00952 fShutdown = callback; 00953 } 00954 } 00955 00956 void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) 00957 { 00958 if (IsActive()) { 00959 jack_error("You cannot set callbacks on an active client"); 00960 } else { 00961 GetClientControl()->fCallback[kShutDownCallback] = (callback != NULL); 00962 fInfoShutdownArg = arg; 00963 fInfoShutdown = callback; 00964 } 00965 } 00966 00967 int JackClient::SetProcessCallback(JackProcessCallback callback, void *arg) 00968 { 00969 if (IsActive()) { 00970 jack_error("You cannot set callbacks on an active client"); 00971 return -1; 00972 } else if (fThreadFun) { 00973 jack_error ("A thread callback has already been setup, both models cannot be used at the same time!"); 00974 return -1; 00975 } else { 00976 fProcessArg = arg; 00977 fProcess = callback; 00978 return 0; 00979 } 00980 } 00981 00982 int JackClient::SetXRunCallback(JackXRunCallback callback, void *arg) 00983 { 00984 if (IsActive()) { 00985 jack_error("You cannot set callbacks on an active client"); 00986 return -1; 00987 } else { 00988 GetClientControl()->fCallback[kXRunCallback] = (callback != NULL); 00989 fXrunArg = arg; 00990 fXrun = callback; 00991 return 0; 00992 } 00993 } 00994 00995 int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg) 00996 { 00997 if (IsActive()) { 00998 jack_error("You cannot set callbacks on an active client"); 00999 return -1; 01000 } else { 01001 fInitArg = arg; 01002 fInit = callback; 01003 /* make sure that the message buffer thread is initialized too */ 01004 JackMessageBuffer::fInstance->SetInitCallback(callback, arg); 01005 return 0; 01006 } 01007 } 01008 01009 int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) 01010 { 01011 if (IsActive()) { 01012 jack_error("You cannot set callbacks on an active client"); 01013 return -1; 01014 } else { 01015 GetClientControl()->fCallback[kGraphOrderCallback] = (callback != NULL); 01016 fGraphOrder = callback; 01017 fGraphOrderArg = arg; 01018 return 0; 01019 } 01020 } 01021 01022 int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg) 01023 { 01024 if (IsActive()) { 01025 jack_error("You cannot set callbacks on an active client"); 01026 return -1; 01027 } else { 01028 GetClientControl()->fCallback[kBufferSizeCallback] = (callback != NULL); 01029 fBufferSizeArg = arg; 01030 fBufferSize = callback; 01031 return 0; 01032 } 01033 } 01034 01035 int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg) 01036 { 01037 if (IsActive()) { 01038 jack_error("You cannot set callbacks on an active client"); 01039 return -1; 01040 } else { 01041 GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); 01042 fSampleRateArg = arg; 01043 fSampleRate = callback; 01044 // Now invoke it 01045 if (callback) 01046 callback(GetEngineControl()->fSampleRate, arg); 01047 return 0; 01048 } 01049 } 01050 01051 int JackClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback, void* arg) 01052 { 01053 if (IsActive()) { 01054 jack_error("You cannot set callbacks on an active client"); 01055 return -1; 01056 } else { 01057 // kAddClient and kRemoveClient notifications must be delivered by the server in any case 01058 fClientRegistrationArg = arg; 01059 fClientRegistration = callback; 01060 return 0; 01061 } 01062 } 01063 01064 int JackClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg) 01065 { 01066 if (IsActive()) { 01067 jack_error("You cannot set callbacks on an active client"); 01068 return -1; 01069 } else { 01070 GetClientControl()->fCallback[kStartFreewheelCallback] = (callback != NULL); 01071 GetClientControl()->fCallback[kStopFreewheelCallback] = (callback != NULL); 01072 fFreewheelArg = arg; 01073 fFreewheel = callback; 01074 return 0; 01075 } 01076 } 01077 01078 int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg) 01079 { 01080 if (IsActive()) { 01081 jack_error("You cannot set callbacks on an active client"); 01082 return -1; 01083 } else { 01084 GetClientControl()->fCallback[kPortRegistrationOnCallback] = (callback != NULL); 01085 GetClientControl()->fCallback[kPortRegistrationOffCallback] = (callback != NULL); 01086 fPortRegistrationArg = arg; 01087 fPortRegistration = callback; 01088 return 0; 01089 } 01090 } 01091 01092 int JackClient::SetPortConnectCallback(JackPortConnectCallback callback, void *arg) 01093 { 01094 if (IsActive()) { 01095 jack_error("You cannot set callbacks on an active client"); 01096 return -1; 01097 } else { 01098 GetClientControl()->fCallback[kPortConnectCallback] = (callback != NULL); 01099 GetClientControl()->fCallback[kPortDisconnectCallback] = (callback != NULL); 01100 fPortConnectArg = arg; 01101 fPortConnect = callback; 01102 return 0; 01103 } 01104 } 01105 01106 int JackClient::SetPortRenameCallback(JackPortRenameCallback callback, void *arg) 01107 { 01108 if (IsActive()) { 01109 jack_error("You cannot set callbacks on an active client"); 01110 return -1; 01111 } else { 01112 GetClientControl()->fCallback[kPortRenameCallback] = (callback != NULL); 01113 fPortRenameArg = arg; 01114 fPortRename = callback; 01115 return 0; 01116 } 01117 } 01118 01119 int JackClient::SetProcessThread(JackThreadCallback fun, void *arg) 01120 { 01121 if (IsActive()) { 01122 jack_error("You cannot set callbacks on an active client"); 01123 return -1; 01124 } else if (fProcess) { 01125 jack_error ("A process callback has already been setup, both models cannot be used at the same time!"); 01126 return -1; 01127 } else { 01128 fThreadFun = fun; 01129 fThreadFunArg = arg; 01130 return 0; 01131 } 01132 } 01133 01134 int JackClient::SetSessionCallback(JackSessionCallback callback, void *arg) 01135 { 01136 if (IsActive()) { 01137 jack_error("You cannot set callbacks on an active client"); 01138 return -1; 01139 } else { 01140 GetClientControl()->fCallback[kSessionCallback] = (callback != NULL); 01141 fSessionArg = arg; 01142 fSession = callback; 01143 return 0; 01144 } 01145 } 01146 01147 int JackClient::SetLatencyCallback(JackLatencyCallback callback, void *arg) 01148 { 01149 if (IsActive()) { 01150 jack_error("You cannot set callbacks on an active client"); 01151 return -1; 01152 } else { 01153 // fCallback[kLatencyCallback] must always be 'true' 01154 fLatencyArg = arg; 01155 fLatency = callback; 01156 return 0; 01157 } 01158 } 01159 01160 //------------------ 01161 // Internal clients 01162 //------------------ 01163 01164 char* JackClient::GetInternalClientName(int ref) 01165 { 01166 char name_res[JACK_CLIENT_NAME_SIZE + 1]; 01167 int result = -1; 01168 fChannel->GetInternalClientName(GetClientControl()->fRefNum, ref, name_res, &result); 01169 return (result < 0) ? NULL : strdup(name_res); 01170 } 01171 01172 int JackClient::InternalClientHandle(const char* client_name, jack_status_t* status) 01173 { 01174 int int_ref, result = -1; 01175 fChannel->InternalClientHandle(GetClientControl()->fRefNum, client_name, (int*)status, &int_ref, &result); 01176 return int_ref; 01177 } 01178 01179 int JackClient::InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va) 01180 { 01181 if (strlen(client_name) >= JACK_CLIENT_NAME_SIZE) { 01182 jack_error ("\"%s\" is too long for a JACK client name.\n" 01183 "Please use %lu characters or less.", 01184 client_name, JACK_CLIENT_NAME_SIZE); 01185 return 0; 01186 } 01187 01188 if (va->load_name && (strlen(va->load_name) >= JACK_PATH_MAX)) { 01189 jack_error("\"%s\" is too long for a shared object name.\n" 01190 "Please use %lu characters or less.", 01191 va->load_name, JACK_PATH_MAX); 01192 int my_status1 = *status | (JackFailure | JackInvalidOption); 01193 *status = (jack_status_t)my_status1; 01194 return 0; 01195 } 01196 01197 if (va->load_init && (strlen(va->load_init) >= JACK_LOAD_INIT_LIMIT)) { 01198 jack_error ("\"%s\" is too long for internal client init " 01199 "string.\nPlease use %lu characters or less.", 01200 va->load_init, JACK_LOAD_INIT_LIMIT); 01201 int my_status1 = *status | (JackFailure | JackInvalidOption); 01202 *status = (jack_status_t)my_status1; 01203 return 0; 01204 } 01205 01206 int int_ref, result = -1; 01207 fChannel->InternalClientLoad(GetClientControl()->fRefNum, client_name, va->load_name, va->load_init, options, (int*)status, &int_ref, -1, &result); 01208 return int_ref; 01209 } 01210 01211 void JackClient::InternalClientUnload(int ref, jack_status_t* status) 01212 { 01213 int result = -1; 01214 fChannel->InternalClientUnload(GetClientControl()->fRefNum, ref, (int*)status, &result); 01215 } 01216 01217 //------------------ 01218 // Session API 01219 //------------------ 01220 01221 jack_session_command_t* JackClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path) 01222 { 01223 jack_session_command_t* res; 01224 fChannel->SessionNotify(GetClientControl()->fRefNum, target, type, path, &res); 01225 return res; 01226 } 01227 01228 int JackClient::SessionReply(jack_session_event_t* ev) 01229 { 01230 if (ev->command_line) { 01231 strncpy(GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand)); 01232 } else { 01233 GetClientControl()->fSessionCommand[0] = '\0'; 01234 } 01235 01236 GetClientControl()->fSessionFlags = ev->flags; 01237 01238 jack_log("JackClient::SessionReply... we are here"); 01239 if (fChannel->IsChannelThread()) { 01240 jack_log("JackClient::SessionReply... in callback reply"); 01241 // OK, immediate reply... 01242 fSessionReply = kImmediateSessionReply; 01243 return 0; 01244 } 01245 01246 jack_log("JackClient::SessionReply... out of cb"); 01247 01248 int result = -1; 01249 fChannel->SessionReply(GetClientControl()->fRefNum, &result); 01250 return result; 01251 } 01252 01253 char* JackClient::GetUUIDForClientName(const char* client_name) 01254 { 01255 char uuid_res[JACK_UUID_SIZE]; 01256 int result = -1; 01257 fChannel->GetUUIDForClientName(GetClientControl()->fRefNum, client_name, uuid_res, &result); 01258 return (result) ? NULL : strdup(uuid_res); 01259 } 01260 01261 char* JackClient::GetClientNameByUUID(const char* uuid) 01262 { 01263 char name_res[JACK_CLIENT_NAME_SIZE + 1]; 01264 int result = -1; 01265 fChannel->GetClientNameForUUID(GetClientControl()->fRefNum, uuid, name_res, &result); 01266 return (result) ? NULL : strdup(name_res); 01267 } 01268 01269 int JackClient::ReserveClientName(const char* client_name, const char* uuid) 01270 { 01271 int result = -1; 01272 fChannel->ReserveClientName( GetClientControl()->fRefNum, client_name, uuid, &result); 01273 return result; 01274 } 01275 01276 int JackClient::ClientHasSessionCallback(const char* client_name) 01277 { 01278 int result = -1; 01279 fChannel->ClientHasSessionCallback(client_name, &result); 01280 return result; 01281 } 01282 01283 } // end of namespace 01284