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

Generated on Thu Feb 14 11:16:01 2008 for Jackdmp by  doxygen 1.5.1