From 275195f15372babf2ed32dae40fb5c256f4ea560 Mon Sep 17 00:00:00 2001 From: moret Date: Fri, 1 Aug 2008 12:43:54 +0000 Subject: [PATCH] Add fast network mode, allowing zero latency transmission when possible git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2760 0c269be4-1314-0410-8aa9-9f06e86f4224 --- common/JackNetDriver.cpp | 39 ++++++++++----------------- common/JackNetManager.cpp | 56 +++++++++++++++++++++++---------------- common/JackNetTool.cpp | 4 +-- common/JackNetTool.h | 2 +- 4 files changed, 50 insertions(+), 51 deletions(-) diff --git a/common/JackNetDriver.cpp b/common/JackNetDriver.cpp index 4588fec8..507db84f 100644 --- a/common/JackNetDriver.cpp +++ b/common/JackNetDriver.cpp @@ -54,7 +54,7 @@ namespace Jack JackNetDriver::JackNetDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, const char* ip, int port, int mtu, int midi_input_ports, int midi_output_ports, - const char* net_name, uint transport_sync, char network_master_mode ) + const char* net_name, uint transport_sync, char network_mode ) : JackAudioDriver ( name, alias, engine, table ), fSocket ( ip, port ) { jack_log ( "JackNetDriver::JackNetDriver ip %s, port %d", ip, port ); @@ -67,7 +67,7 @@ namespace Jack strcpy ( fParams.fName, net_name ); fSocket.GetName ( fParams.fSlaveNetName ); fParams.fTransportSync = transport_sync; - fParams.fNetworkMasterMode = network_master_mode; + fParams.fNetworkMode = network_mode; #ifdef JACK_MONITOR fMonitor = NULL; fMeasure = NULL; @@ -348,7 +348,7 @@ namespace Jack string plot_name = string ( fParams.fName ); plot_name += string ( "_slave" ); plot_name += ( fEngineControl->fSyncMode ) ? string ( "_sync" ) : string ( "_async" ); - plot_name += ( fParams.fNetworkMasterMode == 'f' ) ? string ( "_fast-network" ) : string ( "_slow-network" ); + plot_name += ( fParams.fNetworkMode == 'f' ) ? string ( "_fast-network" ) : string ( "" ); fMonitor = new JackGnuPlotMonitor ( JackNetDriver::fMeasureCnt, JackNetDriver::fMeasurePoints, plot_name ); fMeasure = new float[JackNetDriver::fMeasurePoints]; fMonitor->SetPlotFile ( JackNetDriver::fMonitorPlotOptions, JackNetDriver::fMonitorPlotOptionsCnt, @@ -400,7 +400,7 @@ namespace Jack } port = fGraphManager->GetPort ( port_id ); port->SetAlias ( alias ); - port->SetLatency ( fEngineControl->fBufferSize + ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ); + port->SetLatency ( ( fParams.fNetworkMode == 'f' ) ? 0 : fEngineControl->fBufferSize + ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ); fPlaybackPortList[audio_port_index] = port_id; jack_log ( "JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() ); } @@ -434,7 +434,7 @@ namespace Jack return -1; } port = fGraphManager->GetPort ( port_id ); - port->SetLatency ( fEngineControl->fBufferSize + ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ); + port->SetLatency ( ( fParams.fNetworkMode == 'f' ) ? 0 : fEngineControl->fBufferSize + ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ); fMidiPlaybackPortList[midi_port_index] = port_id; jack_log ( "JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() ); } @@ -614,7 +614,7 @@ namespace Jack if ( fEngineControl->fSyncMode ) fTxHeader.fCycle = fRxHeader.fCycle; else - fTxHeader.fCycle++; + fTxHeader.fCycle = fRxHeader.fCycle - 1; fTxHeader.fSubCycle = 0; fTxHeader.fIsLastPckt = 'n'; @@ -777,10 +777,10 @@ namespace Jack i++; strcpy ( desc->params[i].name, "network_mode" ); - desc->params[i].character = 'N'; - desc->params[i].type = JackDriverParamChar; - desc->params[i].value.ui = 's'; - strcpy ( desc->params[i].short_desc, "Slow network add 1 cycle latency" ); + desc->params[i].character = 'f'; + desc->params[i].type = JackDriverParamString; + strcpy ( desc->params[i].value.str, "" ); + strcpy ( desc->params[i].short_desc, "Fast mode allows a zero latency transmission." ); strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); return desc; @@ -806,7 +806,7 @@ namespace Jack int midi_input_ports = 0; int midi_output_ports = 0; bool monitor = false; - char network_master_mode = 's'; + char network_mode = 'n'; const JSList* node; const jack_driver_param_t* param; @@ -842,26 +842,15 @@ namespace Jack case 't' : transport_sync = param->value.ui; break; - case 'N' : - switch ( param->value.ui ) - { - case 's' : - network_master_mode = 's'; - break; - case 'f' : - network_master_mode = 'f'; - break; - default : - network_master_mode = 's'; - break; - } + case 'f' : + network_mode = 'f'; break; } } Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver ( new Jack::JackNetDriver ( "system", "net_pcm", engine, table, multicast_ip, udp_port, mtu, - midi_input_ports, midi_output_ports, name, transport_sync, network_master_mode ) ); + midi_input_ports, midi_output_ports, name, transport_sync, network_mode ) ); if ( driver->Open ( period_size, sample_rate, 1, 1, audio_capture_ports, audio_playback_ports, monitor, "from_master_", "to_master_", 0, 0 ) == 0 ) return driver; diff --git a/common/JackNetManager.cpp b/common/JackNetManager.cpp index a11b02e1..84596280 100644 --- a/common/JackNetManager.cpp +++ b/common/JackNetManager.cpp @@ -125,7 +125,7 @@ namespace Jack string plot_name = string ( fParams.fName ); plot_name += string ( "_master" ); plot_name += string ( ( fParams.fSlaveSyncMode ) ? "_sync" : "_async" ); - plot_name += ( fParams.fNetworkMasterMode == 'f' ) ? string ( "_fast-network" ) : string ( "_slow-network" ); + plot_name += ( fParams.fNetworkMode == 'f' ) ? string ( "_fast-network" ) : string ( "" ); fMonitor = new JackGnuPlotMonitor ( JackNetMaster::fMeasureCnt, JackNetMaster::fMeasurePoints, plot_name ); fMeasure = new float[JackNetMaster::fMeasurePoints]; fMonitor->SetPlotFile ( JackNetMaster::fMonitorPlotOptions, JackNetMaster::fMonitorPlotOptionsCnt, @@ -253,7 +253,7 @@ namespace Jack sprintf ( name, "from_slave_%d", i+1 ); if ( ( fAudioPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0 ) ) == NULL ) goto fail; - jack_port_set_latency ( fAudioPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); + jack_port_set_latency ( fAudioPlaybackPorts[i], ( fParams.fNetworkMode == 'f' ) ? 0 : port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); } //midi port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal; @@ -270,7 +270,7 @@ namespace Jack sprintf ( name, "midi_from_slave_%d", i+1 ); if ( ( fMidiPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, port_flags, 0 ) ) == NULL ) goto fail; - jack_port_set_latency ( fMidiPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); + jack_port_set_latency ( fMidiPlaybackPorts[i], ( fParams.fNetworkMode == 'f' ) ? 0 : port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); } fRunning = true; @@ -494,28 +494,34 @@ namespace Jack #endif //receive -------------------------------------------------------------------------------------------------------------------- - //sync + //sync : how much data is available ? rx_bytes = Recv ( fParams.fMtu, MSG_PEEK ); - //wait here for sync, switch network mode : - // -fast : this recv will wait for a long time (90% of cycle duration) - // -slow : just wait for a short time, then return, the data will be available at the next cycle if ( ( rx_bytes == 0 ) || ( rx_bytes == SOCKET_ERROR ) ) return rx_bytes; - //slow mode : - if ( fParams.fNetworkMasterMode == 's' ) + switch ( fParams.fNetworkMode ) { - if ( rx_head->fCycle == fTxHeader.fCycle ) - return 0; - else - rx_bytes = Recv ( rx_head->fPacketSize, 0); - } - - //fast mode : - if ( fParams.fNetworkMasterMode == 'f' ) - { - if ( fTxHeader.fCycle - fRxHeader.fCycle ) - jack_log ( "%s : %s = %d", fParams.fName, ( fParams.fSlaveSyncMode ) ? "SyncCycleOffset" : "AsyncCycleOffset", fTxHeader.fCycle - fRxHeader.fCycle ); + case 'n' : //normal mode + //normal use of the network : allow to use full bandwith + // - extra latency is set to one cycle, what corresponds to the time needed to receive streams using full network bandwith + // - 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 ( rx_head->fCycle == fTxHeader.fCycle ) + return 0; + else + { + rx_bytes = Recv ( rx_head->fPacketSize, 0 ); + } + break; + case 'f' : //fast mode + //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 ( rx_head->fCycle != fTxHeader.fCycle ) + jack_error ( "%s, can't stay in fast network mode, data received too late (%d cycle(s) offset)", fParams.fName, fTxHeader.fCycle - rx_head->fCycle ); + break; } #ifdef JACK_MONITOR @@ -526,16 +532,20 @@ namespace Jack { do { + //how much data is queued on the rx buffer ? rx_bytes = Recv ( fParams.fMtu, MSG_PEEK ); if ( rx_bytes == SOCKET_ERROR ) return rx_bytes; - if ( ++jumpcnt == fNSubProcess ) + //if no data, + if ( ( rx_bytes == 0 ) && ( ++jumpcnt == fNSubProcess ) ) { jack_error ( "No data from %s...", fParams.fName ); jumpcnt = 0; } + //else if data is valid, if ( rx_bytes && ( rx_head->fDataStream == 'r' ) && ( rx_head->fID == fParams.fID ) ) { + //read data switch ( rx_head->fDataType ) { case 'm': //midi @@ -558,8 +568,8 @@ namespace Jack jumpcnt = 0; break; case 's': //sync - Recv ( rx_head->fPacketSize, 0 ); - return 0; + if ( rx_head->fCycle == fTxHeader.fCycle ) + return 0; } } } diff --git a/common/JackNetTool.cpp b/common/JackNetTool.cpp index 8cc6f4f2..8c25aeb5 100644 --- a/common/JackNetTool.cpp +++ b/common/JackNetTool.cpp @@ -218,7 +218,7 @@ namespace Jack jack_info ( "Packet per period : %u", params->fPeriodSize / params->fFramesPerPacket ); jack_info ( "Bitdepth : %s", bitdepth ); jack_info ( "Slave mode : %s", ( params->fSlaveSyncMode ) ? "sync" : "async" ); - jack_info ( "Network mode : %s", ( params->fNetworkMasterMode == 'f' ) ? "fast" : "slow" ); + jack_info ( "Network mode : %s", ( params->fNetworkMode == 'f' ) ? "fast" : "normal" ); jack_info ( "****************************************************" ); } @@ -375,7 +375,7 @@ namespace Jack { float time; //fast mode, wait for the entire cycle duration - if ( params->fNetworkMasterMode == 'f' ) + if ( params->fNetworkMode == 'f' ) time = 900000.f * ( static_cast ( params->fPeriodSize ) / static_cast ( params->fSampleRate ) ); //slow mode, just try recv during two subcycle audio packets else diff --git a/common/JackNetTool.h b/common/JackNetTool.h index 6f4ecfec..fecdd532 100644 --- a/common/JackNetTool.h +++ b/common/JackNetTool.h @@ -73,7 +73,7 @@ namespace Jack uint32_t fFramesPerPacket; //complete frames per packet uint32_t fBitdepth; //samples bitdepth (unused) uint32_t fSlaveSyncMode; //is the slave in sync mode ? - char fNetworkMasterMode; //fast or slow mode + char fNetworkMode; //fast or slow mode }; //net status **********************************************************************************