Jack2 1.9.6

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 "JackClient.h"
00022 #include "JackGraphManager.h"
00023 #include "JackClientControl.h"
00024 #include "JackEngineControl.h"
00025 #include "JackGlobals.h"
00026 #include "JackChannel.h"
00027 #include "JackTransportEngine.h"
00028 #include "driver_interface.h"
00029 #include "JackLibGlobals.h"
00030 
00031 #include <math.h>
00032 #include <string>
00033 #include <algorithm>
00034 
00035 using namespace std;
00036 
00037 namespace Jack
00038 {
00039 
00040 #define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL))
00041 
00042 JackClient::JackClient():fThread(this)
00043 {}
00044 
00045 JackClient::JackClient(JackSynchro* table):fThread(this)
00046 {
00047     fSynchroTable = table;
00048     fProcess = NULL;
00049     fGraphOrder = NULL;
00050     fXrun = NULL;
00051     fShutdown = NULL;
00052     fInfoShutdown = NULL;
00053     fInit = NULL;
00054     fBufferSize = NULL;
00055     fClientRegistration = NULL;
00056     fFreewheel = NULL;
00057     fPortRegistration = NULL;
00058     fPortConnect = NULL;
00059     fPortRename = NULL;
00060     fTimebase = NULL;
00061     fSync = NULL;
00062     fThreadFun = NULL;
00063     fProcessArg = NULL;
00064     fGraphOrderArg = NULL;
00065     fXrunArg = NULL;
00066     fShutdownArg = NULL;
00067     fInfoShutdownArg = NULL;
00068     fInitArg = NULL;
00069     fBufferSizeArg = NULL;
00070     fFreewheelArg = NULL;
00071     fClientRegistrationArg = NULL;
00072     fPortRegistrationArg = NULL;
00073     fPortConnectArg = NULL;
00074     fPortRenameArg = NULL;
00075     fSyncArg = NULL;
00076     fTimebaseArg = NULL;
00077     fThreadFunArg = NULL;
00078 }
00079 
00080 JackClient::~JackClient()
00081 {}
00082 
00083 int JackClient::Close()
00084 {
00085     jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum);
00086     int result = 0;
00087     
00088     Deactivate();
00089     fChannel->Stop();  // Channels is stopped first to avoid receiving notifications while closing
00090     
00091     // Request close only if server is still running
00092     if (JackGlobals::fServerRunning) {
00093         fChannel->ClientClose(GetClientControl()->fRefNum, &result);
00094     } else {
00095         jack_log("JackClient::Close server is shutdown"); 
00096     }
00097     
00098     fChannel->Close();
00099     fSynchroTable[GetClientControl()->fRefNum].Disconnect();
00100     JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL;
00101     return result;
00102 }
00103 
00104 bool JackClient::IsActive()
00105 {
00106     return (GetClientControl()) ? GetClientControl()->fActive : false;
00107 }
00108 
00109 pthread_t JackClient::GetThreadID()
00110 {
00111     return fThread.GetThreadID();
00112 }
00113 
00119 void JackClient::SetupDriverSync(bool freewheel)
00120 {
00121     if (!freewheel && !GetEngineControl()->fSyncMode) {
00122         jack_log("JackClient::SetupDriverSync driver sem in flush mode");
00123         for (int i = 0; i < GetEngineControl()->fDriverNum; i++) {
00124             fSynchroTable[i].SetFlush(true);
00125         }
00126     } else {
00127         jack_log("JackClient::SetupDriverSync driver sem in normal mode");
00128         for (int i = 0; i < GetEngineControl()->fDriverNum; i++)
00129             fSynchroTable[i].SetFlush(false);
00130     }
00131 }
00132 
00137 int JackClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
00138 {
00139     return 0;
00140 }
00141 
00142 int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
00143 {
00144     int res = 0;
00145 
00146     // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient
00147     switch (notify) {
00148 
00149         case kAddClient:
00150             res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2);
00151             break;
00152 
00153         case kRemoveClient:
00154             res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2);
00155             break;
00156 
00157         case kActivateClient:
00158             jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum);
00159             Init();
00160             break;
00161     }
00162 
00163     /*
00164     The current semantic is that notifications can only be received when the client has been activated,
00165     although is this implementation, one could imagine calling notifications as soon as the client has be opened.
00166     */
00167     if (IsActive()) {
00168 
00169         switch (notify) {
00170 
00171             case kAddClient:
00172                 jack_log("JackClient::kAddClient fName = %s name = %s", GetClientControl()->fName, name);
00173                 if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) {      // Don't call the callback for the registering client itself
00174                     fClientRegistration(name, 1, fClientRegistrationArg);
00175                 }
00176                 break;
00177 
00178             case kRemoveClient:
00179                 jack_log("JackClient::kRemoveClient fName = %s name = %s", GetClientControl()->fName, name);
00180                 if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself
00181                     fClientRegistration(name, 0, fClientRegistrationArg);
00182                 }
00183                 break;
00184 
00185             case kBufferSizeCallback:
00186                 jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", value1);
00187                 if (fBufferSize) {
00188                     res = fBufferSize(value1, fBufferSizeArg);
00189                 }
00190                 break;
00191                 
00192             case kSampleRateCallback:
00193                 jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1);
00194                 if (fSampleRate) {
00195                     res = fSampleRate(value1, fSampleRateArg);
00196                 }
00197                 break;
00198 
00199             case kGraphOrderCallback:
00200                 jack_log("JackClient::kGraphOrderCallback");
00201                 if (fGraphOrder) {
00202                     res = fGraphOrder(fGraphOrderArg);
00203                 }
00204                 break;
00205 
00206             case kStartFreewheelCallback:
00207                 jack_log("JackClient::kStartFreewheel");
00208                 SetupDriverSync(true);
00209                 fThread.DropRealTime();     // Always done (JACK server in RT mode or not...)
00210                 if (fFreewheel) {
00211                     fFreewheel(1, fFreewheelArg);
00212                 }
00213                 break;
00214 
00215             case kStopFreewheelCallback:
00216                 jack_log("JackClient::kStopFreewheel");
00217                 SetupDriverSync(false);
00218                 if (fFreewheel) {
00219                     fFreewheel(0, fFreewheelArg);
00220                 }
00221                 if (GetEngineControl()->fRealTime) {
00222                     fThread.AcquireRealTime();
00223                 }
00224                 break;
00225 
00226             case kPortRegistrationOnCallback:
00227                 jack_log("JackClient::kPortRegistrationOn port_index = %ld", value1);
00228                 if (fPortRegistration) {
00229                     fPortRegistration(value1, 1, fPortRegistrationArg);
00230                 }
00231                 break;
00232 
00233             case kPortRegistrationOffCallback:
00234                 jack_log("JackClient::kPortRegistrationOff port_index = %ld ", value1);
00235                 if (fPortRegistration) {
00236                     fPortRegistration(value1, 0, fPortRegistrationArg);
00237                 }
00238                 break;
00239 
00240             case kPortConnectCallback:
00241                 jack_log("JackClient::kPortConnectCallback src = %ld dst = %ld", value1, value2);
00242                 if (fPortConnect) {
00243                     fPortConnect(value1, value2, 1, fPortConnectArg);
00244                 }
00245                 break;
00246 
00247             case kPortDisconnectCallback:
00248                 jack_log("JackClient::kPortDisconnectCallback src = %ld dst = %ld", value1, value2);
00249                 if (fPortConnect) {
00250                     fPortConnect(value1, value2, 0, fPortConnectArg);
00251                 }
00252                 break;
00253                 
00254              case kPortRenameCallback:
00255                 jack_log("JackClient::kPortRenameCallback port = %ld", value1);
00256                 if (fPortRename) {
00257                     fPortRename(value1, message, GetGraphManager()->GetPort(value1)->GetName(), fPortRenameArg);
00258                 }
00259                 break;
00260 
00261             case kXRunCallback:
00262                 jack_log("JackClient::kXRunCallback");
00263                 if (fXrun) {
00264                     res = fXrun(fXrunArg);
00265                 }
00266                 break;
00267                 
00268             case kShutDownCallback:
00269                 jack_log("JackClient::kShutDownCallback");
00270                 if (fInfoShutdown) {
00271                     fInfoShutdown((jack_status_t)value1, message, fInfoShutdownArg);
00272                     fInfoShutdown = NULL;
00273                 }
00274                 break;
00275         }
00276     }
00277 
00278     return res;
00279 }
00280 
00285 int JackClient::Activate()
00286 {
00287     jack_log("JackClient::Activate");
00288     if (IsActive())
00289         return 0;
00290 
00291     // RT thread is started only when needed...
00292     if (IsRealTime()) {
00293         if (StartThread() < 0)
00294             return -1;
00295     }
00296     
00297     /*
00298     Insertion of client in the graph will cause a kGraphOrderCallback notification 
00299     to be delivered by the server, the client wants to receive it.
00300     */
00301     GetClientControl()->fActive = true;
00302     
00303     // Transport related callback become "active"
00304     GetClientControl()->fTransportSync = true;
00305     GetClientControl()->fTransportTimebase = true;
00306 
00307     int result = -1;
00308     GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime();
00309     fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result);
00310     return result;
00311 }
00312 
00316 int JackClient::Deactivate()
00317 {
00318     jack_log("JackClient::Deactivate");
00319     if (!IsActive())
00320         return 0;
00321 
00322     GetClientControl()->fActive = false;
00323     
00324     // Transport related callback become "unactive"
00325     GetClientControl()->fTransportSync = false;
00326     GetClientControl()->fTransportTimebase = false;
00327     
00328     // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
00329     int result = -1;
00330     fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
00331     jack_log("JackClient::Deactivate res = %ld", result);
00332   
00333     // RT thread is stopped only when needed...
00334     if (IsRealTime()) 
00335         fThread.Kill();
00336     return result;
00337 }
00338 
00339 //----------------------
00340 // RT thread management
00341 //----------------------
00342 
00346 bool JackClient::Init()
00347 {
00348     if (fInit) {
00349         jack_log("JackClient::Init calling client thread init callback");
00350         fInit(fInitArg);
00351     }
00352     return true;
00353 }
00354 
00355 int JackClient::StartThread()
00356 {
00357     jack_log("JackClient::StartThread : period = %ld computation = %ld constraint = %ld",
00358              long(int64_t(GetEngineControl()->fPeriod) / 1000.0f),
00359              long(int64_t(GetEngineControl()->fComputation) / 1000.0f),
00360              long(int64_t(GetEngineControl()->fConstraint) / 1000.0f));
00361 
00362     // Will do "something" on OSX only...
00363     fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
00364 
00365     if (fThread.StartSync() < 0) {
00366         jack_error("Start thread error");
00367         return -1;
00368     }
00369 
00370     if (GetEngineControl()->fRealTime) {
00371         if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) {
00372             jack_error("AcquireRealTime error");
00373         }
00374     }
00375 
00376     return 0;
00377 }
00378 
00383 bool JackClient::Execute()
00384 {
00385     if (!jack_tls_set(JackGlobals::fRealTime, this)) 
00386         jack_error("failed to set thread realtime key");
00387         
00388     if (GetEngineControl()->fRealTime) 
00389         set_threaded_log_function(); 
00390         
00391     // Execute a dummy cycle to be sure thread has the correct properties
00392     DummyCycle();
00393       
00394     if (fThreadFun) {
00395         fThreadFun(fThreadFunArg);
00396     } else {
00397         ExecuteThread();
00398     }
00399     return false; 
00400 }
00401 
00402 void JackClient::DummyCycle()
00403 {
00404     WaitSync();
00405     SignalSync();
00406 }
00407 
00408 inline void JackClient::ExecuteThread()
00409 {
00410     while (true) { 
00411         CycleWaitAux();
00412         CycleSignalAux(CallProcessCallback());  
00413         }
00414 }
00415 
00416 inline jack_nframes_t JackClient::CycleWaitAux()
00417 {
00418     if (!WaitSync()) 
00419         Error();   // Terminates the thread
00420     CallSyncCallbackAux();
00421     return GetEngineControl()->fBufferSize;
00422 }
00423 
00424 inline void JackClient::CycleSignalAux(int status)
00425 {
00426     if (status == 0)
00427         CallTimebaseCallbackAux();
00428     SignalSync();
00429     if (status != 0) 
00430         End();     // Terminates the thread
00431 }
00432 
00433 jack_nframes_t JackClient::CycleWait()
00434 {
00435     return CycleWaitAux();
00436 }
00437 
00438 void JackClient::CycleSignal(int status)
00439 {
00440     CycleSignalAux(status);
00441 }
00442 
00443 inline int JackClient::CallProcessCallback()
00444 {
00445     return (fProcess != NULL) ? fProcess(GetEngineControl()->fBufferSize, fProcessArg) : 0;
00446 }
00447 
00448 inline bool JackClient::WaitSync()
00449 {
00450     // Suspend itself: wait on the input synchro
00451     if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) {
00452         jack_error("SuspendRefNum error");
00453         return false;
00454     } else {
00455         return true;
00456     }
00457 }
00458 
00459 inline void JackClient::SignalSync()
00460 {
00461     // Resume: signal output clients connected to the running client
00462     if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) {
00463         jack_error("ResumeRefNum error");
00464     }
00465 }
00466 
00467 inline void JackClient::End()
00468 {
00469     jack_log("JackClient::Execute end name = %s", GetClientControl()->fName);
00470     // Hum... not sure about this, the following "close" code is called in the RT thread...
00471     int result;
00472     fThread.DropSelfRealTime();
00473     GetClientControl()->fActive = false;
00474     fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
00475     fThread.Terminate();
00476 }
00477 
00478 inline void JackClient::Error()
00479 {
00480     jack_error("JackClient::Execute error name = %s", GetClientControl()->fName);
00481     // Hum... not sure about this, the following "close" code is called in the RT thread...
00482     int result;
00483     fThread.DropSelfRealTime();
00484     GetClientControl()->fActive = false;
00485     fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
00486     ShutDown();
00487     fThread.Terminate();
00488 }
00489 
00490 //-----------------
00491 // Port management
00492 //-----------------
00493 
00494 int JackClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
00495 {
00496     // Check if port name is empty
00497     string port_name_str = string(port_name);
00498     if (port_name_str.size() == 0) {
00499         jack_error("port_name is empty");
00500         return 0; // Means failure here...
00501     }
00502 
00503     // Check port name length
00504     string name = string(GetClientControl()->fName) + string(":") + port_name_str;
00505     if (name.size() >= JACK_PORT_NAME_SIZE) {
00506         jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n"
00507                    "Please use %lu characters or less",
00508                    GetClientControl()->fName,
00509                    port_name,
00510                    JACK_PORT_NAME_SIZE - 1);
00511         return 0; // Means failure here...
00512     }
00513 
00514     int result = -1;
00515     jack_port_id_t port_index = NO_PORT;
00516     fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result);
00517   
00518     if (result == 0) {
00519         jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, name.c_str(), port_type, port_index);
00520         fPortList.push_back(port_index);
00521         return port_index;
00522     } else {
00523         return 0;
00524     }
00525 }
00526 
00527 int JackClient::PortUnRegister(jack_port_id_t port_index)
00528 {
00529     jack_log("JackClient::PortUnRegister port_index = %ld", port_index);
00530     list<jack_port_id_t>::iterator it = find(fPortList.begin(), fPortList.end(), port_index);
00531 
00532     if (it != fPortList.end()) {
00533         fPortList.erase(it);
00534         int result = -1;
00535         fChannel->PortUnRegister(GetClientControl()->fRefNum, port_index, &result);
00536         return result;
00537     } else {
00538         jack_error("unregistering a port %ld that is not own by the client", port_index);
00539         return -1;
00540     }
00541 }
00542 
00543 int JackClient::PortConnect(const char* src, const char* dst)
00544 {
00545     jack_log("JackClient::Connect src = %s dst = %s", src, dst);
00546     int result = -1;
00547     fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result);
00548     return result;
00549 }
00550 
00551 int JackClient::PortDisconnect(const char* src, const char* dst)
00552 {
00553     jack_log("JackClient::Disconnect src = %s dst = %s", src, dst);
00554     int result = -1;
00555     fChannel->PortDisconnect(GetClientControl()->fRefNum, src, dst, &result);
00556     return result;
00557 }
00558 
00559 int JackClient::PortDisconnect(jack_port_id_t src)
00560 {
00561     jack_log("JackClient::PortDisconnect src = %ld", src);
00562     int result = -1;
00563     fChannel->PortDisconnect(GetClientControl()->fRefNum, src, ALL_PORTS, &result);
00564     return result;
00565 }
00566 
00567 int JackClient::PortIsMine(jack_port_id_t port_index)
00568 {
00569     JackPort* port = GetGraphManager()->GetPort(port_index);
00570     return GetClientControl()->fRefNum == port->GetRefNum();
00571 }
00572 
00573 int JackClient::PortRename(jack_port_id_t port_index, const char* name)
00574 {
00575     int result = -1;
00576     fChannel->PortRename(GetClientControl()->fRefNum, port_index, name, &result);
00577     return result;
00578 }
00579 
00580 //--------------------
00581 // Context management
00582 //--------------------
00583 
00584 int JackClient::SetBufferSize(jack_nframes_t buffer_size)
00585 {
00586     int result = -1;
00587     fChannel->SetBufferSize(buffer_size, &result);
00588     return result;
00589 }
00590 
00591 int JackClient::SetFreeWheel(int onoff)
00592 {
00593     int result = -1;
00594     fChannel->SetFreewheel(onoff, &result);
00595     return result;
00596 }
00597 
00598 /*
00599 ShutDown is called:
00600 - from the RT thread when Execute method fails
00601 - possibly from a "closed" notification channel
00602 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
00603 */
00604 
00605 void JackClient::ShutDown()
00606 {
00607     jack_log("ShutDown");
00608     JackGlobals::fServerRunning = false;
00609     
00610     if (fInfoShutdown) {
00611         fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg);
00612         fInfoShutdown = NULL;
00613     } else if (fShutdown) {
00614         fShutdown(fShutdownArg);
00615         fShutdown = NULL;
00616     }
00617 }
00618 
00619 //----------------------
00620 // Transport management
00621 //----------------------
00622 
00623 inline int JackClient::ActivateAux()
00624 {
00625     // If activated without RT thread...
00626     if (IsActive() && fThread.GetStatus() != JackThread::kRunning) {
00627     
00628         jack_log("ActivateAux");
00629     
00630         // RT thread is started
00631         if (StartThread() < 0)
00632             return -1;
00633         
00634         int result = -1;
00635         GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime();
00636         fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result);
00637         return result;
00638         
00639     } else {
00640         return 0;
00641     }
00642 }
00643 
00644 int JackClient::ReleaseTimebase()
00645 {
00646     int result = -1;
00647     fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result);
00648     if (result == 0) {
00649         GetClientControl()->fTransportTimebase = false;
00650         fTimebase = NULL;
00651         fTimebaseArg = NULL;
00652     }
00653     return result;
00654 }
00655 
00656 /* Call the server if the client is active, otherwise keeps the arguments */
00657 int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg)
00658 {
00659     GetClientControl()->fTransportSync = (fSync != NULL);
00660     fSyncArg = arg;
00661     fSync = sync_callback;
00662     return ActivateAux();
00663 }
00664 
00665 int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg)
00666 {
00667     int result = -1;
00668     fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result);
00669     
00670     if (result == 0) {
00671         GetClientControl()->fTransportTimebase = true;
00672         fTimebase = timebase_callback;
00673         fTimebaseArg = arg;
00674         return ActivateAux();
00675     } else {
00676         fTimebase = NULL;
00677         fTimebaseArg = NULL;
00678         return -1;
00679     }
00680 }
00681 
00682 int JackClient::SetSyncTimeout(jack_time_t timeout)
00683 {
00684     GetEngineControl()->fTransport.SetSyncTimeout(timeout);
00685     return 0;
00686 }
00687 
00688 // Must be RT safe
00689 
00690 void JackClient::TransportLocate(jack_nframes_t frame)
00691 {
00692     jack_position_t pos;
00693     pos.frame = frame;
00694     pos.valid = (jack_position_bits_t)0;
00695     jack_log("TransportLocate pos = %ld", pos.frame);
00696     GetEngineControl()->fTransport.RequestNewPos(&pos);
00697 }
00698 
00699 int JackClient::TransportReposition(jack_position_t* pos)
00700 {
00701     jack_position_t tmp = *pos;
00702     jack_log("TransportReposition pos = %ld", pos->frame);
00703     if (tmp.valid & ~JACK_POSITION_MASK) {
00704         return EINVAL;
00705     } else {
00706         GetEngineControl()->fTransport.RequestNewPos(pos);
00707         return 0;
00708     }
00709 }
00710 
00711 jack_transport_state_t JackClient::TransportQuery(jack_position_t* pos)
00712 {
00713     return GetEngineControl()->fTransport.Query(pos);
00714 }
00715 
00716 jack_nframes_t JackClient::GetCurrentTransportFrame()
00717 {
00718     return GetEngineControl()->fTransport.GetCurrentFrame();
00719 }
00720 
00721 // Must be RT safe: directly write in the transport shared mem
00722 void JackClient::TransportStart()
00723 {
00724     GetEngineControl()->fTransport.SetCommand(TransportCommandStart);
00725 }
00726 
00727 // Must be RT safe: directly write in the transport shared mem
00728 void JackClient::TransportStop()
00729 {
00730     GetEngineControl()->fTransport.SetCommand(TransportCommandStop);
00731 }
00732 
00733 // Never called concurently with the server
00734 // TODO check concurrency with SetSyncCallback
00735 
00736 void JackClient::CallSyncCallback()
00737 {
00738     CallSyncCallbackAux();
00739 }
00740 
00741 inline void JackClient::CallSyncCallbackAux()
00742 {
00743     if (GetClientControl()->fTransportSync) {
00744     
00745         JackTransportEngine& transport = GetEngineControl()->fTransport;
00746         jack_position_t* cur_pos = transport.ReadCurrentState();
00747         jack_transport_state_t transport_state = transport.GetState();
00748     
00749         if (fSync != NULL) {
00750             if (fSync(transport_state, cur_pos, fSyncArg)) {
00751                 GetClientControl()->fTransportState = JackTransportRolling;
00752                 GetClientControl()->fTransportSync = false;
00753             }
00754         } else {
00755             GetClientControl()->fTransportState = JackTransportRolling;
00756             GetClientControl()->fTransportSync = false;
00757         }
00758     }
00759 }
00760 
00761 void JackClient::CallTimebaseCallback()
00762 {
00763     CallTimebaseCallbackAux();
00764 }
00765 
00766 inline void JackClient::CallTimebaseCallbackAux()
00767 {
00768     JackTransportEngine& transport = GetEngineControl()->fTransport;
00769     int master;
00770     bool unused;
00771     
00772     transport.GetTimebaseMaster(master, unused);
00773     
00774     if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase...
00775     
00776         jack_transport_state_t transport_state = transport.GetState();
00777         jack_position_t* cur_pos = transport.WriteNextStateStart(1);
00778         
00779         if (GetClientControl()->fTransportTimebase) {
00780             fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); 
00781             GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true 
00782         } else if (transport_state == JackTransportRolling) {
00783             fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg);
00784         } 
00785         
00786         transport.WriteNextStateStop(1);
00787     }
00788 }
00789 
00790 //---------------------
00791 // Callback management
00792 //---------------------
00793 
00794 void JackClient::OnShutdown(JackShutdownCallback callback, void *arg)
00795 {
00796     if (IsActive()) {
00797         jack_error("You cannot set callbacks on an active client");
00798     } else {
00799         fShutdownArg = arg;
00800         fShutdown = callback;
00801     }
00802 }
00803     
00804 void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg)
00805 {
00806     if (IsActive()) {
00807         jack_error("You cannot set callbacks on an active client");
00808     } else {
00809         GetClientControl()->fCallback[kShutDownCallback] = (callback != NULL);
00810         fInfoShutdownArg = arg;
00811         fInfoShutdown = callback;
00812     }
00813 }
00814 
00815 int JackClient::SetProcessCallback(JackProcessCallback callback, void *arg)
00816 {
00817     if (IsActive()) {
00818         jack_error("You cannot set callbacks on an active client");
00819         return -1;
00820     } else if (fThreadFun) {
00821         jack_error ("A thread callback has already been setup, both models cannot be used at the same time!");
00822         return -1;
00823     } else {
00824         fProcessArg = arg;
00825         fProcess = callback;
00826         return 0;
00827     }
00828 }
00829 
00830 int JackClient::SetXRunCallback(JackXRunCallback callback, void *arg)
00831 {
00832     if (IsActive()) {
00833         jack_error("You cannot set callbacks on an active client");
00834         return -1;
00835     } else {
00836         GetClientControl()->fCallback[kXRunCallback] = (callback != NULL);
00837         fXrunArg = arg;
00838         fXrun = callback;
00839         return 0;
00840     }
00841 }
00842 
00843 int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg)
00844 {
00845     if (IsActive()) {
00846         jack_error("You cannot set callbacks on an active client");
00847         return -1;
00848     } else {
00849         fInitArg = arg;
00850         fInit = callback;
00851         /* make sure that the message buffer thread is initialized too */
00852         JackMessageBuffer::fInstance->SetInitCallback(callback, arg);
00853         return 0;
00854     }
00855 }
00856 
00857 int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
00858 {
00859     jack_log("SetGraphOrderCallback ");
00860 
00861     if (IsActive()) {
00862         jack_error("You cannot set callbacks on an active client");
00863         return -1;
00864     } else {
00865         GetClientControl()->fCallback[kGraphOrderCallback] = (callback != NULL);
00866         fGraphOrder = callback;
00867         fGraphOrderArg = arg;
00868         return 0;
00869     }
00870 }
00871 
00872 int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg)
00873 {
00874     if (IsActive()) {
00875         jack_error("You cannot set callbacks on an active client");
00876         return -1;
00877     } else {
00878         GetClientControl()->fCallback[kBufferSizeCallback] = (callback != NULL);
00879         fBufferSizeArg = arg;
00880         fBufferSize = callback;
00881         return 0;
00882     }
00883 }
00884 
00885 int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg)
00886 {
00887     if (IsActive()) {
00888         jack_error("You cannot set callbacks on an active client");
00889         return -1;
00890     } else {
00891         GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL);
00892         fSampleRateArg = arg;
00893         fSampleRate = callback;
00894         // Now invoke it 
00895         if (callback) 
00896             callback(GetEngineControl()->fSampleRate, arg);
00897         return 0;
00898     }
00899 }
00900 
00901 int JackClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback, void* arg)
00902 {
00903     if (IsActive()) {
00904         jack_error("You cannot set callbacks on an active client");
00905         return -1;
00906     } else {
00907         // kAddClient and kRemoveClient notifications must be delivered by the server in any case
00908         fClientRegistrationArg = arg;
00909         fClientRegistration = callback;
00910         return 0;
00911     }
00912 }
00913 
00914 int JackClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg)
00915 {
00916     if (IsActive()) {
00917         jack_error("You cannot set callbacks on an active client");
00918         return -1;
00919     } else {
00920         GetClientControl()->fCallback[kStartFreewheelCallback] = (callback != NULL);
00921         GetClientControl()->fCallback[kStopFreewheelCallback] = (callback != NULL);
00922         fFreewheelArg = arg;
00923         fFreewheel = callback;
00924         return 0;
00925     }
00926 }
00927 
00928 int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg)
00929 {
00930     if (IsActive()) {
00931         jack_error("You cannot set callbacks on an active client");
00932         return -1;
00933     } else {
00934         GetClientControl()->fCallback[kPortRegistrationOnCallback] = (callback != NULL);
00935         GetClientControl()->fCallback[kPortRegistrationOffCallback] = (callback != NULL);
00936         fPortRegistrationArg = arg;
00937         fPortRegistration = callback;
00938         return 0;
00939     }
00940 }
00941 
00942 int JackClient::SetPortConnectCallback(JackPortConnectCallback callback, void *arg)
00943 {
00944     if (IsActive()) {
00945         jack_error("You cannot set callbacks on an active client");
00946         return -1;
00947     } else {
00948         GetClientControl()->fCallback[kPortConnectCallback] = (callback != NULL);
00949         GetClientControl()->fCallback[kPortDisconnectCallback] = (callback != NULL);
00950         fPortConnectArg = arg;
00951         fPortConnect = callback;
00952         return 0;
00953     }
00954 }
00955 
00956 int JackClient::SetPortRenameCallback(JackPortRenameCallback callback, void *arg)
00957 {
00958     if (IsActive()) {
00959         jack_error("You cannot set callbacks on an active client");
00960         return -1;
00961     } else {
00962         GetClientControl()->fCallback[kPortRenameCallback] = (callback != NULL);
00963         fPortRenameArg = arg;
00964         fPortRename = callback;
00965         return 0;
00966     }
00967 }
00968 
00969 int JackClient::SetProcessThread(JackThreadCallback fun, void *arg)
00970 {
00971     if (IsActive()) {
00972         jack_error("You cannot set callbacks on an active client");
00973         return -1;
00974     } else if (fProcess) {
00975         jack_error ("A process callback has already been setup, both models cannot be used at the same time!");
00976         return -1;
00977     } else {
00978         fThreadFun = fun;
00979         fThreadFunArg = arg;
00980         return 0;
00981     }
00982 }
00983 
00984 //------------------
00985 // Internal clients
00986 //------------------
00987 
00988 char* JackClient::GetInternalClientName(int ref)
00989 {
00990     char name_res[JACK_CLIENT_NAME_SIZE + 1];
00991     int result = -1;
00992     fChannel->GetInternalClientName(GetClientControl()->fRefNum, ref, name_res, &result);
00993     return (result < 0) ? NULL : strdup(name_res);
00994 }
00995 
00996 int JackClient::InternalClientHandle(const char* client_name, jack_status_t* status)
00997 {
00998     int int_ref, result = -1;
00999     fChannel->InternalClientHandle(GetClientControl()->fRefNum, client_name, (int*)status, &int_ref, &result);
01000     return int_ref;
01001 }
01002 
01003 int JackClient::InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va)
01004 {
01005     if (strlen(client_name) >= JACK_CLIENT_NAME_SIZE) {
01006         jack_error ("\"%s\" is too long for a JACK client name.\n"
01007                     "Please use %lu characters or less.",
01008                     client_name, JACK_CLIENT_NAME_SIZE);
01009         return 0;
01010     }
01011 
01012     if (va->load_name && (strlen(va->load_name) >= JACK_PATH_MAX)) {
01013         jack_error("\"%s\" is too long for a shared object name.\n"
01014                    "Please use %lu characters or less.",
01015                    va->load_name, JACK_PATH_MAX);
01016         int my_status1 = *status | (JackFailure | JackInvalidOption);
01017         *status = (jack_status_t)my_status1;
01018         return 0;
01019     }
01020 
01021     if (va->load_init && (strlen(va->load_init) >= JACK_LOAD_INIT_LIMIT)) {
01022         jack_error ("\"%s\" is too long for internal client init "
01023                     "string.\nPlease use %lu characters or less.",
01024                     va->load_init, JACK_LOAD_INIT_LIMIT);
01025         int my_status1 = *status | (JackFailure | JackInvalidOption);
01026         *status = (jack_status_t)my_status1;
01027         return 0;
01028     }
01029 
01030     int int_ref = 0;
01031     int result = -1;
01032     fChannel->InternalClientLoad(GetClientControl()->fRefNum, client_name, va->load_name, va->load_init, options, (int*)status, &int_ref, &result);
01033     return int_ref;
01034 }
01035 
01036 void JackClient::InternalClientUnload(int ref, jack_status_t* status)
01037 {
01038     int result = -1;
01039     fChannel->InternalClientUnload(GetClientControl()->fRefNum, ref, (int*)status, &result);
01040 }
01041 
01042 
01043 } // end of namespace
01044