Jack2 1.9.8

JackClient.cpp

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