Ejemplo n.º 1
0
/*!
\brief Called once when the thread starts.
*/
bool JackClient::Init()
{
    /*
        Execute buffer_size callback.

        Since StartThread uses fThread.StartSync, we are sure that buffer_size callback
        is executed before StartThread returns (and then IsActive will be true).
        So no RT callback can be called at the same time.
    */
    jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", GetEngineControl()->fBufferSize);
    if (fBufferSize) {
        fBufferSize(GetEngineControl()->fBufferSize, fBufferSizeArg);
    }

    // Init callback
    InitAux();

    // Setup context
    if (!jack_tls_set(JackGlobals::fRealTimeThread, this)) {
        jack_error("Failed to set thread realtime key");
    }

    // Setup RT
    if (GetEngineControl()->fRealTime) {
        set_threaded_log_function();
        SetupRealTime();
    }

    return true;
}
Ejemplo n.º 2
0
    bool JackNetAdapter::Init()
    {
        jack_log("JackNetAdapter::Init");

        //init network connection
        if (!JackNetSlaveInterface::Init()) {
            jack_error("JackNetSlaveInterface::Init() error...");
            return false;
        }

        //then set global parameters
        if (!SetParams()) {
            jack_error("SetParams error...");
            return false;
        }

        //set buffers
        if (fCaptureChannels > 0) {
            fSoftCaptureBuffer = new sample_t*[fCaptureChannels];
            for (int port_index = 0; port_index < fCaptureChannels; port_index++) {
                fSoftCaptureBuffer[port_index] = new sample_t[fParams.fPeriodSize];
                fNetAudioCaptureBuffer->SetBuffer(port_index, fSoftCaptureBuffer[port_index]);
            }
        }

        if (fPlaybackChannels > 0) {
            fSoftPlaybackBuffer = new sample_t*[fPlaybackChannels];
            for (int port_index = 0; port_index < fPlaybackChannels; port_index++) {
                fSoftPlaybackBuffer[port_index] = new sample_t[fParams.fPeriodSize];
                fNetAudioPlaybackBuffer->SetBuffer(port_index, fSoftPlaybackBuffer[port_index]);
            }
        }

        //set audio adapter parameters
        SetAdaptedBufferSize(fParams.fPeriodSize);
        SetAdaptedSampleRate(fParams.fSampleRate);

        // Will do "something" on OSX only...
        fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);

        if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) {
            jack_error("AcquireSelfRealTime error");
        } else {
            set_threaded_log_function();
        }

        //init done, display parameters
        SessionParamsDisplay(&fParams);
        return true;
    }
Ejemplo n.º 3
0
/*!
        In "async" mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
        The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
        Drivers synchro are setup in "flush" mode if server is "async" and NOT freewheel.
*/
void JackClient::SetupDriverSync(bool freewheel)
{
    if (!freewheel && !GetEngineControl()->fSyncMode) {
        jack_log("JackClient::SetupDriverSync driver sem in flush mode");
        for (int i = 0; i < GetEngineControl()->fDriverNum; i++) {
            fSynchroTable[i].SetFlush(true);
        }
    } else {
        jack_log("JackClient::SetupDriverSync driver sem in normal mode");
        for (int i = 0; i < GetEngineControl()->fDriverNum; i++) {
            fSynchroTable[i].SetFlush(false);
        }
    }
}
Ejemplo n.º 4
0
inline jack_nframes_t JackClient::CycleWaitAux()
{
    if (!WaitSync()) {
        Error();   // Terminates the thread
    }
    CallSyncCallbackAux();
    return GetEngineControl()->fBufferSize;
}
Ejemplo n.º 5
0
void JackClient::TransportLocate(jack_nframes_t frame)
{
    jack_position_t pos;
    pos.frame = frame;
    pos.valid = (jack_position_bits_t)0;
    jack_log("JackClient::TransportLocate pos = %ld", pos.frame);
    GetEngineControl()->fTransport.RequestNewPos(&pos);
}
Ejemplo n.º 6
0
int JackClient::TransportReposition(const jack_position_t* pos)
{
    jack_position_t tmp = *pos;
    jack_log("JackClient::TransportReposition pos = %ld", pos->frame);
    if (tmp.valid & ~JACK_POSITION_MASK) {
        return EINVAL;
    } else {
        GetEngineControl()->fTransport.RequestNewPos(&tmp);
        return 0;
    }
}
Ejemplo n.º 7
0
// RT
bool JackTransportEngine::CheckAllRolling(JackClientInterface** table)
{
    for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) {
        JackClientInterface* client = table[i];
        if (client && client->GetClientControl()->fTransportState != JackTransportRolling) {
            jack_log("CheckAllRolling ref = %ld is not rolling", i);
            return false;
        }
    }
    jack_log("CheckAllRolling");
    return true;
}
Ejemplo n.º 8
0
// RT
void JackTransportEngine::MakeAllLocating(JackClientInterface** table)
{
    for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) {
        JackClientInterface* client = table[i];
        if (client) {
            JackClientControl* control = client->GetClientControl();
            control->fTransportState = JackTransportStopped;
            control->fTransportSync = true;
            control->fTransportTimebase = true;
            jack_log("MakeAllLocating ref = %ld", i);
        }
    }
}
Ejemplo n.º 9
0
// RT
void JackTransportEngine::MakeAllStartingLocating(JackClientInterface** table)
{
    for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) {
        JackClientInterface* client = table[i];
        if (client) {
            JackClientControl* control = client->GetClientControl();
            // Inactive clients don't have their process function called at all, so they must appear as already "rolling" for the transport....
            control->fTransportState = (control->fActive && control->fCallback[kRealTimeCallback]) ? JackTransportStarting : JackTransportRolling;
            control->fTransportSync = true;
            control->fTransportTimebase = true;
            jack_log("MakeAllStartingLocating ref = %ld", i);
        }
    }
}
Ejemplo n.º 10
0
inline void JackClient::CallTimebaseCallbackAux()
{
    JackTransportEngine& transport = GetEngineControl()->fTransport;
    int master;
    bool unused;

    transport.GetTimebaseMaster(master, unused);

    if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase...

        jack_transport_state_t transport_state = transport.GetState();
        jack_position_t* cur_pos = transport.WriteNextStateStart(1);

        if (GetClientControl()->fTransportTimebase) {
            fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg);
            GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true
        } else if (transport_state == JackTransportRolling) {
            fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg);
        }

        transport.WriteNextStateStop(1);
    }
}
Ejemplo n.º 11
0
void JackThreadedDriver::SetRealTime()
{
    if (fDriver->IsRealTime()) {
        jack_log("JackThreadedDriver::Init real-time");
        // Will do "something" on OSX only...
        GetEngineControl()->fPeriod = GetEngineControl()->fConstraint = GetEngineControl()->fPeriodUsecs * 1000;
        GetEngineControl()->fComputation = JackTools::ComputationMicroSec(GetEngineControl()->fBufferSize) * 1000;
        fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
        if (fThread.AcquireSelfRealTime(GetEngineControl()->fServerPriority) < 0) {
            jack_error("AcquireSelfRealTime error");
        } else {
            set_threaded_log_function();
        }
    } else {
        jack_log("JackThreadedDriver::Init non-realtime");
    }
}
Ejemplo n.º 12
0
void JackClient::SetupRealTime()
{
    jack_log("JackClient::Init : period = %ld computation = %ld constraint = %ld",
             long(int64_t(GetEngineControl()->fPeriod) / 1000.0f),
             long(int64_t(GetEngineControl()->fComputation) / 1000.0f),
             long(int64_t(GetEngineControl()->fConstraint) / 1000.0f));

    // Will do "something" on OSX only...
    fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);

    if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) {
        jack_error("JackClient::AcquireSelfRealTime error");
    }
}
Ejemplo n.º 13
0
int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg)
{
    if (IsActive()) {
        jack_error("You cannot set callbacks on an active client");
        return -1;
    } else {
        GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL);
        fSampleRateArg = arg;
        fSampleRate = callback;
        // Now invoke it
        if (callback) {
            callback(GetEngineControl()->fSampleRate, arg);
        }
        return 0;
    }
}
Ejemplo n.º 14
0
inline void JackClient::CallSyncCallbackAux()
{
    if (GetClientControl()->fTransportSync) {

        JackTransportEngine& transport = GetEngineControl()->fTransport;
        jack_position_t* cur_pos = transport.ReadCurrentState();
        jack_transport_state_t transport_state = transport.GetState();

        if (fSync != NULL) {
            if (fSync(transport_state, cur_pos, fSyncArg)) {
                GetClientControl()->fTransportState = JackTransportRolling;
                GetClientControl()->fTransportSync = false;
            }
        } else {
            GetClientControl()->fTransportState = JackTransportRolling;
            GetClientControl()->fTransportSync = false;
        }
    }
}
Ejemplo n.º 15
0
    int JackAlsaAdapter::Open()
    {
        //open audio interface
        if ( fAudioInterface.open() )
            return -1;

        //start adapter thread
        if ( fThread.StartSync() < 0 )
        {
            jack_error ( "Cannot start audioadapter thread" );
            return -1;
        }

        //display card info
        fAudioInterface.longinfo();

        //turn the thread realtime
        fThread.AcquireRealTime(GetEngineControl()->fClientPriority);
        return 0;
    }
Ejemplo n.º 16
0
int JackClient::StartThread()
{
    jack_log("JackClient::StartThread : period = %ld computation = %ld constraint = %ld",
             long(int64_t(GetEngineControl()->fPeriod) / 1000.0f),
             long(int64_t(GetEngineControl()->fComputation) / 1000.0f),
             long(int64_t(GetEngineControl()->fConstraint) / 1000.0f));

    // Will do "something" on OSX only...
    fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);

    if (fThread.StartSync() < 0) {
        jack_error("Start thread error");
        return -1;
    }

    return 0;
}
bool JackWaitThreadedDriver::Execute()
{
    try {
        // Process a null cycle until NetDriver has started
        while (!fStarter.fRunning && fThread.GetStatus() == JackThread::kRunning) {
            fDriver->ProcessNull();
        }

        // Set RT
        if (fDriver->IsRealTime()) {
            jack_log("JackWaitThreadedDriver::Init IsRealTime");
            // Will do "something" on OSX only...
            GetEngineControl()->fPeriod = GetEngineControl()->fConstraint = GetEngineControl()->fPeriodUsecs * 1000;
            fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
            if (fThread.AcquireSelfRealTime(GetEngineControl()->fServerPriority) < 0) {
                jack_error("AcquireSelfRealTime error");
            } else {
                set_threaded_log_function();
            }
        }

        // Switch to keep running even in case of error
        while (fThread.GetStatus() == JackThread::kRunning) {
            fDriver->Process();
        }
        return false;
    } catch (JackNetException& e) {
        e.PrintMessage();
        jack_info("Driver is restarted");
        fThread.DropSelfRealTime();
        // Thread in kIniting status again...
        fThread.SetStatus(JackThread::kIniting);
        if (Init()) {
            // Thread in kRunning status again...
            fThread.SetStatus(JackThread::kRunning);
            return true;
        } else {
            return false;
        }
	}
}
Ejemplo n.º 18
0
// Must be RT safe: directly write in the transport shared mem
void JackClient::TransportStop()
{
    GetEngineControl()->fTransport.SetCommand(TransportCommandStop);
}
Ejemplo n.º 19
0
jack_nframes_t JackClient::GetCurrentTransportFrame()
{
    return GetEngineControl()->fTransport.GetCurrentFrame();
}
Ejemplo n.º 20
0
jack_transport_state_t JackClient::TransportQuery(jack_position_t* pos)
{
    return GetEngineControl()->fTransport.Query(pos);
}
Ejemplo n.º 21
0
int JackClient::SetSyncTimeout(jack_time_t timeout)
{
    GetEngineControl()->fTransport.SetSyncTimeout(timeout);
    return 0;
}
Ejemplo n.º 22
0
inline int JackClient::CallProcessCallback()
{
    return (fProcess != NULL) ? fProcess(GetEngineControl()->fBufferSize, fProcessArg) : 0;
}
Ejemplo n.º 23
0
int JackLibClient::Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status)
{
    int shared_engine, shared_client, shared_graph, result;
    bool res;
    jack_log("JackLibClient::Open name = %s", name);
    
    if (strlen(name) >= JACK_CLIENT_NAME_SIZE) {
        jack_error("\"%s\" is too long to be used as a JACK client name.\n"
                   "Please use %lu characters or less",
                   name,
                   JACK_CLIENT_NAME_SIZE - 1);
        return -1; 
    }
    
    strncpy(fServerName, server_name, sizeof(fServerName));

    // Open server/client channel
    char name_res[JACK_CLIENT_NAME_SIZE+1];
    if (fChannel->Open(server_name, name, uuid, name_res, this, options, status) < 0) {
        jack_error("Cannot connect to the server");
        goto error;
    }

    // Start receiving notifications
    if (fChannel->Start() < 0) {
        jack_error("Cannot start channel");
        goto error;
    }

    // Require new client
    fChannel->ClientOpen(name_res, JackTools::GetPID(), uuid, &shared_engine, &shared_client, &shared_graph, &result);
    if (result < 0) {
        jack_error("Cannot open %s client", name_res);
        goto error;
    }

    try {
        // Map shared memory segments
        JackLibGlobals::fGlobals->fEngineControl.SetShmIndex(shared_engine, fServerName);
        JackLibGlobals::fGlobals->fGraphManager.SetShmIndex(shared_graph, fServerName);
        fClientControl.SetShmIndex(shared_client, fServerName);
        JackGlobals::fVerbose = GetEngineControl()->fVerbose;
    } catch (...) {
        jack_error("Map shared memory segments exception");
        goto error;
    }

    SetupDriverSync(false);

    // Connect shared synchro : the synchro must be usable in I/O mode when several clients live in the same process
    assert(JackGlobals::fSynchroMutex);
    JackGlobals::fSynchroMutex->Lock();
    res = fSynchroTable[GetClientControl()->fRefNum].Connect(name_res, fServerName);
    JackGlobals::fSynchroMutex->Unlock();
    if (!res) {
        jack_error("Cannot ConnectSemaphore %s client", name_res);
        goto error;
    }

    JackGlobals::fClientTable[GetClientControl()->fRefNum] = this;
    SetClockSource(GetEngineControl()->fClockSource);
    jack_log("JackLibClient::Open name = %s refnum = %ld", name_res, GetClientControl()->fRefNum);
    return 0;

error:
    fChannel->Stop();
    fChannel->Close();
    return -1;
}
Ejemplo n.º 24
0
int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
{
    int res = 0;

    jack_log("JackClient::ClientNotify ref = %ld name = %s notify = %ld", refnum, name, notify);

    // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient
    switch (notify) {

        case kAddClient:
            res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2);
            break;

        case kRemoveClient:
            res = ClientNotifyImp(refnum, name, notify, sync, message, value1, value2);
            break;

        case kActivateClient:
            jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum);
            InitAux();
            break;
    }

    /*
    The current semantic is that notifications can only be received when the client has been activated,
    although is this implementation, one could imagine calling notifications as soon as the client has be opened.
    */
    if (IsActive()) {

        switch (notify) {

            case kAddClient:
                jack_log("JackClient::kAddClient fName = %s name = %s", GetClientControl()->fName, name);
                if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) {      // Don't call the callback for the registering client itself
                    fClientRegistration(name, 1, fClientRegistrationArg);
                }
                break;

            case kRemoveClient:
                jack_log("JackClient::kRemoveClient fName = %s name = %s", GetClientControl()->fName, name);
                if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself
                    fClientRegistration(name, 0, fClientRegistrationArg);
                }
                break;

            case kBufferSizeCallback:
                jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", value1);
                if (fBufferSize) {
                    res = fBufferSize(value1, fBufferSizeArg);
                }
                break;

            case kSampleRateCallback:
                jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1);
                if (fSampleRate) {
                    res = fSampleRate(value1, fSampleRateArg);
                }
                break;

            case kGraphOrderCallback:
                jack_log("JackClient::kGraphOrderCallback");
                if (fGraphOrder) {
                    res = fGraphOrder(fGraphOrderArg);
                }
                break;

            case kStartFreewheelCallback:
                jack_log("JackClient::kStartFreewheel");
                SetupDriverSync(true);
                // Drop RT only when the RT thread is actually running
                if (fThread.GetStatus() == JackThread::kRunning) {
                    fThread.DropRealTime();     
                }
                if (fFreewheel) {
                    fFreewheel(1, fFreewheelArg);
                }
                break;

            case kStopFreewheelCallback:
                jack_log("JackClient::kStopFreewheel");
                SetupDriverSync(false);
                if (fFreewheel) {
                    fFreewheel(0, fFreewheelArg);
                }
                // Acquire RT only when the RT thread is actually running
                if (GetEngineControl()->fRealTime && fThread.GetStatus() == JackThread::kRunning) {
                    if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) {
                        jack_error("JackClient::AcquireRealTime error");
                    }
                }
                break;

            case kPortRegistrationOnCallback:
                jack_log("JackClient::kPortRegistrationOn port_index = %ld", value1);
                if (fPortRegistration) {
                    fPortRegistration(value1, 1, fPortRegistrationArg);
                }
                break;

            case kPortRegistrationOffCallback:
                jack_log("JackClient::kPortRegistrationOff port_index = %ld ", value1);
                if (fPortRegistration) {
                    fPortRegistration(value1, 0, fPortRegistrationArg);
                }
                break;

            case kPortConnectCallback:
                jack_log("JackClient::kPortConnectCallback src = %ld dst = %ld", value1, value2);
                if (fPortConnect) {
                    fPortConnect(value1, value2, 1, fPortConnectArg);
                }
                break;

            case kPortDisconnectCallback:
                jack_log("JackClient::kPortDisconnectCallback src = %ld dst = %ld", value1, value2);
                if (fPortConnect) {
                    fPortConnect(value1, value2, 0, fPortConnectArg);
                }
                break;

             case kPortRenameCallback:
                jack_log("JackClient::kPortRenameCallback port = %ld", value1);
                if (fPortRename) {
                    fPortRename(value1, message, GetGraphManager()->GetPort(value1)->GetName(), fPortRenameArg);
                }
                break;

            case kXRunCallback:
                jack_log("JackClient::kXRunCallback");
                if (fXrun) {
                    res = fXrun(fXrunArg);
                }
                break;

            case kShutDownCallback:
                jack_log("JackClient::kShutDownCallback");
                ShutDown(jack_status_t(value1), message);
                break;

            case kSessionCallback:
                jack_log("JackClient::kSessionCallback");
                if (fSession) {
                    jack_session_event_t* event = (jack_session_event_t*)malloc( sizeof(jack_session_event_t));
                    char uuid_buf[JACK_UUID_SIZE];
                    event->type = (jack_session_event_type_t)value1;
                    event->session_dir = strdup(message);
                    event->command_line = NULL;
                    event->flags = (jack_session_flags_t)0;
                    snprintf(uuid_buf, sizeof(uuid_buf), "%d", GetClientControl()->fSessionID);
                    event->client_uuid = strdup(uuid_buf);
                    fSessionReply = kPendingSessionReply;
                    // Session callback may change fSessionReply by directly using jack_session_reply
                    fSession(event, fSessionArg);
                    res = fSessionReply;
                }
                break;

            case kLatencyCallback:
                res = HandleLatencyCallback(value1);
                break;
        }
    }

    return res;
}