void JackNetAdapter::EncodeTransportData() { //is there a timebase master change ? int refnum = -1; bool conditional = 0; //TODO : get the actual timebase master if (refnum != fLastTimebaseMaster) { //timebase master has released its function if (refnum == -1) { fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER; jack_info("Sending a timebase master release request."); } else { //there is a new timebase master fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER; jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional"); } fLastTimebaseMaster = refnum; } else { fReturnTransportData.fTimebaseMaster = NO_CHANGE; } //update transport state and position fReturnTransportData.fState = jack_transport_query(fClient, &fReturnTransportData.fPosition); //is it a new state (that the master need to know...) ? fReturnTransportData.fNewState = ((fReturnTransportData.fState != fLastTransportState) && (fReturnTransportData.fState != fSendTransportData.fState)); if (fReturnTransportData.fNewState) { jack_info("Sending transport state '%s'.", GetTransportState(fReturnTransportData.fState)); } fLastTransportState = fReturnTransportData.fState; }
JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, const char* server_name) { if (rt) { jack_info("JACK server starting in realtime mode with priority %ld", priority); } else { jack_info("JACK server starting in non-realtime mode"); } fGraphManager = JackGraphManager::Allocate(port_max); fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); // A distinction is made between the threaded freewheel driver and the // regular freewheel driver because the freewheel driver needs to run in // threaded mode when freewheel mode is active and needs to run as a slave // when freewheel mode isn't active. JackFreewheelDriver *freewheelDriver = new JackFreewheelDriver(fEngine, GetSynchroTable()); fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver); fFreewheelDriver = freewheelDriver; fDriverInfo = new JackDriverInfo(); fAudioDriver = NULL; fFreewheel = false; JackServerGlobals::fInstance = this; // Unique instance JackServerGlobals::fUserCount = 1; // One user JackGlobals::fVerbose = verbose; }
//transport--------------------------------------------------------------------------- void JackNetAdapter::DecodeTransportData() { //TODO : we need here to get the actual timebase master to eventually release it from its duty (see JackNetDriver) //is there a new transport state ? if (fSendTransportData.fNewState &&(fSendTransportData.fState != jack_transport_query(fClient, NULL))) { switch (fSendTransportData.fState) { case JackTransportStopped : jack_transport_stop(fClient); jack_info("NetMaster : transport stops"); break; case JackTransportStarting : jack_transport_reposition(fClient, &fSendTransportData.fPosition); jack_transport_start(fClient); jack_info("NetMaster : transport starts"); break; case JackTransportRolling : // TODO, we need to : // - find a way to call TransportEngine->SetNetworkSync() // - turn the transport state to JackTransportRolling jack_info("NetMaster : transport rolls"); break; } } }
SERVER_EXPORT void NetTransportDataDisplay ( net_transport_data_t* data ) { jack_info ( "********************Network Transport********************" ); jack_info ( "Transport new state : %u", data->fNewState ); jack_info ( "Transport timebase master : %u", data->fTimebaseMaster ); jack_info ( "Transport cycle state : %u", data->fState ); jack_info ( "**********************************************" ); }
int JackNetMasterInterface::SyncRecv() { packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer ); int rx_bytes = Recv ( fParams.fMtu, MSG_PEEK ); if ( ( rx_bytes == 0 ) || ( rx_bytes == SOCKET_ERROR ) ) return rx_bytes; fCycleOffset = fTxHeader.fCycle - rx_head->fCycle; switch ( fParams.fNetworkMode ) { case 's' : //slow mode : allow to use full bandwidth and heavy process on the slave // - extra latency is set to two cycles, one cycle for send/receive operations + one cycle for heavy process on the slave // - if the network is two fast, just wait the next cycle, this mode allows a shorter cycle duration for the master // - this mode will skip the two first cycles, thus it lets time for data to be processed and queued on the socket rx buffer //the slow mode is the safest mode because it wait twice the bandwidth relative time (send/return + process) if (fCycleOffset < 2) return 0; else rx_bytes = Recv ( rx_head->fPacketSize, 0 ); if (fCycleOffset > 2) { jack_info("Warning : '%s' runs in slow network mode, but data received too late (%d cycle(s) offset)", fParams.fName, fCycleOffset); } break; case 'n' : //normal use of the network : // - extra latency is set to one cycle, what is the time needed to receive streams using full network bandwidth // - if the network is too fast, just wait the next cycle, the benefit here is the master's cycle is shorter // - indeed, data is supposed to be on the network rx buffer, so we don't have to wait for it if (fCycleOffset < 1) return 0; else rx_bytes = Recv ( rx_head->fPacketSize, 0 ); if (fCycleOffset != 1) jack_info("'%s' can't run in normal network mode, data received too late (%d cycle(s) offset)", fParams.fName, fCycleOffset); break; case 'f' : //fast mode suppose the network bandwith is larger than required for the transmission (only a few channels for example) // - packets can be quickly received, quickly is here relative to the cycle duration // - here, receive data, we can't keep it queued on the rx buffer, // - but if there is a cycle offset, tell the user, that means we're not in fast mode anymore, network is too slow rx_bytes = Recv ( rx_head->fPacketSize, 0 ); if (fCycleOffset != 0) jack_info("'%s' can't run in fast network mode, data received too late (%d cycle(s) offset)", fParams.fName, fCycleOffset); break; } fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; return rx_bytes; }
int JackLoadableInternalClient::Init(const char* so_name) { char path_to_so[JACK_PATH_MAX + 1]; BuildClientPath(path_to_so, sizeof(path_to_so), so_name); fHandle = LoadJackModule(path_to_so); jack_log("JackLoadableInternalClient::JackLoadableInternalClient path_to_so = %s", path_to_so); if (fHandle == NULL) { PrintLoadError(so_name); return -1; } fFinish = (FinishCallback)GetJackProc(fHandle, "jack_finish"); if (fFinish == NULL) { UnloadJackModule(fHandle); jack_error("symbol jack_finish cannot be found in %s", so_name); return -1; } fDescriptor = (JackDriverDescFunction)GetJackProc(fHandle, "jack_get_descriptor"); if (fDescriptor == NULL) { jack_info("No jack_get_descriptor entry-point for %s", so_name); } return 0; }
bool JackNetSlaveInterface::Init() { jack_log("JackNetSlaveInterface::Init()"); // set the parameters to send strcpy(fParams.fPacketType, "params"); fParams.fProtocolVersion = NETWORK_PROTOCOL; SetPacketType(&fParams, SLAVE_AVAILABLE); // init loop : get a master and start, do it until connection is ok net_status_t status; do { // first, get a master, do it until a valid connection is running do { status = SendAvailableToMaster(); if (status == NET_SOCKET_ERROR) { return false; } } while (status != NET_CONNECTED); // then tell the master we are ready jack_info("Initializing connection with %s...", fParams.fMasterNetName); status = SendStartToMaster(); if (status == NET_ERROR) { return false; } } while (status != NET_ROLLING); return true; }
static void hammerfall_check_sync (hammerfall_t *h, snd_ctl_elem_value_t *ctl) { const char *name; int val; snd_ctl_elem_id_t *ctl_id; jack_info ("check sync"); snd_ctl_elem_id_alloca (&ctl_id); snd_ctl_elem_value_get_id (ctl, ctl_id); name = snd_ctl_elem_id_get_name (ctl_id); if (strcmp (name, "ADAT1 Sync Check") == 0) { val = snd_ctl_elem_value_get_enumerated (ctl, 0); hammerfall_check_sync_state (h, val, 0); } else if (strcmp (name, "ADAT2 Sync Check") == 0) { val = snd_ctl_elem_value_get_enumerated (ctl, 0); hammerfall_check_sync_state (h, val, 1); } else if (strcmp (name, "ADAT3 Sync Check") == 0) { val = snd_ctl_elem_value_get_enumerated (ctl, 0); hammerfall_check_sync_state (h, val, 2); } else { jack_error ("Hammerfall: unknown control \"%s\"", name); } }
static char* get_control_device_name(const char * device_name) { char * ctl_name; regex_t expression; regcomp(&expression, "(plug)?hw:[0-9](,[0-9])?", REG_ICASE | REG_EXTENDED); if (!regexec(&expression, device_name, 0, NULL, 0)) { /* the user wants a hw or plughw device, the ctl name * should be hw:x where x is the card number */ char tmp[5]; strncpy(tmp, strstr(device_name, "hw"), 4); tmp[4] = '\0'; jack_info("control device %s",tmp); ctl_name = strdup(tmp); } else { ctl_name = strdup(device_name); } regfree(&expression); if (ctl_name == NULL) { jack_error("strdup(\"%s\") failed.", ctl_name); } return ctl_name; }
void JackNetMasterInterface::Exit() { jack_log("JackNetMasterInterface::Exit, ID %u", fParams.fID); // stop process fRunning = false; // send a 'multicast euthanasia request' - new socket is required on macosx jack_info("Exiting '%s' %s", fParams.fName, fMulticastIP); SetPacketType(&fParams, KILL_MASTER); JackNetSocket mcast_socket(fMulticastIP, fSocket.GetPort()); session_params_t net_params; memset(&net_params, 0, sizeof(session_params_t)); SessionParamsHToN(&fParams, &net_params); if (mcast_socket.NewSocket() == SOCKET_ERROR) { jack_error("Can't create socket : %s", StrError(NET_ERROR_CODE)); } if (mcast_socket.SendTo(&net_params, sizeof(session_params_t), 0, fMulticastIP) == SOCKET_ERROR) { jack_error("Can't send suicide request : %s", StrError(NET_ERROR_CODE)); } mcast_socket.Close(); }
bool JackNetAdapter::Execute() { try { // Keep running even in case of error while (fThread.GetStatus() == JackThread::kRunning) { if (Process() == SOCKET_ERROR) { return false; } } return false; } catch (JackNetException& e) { // Otherwise just restart... e.PrintMessage(); jack_info("NetAdapter is restarted"); Reset(); fThread.DropSelfRealTime(); fThread.SetStatus(JackThread::kIniting); if (Init()) { fThread.SetStatus(JackThread::kRunning); return true; } else { return false; } } }
static OSStatus display_device_names() { UInt32 size; Boolean isWritable; int i, deviceNum; OSStatus err; CFStringRef UIname; err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable); if (err != noErr) return err; deviceNum = size/sizeof(AudioDeviceID); AudioDeviceID devices[deviceNum]; err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices); if (err != noErr) return err; for (i = 0; i < deviceNum; i++) { char device_name[256]; char internal_name[256]; size = sizeof(CFStringRef); UIname = NULL; err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname); if (err == noErr) { CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding()); } else { goto error; } size = 256; err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name); if (err != noErr) return err; jack_info("ICI"); jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -d parameter)", device_name, internal_name); } return noErr; error: if (UIname != NULL) CFRelease(UIname); return err; }
void JackDriver::RestoreConnections() { list<pair<string, string> >::const_iterator it; for (it = fConnections.begin(); it != fConnections.end(); it++) { pair<string, string> connection = *it; jack_info("Restore connection: %s %s", connection.first.c_str(), connection.second.c_str()); fEngine->PortConnect(fClientControl.fRefNum, connection.first.c_str(), connection.second.c_str()); } }
bool JackNetMasterInterface::Init() { jack_log("JackNetMasterInterface::Init : ID %u", fParams.fID); session_params_t host_params; uint attempt = 0; int rx_bytes = 0; // socket if (fSocket.NewSocket() == SOCKET_ERROR) { jack_error("Can't create socket : %s", StrError(NET_ERROR_CODE)); return false; } // timeout on receive (for init) if (fSocket.SetTimeOut(MASTER_INIT_TIMEOUT) < 0) { jack_error("Can't set init timeout : %s", StrError(NET_ERROR_CODE)); } // connect if (fSocket.Connect() == SOCKET_ERROR) { jack_error("Can't connect : %s", StrError(NET_ERROR_CODE)); return false; } // send 'SLAVE_SETUP' until 'START_MASTER' received jack_info("Sending parameters to %s...", fParams.fSlaveNetName); do { session_params_t net_params; memset(&net_params, 0, sizeof(session_params_t)); SetPacketType(&fParams, SLAVE_SETUP); SessionParamsHToN(&fParams, &net_params); if (fSocket.Send(&net_params, sizeof(session_params_t), 0) == SOCKET_ERROR) { jack_error("Error in send : %s", StrError(NET_ERROR_CODE)); } memset(&net_params, 0, sizeof(session_params_t)); if (((rx_bytes = fSocket.Recv(&net_params, sizeof(session_params_t), 0)) == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) { jack_error("Problem with network"); return false; } SessionParamsNToH(&net_params, &host_params); } while ((GetPacketType(&host_params) != START_MASTER) && (++attempt < SLAVE_SETUP_RETRY)); if (attempt == SLAVE_SETUP_RETRY) { jack_error("Slave doesn't respond, exiting"); return false; } return true; }
void NetMidiBuffer::DisplayEvents() { for ( int port_index = 0; port_index < fNPorts; port_index++ ) { for ( uint event = 0; event < fPortBuffer[port_index]->event_count; event++ ) if ( fPortBuffer[port_index]->IsValid() ) jack_info ( "port %d : midi event %u/%u -> time : %u, size : %u", port_index + 1, event + 1, fPortBuffer[port_index]->event_count, fPortBuffer[port_index]->events[event].time, fPortBuffer[port_index]->events[event].size ); } }
void JackDriver::SaveConnections() { const char** connections; fConnections.clear(); char alias1[REAL_JACK_PORT_NAME_SIZE]; char alias2[REAL_JACK_PORT_NAME_SIZE]; char* aliases[2]; aliases[0] = alias1; aliases[1] = alias2; for (int i = 0; i < fCaptureChannels; ++i) { if (fCapturePortList[i] && (connections = fGraphManager->GetConnections(fCapturePortList[i])) != 0) { for (int j = 0; connections[j]; j++) { /* fGraphManager->GetPort(fCapturePortList[i])->GetAliases(aliases); fConnections.push_back(make_pair(aliases[0], connections[j])); jack_info("Save connection: %s %s", aliases[0], connections[j]); */ fConnections.push_back(make_pair(string(fGraphManager->GetPort(fCapturePortList[i])->GetName()), string(connections[j]))); jack_info("Save connection: %s %s", fGraphManager->GetPort(fCapturePortList[i])->GetName(), connections[j]); } free(connections); } } for (int i = 0; i < fPlaybackChannels; ++i) { if (fPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fPlaybackPortList[i])) != 0) { for (int j = 0; connections[j]; j++) { /* fGraphManager->GetPort(fPlaybackPortList[i])->GetAliases(aliases); fConnections.push_back(make_pair(connections[j], aliases[0])); jack_info("Save connection: %s %s", connections[j], aliases[0]); */ fConnections.push_back(make_pair(string(connections[j]), string(fGraphManager->GetPort(fPlaybackPortList[i])->GetName()))); jack_info("Save connection: %s %s", connections[j], fGraphManager->GetPort(fPlaybackPortList[i])->GetName()); } free(connections); } } }
//open/close-------------------------------------------------------------------------- int JackNetAdapter::Open() { jack_info("NetAdapter started in %s mode %s Master's transport sync.", (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without"); if (fThread.StartSync() < 0) { jack_error("Cannot start netadapter thread"); return -1; } return 0; }
int JackNetSlaveInterface::DataRecv() { uint recvd_midi_pckt = 0; uint recvd_audio_pckt = 0; int rx_bytes = 0; packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer ); while ( !fRxHeader.fIsLastPckt ) { rx_bytes = Recv ( fParams.fMtu, MSG_PEEK ); //error here, problem with recv, just skip the cycle (return -1) if ( rx_bytes == SOCKET_ERROR ) return rx_bytes; if ( rx_bytes && ( rx_head->fDataStream == 's' ) && ( rx_head->fID == fParams.fID ) ) { switch ( rx_head->fDataType ) { case 'm': //midi rx_bytes = Recv ( rx_head->fPacketSize, 0 ); fRxHeader.fCycle = rx_head->fCycle; fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; fNetMidiCaptureBuffer->RenderFromNetwork ( rx_head->fSubCycle, rx_bytes - sizeof ( packet_header_t ) ); if ( ++recvd_midi_pckt == rx_head->fNMidiPckt ) fNetMidiCaptureBuffer->RenderToJackPorts(); break; case 'a': //audio rx_bytes = Recv ( rx_head->fPacketSize, 0 ); //SL: 25/01/09 // if ( !IsNextPacket() ) // jack_error ( "Packet(s) missing..." ); if (recvd_audio_pckt++ != rx_head->fSubCycle) { jack_error("Packet(s) missing from '%s'...", fParams.fMasterNetName); } fRxHeader.fCycle = rx_head->fCycle; fRxHeader.fSubCycle = rx_head->fSubCycle; fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; fNetAudioCaptureBuffer->RenderToJackPorts ( rx_head->fSubCycle ); break; case 's': //sync jack_info ( "NetSlave : overloaded, skipping receive." ); return 0; } } } fRxHeader.fCycle = rx_head->fCycle; return 0; }
void JackDriver::LoadConnections(int alias, bool full_name) { list<pair<string, pair<string, string> > >::const_iterator it; if (full_name) { for (it = fConnections.begin(); it != fConnections.end(); it++) { pair<string, string> connection = (*it).second; jack_info("Load connection: %s %s", connection.first.c_str(), connection.second.c_str()); fEngine->PortConnect(fClientControl.fRefNum, connection.first.c_str(), connection.second.c_str()); } } else { const char** inputs = fGraphManager->GetPorts(NULL, NULL, JackPortIsInput); const char** outputs = fGraphManager->GetPorts(NULL, NULL, JackPortIsOutput); for (it = fConnections.begin(); it != fConnections.end(); it++) { pair<string, string> connection = (*it).second; string real_input = MatchPortName(connection.first.c_str(), outputs, alias, (*it).first); string real_output = MatchPortName(connection.second.c_str(), inputs, alias, (*it).first); if ((real_input != "") && (real_output != "")) { jack_info("Load connection: %s %s", real_input.c_str(), real_output.c_str()); fEngine->PortConnect(fClientControl.fRefNum, real_input.c_str(), real_output.c_str()); } } // Wait for connection change if (fGraphManager->IsPendingChange()) { JackSleep(int(fEngineControl->fPeriodUsecs * 1.1f)); } if (inputs) { free(inputs); } if (outputs) { free(outputs); } } }
static int oss_driver_bufsize (oss_driver_t *driver, jack_nframes_t nframes) { oss_driver_stop(driver); set_period_size(driver, nframes); if (driver->engine->set_buffer_size(driver->engine, driver->period_size)) { jack_error ("OSS: cannot set engine buffer size to %d (check MIDI)", driver->period_size); return -1; } jack_info("oss_driver: period size update: %u", nframes); oss_driver_start(driver); return 0; }
SERVER_EXPORT void InitTime() { QueryPerformanceFrequency(&_jack_freq); TIMECAPS caps; if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) { jack_error("InitTime : could not get timer device"); } else { gPeriod = caps.wPeriodMin; if (timeBeginPeriod(gPeriod) != TIMERR_NOERROR) { jack_error("InitTime : could not set minimum timer"); gPeriod = 0; } else { jack_info("InitTime : multimedia timer resolution set to %d milliseconds", gPeriod); } } }
static int jack_process_already_has_real_time_scheduling (int priority) { #if defined(__FreeBSD__) int res; struct rtprio rtp; res = rtprio(RTP_LOOKUP, getpid(), &rtp); if (res == 0 && rtp.type == RTP_PRIO_REALTIME && rtp.prio <= priority) { jack_info("process already runs at sufficient realtime priority %u (<=%d)", (unsigned)rtp.prio, priority); return 1; // process priority is sufficient } #endif return 0; // no or don't know }
bool JackNetSlaveInterface::InitRendering() { jack_log("JackNetSlaveInterface::InitRendering()"); net_status_t status; do { // then tell the master we are ready jack_info("Initializing connection with %s...", fParams.fMasterNetName); status = SendStartToMaster(); if (status == NET_ERROR) { return false; } } while (status != NET_ROLLING); return true; }
static jack_driver_t * dummy_driver_new (jack_client_t * client, char *name, unsigned int capture_ports, unsigned int playback_ports, jack_nframes_t sample_rate, jack_nframes_t period_size, unsigned long wait_time) { dummy_driver_t * driver; jack_info ("creating dummy driver ... %s|%" PRIu32 "|%" PRIu32 "|%lu|%u|%u", name, sample_rate, period_size, wait_time, capture_ports, playback_ports); driver = (dummy_driver_t *) calloc (1, sizeof (dummy_driver_t)); jack_driver_nt_init ((jack_driver_nt_t *) driver); driver->write = (JackDriverReadFunction) dummy_driver_write; driver->null_cycle = (JackDriverNullCycleFunction) dummy_driver_null_cycle; driver->nt_attach = (JackDriverNTAttachFunction) dummy_driver_attach; driver->nt_start = (JackDriverNTStartFunction) dummy_driver_nt_start; driver->nt_detach = (JackDriverNTDetachFunction) dummy_driver_detach; driver->nt_bufsize = (JackDriverNTBufSizeFunction) dummy_driver_bufsize; driver->nt_run_cycle = (JackDriverNTRunCycleFunction) dummy_driver_run_cycle; driver->period_usecs = (jack_time_t) floor ((((float) period_size) / sample_rate) * 1000000.0f); driver->sample_rate = sample_rate; driver->period_size = period_size; driver->wait_time = wait_time; //driver->next_time = 0; // not needed since calloc clears the memory driver->last_wait_ust = 0; driver->capture_channels = capture_ports; driver->capture_ports = NULL; driver->playback_channels = playback_ports; driver->playback_ports = NULL; driver->client = client; driver->engine = NULL; return (jack_driver_t *) driver; }
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; } } }
// this check is to prevent apps to self connect to other apps // TODO: make this work with multiple clients per app int JackEngine::CheckPortsConnect(int refnum, jack_port_id_t src, jack_port_id_t dst) { if (fSelfConnectMode == ' ') return 1; JackPort* src_port = fGraphManager->GetPort(src); JackPort* dst_port = fGraphManager->GetPort(dst); jack_log("JackEngine::CheckPortsConnect(ref = %d, src = %d, dst = %d)", refnum, src_port->GetRefNum(), dst_port->GetRefNum()); //jack_log("%s -> %s", src_port->GetName(), dst_port->GetName()); //jack_log("mode = '%c'", fSelfConnectMode); int src_self = src_port->GetRefNum() == refnum ? 1 : 0; int dst_self = dst_port->GetRefNum() == refnum ? 1 : 0; //jack_log("src_self is %s", src_self ? "true" : "false"); //jack_log("dst_self is %s", dst_self ? "true" : "false"); // 0 means client is connecting other client ports (control app patchbay functionality) // 1 means client is connecting its own port to port of other client (e.g. self connecting into "system" client) // 2 means client is connecting its own ports (for app internal functionality) int sum = src_self + dst_self; //jack_log("sum = %d", sum); if (sum == 0) return 1; char lmode = tolower(fSelfConnectMode); //jack_log("lmode = '%c'", lmode); if (sum == 2 && lmode == 'e') return 1; bool fail = lmode != fSelfConnectMode; // fail modes are upper case //jack_log("fail = %d", (int)fail); jack_info( "%s port self connect request%s (%s -> %s)", fail ? "rejecting" : "ignoring", sum == 1 ? " to external port" : "", src_port->GetName(), dst_port->GetName()); return fail ? -1 : 0; }
int JackNetMasterInterface::SyncRecv() { int rx_bytes = 0; packet_header_t* rx_head = reinterpret_cast<packet_header_t*>(fRxBuffer); // receive sync (launch the cycle) do { rx_bytes = Recv(fParams.fMtu, MSG_PEEK); // connection issue (return -1) if (rx_bytes == SOCKET_ERROR) { return SOCKET_ERROR; } } while (strcmp(rx_head->fPacketType, "header") != 0); //PacketHeaderDisplay(rx_head); if (rx_head->fDataType != 's') { jack_error("Wrong packet type : %c", rx_head->fDataType); // not the last packet.. fRxHeader.fIsLastPckt = 0; return SYNC_PACKET_ERROR; } fCurrentCycleOffset = fTxHeader.fCycle - rx_head->fCycle; if (fCurrentCycleOffset < fMaxCycleOffset && !fSynched) { jack_info("Synching with latency = %d", fCurrentCycleOffset); return NET_SYNCHING; } else { if (fCurrentCycleOffset == fMaxCycleOffset) { // when the sync offset is reached fSynched = true; } rx_bytes = Recv(rx_head->fPacketSize, 0); fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; return rx_bytes; } }
int JackNetSlaveInterface::DataRecv() { int rx_bytes = 0; uint recvd_midi_pckt = 0; packet_header_t* rx_head = reinterpret_cast<packet_header_t*>(fRxBuffer); while (!fRxHeader.fIsLastPckt) { // how much data is queued on the rx buffer ? rx_bytes = Recv(fParams.fMtu, MSG_PEEK); // error here, just skip the cycle (return -1) if (rx_bytes == SOCKET_ERROR) { return rx_bytes; } if (rx_bytes && (rx_head->fDataStream == 's') && (rx_head->fID == fParams.fID)) { // read data switch (rx_head->fDataType) { case 'm': // midi rx_bytes = MidiRecv(rx_head, fNetMidiCaptureBuffer, recvd_midi_pckt); break; case 'a': // audio rx_bytes = AudioRecv(rx_head, fNetAudioCaptureBuffer); break; case 's': // sync jack_info("NetSlave : missing last data packet"); return FinishRecv(fNetAudioCaptureBuffer); } } } fRxHeader.fCycle = rx_head->fCycle; return rx_bytes; }
int netjack_wait( netjack_driver_state_t *netj ) { int we_have_the_expected_frame = 0; jack_nframes_t next_frame_avail; jack_time_t packet_recv_time_stamp; jacknet_packet_header *pkthdr; if( !netj->next_deadline_valid ) { netj->next_deadline = jack_get_time() + netj->period_usecs; netj->next_deadline_valid = 1; } // Increment expected frame here. if( netj->expected_framecnt_valid ) { netj->expected_framecnt += 1; } else { // starting up.... lets look into the packetcache, and fetch the highest packet. packet_cache_drain_socket( netj->packcache, netj->sockfd ); if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail ) ) { netj->expected_framecnt = next_frame_avail; netj->expected_framecnt_valid = 1; } else { // no packets there... start normally. netj->expected_framecnt = 0; netj->expected_framecnt_valid = 1; } } //jack_log( "expect %d", netj->expected_framecnt ); // Now check if required packet is already in the cache. // then poll (have deadline calculated) // then drain socket, rinse and repeat. while(1) { if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) ) { if( next_frame_avail == netj->expected_framecnt ) { we_have_the_expected_frame = 1; if( !netj->always_deadline ) break; } } if( ! netjack_poll_deadline( netj->sockfd, netj->next_deadline ) ) { break; } packet_cache_drain_socket( netj->packcache, netj->sockfd ); } // check if we know who to send our packets too. if (!netj->srcaddress_valid) if( netj->packcache->master_address_valid ) { memcpy (&(netj->syncsource_address), &(netj->packcache->master_address), sizeof( struct sockaddr_in ) ); netj->srcaddress_valid = 1; } // XXX: switching mode unconditionally is stupid. // if we were running free perhaps we like to behave differently // ie. fastforward one packet etc. // well... this is the first packet we see. hmm.... dunno ;S // it works... so... netj->running_free = 0; //if( !we_have_the_expected_frame ) // jack_error( "netxrun... %d", netj->expected_framecnt ); if( we_have_the_expected_frame ) { jack_time_t now = jack_get_time(); if( now < netj->next_deadline ) netj->time_to_deadline = netj->next_deadline - now; else netj->time_to_deadline = 0; packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp); pkthdr = (jacknet_packet_header *) netj->rx_buf; packet_header_ntoh(pkthdr); netj->deadline_goodness = (int)pkthdr->sync_state; netj->packet_data_valid = 1; int want_deadline; if( netj->jitter_val != 0 ) want_deadline = netj->jitter_val; else if( netj->latency < 4 ) want_deadline = -netj->period_usecs/2; else want_deadline = (netj->period_usecs/4+10*(int)netj->period_usecs*netj->latency/100); if( netj->deadline_goodness != MASTER_FREEWHEELS ) { if( netj->deadline_goodness < want_deadline ) { netj->next_deadline -= netj->period_usecs/100; //jack_log( "goodness: %d, Adjust deadline: --- %d\n", netj->deadline_goodness, (int) netj->period_usecs*netj->latency/100 ); } if( netj->deadline_goodness > want_deadline ) { netj->next_deadline += netj->period_usecs/100; //jack_log( "goodness: %d, Adjust deadline: +++ %d\n", netj->deadline_goodness, (int) netj->period_usecs*netj->latency/100 ); } } // if( netj->next_deadline < (netj->period_usecs*70/100) ) { // jack_error( "master is forcing deadline_offset to below 70%% of period_usecs... increase latency setting on master" ); // netj->deadline_offset = (netj->period_usecs*90/100); // } netj->next_deadline += netj->period_usecs; } else { netj->time_to_deadline = 0; netj->next_deadline += netj->period_usecs; // bah... the packet is not there. // either // - it got lost. // - its late // - sync source is not sending anymore. // lets check if we have the next packets, we will just run a cycle without data. // in that case. if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) ) { jack_nframes_t offset = next_frame_avail - netj->expected_framecnt; //XXX: hmm... i need to remember why resync_threshold wasnt right. //if( offset < netj->resync_threshold ) if( offset < 10 ) { // ok. dont do nothing. we will run without data. // this seems to be one or 2 lost packets. // // this can also be reordered packet jitter. // (maybe this is not happening in real live) // but it happens in netem. netj->packet_data_valid = 0; // I also found this happening, when the packet queue, is too full. // but wtf ? use a smaller latency. this link can handle that ;S if( packet_cache_get_fill( netj->packcache, netj->expected_framecnt ) > 80.0 ) netj->next_deadline -= netj->period_usecs/2; } else { // the diff is too high. but we have a packet in the future. // lets resync. netj->expected_framecnt = next_frame_avail; packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); pkthdr = (jacknet_packet_header *) netj->rx_buf; packet_header_ntoh(pkthdr); //netj->deadline_goodness = 0; netj->deadline_goodness = (int)pkthdr->sync_state - (int)netj->period_usecs * offset; netj->next_deadline_valid = 0; netj->packet_data_valid = 1; } } else { // no packets in buffer. netj->packet_data_valid = 0; //printf( "frame %d No Packet in queue. num_lost_packets = %d \n", netj->expected_framecnt, netj->num_lost_packets ); if( netj->num_lost_packets < 5 ) { // ok. No Packet in queue. The packet was either lost, // or we are running too fast. // // Adjusting the deadline unconditionally resulted in // too many xruns on master. // But we need to adjust for the case we are running too fast. // So lets check if the last packet is there now. // // It would not be in the queue anymore, if it had been // retrieved. This might break for redundancy, but // i will make the packet cache drop redundant packets, // that have already been retreived. // if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) { if( next_frame_avail == (netj->expected_framecnt - 1) ) { // Ok. the last packet is there now. // and it had not been retrieved. // // TODO: We are still dropping 2 packets. // perhaps we can adjust the deadline // when (num_packets lost == 0) // This might still be too much. netj->next_deadline += netj->period_usecs; } } } else if( (netj->num_lost_packets <= 100) ) { // lets try adjusting the deadline harder, for some packets, we might have just ran 2 fast. netj->next_deadline += netj->period_usecs*netj->latency/8; } else { // But now we can check for any new frame available. // if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) { netj->expected_framecnt = next_frame_avail; packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); pkthdr = (jacknet_packet_header *) netj->rx_buf; packet_header_ntoh(pkthdr); netj->deadline_goodness = pkthdr->sync_state; netj->next_deadline_valid = 0; netj->packet_data_valid = 1; netj->running_free = 0; jack_info( "resync after freerun... %d", netj->expected_framecnt ); } else { if( netj->num_lost_packets == 101 ) { jack_info( "master seems gone... entering freerun mode", netj->expected_framecnt ); } netj->running_free = 1; // when we really dont see packets. // reset source address. and open possibility for new master. // maybe dsl reconnect. Also restart of netsource without fix // reply address changes port. if (netj->num_lost_packets > 200 ) { netj->srcaddress_valid = 0; packet_cache_reset_master_address( netj->packcache ); } } } } } int retval = 0; if( !netj->packet_data_valid ) { netj->num_lost_packets += 1; if( netj->num_lost_packets == 1 ) retval = netj->period_usecs; } else { if( (netj->num_lost_packets>1) && !netj->running_free ) retval = (netj->num_lost_packets-1) * netj->period_usecs; netj->num_lost_packets = 0; } return retval; }
int netjack_startup( netjack_driver_state_t *netj ) { int first_pack_len; struct sockaddr_in address; // Now open the socket, and wait for the first packet to arrive... netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0); #ifdef WIN32 if (netj->sockfd == INVALID_SOCKET) #else if (netj->sockfd == -1) #endif { jack_info ("socket error"); return -1; } address.sin_family = AF_INET; address.sin_port = htons(netj->listen_port); address.sin_addr.s_addr = htonl(INADDR_ANY); if (bind (netj->sockfd, (struct sockaddr *) &address, sizeof (address)) < 0) { jack_info("bind error"); return -1; } netj->outsockfd = socket (AF_INET, SOCK_DGRAM, 0); #ifdef WIN32 if (netj->outsockfd == INVALID_SOCKET) #else if (netj->outsockfd == -1) #endif { jack_info ("socket error"); return -1; } netj->srcaddress_valid = 0; if (netj->use_autoconfig) { jacknet_packet_header *first_packet = alloca (sizeof (jacknet_packet_header)); #ifdef WIN32 int address_size = sizeof( struct sockaddr_in ); #else socklen_t address_size = sizeof (struct sockaddr_in); #endif //jack_info ("Waiting for an incoming packet !!!"); //jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); while(1) { if( ! netjack_poll( netj->sockfd, 1000 ) ) { jack_info ("Waiting aborted"); return -1; } first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); #ifdef WIN32 if( first_pack_len == -1 ) { first_pack_len = sizeof(jacknet_packet_header); break; } #else if (first_pack_len == sizeof (jacknet_packet_header)) break; #endif } netj->srcaddress_valid = 1; if (first_pack_len == sizeof (jacknet_packet_header)) { packet_header_ntoh (first_packet); jack_info ("AutoConfig Override !!!"); if (netj->sample_rate != first_packet->sample_rate) { jack_info ("AutoConfig Override: Master JACK sample rate = %d", first_packet->sample_rate); netj->sample_rate = first_packet->sample_rate; } if (netj->period_size != first_packet->period_size) { jack_info ("AutoConfig Override: Master JACK period size is %d", first_packet->period_size); netj->period_size = first_packet->period_size; } if (netj->capture_channels_audio != first_packet->capture_channels_audio) { jack_info ("AutoConfig Override: capture_channels_audio = %d", first_packet->capture_channels_audio); netj->capture_channels_audio = first_packet->capture_channels_audio; } if (netj->capture_channels_midi != first_packet->capture_channels_midi) { jack_info ("AutoConfig Override: capture_channels_midi = %d", first_packet->capture_channels_midi); netj->capture_channels_midi = first_packet->capture_channels_midi; } if (netj->playback_channels_audio != first_packet->playback_channels_audio) { jack_info ("AutoConfig Override: playback_channels_audio = %d", first_packet->playback_channels_audio); netj->playback_channels_audio = first_packet->playback_channels_audio; } if (netj->playback_channels_midi != first_packet->playback_channels_midi) { jack_info ("AutoConfig Override: playback_channels_midi = %d", first_packet->playback_channels_midi); netj->playback_channels_midi = first_packet->playback_channels_midi; } netj->mtu = first_packet->mtu; jack_info ("MTU is set to %d bytes", first_packet->mtu); netj->latency = first_packet->latency; } } netj->capture_channels = netj->capture_channels_audio + netj->capture_channels_midi; netj->playback_channels = netj->playback_channels_audio + netj->playback_channels_midi; if( (netj->capture_channels * netj->period_size * netj->latency * 4) > 100000000 ) { jack_error( "autoconfig requests more than 100MB packet cache... bailing out" ); exit(1); } if( netj->playback_channels > 1000 ) { jack_error( "autoconfig requests more than 1000 playback channels... bailing out" ); exit(1); } if( netj->mtu < (2*sizeof( jacknet_packet_header )) ) { jack_error( "bullshit mtu requested by autoconfig" ); exit(1); } if( netj->sample_rate == 0 ) { jack_error( "sample_rate 0 requested by autoconfig" ); exit(1); } // After possible Autoconfig: do all calculations... netj->period_usecs = (jack_time_t) floor ((((float) netj->period_size) / (float)netj->sample_rate) * 1000000.0f); if( netj->latency == 0 ) netj->deadline_offset = 50*netj->period_usecs; else netj->deadline_offset = netj->period_usecs + 10*netj->latency*netj->period_usecs/100; if( netj->bitdepth == CELT_MODE ) { // celt mode. // TODO: this is a hack. But i dont want to change the packet header. netj->resample_factor = (netj->resample_factor * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); netj->resample_factor_up = (netj->resample_factor_up * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); netj->net_period_down = netj->resample_factor; netj->net_period_up = netj->resample_factor_up; } else { netj->net_period_down = (float) netj->period_size / (float) netj->resample_factor; netj->net_period_up = (float) netj->period_size / (float) netj->resample_factor_up; } netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth); netj->packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu); netj->expected_framecnt_valid = 0; netj->num_lost_packets = 0; netj->next_deadline_valid = 0; netj->deadline_goodness = 0; netj->time_to_deadline = 0; // Special handling for latency=0 if( netj->latency == 0 ) netj->resync_threshold = 0; else netj->resync_threshold = MIN( 15, netj->latency-1 ); netj->running_free = 0; return 0; }