Jack2 1.9.7

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 
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 

Generated for Jack2 by doxygen 1.7.3