|
|
|
@@ -94,27 +94,27 @@ namespace Jack |
|
|
|
|
|
|
|
int JackNetInterface::SetNetBufferSize() |
|
|
|
{ |
|
|
|
//audio |
|
|
|
// audio |
|
|
|
float audio_size = (fNetAudioCaptureBuffer) |
|
|
|
? fNetAudioCaptureBuffer->GetCycleSize() |
|
|
|
: (fNetAudioPlaybackBuffer) ? fNetAudioPlaybackBuffer->GetCycleSize() : 0; |
|
|
|
? fNetAudioCaptureBuffer->GetCycleSize() |
|
|
|
: (fNetAudioPlaybackBuffer) ? fNetAudioPlaybackBuffer->GetCycleSize() : 0; |
|
|
|
jack_log("audio_size %f", audio_size); |
|
|
|
|
|
|
|
//midi |
|
|
|
// midi |
|
|
|
float midi_size = (fNetMidiCaptureBuffer) |
|
|
|
? fNetMidiCaptureBuffer->GetCycleSize() |
|
|
|
: (fNetMidiPlaybackBuffer) ? fNetMidiPlaybackBuffer->GetCycleSize() : 0; |
|
|
|
? fNetMidiCaptureBuffer->GetCycleSize() |
|
|
|
: (fNetMidiPlaybackBuffer) ? fNetMidiPlaybackBuffer->GetCycleSize() : 0; |
|
|
|
jack_log("midi_size %f", midi_size); |
|
|
|
|
|
|
|
//bufsize = sync + audio + midi |
|
|
|
int bufsize = NETWORK_MAX_LATENCY * (fParams.fMtu + (int)audio_size + (int) midi_size); |
|
|
|
// bufsize = sync + audio + midi |
|
|
|
int bufsize = NETWORK_MAX_LATENCY * (fParams.fMtu + (int)audio_size + (int)midi_size); |
|
|
|
jack_log("SetNetBufferSize bufsize = %d", bufsize); |
|
|
|
|
|
|
|
//tx buffer |
|
|
|
// tx buffer |
|
|
|
if (fSocket.SetOption(SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
|
|
|
|
//rx buffer |
|
|
|
// rx buffer |
|
|
|
if (fSocket.SetOption(SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
|
|
|
|
@@ -123,33 +123,108 @@ namespace Jack |
|
|
|
|
|
|
|
bool JackNetInterface::SetParams() |
|
|
|
{ |
|
|
|
//TX header init |
|
|
|
// TX header init |
|
|
|
strcpy(fTxHeader.fPacketType, "header"); |
|
|
|
fTxHeader.fID = fParams.fID; |
|
|
|
fTxHeader.fCycle = 0; |
|
|
|
fTxHeader.fSubCycle = 0; |
|
|
|
fTxHeader.fIsLastPckt = 0; |
|
|
|
|
|
|
|
//RX header init |
|
|
|
// RX header init |
|
|
|
strcpy(fRxHeader.fPacketType, "header"); |
|
|
|
fRxHeader.fID = fParams.fID; |
|
|
|
fRxHeader.fCycle = 0; |
|
|
|
fRxHeader.fSubCycle = 0; |
|
|
|
fRxHeader.fIsLastPckt = 0; |
|
|
|
|
|
|
|
//network buffers |
|
|
|
// network buffers |
|
|
|
fTxBuffer = new char[fParams.fMtu]; |
|
|
|
fRxBuffer = new char[fParams.fMtu]; |
|
|
|
assert(fTxBuffer); |
|
|
|
assert(fRxBuffer); |
|
|
|
|
|
|
|
//net audio/midi buffers'addresses |
|
|
|
// net audio/midi buffers'addresses |
|
|
|
fTxData = fTxBuffer + HEADER_SIZE; |
|
|
|
fRxData = fRxBuffer + HEADER_SIZE; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetInterface::MidiSend(NetMidiBuffer* buffer, int midi_channnels, int audio_channels) |
|
|
|
{ |
|
|
|
if (midi_channnels > 0) { |
|
|
|
// set global header fields and get the number of midi packets |
|
|
|
fTxHeader.fDataType = 'm'; |
|
|
|
uint data_size = buffer->RenderFromJackPorts(); |
|
|
|
fTxHeader.fNumPacket = buffer->GetNumPackets(data_size, PACKET_AVAILABLE_SIZE); |
|
|
|
|
|
|
|
for (uint subproc = 0; subproc < fTxHeader.fNumPacket; subproc++) { |
|
|
|
fTxHeader.fSubCycle = subproc; |
|
|
|
// fTxHeader.fIsLastPckt = ((subproc == (fTxHeader.fNumPacket - 1)) && !fParams.fReturnAudioChannels) ? 1 : 0; |
|
|
|
fTxHeader.fIsLastPckt = ((subproc == (fTxHeader.fNumPacket - 1)) && audio_channels == 0) ? 1 : 0; |
|
|
|
fTxHeader.fPacketSize = HEADER_SIZE + buffer->RenderToNetwork(subproc, data_size); |
|
|
|
memcpy(fTxBuffer, &fTxHeader, HEADER_SIZE); |
|
|
|
if (Send(fTxHeader.fPacketSize, 0) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetInterface::AudioSend(NetAudioBuffer* buffer, int audio_channels) |
|
|
|
{ |
|
|
|
// audio |
|
|
|
if (audio_channels > 0) { |
|
|
|
fTxHeader.fDataType = 'a'; |
|
|
|
buffer->RenderFromJackPorts(); |
|
|
|
fTxHeader.fNumPacket = buffer->GetNumPackets(); |
|
|
|
|
|
|
|
for (uint subproc = 0; subproc < fTxHeader.fNumPacket; subproc++) { |
|
|
|
fTxHeader.fSubCycle = subproc; |
|
|
|
fTxHeader.fIsLastPckt = (subproc == (fTxHeader.fNumPacket - 1)) ? 1 : 0; |
|
|
|
fTxHeader.fPacketSize = HEADER_SIZE + buffer->RenderToNetwork(subproc, fTxHeader.fActivePorts); |
|
|
|
memcpy(fTxBuffer, &fTxHeader, HEADER_SIZE); |
|
|
|
// PacketHeaderDisplay(&fTxHeader); |
|
|
|
if (Send(fTxHeader.fPacketSize, 0) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetInterface::MidiRecv(packet_header_t* rx_head, NetMidiBuffer* buffer, uint& recvd_midi_pckt) |
|
|
|
{ |
|
|
|
int rx_bytes = Recv(rx_head->fPacketSize, 0); |
|
|
|
fRxHeader.fCycle = rx_head->fCycle; |
|
|
|
fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; |
|
|
|
buffer->RenderFromNetwork(rx_head->fSubCycle, rx_bytes - HEADER_SIZE); |
|
|
|
// Last midi packet is received, so finish rendering... |
|
|
|
if (++recvd_midi_pckt == rx_head->fNumPacket) |
|
|
|
buffer->RenderToJackPorts(); |
|
|
|
return rx_bytes; |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetInterface::AudioRecv(packet_header_t* rx_head, NetAudioBuffer* buffer) |
|
|
|
{ |
|
|
|
int rx_bytes = Recv(rx_head->fPacketSize, 0); |
|
|
|
fRxHeader.fCycle = rx_head->fCycle; |
|
|
|
fRxHeader.fSubCycle = rx_head->fSubCycle; |
|
|
|
fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; |
|
|
|
fRxHeader.fActivePorts = rx_head->fActivePorts; |
|
|
|
rx_bytes = buffer->RenderFromNetwork(rx_head->fCycle, rx_head->fSubCycle, rx_bytes - HEADER_SIZE, fRxHeader.fActivePorts); |
|
|
|
// Last audio packet is received, so finish rendering... |
|
|
|
if (fRxHeader.fIsLastPckt) |
|
|
|
buffer->RenderToJackPorts(); |
|
|
|
return rx_bytes; |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetInterface::FinishRecv(NetAudioBuffer* buffer) |
|
|
|
{ |
|
|
|
// TODO : finish midi and audio rendering ? |
|
|
|
buffer->RenderToJackPorts(); |
|
|
|
return NET_PACKET_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
// JackNetMasterInterface ************************************************************************************ |
|
|
|
|
|
|
|
bool JackNetMasterInterface::Init() |
|
|
|
@@ -160,23 +235,23 @@ namespace Jack |
|
|
|
uint attempt = 0; |
|
|
|
int rx_bytes = 0; |
|
|
|
|
|
|
|
//socket |
|
|
|
// socket |
|
|
|
if (fSocket.NewSocket() == SOCKET_ERROR) { |
|
|
|
jack_error("Can't create socket : %s", StrError(NET_ERROR_CODE)); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
//timeout on receive (for init) |
|
|
|
// timeout on receive (for init) |
|
|
|
if (fSocket.SetTimeOut(MASTER_INIT_TIMEOUT) < 0) |
|
|
|
jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE)); |
|
|
|
|
|
|
|
//connect |
|
|
|
// 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 |
|
|
|
// send 'SLAVE_SETUP' until 'START_MASTER' received |
|
|
|
jack_info("Sending parameters to %s...", fParams.fSlaveNetName); |
|
|
|
do |
|
|
|
{ |
|
|
|
@@ -223,7 +298,9 @@ namespace Jack |
|
|
|
fTxHeader.fDataStream = 's'; |
|
|
|
fRxHeader.fDataStream = 'r'; |
|
|
|
|
|
|
|
//midi net buffers |
|
|
|
fMaxCycleOffset = fParams.fNetworkLatency; |
|
|
|
|
|
|
|
// midi net buffers |
|
|
|
if (fParams.fSendMidiChannels > 0) |
|
|
|
fNetMidiCaptureBuffer = new NetMidiBuffer(&fParams, fParams.fSendMidiChannels, fTxData); |
|
|
|
|
|
|
|
@@ -232,7 +309,7 @@ namespace Jack |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
//audio net buffers |
|
|
|
// audio net buffers |
|
|
|
if (fParams.fSendAudioChannels > 0) { |
|
|
|
|
|
|
|
switch (fParams.fSampleEncoder) { |
|
|
|
@@ -282,13 +359,13 @@ namespace Jack |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
//set the new timeout for the socket |
|
|
|
// set the new timeout for the socket |
|
|
|
if (SetRxTimeout() == SOCKET_ERROR) { |
|
|
|
jack_error("Can't set rx timeout : %s", StrError(NET_ERROR_CODE)); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
//set the new rx buffer size |
|
|
|
// set the new rx buffer size |
|
|
|
if (SetNetBufferSize() == SOCKET_ERROR) { |
|
|
|
jack_error("Can't set net buffer sizes : %s", StrError(NET_ERROR_CODE)); |
|
|
|
goto error; |
|
|
|
@@ -305,10 +382,10 @@ namespace Jack |
|
|
|
{ |
|
|
|
jack_log("JackNetMasterInterface::Exit, ID %u", fParams.fID); |
|
|
|
|
|
|
|
//stop process |
|
|
|
// stop process |
|
|
|
fRunning = false; |
|
|
|
|
|
|
|
//send a 'multicast euthanasia request' - new socket is required on macosx |
|
|
|
// send a 'multicast euthanasia request' - new socket is required on macosx |
|
|
|
jack_info("Exiting '%s'", fParams.fName); |
|
|
|
SetPacketType(&fParams, KILL_MASTER); |
|
|
|
JackNetSocket mcast_socket(fMulticastIP, fSocket.GetPort()); |
|
|
|
@@ -327,9 +404,9 @@ namespace Jack |
|
|
|
|
|
|
|
void JackNetMasterInterface::FatalError() |
|
|
|
{ |
|
|
|
//fatal connection issue, exit |
|
|
|
// fatal connection issue, exit |
|
|
|
jack_error("'%s' : %s, exiting", fParams.fName, StrError(NET_ERROR_CODE)); |
|
|
|
//ask to the manager to properly remove the master |
|
|
|
// ask to the manager to properly remove the master |
|
|
|
Exit(); |
|
|
|
// UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine. |
|
|
|
ThreadExit(); |
|
|
|
@@ -343,7 +420,7 @@ namespace Jack |
|
|
|
|
|
|
|
/* |
|
|
|
net_error_t error = fSocket.GetError(); |
|
|
|
//no data isn't really a network error, so just return 0 available read bytes |
|
|
|
// no data isn't really a network error, so just return 0 available read bytes |
|
|
|
if (error == NET_NO_DATA) { |
|
|
|
return 0; |
|
|
|
} else if (error == NET_CONN_ERROR) { |
|
|
|
@@ -399,18 +476,19 @@ namespace Jack |
|
|
|
fNetAudioPlaybackBuffer->ActivePortsToNetwork(fTxData, fTxHeader.fActivePorts); |
|
|
|
|
|
|
|
memcpy(fTxBuffer, &fTxHeader, HEADER_SIZE); |
|
|
|
//PacketHeaderDisplay(&fTxHeader); |
|
|
|
// PacketHeaderDisplay(&fTxHeader); |
|
|
|
return Send(fTxHeader.fPacketSize, 0); |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetMasterInterface::DataSend() |
|
|
|
{ |
|
|
|
/* |
|
|
|
uint subproc; |
|
|
|
uint data_size; |
|
|
|
|
|
|
|
//midi |
|
|
|
// midi |
|
|
|
if (fParams.fSendMidiChannels > 0) { |
|
|
|
//set global header fields and get the number of midi packets |
|
|
|
// set global header fields and get the number of midi packets |
|
|
|
fTxHeader.fDataType = 'm'; |
|
|
|
data_size = fNetMidiCaptureBuffer->RenderFromJackPorts(); |
|
|
|
fTxHeader.fNumPacket = fNetMidiCaptureBuffer->GetNumPackets(data_size, PACKET_AVAILABLE_SIZE); |
|
|
|
@@ -424,8 +502,13 @@ namespace Jack |
|
|
|
return SOCKET_ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
if (MidiSend(fNetMidiCaptureBuffer, fParams.fSendMidiChannels, fParams.fSendAudioChannels) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
|
|
|
|
//audio |
|
|
|
/* |
|
|
|
// audio |
|
|
|
if (fParams.fSendAudioChannels > 0) { |
|
|
|
fTxHeader.fDataType = 'a'; |
|
|
|
fNetAudioCaptureBuffer->RenderFromJackPorts(); |
|
|
|
@@ -436,13 +519,14 @@ namespace Jack |
|
|
|
fTxHeader.fIsLastPckt = (subproc == (fTxHeader.fNumPacket - 1)) ? 1 : 0; |
|
|
|
fTxHeader.fPacketSize = HEADER_SIZE + fNetAudioCaptureBuffer->RenderToNetwork(subproc, fTxHeader.fActivePorts); |
|
|
|
memcpy(fTxBuffer, &fTxHeader, HEADER_SIZE); |
|
|
|
//PacketHeaderDisplay(&fTxHeader); |
|
|
|
// PacketHeaderDisplay(&fTxHeader); |
|
|
|
if (Send(fTxHeader.fPacketSize, 0) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
*/ |
|
|
|
return AudioSend(fNetAudioPlaybackBuffer, fParams.fSendAudioChannels); |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetMasterInterface::SyncRecv() |
|
|
|
@@ -477,21 +561,20 @@ namespace Jack |
|
|
|
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 ? |
|
|
|
while (!fRxHeader.fIsLastPckt) { |
|
|
|
// how much data is queued on the rx buffer ? |
|
|
|
rx_bytes = Recv(fParams.fMtu, MSG_PEEK); |
|
|
|
|
|
|
|
//error here, problem with recv, just skip the cycle (return -1) |
|
|
|
// 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 == 'r') && (rx_head->fID == fParams.fID)) |
|
|
|
{ |
|
|
|
//read data |
|
|
|
switch (rx_head->fDataType) |
|
|
|
{ |
|
|
|
case 'm': //midi |
|
|
|
if (rx_bytes && (rx_head->fDataStream == 'r') && (rx_head->fID == fParams.fID)) { |
|
|
|
// read data |
|
|
|
switch (rx_head->fDataType) { |
|
|
|
|
|
|
|
case 'm': // midi |
|
|
|
/* |
|
|
|
rx_bytes = Recv(rx_head->fPacketSize, 0); |
|
|
|
fRxHeader.fCycle = rx_head->fCycle; |
|
|
|
fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; |
|
|
|
@@ -499,9 +582,12 @@ namespace Jack |
|
|
|
// Last midi packet is received, so finish rendering... |
|
|
|
if (++recvd_midi_pckt == rx_head->fNumPacket) |
|
|
|
fNetMidiPlaybackBuffer->RenderToJackPorts(); |
|
|
|
*/ |
|
|
|
rx_bytes = MidiRecv(rx_head, fNetMidiPlaybackBuffer, recvd_midi_pckt); |
|
|
|
break; |
|
|
|
|
|
|
|
case 'a': //audio |
|
|
|
case 'a': // audio |
|
|
|
/* |
|
|
|
rx_bytes = Recv(rx_head->fPacketSize, 0); |
|
|
|
fRxHeader.fCycle = rx_head->fCycle; |
|
|
|
fRxHeader.fSubCycle = rx_head->fSubCycle; |
|
|
|
@@ -511,13 +597,18 @@ namespace Jack |
|
|
|
// Last audio packet is received, so finish rendering... |
|
|
|
if (fRxHeader.fIsLastPckt) |
|
|
|
fNetAudioPlaybackBuffer->RenderToJackPorts(); |
|
|
|
*/ |
|
|
|
rx_bytes = AudioRecv(rx_head, fNetAudioPlaybackBuffer); |
|
|
|
break; |
|
|
|
|
|
|
|
case 's': //sync |
|
|
|
case 's': // sync |
|
|
|
jack_info("NetMaster : overloaded, skipping receive from '%s'", fParams.fName); |
|
|
|
/* |
|
|
|
// TODO : finish midi and audio rendering ? |
|
|
|
fNetAudioPlaybackBuffer->RenderToJackPorts(); |
|
|
|
return NET_PACKET_ERROR; |
|
|
|
*/ |
|
|
|
return FinishRecv(fNetAudioPlaybackBuffer); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -527,35 +618,35 @@ namespace Jack |
|
|
|
|
|
|
|
void JackNetMasterInterface::EncodeSyncPacket() |
|
|
|
{ |
|
|
|
//this method contains every step of sync packet informations coding |
|
|
|
//first of all, reset sync packet |
|
|
|
// This method contains every step of sync packet informations coding |
|
|
|
// first of all, reset sync packet |
|
|
|
memset(fTxData, 0, PACKET_AVAILABLE_SIZE); |
|
|
|
|
|
|
|
//then, first step : transport |
|
|
|
// then, first step : transport |
|
|
|
if (fParams.fTransportSync) { |
|
|
|
// desactivated... |
|
|
|
//EncodeTransportData(); |
|
|
|
// EncodeTransportData(); |
|
|
|
TransportDataHToN(&fSendTransportData, &fSendTransportData); |
|
|
|
//copy to TxBuffer |
|
|
|
// copy to TxBuffer |
|
|
|
memcpy(fTxData, &fSendTransportData, sizeof(net_transport_data_t)); |
|
|
|
} |
|
|
|
//then others (freewheel etc.) |
|
|
|
//... |
|
|
|
// then others (freewheel etc.) |
|
|
|
// ... |
|
|
|
} |
|
|
|
|
|
|
|
void JackNetMasterInterface::DecodeSyncPacket() |
|
|
|
{ |
|
|
|
//this method contains every step of sync packet informations decoding process |
|
|
|
//first : transport |
|
|
|
// This method contains every step of sync packet informations decoding process |
|
|
|
// first : transport |
|
|
|
if (fParams.fTransportSync) { |
|
|
|
//copy received transport data to transport data structure |
|
|
|
// copy received transport data to transport data structure |
|
|
|
memcpy(&fReturnTransportData, fRxData, sizeof(net_transport_data_t)); |
|
|
|
TransportDataNToH(&fReturnTransportData, &fReturnTransportData); |
|
|
|
// desactivated... |
|
|
|
//DecodeTransportData(); |
|
|
|
// DecodeTransportData(); |
|
|
|
} |
|
|
|
//then others |
|
|
|
//... |
|
|
|
// then others |
|
|
|
// ... |
|
|
|
} |
|
|
|
|
|
|
|
// JackNetSlaveInterface ************************************************************************************************ |
|
|
|
@@ -566,15 +657,15 @@ namespace Jack |
|
|
|
{ |
|
|
|
jack_log("JackNetSlaveInterface::Init()"); |
|
|
|
|
|
|
|
//set the parameters to send |
|
|
|
// set the parameters to send |
|
|
|
strcpy(fParams.fPacketType, "params"); |
|
|
|
fParams.fProtocolVersion = SLAVE_PROTOCOL; |
|
|
|
SetPacketType(&fParams, SLAVE_AVAILABLE); |
|
|
|
|
|
|
|
//init loop : get a master and start, do it until connection is ok |
|
|
|
// 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 |
|
|
|
// first, get a master, do it until a valid connection is running |
|
|
|
do { |
|
|
|
status = SendAvailableToMaster(); |
|
|
|
if (status == NET_SOCKET_ERROR) |
|
|
|
@@ -582,7 +673,7 @@ namespace Jack |
|
|
|
} |
|
|
|
while (status != NET_CONNECTED); |
|
|
|
|
|
|
|
//then tell the master we are ready |
|
|
|
// then tell the master we are ready |
|
|
|
jack_info("Initializing connection with %s...", fParams.fMasterNetName); |
|
|
|
status = SendStartToMaster(); |
|
|
|
if (status == NET_ERROR) |
|
|
|
@@ -597,16 +688,16 @@ namespace Jack |
|
|
|
bool JackNetSlaveInterface::InitConnection(int time_out) |
|
|
|
{ |
|
|
|
jack_log("JackNetSlaveInterface::InitConnection()"); |
|
|
|
unsigned int try_count = (time_out > 0) ? ((1000000 * time_out) / SLAVE_INIT_TIMEOUT) : LONG_MAX; |
|
|
|
uint try_count = (time_out > 0) ? ((1000000 * time_out) / SLAVE_INIT_TIMEOUT) : LONG_MAX; |
|
|
|
|
|
|
|
//set the parameters to send |
|
|
|
// set the parameters to send |
|
|
|
strcpy(fParams.fPacketType, "params"); |
|
|
|
fParams.fProtocolVersion = SLAVE_PROTOCOL; |
|
|
|
SetPacketType(&fParams, SLAVE_AVAILABLE); |
|
|
|
|
|
|
|
net_status_t status; |
|
|
|
do { |
|
|
|
//get a master |
|
|
|
// get a master |
|
|
|
status = SendAvailableToMaster(try_count); |
|
|
|
if (status == NET_SOCKET_ERROR) |
|
|
|
return false; |
|
|
|
@@ -622,7 +713,7 @@ namespace Jack |
|
|
|
|
|
|
|
net_status_t status; |
|
|
|
do { |
|
|
|
//then tell the master we are ready |
|
|
|
// then tell the master we are ready |
|
|
|
jack_info("Initializing connection with %s...", fParams.fMasterNetName); |
|
|
|
status = SendStartToMaster(); |
|
|
|
if (status == NET_ERROR) |
|
|
|
@@ -636,41 +727,41 @@ namespace Jack |
|
|
|
net_status_t JackNetSlaveInterface::SendAvailableToMaster(long try_count) |
|
|
|
{ |
|
|
|
jack_log("JackNetSlaveInterface::SendAvailableToMaster()"); |
|
|
|
//utility |
|
|
|
// utility |
|
|
|
session_params_t host_params; |
|
|
|
int rx_bytes = 0; |
|
|
|
|
|
|
|
//socket |
|
|
|
// socket |
|
|
|
if (fSocket.NewSocket() == SOCKET_ERROR) { |
|
|
|
jack_error("Fatal error : network unreachable - %s", StrError(NET_ERROR_CODE)); |
|
|
|
return NET_SOCKET_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
//bind the socket |
|
|
|
// bind the socket |
|
|
|
if (fSocket.Bind() == SOCKET_ERROR) { |
|
|
|
jack_error("Can't bind the socket : %s", StrError(NET_ERROR_CODE)); |
|
|
|
return NET_SOCKET_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
//timeout on receive |
|
|
|
// timeout on receive |
|
|
|
if (fSocket.SetTimeOut(SLAVE_INIT_TIMEOUT) == SOCKET_ERROR) |
|
|
|
jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE)); |
|
|
|
|
|
|
|
//disable local loop |
|
|
|
// disable local loop |
|
|
|
if (fSocket.SetLocalLoop() == SOCKET_ERROR) |
|
|
|
jack_error("Can't disable multicast loop : %s", StrError(NET_ERROR_CODE)); |
|
|
|
|
|
|
|
//send 'AVAILABLE' until 'SLAVE_SETUP' received |
|
|
|
// send 'AVAILABLE' until 'SLAVE_SETUP' received |
|
|
|
jack_info("Waiting for a master..."); |
|
|
|
do { |
|
|
|
//send 'available' |
|
|
|
// send 'available' |
|
|
|
session_params_t net_params; |
|
|
|
memset(&net_params, 0, sizeof(session_params_t)); |
|
|
|
SessionParamsHToN(&fParams, &net_params); |
|
|
|
if (fSocket.SendTo(&net_params, 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 no error is detected |
|
|
|
// filter incoming packets : don't exit while no error is detected |
|
|
|
memset(&net_params, 0, sizeof(session_params_t)); |
|
|
|
rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0); |
|
|
|
SessionParamsNToH(&net_params, &host_params); |
|
|
|
@@ -687,10 +778,10 @@ namespace Jack |
|
|
|
return NET_CONNECT_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
//everything is OK, copy parameters |
|
|
|
// everything is OK, copy parameters |
|
|
|
fParams = host_params; |
|
|
|
|
|
|
|
//connect the socket |
|
|
|
// connect the socket |
|
|
|
if (fSocket.Connect() == SOCKET_ERROR) { |
|
|
|
jack_error("Error in connect : %s", StrError(NET_ERROR_CODE)); |
|
|
|
return NET_CONNECT_ERROR; |
|
|
|
@@ -702,7 +793,7 @@ namespace Jack |
|
|
|
{ |
|
|
|
jack_log("JackNetSlaveInterface::SendStartToMaster"); |
|
|
|
|
|
|
|
//tell the master to start |
|
|
|
// tell the master to start |
|
|
|
session_params_t net_params; |
|
|
|
memset(&net_params, 0, sizeof(session_params_t)); |
|
|
|
SetPacketType(&fParams, START_MASTER); |
|
|
|
@@ -724,7 +815,7 @@ namespace Jack |
|
|
|
fTxHeader.fDataStream = 'r'; |
|
|
|
fRxHeader.fDataStream = 's'; |
|
|
|
|
|
|
|
//midi net buffers |
|
|
|
// midi net buffers |
|
|
|
if (fParams.fSendMidiChannels > 0) |
|
|
|
fNetMidiCaptureBuffer = new NetMidiBuffer(&fParams, fParams.fSendMidiChannels, fRxData); |
|
|
|
|
|
|
|
@@ -733,7 +824,7 @@ namespace Jack |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
//audio net buffers |
|
|
|
// audio net buffers |
|
|
|
if (fParams.fSendAudioChannels > 0) { |
|
|
|
|
|
|
|
switch (fParams.fSampleEncoder) { |
|
|
|
@@ -783,7 +874,7 @@ namespace Jack |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
//set the new buffer sizes |
|
|
|
// set the new buffer sizes |
|
|
|
if (SetNetBufferSize() == SOCKET_ERROR) { |
|
|
|
jack_error("Can't set net buffer sizes : %s", StrError(NET_ERROR_CODE)); |
|
|
|
goto error; |
|
|
|
@@ -799,14 +890,14 @@ namespace Jack |
|
|
|
int JackNetSlaveInterface::Recv(size_t size, int flags) |
|
|
|
{ |
|
|
|
int rx_bytes = fSocket.Recv(fRxBuffer, size, flags); |
|
|
|
//handle errors |
|
|
|
// handle errors |
|
|
|
if (rx_bytes == SOCKET_ERROR) { |
|
|
|
/* |
|
|
|
net_error_t error = fSocket.GetError(); |
|
|
|
//no data isn't really an error in realtime processing, so just return 0 |
|
|
|
// no data isn't really an error in realtime processing, so just return 0 |
|
|
|
if (error == NET_NO_DATA) { |
|
|
|
jack_error("No data, is the master still running ?"); |
|
|
|
//if a network error occurs, this exception will restart the driver |
|
|
|
// if a network error occurs, this exception will restart the driver |
|
|
|
} else if (error == NET_CONN_ERROR) { |
|
|
|
FatalError(); |
|
|
|
} else { |
|
|
|
@@ -833,11 +924,11 @@ namespace Jack |
|
|
|
PacketHeaderHToN(header, header); |
|
|
|
int tx_bytes = fSocket.Send(fTxBuffer, size, flags); |
|
|
|
|
|
|
|
//handle errors |
|
|
|
// handle errors |
|
|
|
if (tx_bytes == SOCKET_ERROR) { |
|
|
|
/* |
|
|
|
net_error_t error = fSocket.GetError(); |
|
|
|
//if a network error occurs, this exception will restart the driver |
|
|
|
// if a network error occurs, this exception will restart the driver |
|
|
|
if (error == NET_CONN_ERROR) { |
|
|
|
FatalError(); |
|
|
|
} else { |
|
|
|
@@ -854,10 +945,10 @@ namespace Jack |
|
|
|
int rx_bytes = 0; |
|
|
|
packet_header_t* rx_head = reinterpret_cast<packet_header_t*>(fRxBuffer); |
|
|
|
|
|
|
|
//receive sync (launch the cycle) |
|
|
|
// receive sync (launch the cycle) |
|
|
|
do { |
|
|
|
rx_bytes = Recv(fParams.fMtu, 0); |
|
|
|
//connection issue, send will detect it, so don't skip the cycle (return 0) |
|
|
|
// connection issue, send will detect it, so don't skip the cycle (return 0) |
|
|
|
if (rx_bytes == SOCKET_ERROR) |
|
|
|
return rx_bytes; |
|
|
|
} |
|
|
|
@@ -878,17 +969,19 @@ namespace Jack |
|
|
|
packet_header_t* rx_head = reinterpret_cast<packet_header_t*>(fRxBuffer); |
|
|
|
|
|
|
|
while (!fRxHeader.fIsLastPckt) { |
|
|
|
//how much data is queued on the rx buffer ? |
|
|
|
// how much data is queued on the rx buffer ? |
|
|
|
rx_bytes = Recv(fParams.fMtu, MSG_PEEK); |
|
|
|
|
|
|
|
//error here, problem with recv, just skip the cycle (return -1) |
|
|
|
// 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 |
|
|
|
// read data |
|
|
|
switch (rx_head->fDataType) { |
|
|
|
|
|
|
|
case 'm': // midi |
|
|
|
/* |
|
|
|
rx_bytes = Recv(rx_head->fPacketSize, 0); |
|
|
|
fRxHeader.fCycle = rx_head->fCycle; |
|
|
|
fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; |
|
|
|
@@ -896,9 +989,12 @@ namespace Jack |
|
|
|
// Last midi packet is received, so finish rendering... |
|
|
|
if (++recvd_midi_pckt == rx_head->fNumPacket) |
|
|
|
fNetMidiCaptureBuffer->RenderToJackPorts(); |
|
|
|
*/ |
|
|
|
rx_bytes = MidiRecv(rx_head, fNetMidiCaptureBuffer, recvd_midi_pckt); |
|
|
|
break; |
|
|
|
|
|
|
|
case 'a': //audio |
|
|
|
case 'a': // audio |
|
|
|
/* |
|
|
|
rx_bytes = Recv(rx_head->fPacketSize, 0); |
|
|
|
fRxHeader.fCycle = rx_head->fCycle; |
|
|
|
fRxHeader.fSubCycle = rx_head->fSubCycle; |
|
|
|
@@ -908,13 +1004,18 @@ namespace Jack |
|
|
|
// Last audio packet is received, so finish rendering... |
|
|
|
if (fRxHeader.fIsLastPckt) |
|
|
|
fNetAudioCaptureBuffer->RenderToJackPorts(); |
|
|
|
*/ |
|
|
|
rx_bytes = AudioRecv(rx_head, fNetAudioCaptureBuffer); |
|
|
|
break; |
|
|
|
|
|
|
|
case 's': //sync |
|
|
|
case 's': // sync |
|
|
|
jack_info("NetSlave : overloaded, skipping receive"); |
|
|
|
/* |
|
|
|
// TODO : finish midi and audio rendering ? |
|
|
|
fNetAudioCaptureBuffer->RenderToJackPorts(); |
|
|
|
return NET_PACKET_ERROR; |
|
|
|
*/ |
|
|
|
return FinishRecv(fNetAudioCaptureBuffer); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -925,7 +1026,7 @@ namespace Jack |
|
|
|
|
|
|
|
int JackNetSlaveInterface::SyncSend() |
|
|
|
{ |
|
|
|
//tx header |
|
|
|
// tx header |
|
|
|
if (fParams.fSlaveSyncMode) { |
|
|
|
fTxHeader.fCycle = fRxHeader.fCycle; |
|
|
|
} else { |
|
|
|
@@ -941,33 +1042,39 @@ namespace Jack |
|
|
|
fNetAudioCaptureBuffer->ActivePortsToNetwork(fTxData, fTxHeader.fActivePorts); |
|
|
|
|
|
|
|
memcpy(fTxBuffer, &fTxHeader, HEADER_SIZE); |
|
|
|
// PacketHeaderDisplay(&fTxHeader); |
|
|
|
return Send(fTxHeader.fPacketSize, 0); |
|
|
|
} |
|
|
|
|
|
|
|
int JackNetSlaveInterface::DataSend() |
|
|
|
{ |
|
|
|
/* |
|
|
|
uint subproc, data_size; |
|
|
|
|
|
|
|
//midi |
|
|
|
// midi |
|
|
|
if (fParams.fReturnMidiChannels > 0) { |
|
|
|
//set global header fields and get the number of midi packets |
|
|
|
// set global header fields and get the number of midi packets |
|
|
|
fTxHeader.fDataType = 'm'; |
|
|
|
data_size = fNetMidiPlaybackBuffer->RenderFromJackPorts(); |
|
|
|
fTxHeader.fNumPacket = fNetMidiPlaybackBuffer->GetNumPackets(data_size, PACKET_AVAILABLE_SIZE); |
|
|
|
|
|
|
|
for (subproc = 0; subproc < fTxHeader.fNumPacket; subproc++) { |
|
|
|
fTxHeader.fSubCycle = subproc; |
|
|
|
fTxHeader.fIsLastPckt = ((subproc == (fTxHeader.fNumPacket - 1)) && !fParams.fReturnAudioChannels) ? 1 : 0; |
|
|
|
// fTxHeader.fIsLastPckt = ((subproc == (fTxHeader.fNumPacket - 1)) && !fParams.fReturnAudioChannels) ? 1 : 0; |
|
|
|
fTxHeader.fIsLastPckt = ((subproc == (fTxHeader.fNumPacket - 1)) && fParams.fReturnAudioChannels == 0) ? 1 : 0; |
|
|
|
fTxHeader.fPacketSize = HEADER_SIZE + fNetMidiPlaybackBuffer->RenderToNetwork(subproc, data_size); |
|
|
|
memcpy(fTxBuffer, &fTxHeader, HEADER_SIZE); |
|
|
|
if (Send(fTxHeader.fPacketSize, 0) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
*/ |
|
|
|
if (MidiSend(fNetMidiPlaybackBuffer, fParams.fReturnMidiChannels, fParams.fReturnAudioChannels) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
|
|
|
|
//audio |
|
|
|
/* |
|
|
|
// audio |
|
|
|
if (fParams.fReturnAudioChannels > 0) { |
|
|
|
|
|
|
|
fTxHeader.fDataType = 'a'; |
|
|
|
fNetAudioPlaybackBuffer->RenderFromJackPorts(); |
|
|
|
fTxHeader.fNumPacket = fNetAudioPlaybackBuffer->GetNumPackets(); |
|
|
|
@@ -977,45 +1084,48 @@ namespace Jack |
|
|
|
fTxHeader.fIsLastPckt = (subproc == (fTxHeader.fNumPacket - 1)) ? 1 : 0; |
|
|
|
fTxHeader.fPacketSize = HEADER_SIZE + fNetAudioPlaybackBuffer->RenderToNetwork(subproc, fTxHeader.fActivePorts); |
|
|
|
memcpy(fTxBuffer, &fTxHeader, HEADER_SIZE); |
|
|
|
//PacketHeaderDisplay(&fTxHeader); |
|
|
|
// PacketHeaderDisplay(&fTxHeader); |
|
|
|
if (Send(fTxHeader.fPacketSize, 0) == SOCKET_ERROR) |
|
|
|
return SOCKET_ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
*/ |
|
|
|
|
|
|
|
return AudioSend(fNetAudioPlaybackBuffer, fParams.fReturnAudioChannels); |
|
|
|
} |
|
|
|
|
|
|
|
//network sync------------------------------------------------------------------------ |
|
|
|
// network sync------------------------------------------------------------------------ |
|
|
|
void JackNetSlaveInterface::EncodeSyncPacket() |
|
|
|
{ |
|
|
|
//this method contains every step of sync packet informations coding |
|
|
|
//first of all, reset sync packet |
|
|
|
// This method contains every step of sync packet informations coding |
|
|
|
// first of all, reset sync packet |
|
|
|
memset(fTxData, 0, PACKET_AVAILABLE_SIZE); |
|
|
|
//then first step : transport |
|
|
|
// then first step : transport |
|
|
|
if (fParams.fTransportSync) { |
|
|
|
// desactivated... |
|
|
|
//EncodeTransportData(); |
|
|
|
// EncodeTransportData(); |
|
|
|
TransportDataHToN(&fReturnTransportData, &fReturnTransportData); |
|
|
|
//copy to TxBuffer |
|
|
|
// copy to TxBuffer |
|
|
|
memcpy(fTxData, &fReturnTransportData, sizeof(net_transport_data_t)); |
|
|
|
} |
|
|
|
//then others |
|
|
|
//... |
|
|
|
// then others |
|
|
|
// ... |
|
|
|
} |
|
|
|
|
|
|
|
void JackNetSlaveInterface::DecodeSyncPacket() |
|
|
|
{ |
|
|
|
//this method contains every step of sync packet informations decoding process |
|
|
|
//first : transport |
|
|
|
// This method contains every step of sync packet informations decoding process |
|
|
|
// first : transport |
|
|
|
if (fParams.fTransportSync) { |
|
|
|
//copy received transport data to transport data structure |
|
|
|
// copy received transport data to transport data structure |
|
|
|
memcpy(&fSendTransportData, fRxData, sizeof(net_transport_data_t)); |
|
|
|
TransportDataNToH(&fSendTransportData, &fSendTransportData); |
|
|
|
// desactivated... |
|
|
|
//DecodeTransportData(); |
|
|
|
// DecodeTransportData(); |
|
|
|
} |
|
|
|
//then others |
|
|
|
//... |
|
|
|
// then others |
|
|
|
// ... |
|
|
|
} |
|
|
|
|
|
|
|
} |