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