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