git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2755 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.90
| @@ -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, char network_slave_mode ) | |||
| const char* net_name, uint transport_sync, char network_master_mode ) | |||
| : JackAudioDriver ( name, alias, engine, table ), fSocket ( ip, port ) | |||
| { | |||
| jack_log ( "JackNetDriver::JackNetDriver ip %s, port %d", ip, port ); | |||
| @@ -68,7 +68,6 @@ namespace Jack | |||
| fSocket.GetName ( fParams.fSlaveNetName ); | |||
| fParams.fTransportSync = transport_sync; | |||
| fParams.fNetworkMasterMode = network_master_mode; | |||
| fParams.fNetworkSlaveMode = network_slave_mode; | |||
| #ifdef JACK_MONITOR | |||
| fMonitor = NULL; | |||
| fMeasure = NULL; | |||
| @@ -190,6 +189,7 @@ namespace Jack | |||
| session_params_t params; | |||
| int us_timeout = 2000000; | |||
| int rx_bytes = 0; | |||
| unsigned char loop = 0; | |||
| //socket | |||
| if ( fSocket.NewSocket() == SOCKET_ERROR ) | |||
| @@ -206,6 +206,10 @@ namespace Jack | |||
| if ( fSocket.SetTimeOut ( us_timeout ) == SOCKET_ERROR ) | |||
| jack_error ( "Can't set timeout : %s", StrError ( NET_ERROR_CODE ) ); | |||
| //disable local loop | |||
| if ( fSocket.SetOption ( IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof ( loop ) ) == SOCKET_ERROR ) | |||
| jack_error ( "Can't disable multicast loop : %s", StrError ( NET_ERROR_CODE ) ); | |||
| //send 'AVAILABLE' until 'SLAVE_SETUP' received | |||
| jack_info ( "Waiting for a master..." ); | |||
| do | |||
| @@ -213,19 +217,15 @@ namespace Jack | |||
| //send 'available' | |||
| if ( fSocket.SendTo ( &fParams, sizeof ( session_params_t ), 0, fMulticastIP ) == SOCKET_ERROR ) | |||
| jack_error ( "Error in data send : %s", StrError ( NET_ERROR_CODE ) ); | |||
| //filter incoming packets : don't exit while receiving wrong packets | |||
| do | |||
| //filter incoming packets : don't exit while no error is detected | |||
| rx_bytes = fSocket.CatchHost ( ¶ms, sizeof ( session_params_t ), 0 ); | |||
| if ( ( rx_bytes == SOCKET_ERROR ) && ( fSocket.GetError() != NET_NO_DATA ) ) | |||
| { | |||
| rx_bytes = fSocket.CatchHost ( ¶ms, sizeof ( session_params_t ), 0 ); | |||
| if ( ( rx_bytes == SOCKET_ERROR ) && ( fSocket.GetError() != NET_NO_DATA ) ) | |||
| { | |||
| jack_error ( "Can't receive : %s", StrError ( NET_ERROR_CODE ) ); | |||
| return NET_RECV_ERROR; | |||
| } | |||
| jack_error ( "Can't receive : %s", StrError ( NET_ERROR_CODE ) ); | |||
| return NET_RECV_ERROR; | |||
| } | |||
| while ( ( rx_bytes > 0 ) && strcmp ( params.fPacketType, fParams.fPacketType ) ); | |||
| } | |||
| while ( ( GetPacketType ( ¶ms ) != SLAVE_SETUP ) ); | |||
| while ( strcmp ( params.fPacketType, fParams.fPacketType ) && ( GetPacketType ( ¶ms ) != SLAVE_SETUP ) ); | |||
| //connect the socket | |||
| if ( fSocket.Connect() == SOCKET_ERROR ) | |||
| @@ -526,10 +526,6 @@ namespace Jack | |||
| int JackNetDriver::Read() | |||
| { | |||
| //slow mode and first cycle : skip read | |||
| if ( ( fParams.fNetworkSlaveMode == 's' ) && ( fRxHeader.fCycle == 0 ) ) | |||
| return 0; | |||
| int rx_bytes; | |||
| uint recvd_midi_pckt = 0; | |||
| packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer ); | |||
| @@ -779,7 +775,7 @@ namespace Jack | |||
| desc->params[i].value.ui = 's'; | |||
| strcpy ( desc->params[i].short_desc, "Slow network add 1 cycle latency" ); | |||
| strcpy ( desc->params[i].long_desc, "'s' for slow, 'f' for fast, default is slow.\ | |||
| Fast network will make the master waiting for the current cycle return data." ); | |||
| Fast network will make the master waiting for the current cycle return data." ); | |||
| i++; | |||
| strcpy ( desc->params[i].name, "network_slave_mode" ); | |||
| @@ -788,7 +784,7 @@ namespace Jack | |||
| desc->params[i].value.ui = 's'; | |||
| strcpy ( desc->params[i].short_desc, "Slow network add 1 cycle latency" ); | |||
| strcpy ( desc->params[i].long_desc, "'s' for slow, 'f' for fast, default is slow.\ | |||
| Fast network will make the slave waiting for the first cycle data." ); | |||
| Fast network will make the slave waiting for the first cycle data." ); | |||
| return desc; | |||
| } | |||
| @@ -814,7 +810,6 @@ namespace Jack | |||
| int midi_output_ports = 0; | |||
| bool monitor = false; | |||
| char network_master_mode = 's'; | |||
| char network_slave_mode = 's'; | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| @@ -850,40 +845,26 @@ namespace Jack | |||
| case 't' : | |||
| transport_sync = param->value.ui; | |||
| break; | |||
| case 'm' : | |||
| switch ( param->value.ui ) | |||
| { | |||
| case 's' : | |||
| network_master_mode = 's'; | |||
| break; | |||
| case 'f' : | |||
| network_master_mode = 'f'; | |||
| break; | |||
| default : | |||
| network_master_mode = 's'; | |||
| break; | |||
| } | |||
| break; | |||
| case 's' : | |||
| switch ( param->value.ui ) | |||
| { | |||
| case 's' : | |||
| network_slave_mode = 's'; | |||
| break; | |||
| case 'f' : | |||
| network_slave_mode = 'f'; | |||
| break; | |||
| default : | |||
| network_slave_mode = 's'; | |||
| break; | |||
| } | |||
| 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; | |||
| } | |||
| 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, network_slave_mode ) ); | |||
| midi_input_ports, midi_output_ports, name, transport_sync, network_master_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; | |||
| @@ -30,9 +30,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| namespace Jack | |||
| { | |||
| /** | |||
| \Brief This class describes the Net Backend | |||
| */ | |||
| /** | |||
| \Brief This class describes the Net Backend | |||
| */ | |||
| class JackNetDriver : public JackAudioDriver | |||
| { | |||
| @@ -100,7 +100,7 @@ namespace Jack | |||
| public: | |||
| 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* master_name, uint transport_sync, char network_master_mode, char network_slave_mode ); | |||
| const char* master_name, uint transport_sync, char network_master_mode ); | |||
| ~JackNetDriver(); | |||
| int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, bool capturing, bool playing, | |||
| @@ -166,6 +166,7 @@ namespace Jack | |||
| int usec_timeout = 1000000; | |||
| uint attempt = 0; | |||
| int rx_bytes = 0; | |||
| int rx_bufsize = 0; | |||
| //socket | |||
| if ( fSocket.NewSocket() == SOCKET_ERROR ) | |||
| @@ -212,6 +213,14 @@ namespace Jack | |||
| return false; | |||
| } | |||
| //set the new rx buffer size | |||
| rx_bufsize = GetNetBufferSize ( &fParams ); | |||
| if ( fSocket.SetOption ( SOL_SOCKET, SO_RCVBUF, &rx_bufsize, sizeof ( rx_bufsize ) ) == SOCKET_ERROR ) | |||
| { | |||
| jack_error ( "Can't set rx buffer size : %s", StrError ( NET_ERROR_CODE ) ); | |||
| return false; | |||
| } | |||
| //jack client and process | |||
| jack_status_t status; | |||
| jack_options_t options = JackNullOption; | |||
| @@ -354,12 +363,9 @@ namespace Jack | |||
| if ( ( rx_bytes = fSocket.Recv ( fRxBuffer, size, flags ) ) == SOCKET_ERROR ) | |||
| { | |||
| net_error_t error = fSocket.GetError(); | |||
| //no data isn't really a network error, so just return 0 avalaible read bytes | |||
| if ( error == NET_NO_DATA ) | |||
| { | |||
| //no data isn't really a network error, so just return 0 avalaible read bytes | |||
| jack_error ( "No data from %s...", fParams.fName ); | |||
| return 0; | |||
| } | |||
| else if ( fRunning && ( error == NET_CONN_ERROR ) ) | |||
| { | |||
| //fatal connection issue, exit | |||
| @@ -387,8 +393,8 @@ namespace Jack | |||
| int tx_bytes = 0; | |||
| int rx_bytes = 0; | |||
| int copy_size = 0; | |||
| size_t midi_recvd_pckt = 0; | |||
| uint midi_recvd_pckt = 0; | |||
| uint jumpcnt = 0; | |||
| fTxHeader.fCycle++; | |||
| fTxHeader.fSubCycle = 0; | |||
| fTxHeader.fIsLastPckt = 'n'; | |||
| @@ -421,12 +427,13 @@ namespace Jack | |||
| //send ------------------------------------------------------------------------------------------------------------------ | |||
| //sync | |||
| fTxHeader.fDataType = 's'; | |||
| //memset ( fTxData, 0, fPayloadSize ); | |||
| //SetSyncPacket(); | |||
| if ( !fParams.fSendMidiChannels && !fParams.fSendAudioChannels ) | |||
| fTxHeader.fIsLastPckt = 'y'; | |||
| fTxHeader.fPacketSize = sizeof ( packet_header_t ); | |||
| memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) ); | |||
| //memset ( fTxData, 0, fPayloadSize ); | |||
| //SetSyncPacket(); | |||
| tx_bytes = Send ( fTxBuffer, sizeof ( packet_header_t ), 0 ); | |||
| tx_bytes = Send ( fTxBuffer, fTxHeader.fPacketSize, 0 ); | |||
| if ( tx_bytes == SOCKET_ERROR ) | |||
| return tx_bytes; | |||
| @@ -445,9 +452,10 @@ namespace Jack | |||
| fTxHeader.fSubCycle = subproc; | |||
| if ( ( subproc == ( fTxHeader.fNMidiPckt - 1 ) ) && !fParams.fSendAudioChannels ) | |||
| fTxHeader.fIsLastPckt = 'y'; | |||
| fTxHeader.fPacketSize = fNetMidiCaptureBuffer->RenderToNetwork ( subproc, fTxHeader.fMidiDataSize ); | |||
| fTxHeader.fPacketSize += sizeof ( packet_header_t ); | |||
| memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) ); | |||
| copy_size = fNetMidiCaptureBuffer->RenderToNetwork ( subproc, fTxHeader.fMidiDataSize ); | |||
| tx_bytes = Send ( fTxBuffer, sizeof ( packet_header_t ) + copy_size, 0 ); | |||
| tx_bytes = Send ( fTxBuffer, fTxHeader.fPacketSize, 0 ); | |||
| if ( tx_bytes == SOCKET_ERROR ) | |||
| return tx_bytes; | |||
| } | |||
| @@ -462,9 +470,10 @@ namespace Jack | |||
| fTxHeader.fSubCycle = subproc; | |||
| if ( subproc == ( fNSubProcess - 1 ) ) | |||
| fTxHeader.fIsLastPckt = 'y'; | |||
| memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) ); | |||
| fTxHeader.fPacketSize = fAudioTxLen; | |||
| fNetAudioCaptureBuffer->RenderFromJackPorts ( subproc ); | |||
| tx_bytes = Send ( fTxBuffer, fAudioTxLen, 0 ); | |||
| memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) ); | |||
| tx_bytes = Send ( fTxBuffer, fTxHeader.fPacketSize, 0 ); | |||
| if ( tx_bytes == SOCKET_ERROR ) | |||
| return tx_bytes; | |||
| } | |||
| @@ -476,10 +485,10 @@ namespace Jack | |||
| //receive -------------------------------------------------------------------------------------------------------------------- | |||
| //sync | |||
| rx_bytes == Recv ( sizeof ( packet_header_t ), 0 ); | |||
| rx_bytes = Recv ( sizeof ( packet_header_t ), 0 ); | |||
| //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 | |||
| // -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; | |||
| @@ -492,33 +501,38 @@ namespace Jack | |||
| do | |||
| { | |||
| rx_bytes = Recv ( fParams.fMtu, MSG_PEEK ); | |||
| if ( ( rx_bytes == 0 ) || ( rx_bytes == SOCKET_ERROR ) ) | |||
| if ( rx_bytes == SOCKET_ERROR ) | |||
| return rx_bytes; | |||
| if ( ++jumpcnt == fNSubProcess ) | |||
| { | |||
| jack_error ( "No data from %s...", fParams.fName ); | |||
| jumpcnt = 0; | |||
| } | |||
| if ( rx_bytes && ( rx_head->fDataStream == 'r' ) && ( rx_head->fID == fParams.fID ) ) | |||
| { | |||
| switch ( rx_head->fDataType ) | |||
| { | |||
| case 'm': //midi | |||
| rx_bytes = Recv ( rx_bytes, 0 ); | |||
| Recv ( rx_head->fPacketSize, 0 ); | |||
| fRxHeader.fCycle = rx_head->fCycle; | |||
| fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; | |||
| fNetMidiPlaybackBuffer->RenderFromNetwork ( rx_head->fSubCycle, rx_bytes - sizeof ( packet_header_t ) ); | |||
| if ( ++midi_recvd_pckt == rx_head->fNMidiPckt ) | |||
| fNetMidiPlaybackBuffer->RenderToJackPorts(); | |||
| jumpcnt = 0; | |||
| break; | |||
| case 'a': //audio | |||
| rx_bytes = Recv ( fAudioRxLen, 0 ); | |||
| Recv ( rx_head->fPacketSize, 0 ); | |||
| if ( !IsNextPacket ( &fRxHeader, rx_head, fNSubProcess ) ) | |||
| jack_error ( "Packet(s) missing from '%s'...", fParams.fName ); | |||
| fRxHeader.fCycle = rx_head->fCycle; | |||
| fRxHeader.fSubCycle = rx_head->fSubCycle; | |||
| fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; | |||
| fNetAudioPlaybackBuffer->RenderToJackPorts ( rx_head->fSubCycle ); | |||
| jumpcnt = 0; | |||
| break; | |||
| case 's': //sync | |||
| rx_bytes = Recv ( rx_bytes, 0 ); | |||
| fRxHeader.fCycle = rx_head->fCycle; | |||
| fRxHeader.fSubCycle = rx_head->fSubCycle; | |||
| Recv ( rx_head->fPacketSize, 0 ); | |||
| return 0; | |||
| } | |||
| } | |||
| @@ -271,6 +271,7 @@ namespace Jack | |||
| header->fMidiDataSize = htonl ( header->fMidiDataSize ); | |||
| header->fBitdepth = htonl ( header->fBitdepth ); | |||
| header->fNMidiPckt = htonl ( header->fNMidiPckt ); | |||
| header->fPacketSize = htonl ( header->fPacketSize ); | |||
| header->fCycle = ntohl ( header->fCycle ); | |||
| header->fSubCycle = htonl ( header->fSubCycle ); | |||
| } | |||
| @@ -281,6 +282,7 @@ namespace Jack | |||
| header->fMidiDataSize = ntohl ( header->fMidiDataSize ); | |||
| header->fBitdepth = ntohl ( header->fBitdepth ); | |||
| header->fNMidiPckt = ntohl ( header->fNMidiPckt ); | |||
| header->fPacketSize = ntohl ( header->fPacketSize ); | |||
| header->fCycle = ntohl ( header->fCycle ); | |||
| header->fSubCycle = ntohl ( header->fSubCycle ); | |||
| } | |||
| @@ -338,12 +340,23 @@ namespace Jack | |||
| { | |||
| if ( !params->fSendAudioChannels && !params->fReturnAudioChannels ) | |||
| return ( params->fFramesPerPacket = params->fPeriodSize ); | |||
| size_t period = ( int ) powf ( 2.f, ( int ) ( log ( ( params->fMtu - sizeof ( packet_header_t ) ) | |||
| jack_nframes_t period = ( int ) powf ( 2.f, ( int ) ( log ( ( params->fMtu - sizeof ( packet_header_t ) ) | |||
| / ( max ( params->fReturnAudioChannels, params->fSendAudioChannels ) * sizeof ( sample_t ) ) ) / log ( 2 ) ) ); | |||
| ( period > params->fPeriodSize ) ? params->fFramesPerPacket = params->fPeriodSize : params->fFramesPerPacket = period; | |||
| return params->fFramesPerPacket; | |||
| } | |||
| EXPORT int GetNetBufferSize ( session_params_t* params ) | |||
| { | |||
| //audio | |||
| float audio_size = params->fMtu * ( params->fPeriodSize / params->fFramesPerPacket ); | |||
| //midi | |||
| float midi_size = params->fMtu * ( max ( params->fSendMidiChannels, params->fReturnMidiChannels ) * | |||
| params->fPeriodSize * sizeof ( sample_t ) / ( params->fMtu - sizeof ( packet_header_t ) ) ); | |||
| //return : sizes of sync + audio + midi | |||
| return ( params->fMtu + ( int ) audio_size + ( int ) midi_size ); | |||
| } | |||
| EXPORT int GetNMidiPckt ( session_params_t* params, size_t data_size ) | |||
| { | |||
| //even if there is no midi data, jack need an empty buffer to know there is no event to read | |||
| @@ -357,18 +370,18 @@ namespace Jack | |||
| return npckt; | |||
| } | |||
| EXPORT int SetRxTimeout ( JackNetSocket* socket, session_params_t* params ) | |||
| { | |||
| float time; | |||
| //fast mode, wait for the entire cycle duration | |||
| if ( params->fNetworkMasterMode == 'f' ) | |||
| time = 900000.f * ( static_cast<float> ( params->fPeriodSize ) / static_cast<float> ( params->fSampleRate ) ); | |||
| //slow mode, just try recv during a subcycle audio packet | |||
| else | |||
| time = 1250000.f * ( static_cast<float> ( params->fFramesPerPacket ) / static_cast<float> ( params->fSampleRate ) ); | |||
| EXPORT int SetRxTimeout ( JackNetSocket* socket, session_params_t* params ) | |||
| { | |||
| float time; | |||
| //fast mode, wait for the entire cycle duration | |||
| if ( params->fNetworkMasterMode == 'f' ) | |||
| time = 900000.f * ( static_cast<float> ( params->fPeriodSize ) / static_cast<float> ( params->fSampleRate ) ); | |||
| //slow mode, just try recv during two subcycle audio packets | |||
| else | |||
| time = 2000000.f * ( static_cast<float> ( params->fFramesPerPacket ) / static_cast<float> ( params->fSampleRate ) ); | |||
| int usec = ( int ) time; | |||
| return socket->SetTimeOut ( usec ); | |||
| } | |||
| return socket->SetTimeOut ( usec ); | |||
| } | |||
| // Packet ******************************************************************************************************* | |||
| @@ -39,19 +39,19 @@ namespace Jack | |||
| //session params ****************************************************************************** | |||
| /** | |||
| \brief This structure containes master/slave connection parameters, it's used to setup the whole system | |||
| We have : | |||
| - some info like version, type and packet id | |||
| - names | |||
| - network parameters (hostnames and mtu) | |||
| - nunber of audio and midi channels | |||
| - sample rate and buffersize | |||
| - number of audio frames in one network packet (depends on the channel number) | |||
| - is the NetDriver in Sync or ASync mode ? | |||
| - is the NetDriver linked with the master's transport | |||
| */ | |||
| /** | |||
| \brief This structure containes master/slave connection parameters, it's used to setup the whole system | |||
| We have : | |||
| - some info like version, type and packet id | |||
| - names | |||
| - network parameters (hostnames and mtu) | |||
| - nunber of audio and midi channels | |||
| - sample rate and buffersize | |||
| - number of audio frames in one network packet (depends on the channel number) | |||
| - is the NetDriver in Sync or ASync mode ? | |||
| - is the NetDriver linked with the master's transport | |||
| */ | |||
| struct _session_params | |||
| { | |||
| @@ -73,15 +73,14 @@ We have : | |||
| 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 fNetworkSlaveMode; //fast or slow mode | |||
| char fNetworkMasterMode; //fast or slow mode | |||
| }; | |||
| //net status ********************************************************************************** | |||
| /** | |||
| \Brief This enum groups network error by type | |||
| */ | |||
| /** | |||
| \Brief This enum groups network error by type | |||
| */ | |||
| enum _net_status | |||
| { | |||
| @@ -98,9 +97,9 @@ We have : | |||
| //sync packet type **************************************************************************** | |||
| /** | |||
| \Brief This enum indicates the type of a sync packet (used in the initialization phase) | |||
| */ | |||
| /** | |||
| \Brief This enum indicates the type of a sync packet (used in the initialization phase) | |||
| */ | |||
| enum _sync_packet_type | |||
| { | |||
| @@ -117,24 +116,24 @@ We have : | |||
| //packet header ******************************************************************************* | |||
| /** | |||
| \Brief This structure is a complete header | |||
| A header indicates : | |||
| - it is a header | |||
| - the type of data the packet contains (sync, midi or audio) | |||
| - the path of the packet (send -master->slave- or return -slave->master-) | |||
| - the unique ID of the slave | |||
| - the sample's bitdepth (unused for now) | |||
| - the size of the midi data contains in the packet (indicates how much midi data will be sent) | |||
| - the number of midi packet(s) : more than one is very unusual, it depends on the midi load | |||
| - the ID of the current cycle (used to check missing packets) | |||
| - the ID of the packet subcycle (for audio data) | |||
| - a flag indicating this packet is the last of the cycle (for sync robustness, it's better to process this way) | |||
| - a flag indicating if, in async mode, the previous graph was not finished or not | |||
| - padding to fill 64 bytes | |||
| */ | |||
| /** | |||
| \Brief This structure is a complete header | |||
| A header indicates : | |||
| - it is a header | |||
| - the type of data the packet contains (sync, midi or audio) | |||
| - the path of the packet (send -master->slave- or return -slave->master-) | |||
| - the unique ID of the slave | |||
| - the sample's bitdepth (unused for now) | |||
| - the size of the midi data contains in the packet (indicates how much midi data will be sent) | |||
| - the number of midi packet(s) : more than one is very unusual, it depends on the midi load | |||
| - the ID of the current cycle (used to check missing packets) | |||
| - the ID of the packet subcycle (for audio data) | |||
| - a flag indicating this packet is the last of the cycle (for sync robustness, it's better to process this way) | |||
| - a flag indicating if, in async mode, the previous graph was not finished or not | |||
| - padding to fill 64 bytes | |||
| */ | |||
| struct _packet_header | |||
| { | |||
| @@ -143,8 +142,9 @@ A header indicates : | |||
| char fDataStream; //s for send, r for return | |||
| uint32_t fID; //unique ID of the slave | |||
| uint32_t fBitdepth; //bitdepth of the data samples | |||
| uint32_t fMidiDataSize; //size of midi data (if packet is 'midi typed') in bytes | |||
| uint32_t fMidiDataSize; //size of midi data in bytes | |||
| uint32_t fNMidiPckt; //number of midi packets of the cycle | |||
| uint32_t fPacketSize; //packet size in bytes | |||
| uint32_t fCycle; //process cycle counter | |||
| uint32_t fSubCycle; //midi/audio subcycle counter | |||
| char fIsLastPckt; //is it the last packet of a given cycle ('y' or 'n') | |||
| @@ -154,9 +154,9 @@ A header indicates : | |||
| //transport data ****************************************************************************** | |||
| /** | |||
| \Brief This structure contains transport info | |||
| */ | |||
| /** | |||
| \Brief This structure contains transport info | |||
| */ | |||
| struct _net_transport_data | |||
| { | |||
| @@ -166,20 +166,20 @@ A header indicates : | |||
| //midi data *********************************************************************************** | |||
| /** | |||
| \Brief Midi buffer and operations class | |||
| /** | |||
| \Brief Midi buffer and operations class | |||
| This class is a toolset to manipulate Midi buffers. | |||
| A JackMidiBuffer has a fixed size, which is the same than an audio buffer size. | |||
| An intermediate fixed size buffer allows to uninterleave midi data (from jack ports). | |||
| But for a big majority of the process cycles, this buffer is filled less than 1%, | |||
| Sending over a network 99% of useless data seems completely unappropriate. | |||
| The idea is to count effective midi data, and then send the smallest packet we can. | |||
| To do it, we use an intermediate buffer. | |||
| We have two methods to convert data from jack ports to intermediate buffer, | |||
| And two others to convert this intermediate buffer to a network buffer (header + payload data) | |||
| This class is a toolset to manipulate Midi buffers. | |||
| A JackMidiBuffer has a fixed size, which is the same than an audio buffer size. | |||
| An intermediate fixed size buffer allows to uninterleave midi data (from jack ports). | |||
| But for a big majority of the process cycles, this buffer is filled less than 1%, | |||
| Sending over a network 99% of useless data seems completely unappropriate. | |||
| The idea is to count effective midi data, and then send the smallest packet we can. | |||
| To do it, we use an intermediate buffer. | |||
| We have two methods to convert data from jack ports to intermediate buffer, | |||
| And two others to convert this intermediate buffer to a network buffer (header + payload data) | |||
| */ | |||
| */ | |||
| class EXPORT NetMidiBuffer | |||
| { | |||
| @@ -212,15 +212,15 @@ And two others to convert this intermediate buffer to a network buffer (header + | |||
| // audio data ********************************************************************************* | |||
| /** | |||
| \Brief Audio buffer and operations class | |||
| /** | |||
| \Brief Audio buffer and operations class | |||
| This class is a toolset to manipulate audio buffers. | |||
| The manipulation of audio buffers is similar to midi buffer, except those buffers have fixed size. | |||
| The interleaving/uninterleaving operations are simplier here because audio buffers have fixed size, | |||
| So there is no need of an intermediate buffer as in NetMidiBuffer. | |||
| This class is a toolset to manipulate audio buffers. | |||
| The manipulation of audio buffers is similar to midi buffer, except those buffers have fixed size. | |||
| The interleaving/uninterleaving operations are simplier here because audio buffers have fixed size, | |||
| So there is no need of an intermediate buffer as in NetMidiBuffer. | |||
| */ | |||
| */ | |||
| class EXPORT NetAudioBuffer | |||
| { | |||
| @@ -264,6 +264,8 @@ So there is no need of an intermediate buffer as in NetMidiBuffer. | |||
| EXPORT int SetPacketType ( session_params_t* params, sync_packet_type_t packet_type ); | |||
| //step of network initialization | |||
| EXPORT jack_nframes_t SetFramesPerPacket ( session_params_t* params ); | |||
| //step of network initialization | |||
| EXPORT int GetNetBufferSize ( session_params_t* params ); | |||
| //get the midi packet number for a given cycle | |||
| EXPORT int GetNMidiPckt ( session_params_t* params, size_t data_size ); | |||
| //set the recv timeout on a socket | |||
| @@ -273,6 +273,8 @@ namespace Jack | |||
| return NET_NO_DATA; | |||
| case ECONNABORTED: | |||
| return NET_CONN_ERROR; | |||
| case EINVAL: | |||
| return NET_CONN_ERROR; | |||
| case ECONNREFUSED: | |||
| return NET_CONN_ERROR; | |||
| case ECONNRESET: | |||