Browse Source

Add JackNetSlaveInterface, base class for netjack slave management (netdriver and netadapter)

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2770 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.90
moret 17 years ago
parent
commit
f630c4eb92
5 changed files with 523 additions and 383 deletions
  1. +53
    -346
      common/JackNetDriver.cpp
  2. +5
    -37
      common/JackNetDriver.h
  3. +377
    -0
      common/JackNetSlaveInterface.cpp
  4. +87
    -0
      common/JackNetSlaveInterface.h
  5. +1
    -0
      common/wscript

+ 53
- 346
common/JackNetDriver.cpp View File

@@ -37,7 +37,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_mode )
: JackAudioDriver ( name, alias, engine, table ), fSocket ( ip, port )
: JackAudioDriver ( name, alias, engine, table ), JackNetSlaveInterface ( ip, port )
{
jack_log ( "JackNetDriver::JackNetDriver ip %s, port %d", ip, port );

@@ -59,14 +59,6 @@ namespace Jack
JackNetDriver::~JackNetDriver()
{
fSocket.Close();
SocketAPIEnd();
delete fNetAudioCaptureBuffer;
delete fNetAudioPlaybackBuffer;
delete fNetMidiCaptureBuffer;
delete fNetMidiPlaybackBuffer;
delete[] fTxBuffer;
delete[] fRxBuffer;
delete[] fMulticastIP;
delete[] fMidiCapturePortList;
delete[] fMidiPlaybackPortList;
#ifdef JACK_MONITOR
@@ -120,9 +112,6 @@ namespace Jack
Restart();

//set the parameters to send
strcpy ( fParams.fPacketType, "params" );
fParams.fProtocolVersion = 'a';
SetPacketType ( &fParams, SLAVE_AVAILABLE );
fParams.fSendAudioChannels = fCaptureChannels;
fParams.fReturnAudioChannels = fPlaybackChannels;
fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
@@ -131,144 +120,10 @@ namespace Jack
if ( fParams.fTransportSync )
jack_info ( "NetDriver started with Master's Transport Sync." );

//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
jack_info ( "Initializing Net Driver..." );
do
{
status = GetNetMaster();
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 = SendMasterStartSync();
if ( status == NET_ERROR )
return false;
}
while ( status != NET_ROLLING );
if ( !JackNetSlaveInterface::Init() )
return false;;

//driver parametering
if ( SetParams() )
{
jack_error ( "Fatal error : can't alloc net driver ports." );
return false;
}

//init done, display parameters
SessionParamsDisplay ( &fParams );

return true;
}

net_status_t JackNetDriver::GetNetMaster()
{
jack_log ( "JackNetDriver::GetNetMaster()" );
//utility
session_params_t params;
int us_timeout = 2000000;
int rx_bytes = 0;
unsigned char loop = 0;

//socket
if ( fSocket.NewSocket() == SOCKET_ERROR )
{
jack_error ( "Fatal error : network unreachable - %s", StrError ( NET_ERROR_CODE ) );
return NET_SOCKET_ERROR;
}

//bind the socket
if ( fSocket.Bind() == SOCKET_ERROR )
jack_error ( "Can't bind the socket : %s", StrError ( NET_ERROR_CODE ) );

//timeout on receive
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
{
//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 no error is detected
rx_bytes = fSocket.CatchHost ( &params, 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;
}
}
while ( strcmp ( params.fPacketType, fParams.fPacketType ) && ( GetPacketType ( &params ) != SLAVE_SETUP ) );

//connect the socket
if ( fSocket.Connect() == SOCKET_ERROR )
{
jack_error ( "Error in connect : %s", StrError ( NET_ERROR_CODE ) );
return NET_CONNECT_ERROR;
}

//everything is OK, copy parameters and return
fParams = params;

return NET_CONNECTED;
}

net_status_t JackNetDriver::SendMasterStartSync()
{
jack_log ( "JackNetDriver::GetNetMasterStartSync()" );
//tell the master to start
SetPacketType ( &fParams, START_MASTER );
if ( fSocket.Send ( &fParams, sizeof ( session_params_t ), 0 ) == SOCKET_ERROR )
{
jack_error ( "Error in send : %s", StrError ( NET_ERROR_CODE ) );
return ( fSocket.GetError() == NET_CONN_ERROR ) ? NET_ERROR : NET_SEND_ERROR;
}
return NET_ROLLING;
}

void JackNetDriver::Restart()
{
jack_log ( "JackNetDriver::Restart" );
jack_info ( "Restarting driver..." );
delete[] fTxBuffer;
fTxBuffer = NULL;
delete[] fRxBuffer;
fRxBuffer = NULL;
delete fNetAudioCaptureBuffer;
fNetAudioCaptureBuffer = NULL;
delete fNetAudioPlaybackBuffer;
fNetAudioPlaybackBuffer = NULL;
delete fNetMidiCaptureBuffer;
fNetMidiCaptureBuffer = NULL;
delete fNetMidiPlaybackBuffer;
fNetMidiPlaybackBuffer = NULL;
FreePorts();
delete[] fMidiCapturePortList;
fMidiCapturePortList = NULL;
delete[] fMidiPlaybackPortList;
fMidiPlaybackPortList = NULL;
#ifdef JACK_MONITOR
delete fNetTimeMon;
fNetTimeMon = NULL;
delete fCycleTimeMon;
fCycleTimeMon = NULL;
#endif
}

int JackNetDriver::SetParams()
{
fNSubProcess = fParams.fPeriodSize / fParams.fFramesPerPacket;
JackAudioDriver::SetBufferSize ( fParams.fPeriodSize );
JackAudioDriver::SetSampleRate ( fParams.fSampleRate );

@@ -279,54 +134,6 @@ namespace Jack
fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];

//register jack ports
if ( AllocPorts() != 0 )
{
jack_error ( "Can't allocate ports." );
return -1;
}

//TX header init
strcpy ( fTxHeader.fPacketType, "header" );
fTxHeader.fDataStream = 'r';
fTxHeader.fID = fParams.fID;
fTxHeader.fCycle = 0;
fTxHeader.fSubCycle = 0;
fTxHeader.fMidiDataSize = 0;
fTxHeader.fBitdepth = fParams.fBitdepth;

//RX header init
strcpy ( fRxHeader.fPacketType, "header" );
fRxHeader.fDataStream = 's';
fRxHeader.fID = fParams.fID;
fRxHeader.fCycle = 0;
fRxHeader.fSubCycle = 0;
fRxHeader.fMidiDataSize = 0;
fRxHeader.fBitdepth = fParams.fBitdepth;

//network buffers
fTxBuffer = new char[fParams.fMtu];
fRxBuffer = new char[fParams.fMtu];

//net audio/midi buffers
fTxData = fTxBuffer + sizeof ( packet_header_t );
fRxData = fRxBuffer + sizeof ( packet_header_t );

//midi net buffers
fNetMidiCaptureBuffer = new NetMidiBuffer ( &fParams, fParams.fSendMidiChannels, fRxData );
fNetMidiPlaybackBuffer = new NetMidiBuffer ( &fParams, fParams.fReturnMidiChannels, fTxData );

//audio net buffers
fNetAudioCaptureBuffer = new NetAudioBuffer ( &fParams, fParams.fSendAudioChannels, fRxData );
fNetAudioPlaybackBuffer = new NetAudioBuffer ( &fParams, fParams.fReturnAudioChannels, fTxData );

//audio netbuffer length
fAudioTxLen = sizeof ( packet_header_t ) + fNetAudioPlaybackBuffer->GetSize();
fAudioRxLen = sizeof ( packet_header_t ) + fNetAudioCaptureBuffer->GetSize();

//payload size
fPayloadSize = fParams.fMtu - sizeof ( packet_header_t );

//monitor
#ifdef JACK_MONITOR
string plot_name;
@@ -366,7 +173,45 @@ namespace Jack
fLastCycleBeginDate = GetMicroSeconds();
#endif

return 0;
if ( SetParams() )
{
jack_error ( "Fatal error : can't alloc net driver ports." );
return false;
}

//init done, display parameters
SessionParamsDisplay ( &fParams );

return true;
}

void JackNetDriver::Restart()
{
jack_log ( "JackNetDriver::Restart" );
jack_info ( "Restarting driver..." );
delete[] fTxBuffer;
fTxBuffer = NULL;
delete[] fRxBuffer;
fRxBuffer = NULL;
delete fNetAudioCaptureBuffer;
fNetAudioCaptureBuffer = NULL;
delete fNetAudioPlaybackBuffer;
fNetAudioPlaybackBuffer = NULL;
delete fNetMidiCaptureBuffer;
fNetMidiCaptureBuffer = NULL;
delete fNetMidiPlaybackBuffer;
fNetMidiPlaybackBuffer = NULL;
FreePorts();
delete[] fMidiCapturePortList;
fMidiCapturePortList = NULL;
delete[] fMidiPlaybackPortList;
fMidiPlaybackPortList = NULL;
#ifdef JACK_MONITOR
delete fNetTimeMon;
fNetTimeMon = NULL;
delete fCycleTimeMon;
fCycleTimeMon = NULL;
#endif
}

int JackNetDriver::AllocPorts()
@@ -491,57 +336,10 @@ namespace Jack
return 0;
}

//***********************************network operations*************************************************************

int JackNetDriver::Recv ( size_t size, int flags )
{
int rx_bytes = fSocket.Recv ( fRxBuffer, size, flags );
//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
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
else if ( error == NET_CONN_ERROR )
{
jack_error ( "Connection lost." );
throw JackDriverException();
}
else
jack_error ( "Fatal error in receive : %s", StrError ( NET_ERROR_CODE ) );
}
return rx_bytes;
}

int JackNetDriver::Send ( size_t size, int flags )
{
int tx_bytes = fSocket.Send ( fTxBuffer, size, flags );
//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 ( error == NET_CONN_ERROR )
{
jack_error ( "Connection lost." );
throw JackDriverException();
}
else
jack_error ( "Fatal error in send : %s", StrError ( NET_ERROR_CODE ) );
}
return tx_bytes;
}

//*************************************process************************************************************************

int JackNetDriver::Read()
{
int rx_bytes;
uint recvd_midi_pckt = 0;
packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer );
fRxHeader.fIsLastPckt = 'n';
uint midi_port_index;
int audio_port_index;

@@ -556,14 +354,8 @@ namespace Jack
#endif

//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)
if ( rx_bytes == SOCKET_ERROR )
return 0;
}
while ( !rx_bytes && ( rx_head->fDataType != 's' ) );
if ( SyncRecv() == SOCKET_ERROR )
return 0;

//take the time at the beginning of the cycle
JackDriver::CycleTakeBeginTime();
@@ -575,45 +367,8 @@ namespace Jack
#endif

//audio, midi or sync if driver is late
if ( fParams.fSendMidiChannels || fParams.fSendAudioChannels )
{
do
{
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 );
if ( !IsNextPacket ( &fRxHeader, rx_head, fNSubProcess ) )
jack_error ( "Packet(s) missing..." );
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 ( "NetDriver : driver overloaded, skipping receive." );
fRxHeader.fCycle = rx_head->fCycle;
return 0;
}
}
}
while ( fRxHeader.fIsLastPckt != 'y' );
}
fRxHeader.fCycle = rx_head->fCycle;
if ( DataRecv() == SOCKET_ERROR )
return SOCKET_ERROR;

#ifdef JACK_MONITOR
fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - JackDriver::fBeginDateUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f );
@@ -625,15 +380,7 @@ namespace Jack
int JackNetDriver::Write()
{
uint midi_port_index;
int tx_bytes, audio_port_index;

//tx header
if ( fEngineControl->fSyncMode )
fTxHeader.fCycle = fRxHeader.fCycle;
else
fTxHeader.fCycle++;
fTxHeader.fSubCycle = 0;
fTxHeader.fIsLastPckt = 'n';
int audio_port_index;

//buffers
for ( midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++ )
@@ -646,58 +393,18 @@ namespace Jack
#endif

//sync
fTxHeader.fDataType = 's';
if ( !fParams.fSendMidiChannels && !fParams.fSendAudioChannels )
fTxHeader.fIsLastPckt = 'y';
fTxHeader.fPacketSize = fParams.fMtu;
memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) );
memset ( fTxData, 0, fPayloadSize );
SetSyncPacket();
tx_bytes = Send ( fTxHeader.fPacketSize, 0 );
if ( tx_bytes == SOCKET_ERROR )
return tx_bytes;

if ( SyncSend() == SOCKET_ERROR )
return SOCKET_ERROR;

#ifdef JACK_MONITOR
fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - JackDriver::fBeginDateUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f );
#endif

//midi
if ( fParams.fReturnMidiChannels )
{
fTxHeader.fDataType = 'm';
fTxHeader.fMidiDataSize = fNetMidiPlaybackBuffer->RenderFromJackPorts();
fTxHeader.fNMidiPckt = GetNMidiPckt ( &fParams, fTxHeader.fMidiDataSize );
for ( uint subproc = 0; subproc < fTxHeader.fNMidiPckt; subproc++ )
{
fTxHeader.fSubCycle = subproc;
if ( ( subproc == ( fTxHeader.fNMidiPckt - 1 ) ) && !fParams.fReturnAudioChannels )
fTxHeader.fIsLastPckt = 'y';
fTxHeader.fPacketSize = fNetMidiPlaybackBuffer->RenderToNetwork ( subproc, fTxHeader.fMidiDataSize );
fTxHeader.fPacketSize += sizeof ( packet_header_t );
memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) );
tx_bytes = Send ( fTxHeader.fPacketSize, 0 );
if ( tx_bytes == SOCKET_ERROR )
return tx_bytes;
}
}

//audio
if ( fParams.fReturnAudioChannels )
{
fTxHeader.fDataType = 'a';
for ( uint subproc = 0; subproc < fNSubProcess; subproc++ )
{
fTxHeader.fSubCycle = subproc;
if ( subproc == ( fNSubProcess - 1 ) )
fTxHeader.fIsLastPckt = 'y';
fTxHeader.fPacketSize = fAudioTxLen;
memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) );
fNetAudioPlaybackBuffer->RenderFromJackPorts ( subproc );
tx_bytes = Send ( fTxHeader.fPacketSize, 0 );
if ( tx_bytes == SOCKET_ERROR )
return tx_bytes;
}
}
if ( DataSend() == SOCKET_ERROR )
return SOCKET_ERROR;

#ifdef JACK_MONITOR
fNetTimeMon->AddLast ( ( ( float ) ( GetMicroSeconds() - JackDriver::fBeginDateUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f );
@@ -792,7 +499,7 @@ namespace Jack
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

i++;
strcpy ( desc->params[i].name, "network_mode" );
strcpy ( desc->params[i].name, "fast_mode" );
desc->params[i].character = 'f';
desc->params[i].type = JackDriverParamString;
strcpy ( desc->params[i].value.str, "" );


+ 5
- 37
common/JackNetDriver.h View File

@@ -22,7 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#define __JackNetDriver__

#include "JackAudioDriver.h"
#include "JackNetTool.h"
#include "JackNetSlaveInterface.h"

#ifdef JACK_MONITOR
#include "JackFrameTimer.h"
@@ -34,40 +34,14 @@ namespace Jack
\Brief This class describes the Net Backend
*/

class JackNetDriver : public JackAudioDriver
class JackNetDriver : public JackAudioDriver, public JackNetSlaveInterface
{
private:
session_params_t fParams;
char* fMulticastIP;
JackNetSocket fSocket;
uint fNSubProcess;
//jack data
net_transport_data_t fTransportData;

//jack ports
jack_port_id_t* fMidiCapturePortList;
jack_port_id_t* fMidiPlaybackPortList;

//headers
packet_header_t fTxHeader;
packet_header_t fRxHeader;

//network buffers
char* fTxBuffer;
char* fRxBuffer;
char* fTxData;
char* fRxData;

//jack buffers
NetMidiBuffer* fNetMidiCaptureBuffer;
NetMidiBuffer* fNetMidiPlaybackBuffer;
NetAudioBuffer* fNetAudioCaptureBuffer;
NetAudioBuffer* fNetAudioPlaybackBuffer;

//sizes
int fAudioRxLen;
int fAudioTxLen;
int fPayloadSize;

//monitoring
#ifdef JACK_MONITOR
//time measurment
@@ -78,21 +52,15 @@ namespace Jack
#endif

bool Init();
net_status_t GetNetMaster();
net_status_t SendMasterStartSync();
void Restart();
int SetParams();
int AllocPorts();
int FreePorts();
int SetSyncPacket();
int TransportSync();

JackMidiBuffer* GetMidiInputBuffer ( int port_index );
JackMidiBuffer* GetMidiOutputBuffer ( int port_index );

int Recv ( size_t size, int flags );
int Send ( size_t size, int flags );

int SetSyncPacket();
int TransportSync();

public:
JackNetDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,


+ 377
- 0
common/JackNetSlaveInterface.cpp View File

@@ -0,0 +1,377 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2008 Romain Moret at Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "JackNetSlaveInterface.h"
#include "JackEngineControl.h"
#include "JackClientControl.h"
#include "JackGraphManager.h"
#include "JackException.h"

#define DEFAULT_MULTICAST_IP "225.3.19.154"
#define DEFAULT_PORT 19000

using namespace std;

namespace Jack
{
JackNetSlaveInterface::JackNetSlaveInterface()
{
fMulticastIP = NULL;
}

JackNetSlaveInterface::~JackNetSlaveInterface()
{
SocketAPIEnd();
delete[] fTxBuffer;
delete[] fRxBuffer;
delete[] fMulticastIP;
delete fNetAudioCaptureBuffer;
delete fNetAudioPlaybackBuffer;
delete fNetMidiCaptureBuffer;
delete fNetMidiPlaybackBuffer;
}

//*************************************initialization***********************************************************************


bool JackNetSlaveInterface::Init()
{
jack_log ( "JackNetSlaveInterface::NetInit()" );

//set the parameters to send
strcpy ( fParams.fPacketType, "params" );
fParams.fProtocolVersion = 'a';
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
jack_info ( "Initializing Net Driver..." );
do
{
status = GetNetMaster();
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 = SendMasterStartSync();
if ( status == NET_ERROR )
return false;
}
while ( status != NET_ROLLING );

return true;
}

net_status_t JackNetSlaveInterface::GetNetMaster()
{
jack_log ( "JackNetSlaveInterface::GetNetMaster()" );
//utility
session_params_t params;
int us_timeout = 2000000;
int rx_bytes = 0;
unsigned char loop = 0;

//socket
if ( fSocket.NewSocket() == SOCKET_ERROR )
{
jack_error ( "Fatal error : network unreachable - %s", StrError ( NET_ERROR_CODE ) );
return NET_SOCKET_ERROR;
}

//bind the socket
if ( fSocket.Bind() == SOCKET_ERROR )
jack_error ( "Can't bind the socket : %s", StrError ( NET_ERROR_CODE ) );

//timeout on receive
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
{
//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 no error is detected
rx_bytes = fSocket.CatchHost ( &params, 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;
}
}
while ( strcmp ( params.fPacketType, fParams.fPacketType ) && ( GetPacketType ( &params ) != SLAVE_SETUP ) );

//connect the socket
if ( fSocket.Connect() == SOCKET_ERROR )
{
jack_error ( "Error in connect : %s", StrError ( NET_ERROR_CODE ) );
return NET_CONNECT_ERROR;
}

//everything is OK, copy parameters and return
fParams = params;

return NET_CONNECTED;
}

net_status_t JackNetSlaveInterface::SendMasterStartSync()
{
jack_log ( "JackNetSlaveInterface::GetNetMasterStartSync()" );
//tell the master to start
SetPacketType ( &fParams, START_MASTER );
if ( fSocket.Send ( &fParams, sizeof ( session_params_t ), 0 ) == SOCKET_ERROR )
{
jack_error ( "Error in send : %s", StrError ( NET_ERROR_CODE ) );
return ( fSocket.GetError() == NET_CONN_ERROR ) ? NET_ERROR : NET_SEND_ERROR;
}
return NET_ROLLING;
}

int JackNetSlaveInterface::SetParams()
{
fNSubProcess = fParams.fPeriodSize / fParams.fFramesPerPacket;

//TX header init
strcpy ( fTxHeader.fPacketType, "header" );
fTxHeader.fDataStream = 'r';
fTxHeader.fID = fParams.fID;
fTxHeader.fCycle = 0;
fTxHeader.fSubCycle = 0;
fTxHeader.fMidiDataSize = 0;
fTxHeader.fBitdepth = fParams.fBitdepth;

//RX header init
strcpy ( fRxHeader.fPacketType, "header" );
fRxHeader.fDataStream = 's';
fRxHeader.fID = fParams.fID;
fRxHeader.fCycle = 0;
fRxHeader.fSubCycle = 0;
fRxHeader.fMidiDataSize = 0;
fRxHeader.fBitdepth = fParams.fBitdepth;

//network buffers
fTxBuffer = new char[fParams.fMtu];
fRxBuffer = new char[fParams.fMtu];

//net audio/midi buffers
fTxData = fTxBuffer + sizeof ( packet_header_t );
fRxData = fRxBuffer + sizeof ( packet_header_t );

//midi net buffers
fNetMidiCaptureBuffer = new NetMidiBuffer ( &fParams, fParams.fSendMidiChannels, fRxData );
fNetMidiPlaybackBuffer = new NetMidiBuffer ( &fParams, fParams.fReturnMidiChannels, fTxData );

//audio net buffers
fNetAudioCaptureBuffer = new NetAudioBuffer ( &fParams, fParams.fSendAudioChannels, fRxData );
fNetAudioPlaybackBuffer = new NetAudioBuffer ( &fParams, fParams.fReturnAudioChannels, fTxData );

//audio netbuffer length
fAudioTxLen = sizeof ( packet_header_t ) + fNetAudioPlaybackBuffer->GetSize();
fAudioRxLen = sizeof ( packet_header_t ) + fNetAudioCaptureBuffer->GetSize();

//payload size
fPayloadSize = fParams.fMtu - sizeof ( packet_header_t );

return 0;
}

//***********************************network operations*************************************************************

int JackNetSlaveInterface::Recv ( size_t size, int flags )
{
int rx_bytes = fSocket.Recv ( fRxBuffer, size, flags );
//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
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
else if ( error == NET_CONN_ERROR )
{
jack_error ( "Connection lost." );
throw JackDriverException();
}
else
jack_error ( "Fatal error in receive : %s", StrError ( NET_ERROR_CODE ) );
}
return rx_bytes;
}

int JackNetSlaveInterface::Send ( size_t size, int flags )
{
int tx_bytes = fSocket.Send ( fTxBuffer, size, flags );
//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 ( error == NET_CONN_ERROR )
{
jack_error ( "Connection lost." );
throw JackDriverException();
}
else
jack_error ( "Fatal error in send : %s", StrError ( NET_ERROR_CODE ) );
}
return tx_bytes;
}

//**************************************processes***************************************************

int JackNetSlaveInterface::SyncRecv()
{
int rx_bytes;
packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer );
fRxHeader.fIsLastPckt = 'n';
//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)
if ( rx_bytes == SOCKET_ERROR )
return rx_bytes;
}
while ( !rx_bytes && ( rx_head->fDataType != 's' ) );
return rx_bytes;
}

int JackNetSlaveInterface::DataRecv()
{
uint recvd_midi_pckt = 0;
int rx_bytes;
packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer );

//audio, midi or sync if driver is late
if ( fParams.fSendMidiChannels || fParams.fSendAudioChannels )
{
do
{
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 );
if ( !IsNextPacket ( &fRxHeader, rx_head, fNSubProcess ) )
jack_error ( "Packet(s) missing..." );
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." );
fRxHeader.fCycle = rx_head->fCycle;
return 0;
}
}
}
while ( fRxHeader.fIsLastPckt != 'y' );
}
fRxHeader.fCycle = rx_head->fCycle;
return 0;
}

int JackNetSlaveInterface::SyncSend()
{
//tx header
if ( fParams.fSlaveSyncMode )
fTxHeader.fCycle = fRxHeader.fCycle;
else
fTxHeader.fCycle++;
fTxHeader.fSubCycle = 0;

//sync
fTxHeader.fDataType = 's';
fTxHeader.fIsLastPckt = ( !fParams.fSendMidiChannels && !fParams.fSendAudioChannels ) ? 'y' : 'n';
fTxHeader.fPacketSize = fParams.fMtu;
memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) );
return Send ( fTxHeader.fPacketSize, 0 );
}

int JackNetSlaveInterface::DataSend()
{
int tx_bytes;
//midi
if ( fParams.fReturnMidiChannels )
{
fTxHeader.fDataType = 'm';
fTxHeader.fMidiDataSize = fNetMidiPlaybackBuffer->RenderFromJackPorts();
fTxHeader.fNMidiPckt = GetNMidiPckt ( &fParams, fTxHeader.fMidiDataSize );
for ( uint subproc = 0; subproc < fTxHeader.fNMidiPckt; subproc++ )
{
fTxHeader.fSubCycle = subproc;
if ( ( subproc == ( fTxHeader.fNMidiPckt - 1 ) ) && !fParams.fReturnAudioChannels )
fTxHeader.fIsLastPckt = 'y';
fTxHeader.fPacketSize = fNetMidiPlaybackBuffer->RenderToNetwork ( subproc, fTxHeader.fMidiDataSize );
fTxHeader.fPacketSize += sizeof ( packet_header_t );
memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) );
tx_bytes = Send ( fTxHeader.fPacketSize, 0 );
if ( tx_bytes == SOCKET_ERROR )
return tx_bytes;
}
}

//audio
if ( fParams.fReturnAudioChannels )
{
fTxHeader.fDataType = 'a';
for ( uint subproc = 0; subproc < fNSubProcess; subproc++ )
{
fTxHeader.fSubCycle = subproc;
if ( subproc == ( fNSubProcess - 1 ) )
fTxHeader.fIsLastPckt = 'y';
fTxHeader.fPacketSize = fAudioTxLen;
memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) );
fNetAudioPlaybackBuffer->RenderFromJackPorts ( subproc );
tx_bytes = Send ( fTxHeader.fPacketSize, 0 );
if ( tx_bytes == SOCKET_ERROR )
return tx_bytes;
}
}
return 0;
}
}

+ 87
- 0
common/JackNetSlaveInterface.h View File

@@ -0,0 +1,87 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2008 Romain Moret at Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef __JackNetSlaveInterface__
#define __JackNetSlaveInterface__

#include "JackNetTool.h"

#ifdef JACK_MONITOR
#include "JackFrameTimer.h"
#endif

namespace Jack
{
/**
\Brief This class describes the Net Interface for slaves (NetDriver and NetAdapter)
*/

class EXPORT JackNetSlaveInterface
{
protected:
session_params_t fParams;
char* fMulticastIP;
JackNetSocket fSocket;
uint fNSubProcess;

//headers
packet_header_t fTxHeader;
packet_header_t fRxHeader;

//network buffers
char* fTxBuffer;
char* fRxBuffer;
char* fTxData;
char* fRxData;

//jack buffers
NetMidiBuffer* fNetMidiCaptureBuffer;
NetMidiBuffer* fNetMidiPlaybackBuffer;
NetAudioBuffer* fNetAudioCaptureBuffer;
NetAudioBuffer* fNetAudioPlaybackBuffer;

//sizes
int fAudioRxLen;
int fAudioTxLen;
int fPayloadSize;

//sub processes
bool Init();
net_status_t GetNetMaster();
net_status_t SendMasterStartSync();
int SetParams();
int SyncRecv();
int SyncSend();
int DataRecv();
int DataSend();

//network operations
int Recv ( size_t size, int flags );
int Send ( size_t size, int flags );

public:
JackNetSlaveInterface();
JackNetSlaveInterface ( const char* ip, int port ) : fMulticastIP ( NULL ), fSocket ( ip, port )
{}
~JackNetSlaveInterface();
};
}

#endif

+ 1
- 0
common/wscript View File

@@ -130,6 +130,7 @@ def build(bld):
'JackServerGlobals.cpp',
'JackControl.cpp',
'JackNetTool.cpp',
'JackNetSlaveInterface.cpp',
]

if bld.env()['IS_LINUX']:


Loading…
Cancel
Save