Browse Source

Merge network branch

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2445 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.90
sletz 17 years ago
parent
commit
4c488ee522
16 changed files with 2595 additions and 144 deletions
  1. +1
    -0
      SConstruct
  2. +10
    -10
      common/JackAudioDriver.h
  3. +67
    -67
      common/JackDriver.h
  4. +1
    -66
      common/JackException.h
  5. +690
    -0
      common/JackNetDriver.cpp
  6. +88
    -0
      common/JackNetDriver.h
  7. +673
    -0
      common/JackNetManager.cpp
  8. +118
    -0
      common/JackNetManager.h
  9. +312
    -0
      common/JackNetTool.cpp
  10. +174
    -0
      common/JackNetTool.h
  11. +2
    -0
      common/SConscript
  12. +9
    -1
      common/wscript
  13. +4
    -0
      linux/SConscript
  14. +3
    -0
      linux/wscript
  15. +439
    -0
      macosx/Jackdmp.xcodeproj/project.pbxproj
  16. +4
    -0
      macosx/install_jackdmp

+ 1
- 0
SConstruct View File

@@ -215,6 +215,7 @@ env['INCLUDEDIR'] = env.subst(env['INCLUDEDIR'])
env['SERVER'] = 'jackd'
env['CLIENTLIB'] = 'jack'
env['SERVERLIB'] = 'jackserver'
env['NETMANAGERLIB'] = 'netmanager'
env['ADDON_DIR'] = env.subst(env['LIBDIR']) + "/jack"
env['INSTALL_ADDON_DIR'] = env['DESTDIR'] + env.subst(env['LIBDIR']) + "/jack"



+ 10
- 10
common/JackAudioDriver.h View File

@@ -63,16 +63,16 @@ class EXPORT JackAudioDriver : public JackDriver
virtual int Process();

virtual int Open(jack_nframes_t nframes,
jack_nframes_t samplerate,
int capturing,
int playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency);
jack_nframes_t samplerate,
int capturing,
int playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency);

virtual int Attach();
virtual int Detach();


+ 67
- 67
common/JackDriver.h View File

@@ -1,22 +1,22 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2004-2008 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.
*/
Copyright (C) 2001 Paul Davis
Copyright (C) 2004-2008 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 __JackDriver__
#define __JackDriver__
@@ -29,28 +29,28 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

namespace Jack
{
class JackEngineInterface;
class JackGraphManager;
struct JackEngineControl;
struct JackClientControl;
/*!
\brief The base interface for drivers.
*/
class EXPORT JackDriverInterface
{

public:
JackDriverInterface()
{}
virtual ~JackDriverInterface()
{}
virtual int Open() = 0;
virtual int Open(jack_nframes_t nframes,
jack_nframes_t samplerate,
bool capturing,
@@ -62,71 +62,71 @@ class EXPORT JackDriverInterface
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency) = 0;
virtual int Attach() = 0;
virtual int Detach() = 0;
virtual int Read() = 0;
virtual int Write() = 0;
virtual int Start() = 0;
virtual int Stop() = 0;
virtual int SetBufferSize(jack_nframes_t buffer_size) = 0;
virtual int SetSampleRate(jack_nframes_t sample_rate) = 0;
virtual int Process() = 0;
virtual void SetMaster(bool onoff) = 0;
virtual bool GetMaster() = 0;
virtual void AddSlave(JackDriverInterface* slave) = 0;
virtual void RemoveSlave(JackDriverInterface* slave) = 0;
virtual int ProcessSlaves() = 0;
virtual bool IsRealTime() = 0;
};
/*
\brief The base interface for blocking drivers.
*/
\brief The base interface for blocking drivers.
*/

class EXPORT JackBlockingInterface
{
public:
JackBlockingInterface()
{}
virtual ~JackBlockingInterface()
{}
virtual bool Init() = 0; /* To be called by the wrapping thread Init method when the driver is a "blocking" one */
};

/*!
\brief The base interface for drivers clients.
*/
\brief The base interface for drivers clients.
*/

class EXPORT JackDriverClientInterface : public JackDriverInterface, public JackClientInterface
{};

/*!
\brief The base class for drivers clients.
*/
\brief The base class for drivers clients.
*/

class EXPORT JackDriverClient : public JackDriverClientInterface, public JackBlockingInterface
{
private:
std::list<JackDriverInterface*> fSlaveList;
protected:
bool fIsMaster;
public:
virtual void SetMaster(bool onoff);
virtual bool GetMaster();
virtual void AddSlave(JackDriverInterface* slave);
@@ -135,14 +135,14 @@ class EXPORT JackDriverClient : public JackDriverClientInterface, public JackBlo
};

/*!
\brief The base class for drivers.
*/
\brief The base class for drivers.
*/

class EXPORT JackDriver : public JackDriverClient
{
protected:
char fCaptureDriverName[JACK_CLIENT_NAME_SIZE + 1];
char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE + 1];
char fAliasName[JACK_CLIENT_NAME_SIZE + 1];
@@ -155,20 +155,20 @@ class EXPORT JackDriver : public JackDriverClient
JackSynchro* fSynchroTable;
JackEngineControl* fEngineControl;
JackClientControl* fClientControl;

JackClientControl* GetClientControl() const;
JackClientControl* GetClientControl() const;
void CycleIncTime();
void CycleTakeTime();

public:
JackDriver(const char* name, const char* alias, JackEngineInterface* engine, JackSynchro* table);
JackDriver();
virtual ~JackDriver();
virtual int Open();
virtual int Open(jack_nframes_t nframes,
jack_nframes_t samplerate,
bool capturing,
@@ -180,14 +180,14 @@ class EXPORT JackDriver : public JackDriverClient
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency);
virtual int Close();
virtual int Process()
{
return 0;
}
virtual int Attach()
{
return 0;
@@ -196,7 +196,7 @@ class EXPORT JackDriver : public JackDriverClient
{
return 0;
}
virtual int Read()
{
return 0;
@@ -205,7 +205,7 @@ class EXPORT JackDriver : public JackDriverClient
{
return 0;
}
virtual int Start()
{
return 0;
@@ -214,32 +214,32 @@ class EXPORT JackDriver : public JackDriverClient
{
return 0;
}
virtual int SetBufferSize(jack_nframes_t buffer_size)
{
return 0;
}
virtual int SetSampleRate(jack_nframes_t sample_rate)
{
return 0;
}
void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); // XRun notification sent by the driver
virtual bool IsRealTime();
int ClientNotify(int refnum, const char* name, int notify, int sync, int value1, int value2);
void SetupDriverSync(int ref, bool freewheel);
virtual bool Init()
{
return true;
}
};
} // end of namespace

#endif

+ 1
- 66
common/JackException.h View File

@@ -60,69 +60,4 @@ namespace Jack
};

}

#endif
/*
Copyright (C) 2008 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 __JackException__
#define __JackException__

#include <stdexcept>
#include <iostream>
#include <string>
#include "JackError.h"

namespace Jack
{

class JackException : public std::runtime_error {
public:
JackException(const std::string& msg) : runtime_error(msg)
{}
JackException(const char* msg) : runtime_error(msg)
{}
std::string Message()
{
return what();
}

void PrintMessage()
{
std::string str = what();
jack_error(str.c_str());
}
};
class JackDriverException : public JackException {
public:
JackDriverException(const std::string& msg) : JackException(msg)
{}
JackDriverException(const char* msg) : JackException(msg)
{}
};

}

#endif
#endif

+ 690
- 0
common/JackNetDriver.cpp View File

@@ -0,0 +1,690 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2004-2008 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 "JackNetDriver.h"
#include "JackEngineControl.h"
#include "JackClientControl.h"
#include "JackGraphManager.h"
#include "driver_interface.h"
#include "JackDriverLoader.h"
#include "JackThreadedDriver.h"
#include "JackException.h"

#define DEFAULT_MULTICAST_IP "225.3.19.154"
#define DEFAULT_PORT 19000

namespace Jack
{
JackNetDriver::JackNetDriver ( const char* name, const char* alias, JackEngineInterface* engine, JackSynchro* table,
char* ip, size_t port, int midi_input_ports, int midi_output_ports, char* net_name )
: JackAudioDriver ( name, alias, engine, table )
{
fMulticastIP = new char[strlen ( ip ) + 1];
strcpy ( fMulticastIP, ip );
fPort = port;
fParams.fSendMidiChannels = midi_input_ports;
fParams.fReturnMidiChannels = midi_output_ports;
strcpy ( fParams.fName, net_name );
fSockfd = 0;
}

JackNetDriver::~JackNetDriver()
{
if ( fSockfd )
close ( fSockfd );
delete fNetAudioCaptureBuffer;
delete fNetAudioPlaybackBuffer;
delete fNetMidiCaptureBuffer;
delete fNetMidiPlaybackBuffer;
delete[] fTxBuffer;
delete[] fRxBuffer;
delete[] fMulticastIP;
delete[] fMidiCapturePortList;
delete[] fMidiPlaybackPortList;
}

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

int JackNetDriver::Open ( jack_nframes_t nframes, jack_nframes_t samplerate, bool capturing, bool playing,
int inchannels, int outchannels, bool monitor,
const char* capture_driver_name, const char* playback_driver_name,
jack_nframes_t capture_latency, jack_nframes_t playback_latency )
{
int res = JackAudioDriver::Open ( nframes, samplerate, capturing, playing, inchannels, outchannels, monitor,
capture_driver_name, playback_driver_name, capture_latency, playback_latency );
fEngineControl->fPeriod = 0;
fEngineControl->fComputation = 500 * 1000;
fEngineControl->fConstraint = 500 * 1000;
return res;
}

int JackNetDriver::Attach()
{
return 0;
}

int JackNetDriver::Detach()
{
return 0;
}

bool JackNetDriver::Init()
{
jack_log ( "JackNetDriver::Init()" );
if ( fSockfd )
Restart();

//set the parameters to send
strcpy ( fParams.fPacketType, "params" );
fParams.fProtocolVersion = 'a';
SetPacketType ( &fParams, SLAVE_AVAILABLE );
gethostname ( fParams.fSlaveNetName, 255 );
fParams.fSendAudioChannels = fCaptureChannels;
fParams.fReturnAudioChannels = fPlaybackChannels;

//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 == SOCKET_ERROR )
return false;
}
while ( status != CONNECTED );

//then tell the master we are ready
jack_info ( "Initializing connection with %s...", fParams.fMasterNetName );
status = SendMasterStartSync();
}
while ( status != ROLLING );

//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;
struct sockaddr_in mcast_addr, listen_addr;
struct timeval rcv_timeout;
rcv_timeout.tv_sec = 2;
rcv_timeout.tv_usec = 0;
socklen_t addr_len = sizeof ( socket_address_t );
int rx_bytes = 0;

//set the multicast address
mcast_addr.sin_family = AF_INET;
mcast_addr.sin_port = htons ( fPort );
inet_aton ( fMulticastIP, &mcast_addr.sin_addr );
memset ( &mcast_addr.sin_zero, 0, 8 );

//set the listening address
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = htons ( fPort );
listen_addr.sin_addr.s_addr = htonl ( INADDR_ANY );
memset ( &listen_addr.sin_zero, 0, 8 );

//set the master address family
fMasterAddr.sin_family = AF_INET;

//socket
if ( fSockfd )
close ( fSockfd );
if ( ( fSockfd = socket ( AF_INET, SOCK_DGRAM, 0 ) ) < 0 )
{
jack_error ( "Fatal error : network unreachable - %s", strerror ( errno ) );
return SOCKET_ERROR;
}

//bind the socket
if ( bind ( fSockfd, reinterpret_cast<socket_address_t*> ( &listen_addr ), addr_len ) < 0 )
jack_error ( "Can't bind the socket : %s", strerror ( errno ) );

//timeout on receive
setsockopt ( fSockfd, SOL_SOCKET, SO_RCVTIMEO, &rcv_timeout, sizeof ( rcv_timeout ) );

//send 'AVAILABLE' until 'SLAVE_SETUP' received
jack_info ( "Waiting for a master..." );
do
{
//send 'available'
if ( sendto ( fSockfd, &fParams, sizeof ( session_params_t ), MSG_DONTWAIT,
reinterpret_cast<socket_address_t*> ( &mcast_addr ), addr_len ) < 0 )
jack_error ( "Error in data send : %s", strerror ( errno ) );
//filter incoming packets : don't exit while receiving wrong packets
do
{
rx_bytes = recvfrom ( fSockfd, &params, sizeof ( session_params_t ), 0,
reinterpret_cast<socket_address_t*> ( &fMasterAddr ), &addr_len );
if ( ( rx_bytes < 0 ) && ( errno != EAGAIN ) )
{
jack_error ( "Can't receive : %s", strerror ( errno ) );
return RECV_ERROR;
}
}
while ( ( rx_bytes > 0 ) && strcmp ( params.fPacketType, fParams.fPacketType ) );
}
while ( ( GetPacketType ( &params ) != SLAVE_SETUP ) );

//connect the socket
if ( connect ( fSockfd, reinterpret_cast<socket_address_t*> ( &fMasterAddr ), sizeof ( socket_address_t ) ) < 0 )
{
jack_error ( "Error in connect : %s", strerror ( errno ) );
return CONNECT_ERROR;
}

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

return CONNECTED;
}

net_status_t JackNetDriver::SendMasterStartSync()
{
jack_log ( "JackNetDriver::GetNetMasterStartSync()" );
//tell the master to start
SetPacketType ( &fParams, START_MASTER );
if ( send ( fSockfd, &fParams, sizeof ( session_params_t ), MSG_DONTWAIT ) < 0 )
jack_error ( "Error in send : %s", strerror ( errno ) );
return ROLLING;
}

void JackNetDriver::Restart()
{
jack_info ( "Restarting driver..." );
close ( fSockfd );
delete[] fTxBuffer;
delete[] fRxBuffer;
delete fNetAudioCaptureBuffer;
delete fNetAudioPlaybackBuffer;
delete fNetMidiCaptureBuffer;
delete fNetMidiPlaybackBuffer;
FreePorts();
delete[] fMidiCapturePortList;
delete[] fMidiPlaybackPortList;
fTxBuffer = NULL;
fRxBuffer = NULL;
fNetAudioCaptureBuffer = NULL;
fNetAudioCaptureBuffer = NULL;
fNetMidiCaptureBuffer = NULL;
fNetMidiPlaybackBuffer = NULL;
fMidiCapturePortList = NULL;
fMidiPlaybackPortList = NULL;
}


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

//allocate midi ports lists
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();

return 0;
}

int JackNetDriver::AllocPorts()
{
jack_log ( "JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate );
JackPort* port;
jack_port_id_t port_id;
char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
unsigned long port_flags;

//audio
port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
for ( int port_index = 0; port_index < fCaptureChannels; port_index++ )
{
snprintf ( alias, sizeof ( alias ) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, port_index + 1 );
snprintf ( name, sizeof ( name ) - 1, "%s:capture_%d", fClientControl->fName, port_index + 1 );
if ( ( port_id = fGraphManager->AllocatePort ( fClientControl->fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
static_cast<JackPortFlags> ( port_flags ), fEngineControl->fBufferSize ) ) == NO_PORT )
{
jack_error ( "driver: cannot register port for %s", name );
return -1;
}
port = fGraphManager->GetPort ( port_id );
port->SetAlias ( alias );
port->SetLatency ( fEngineControl->fBufferSize + fCaptureLatency );
fCapturePortList[port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fCapturePortList[%d] port_index = %ld", port_index, port_id );
}
port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;
for ( int port_index = 0; port_index < fPlaybackChannels; port_index++ )
{
snprintf ( alias, sizeof ( alias ) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, port_index + 1 );
snprintf ( name, sizeof ( name ) - 1, "%s:playback_%d",fClientControl->fName, port_index + 1 );
if ( ( port_id = fGraphManager->AllocatePort ( fClientControl->fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
static_cast<JackPortFlags> ( port_flags ), fEngineControl->fBufferSize ) ) == NO_PORT )
{
jack_error ( "driver: cannot register port for %s", name );
return -1;
}
port = fGraphManager->GetPort ( port_id );
port->SetAlias ( alias );
port->SetLatency ( fEngineControl->fBufferSize + ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) + fPlaybackLatency );
fPlaybackPortList[port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fPlaybackPortList[%d] port_index = %ld", port_index, port_id );
}
//midi
port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
for ( int port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
{
snprintf ( alias, sizeof ( alias ) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, port_index + 1 );
snprintf ( name, sizeof ( name ) - 1, "%s:midi_capture_%d", fClientControl->fName, port_index + 1 );
if ( ( port_id = fGraphManager->AllocatePort ( fClientControl->fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
static_cast<JackPortFlags> ( port_flags ), fEngineControl->fBufferSize ) ) == NO_PORT )
{
jack_error ( "driver: cannot register port for %s", name );
return -1;
}
fMidiCapturePortList[port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fMidiCapturePortList[%d] port_index = %ld", port_index, port_id );
}

port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;
for ( int port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
{
snprintf ( alias, sizeof ( alias ) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, port_index + 1 );
snprintf ( name, sizeof ( name ) - 1, "%s:midi_playback_%d", fClientControl->fName, port_index + 1 );
if ( ( port_id = fGraphManager->AllocatePort ( fClientControl->fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
static_cast<JackPortFlags> ( port_flags ), fEngineControl->fBufferSize ) ) == NO_PORT )
{
jack_error ( "driver: cannot register port for %s", name );
return -1;
}
fMidiPlaybackPortList[port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] port_index = %ld", port_index, port_id );
}

return 0;
}

int JackNetDriver::FreePorts()
{
jack_log ( "JackNetDriver::FreePorts" );
for ( int port_index = 0; port_index < fCaptureChannels; port_index++ )
fGraphManager->ReleasePort ( fClientControl->fRefNum, fCapturePortList[port_index] );
for ( int port_index = 0; port_index < fPlaybackChannels; port_index++ )
fGraphManager->ReleasePort ( fClientControl->fRefNum, fPlaybackPortList[port_index] );
for ( int port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
fGraphManager->ReleasePort ( fClientControl->fRefNum, fMidiCapturePortList[port_index] );
for ( int port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
fGraphManager->ReleasePort ( fClientControl->fRefNum, fMidiPlaybackPortList[port_index] );
return 0;
}

JackMidiBuffer* JackNetDriver::GetMidiInputBuffer ( int port_index )
{
return static_cast<JackMidiBuffer*> ( fGraphManager->GetBuffer ( fMidiCapturePortList[port_index], fEngineControl->fBufferSize ) );
}

JackMidiBuffer* JackNetDriver::GetMidiOutputBuffer ( int port_index )
{
return static_cast<JackMidiBuffer*> ( fGraphManager->GetBuffer ( fMidiPlaybackPortList[port_index], fEngineControl->fBufferSize ) );
}

int JackNetDriver::Recv ( size_t size, int flags )
{
int rx_bytes;
if ( ( rx_bytes = recv ( fSockfd, fRxBuffer, size, flags ) ) < 0 )
{
if ( errno == EAGAIN )
{
jack_error ( "No incoming data, is the master still running ?" );
return 0;
}
else if ( ( errno == ECONNABORTED ) || ( errno == ECONNREFUSED ) || ( errno == ECONNRESET ) )
{
jack_error ( "Fatal error : %s.", strerror ( errno ) );
throw JackDriverException ( "" );
return -1;
}
else
{
jack_error ( "Error in receive : %s", strerror ( errno ) );
return 0;
}
}
return rx_bytes;
}

int JackNetDriver::Send ( size_t size, int flags )
{
int tx_bytes;
if ( ( tx_bytes = send ( fSockfd, fTxBuffer, size, flags ) ) < 0 )
{
if ( ( errno == ECONNABORTED ) || ( errno == ECONNREFUSED ) || ( errno == ECONNRESET ) )
{
jack_error ( "Fatal error : %s.", strerror ( errno ) );
throw JackDriverException ( "" );
return -1;
}
else
jack_error ( "Error in send : %s", strerror ( errno ) );
}
return tx_bytes;
}

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

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

//buffers
for ( int port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
fNetMidiCaptureBuffer->fPortBuffer[port_index] = GetMidiInputBuffer ( port_index );
for ( int port_index = 0; port_index < fCaptureChannels; port_index++ )
fNetAudioCaptureBuffer->fPortBuffer[port_index] = GetInputBuffer ( port_index );

//receive sync (launch the cycle)
do
{
if ( ( rx_bytes = Recv ( sizeof ( packet_header_t ), 0 ) ) < 1 )
return rx_bytes;
}
while ( !rx_bytes && ( rx_head->fDataType != 's' ) );

JackDriver::CycleTakeTime();

//audio, midi or sync if driver is late
if ( fParams.fSendMidiChannels || fParams.fSendAudioChannels )
{
do
{
rx_bytes = Recv ( fParams.fMtu, MSG_PEEK );
if ( rx_bytes < 1 )
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_bytes, MSG_DONTWAIT );
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 ( fAudioRxLen, MSG_DONTWAIT );
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;
return 0;
}

int JackNetDriver::Write()
{
int tx_bytes, copy_size;
fTxHeader.fCycle = fRxHeader.fCycle;
fTxHeader.fSubCycle = 0;
fTxHeader.fIsLastPckt = 'n';

//buffers
for ( int port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
fNetMidiPlaybackBuffer->fPortBuffer[port_index] = GetMidiOutputBuffer ( port_index );
for ( int port_index = 0; port_index < fPlaybackChannels; port_index++ )
fNetAudioPlaybackBuffer->fPortBuffer[port_index] = GetOutputBuffer ( port_index );

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

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

//*************************************loader*******************************************************

#ifdef __cplusplus
extern "C"
{
#endif
jack_driver_desc_t* driver_get_descriptor ()
{
jack_driver_desc_t* desc = ( jack_driver_desc_t* ) calloc ( 1, sizeof ( jack_driver_desc_t ) );
strcpy ( desc->name, "net" );
desc->nparams = 7;
desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) );

size_t i = 0;
strcpy ( desc->params[i].name, "multicast_ip" );
desc->params[i].character = 'a';
desc->params[i].type = JackDriverParamString;
strcpy ( desc->params[i].value.str, DEFAULT_MULTICAST_IP );
strcpy ( desc->params[i].short_desc, "Multicast Address" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

i++;
strcpy ( desc->params[i].name, "udp_net_port" );
desc->params[i].character = 'p';
desc->params[i].type = JackDriverParamUInt;
desc->params[i].value.ui = 19000U;
strcpy ( desc->params[i].short_desc, "UDP port" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

i++;
strcpy ( desc->params[i].name, "input_ports" );
desc->params[i].character = 'C';
desc->params[i].type = JackDriverParamInt;
desc->params[i].value.i = 2;
strcpy ( desc->params[i].short_desc, "Number of audio input ports" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

i++;
strcpy ( desc->params[i].name, "output_ports" );
desc->params[i].character = 'P';
desc->params[i].type = JackDriverParamUInt;
desc->params[i].value.i = 2;
strcpy ( desc->params[i].short_desc, "Number of audio output ports" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

i++;
strcpy ( desc->params[i].name, "midi_in_ports" );
desc->params[i].character = 'i';
desc->params[i].type = JackDriverParamInt;
desc->params[i].value.i = 0;
strcpy ( desc->params[i].short_desc, "Number of midi input ports" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

i++;
strcpy ( desc->params[i].name, "midi_out_ports" );
desc->params[i].character = 'o';
desc->params[i].type = JackDriverParamUInt;
desc->params[i].value.i = 0;
strcpy ( desc->params[i].short_desc, "Number of midi output ports" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

i++;
strcpy ( desc->params[i].name, "client_name" );
desc->params[i].character = 'n';
desc->params[i].type = JackDriverParamString;
strcpy ( desc->params[i].value.str, "'hostname'" );
strcpy ( desc->params[i].short_desc, "Name of the jack client" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

return desc;
}

Jack::JackDriverClientInterface* driver_initialize ( Jack::JackEngineInterface* engine, Jack::JackSynchro* table, const JSList* params )
{
char* multicast_ip = DEFAULT_MULTICAST_IP;
char name[JACK_CLIENT_NAME_SIZE];
gethostname ( name, JACK_CLIENT_NAME_SIZE );
jack_nframes_t udp_port = DEFAULT_PORT;
jack_nframes_t period_size = 128;
jack_nframes_t sample_rate = 48000;
int audio_capture_ports = 2;
int audio_playback_ports = 2;
int midi_input_ports = 0;
int midi_output_ports = 0;
bool monitor = false;

const JSList* node;
const jack_driver_param_t* param;
for ( node = params; node; node = jack_slist_next ( node ) )
{
param = ( const jack_driver_param_t* ) node->data;
switch ( param->character )
{
case 'a' :
multicast_ip = strdup ( param->value.str );
break;
case 'p':
udp_port = param->value.ui;
break;
case 'C':
audio_capture_ports = param->value.i;
break;
case 'P':
audio_playback_ports = param->value.i;
break;
case 'i':
midi_input_ports = param->value.i;
break;
case 'o':
midi_output_ports = param->value.i;
break;
case 'n' :
strncpy ( name, param->value.str, JACK_CLIENT_NAME_SIZE );
}
}
Jack::JackDriverClientInterface* driver = new Jack::JackRestartThreadedDriver (
new Jack::JackNetDriver ( "system", "net_pcm", engine, table, multicast_ip, udp_port, midi_input_ports, midi_output_ports, name ) );
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;
delete driver;
return NULL;
}

#ifdef __cplusplus
}
#endif
}

+ 88
- 0
common/JackNetDriver.h View File

@@ -0,0 +1,88 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2004-2008 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 __JackNetDriver__
#define __JackNetDriver__

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

namespace Jack
{

class JackNetDriver : public JackAudioDriver
{
private:
session_params_t fParams;
char* fMulticastIP;
size_t fPort;
int fSockfd;
struct sockaddr_in fMasterAddr;
size_t fNSubProcess;

jack_port_id_t* fMidiCapturePortList;
jack_port_id_t* fMidiPlaybackPortList;

packet_header_t fTxHeader;
packet_header_t fRxHeader;

char* fTxBuffer;
char* fRxBuffer;
char* fTxData;
char* fRxData;

NetMidiBuffer* fNetMidiCaptureBuffer;
NetMidiBuffer* fNetMidiPlaybackBuffer;
NetAudioBuffer* fNetAudioCaptureBuffer;
NetAudioBuffer* fNetAudioPlaybackBuffer;

int fAudioRxLen;
int fAudioTxLen;

int Attach();
int Detach();

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

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 Read();
int Write();
public:
JackNetDriver ( const char* name, const char* alias, JackEngineInterface* engine, JackSynchro* table,
char* ip, size_t port, int midi_input_ports, int midi_output_ports, char* master_name );
~JackNetDriver();

int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, bool capturing, bool playing,
int inchannels, int outchannels, bool monitor, const char* capture_driver_name,
const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency );
};
}

#endif

+ 673
- 0
common/JackNetManager.cpp View File

@@ -0,0 +1,673 @@
/***************************************************************************
* Copyright (C) 2008 by Romain Moret *
* moret@grame.fr *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#include "JackNetManager.h"
#include "JackError.h"

#define DEFAULT_MULTICAST_IP "225.3.19.154"
#define DEFAULT_PORT 19000

using namespace std;

namespace Jack
{
//JackNetMaster******************************************************************************************************

JackNetMaster::JackNetMaster ( JackNetMasterManager* manager, session_params_t& params, struct sockaddr_in& address, struct sockaddr_in& mcast_addr )
{
jack_log ( "JackNetMaster::JackNetMaster" );
//settings
fMasterManager = manager;
fParams = params;
fAddr = address;
fMcastAddr = mcast_addr;
fNSubProcess = fParams.fPeriodSize / fParams.fFramesPerPacket;
fClientName = const_cast<char*> ( fParams.fName );
fNetJumpCnt = 0;
fJackClient = NULL;
fSockfd = 0;
fRunning = false;

//jack audio ports
fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels];
for ( int port_index = 0; port_index < fParams.fSendAudioChannels; port_index++ )
fAudioCapturePorts[port_index] = NULL;
fAudioPlaybackPorts = new jack_port_t* [fParams.fReturnAudioChannels];
for ( int port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++ )
fAudioPlaybackPorts[port_index] = NULL;
//jack midi ports
fMidiCapturePorts = new jack_port_t* [fParams.fSendMidiChannels];
for ( int port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
fMidiCapturePorts[port_index] = NULL;
fMidiPlaybackPorts = new jack_port_t* [fParams.fReturnMidiChannels];
for ( int port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
fMidiPlaybackPorts[port_index] = NULL;

//TX header init
strcpy ( fTxHeader.fPacketType, "header" );
fTxHeader.fDataStream = 's';
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 = 'r';
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 buffers
fTxData = fTxBuffer + sizeof ( packet_header_t );
fRxData = fRxBuffer + sizeof ( packet_header_t );

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

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

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

JackNetMaster::~JackNetMaster()
{
jack_log ( "JackNetMaster::~JackNetMaster, ID %u.", fParams.fID );
if ( fJackClient )
{
jack_deactivate ( fJackClient );
FreePorts();
jack_client_close ( fJackClient );
}
if ( fSockfd )
close ( fSockfd );
delete fNetAudioCaptureBuffer;
delete fNetAudioPlaybackBuffer;
delete fNetMidiCaptureBuffer;
delete fNetMidiPlaybackBuffer;
delete[] fAudioCapturePorts;
delete[] fAudioPlaybackPorts;
delete[] fMidiCapturePorts;
delete[] fMidiPlaybackPorts;
delete[] fTxBuffer;
delete[] fRxBuffer;
}

bool JackNetMaster::Init()
{
jack_log ( "JackNetMaster::Init, ID %u.", fParams.fID );
session_params_t params;
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
size_t attempt = 0;
int rx_bytes = 0;

//socket
if ( ( fSockfd = socket ( AF_INET, SOCK_DGRAM, 0 ) ) < 0 )
{
jack_error ( "Can't create socket : %s", strerror ( errno ) );
return false;
}

//timeout on receive (for init)
if ( setsockopt ( fSockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof ( timeout ) ) < 0 )
jack_error ( "Can't set timeout : %s", strerror ( errno ) );

//connect
if ( connect ( fSockfd, reinterpret_cast<sockaddr*> ( &fAddr ), sizeof ( struct sockaddr ) ) < 0 )
{
jack_error ( "Can't connect : %s", strerror ( errno ) );
return false;
}

//send 'SLAVE_SETUP' until 'START_MASTER' received
jack_info ( "Sending parameters to %s ...", fParams.fSlaveNetName );
do
{
SetPacketType ( &fParams, SLAVE_SETUP );
if ( send ( fSockfd, &fParams, sizeof ( session_params_t ), 0 ) < 0 )
jack_error ( "Error in send : ", strerror ( errno ) );
if ( ( ( rx_bytes = recv ( fSockfd, &params, sizeof ( session_params_t ), 0 ) ) < 0 ) && ( errno != EAGAIN ) )
{
jack_error ( "Problem with network." );
return false;
}
}
while ( ( GetPacketType ( &params ) != START_MASTER ) && ( ++attempt < 5 ) );
if ( attempt == 5 )
{
jack_error ( "Slave doesn't respond, exiting." );
return false;
}

//set the new timeout for the socket
if ( SetRxTimeout ( &fSockfd, &fParams ) < 0 )
{
jack_error ( "Can't set rx timeout : %s", strerror ( errno ) );
return false;
}

//jack client and process
jack_status_t status;
jack_options_t options = JackNullOption;
if ( ( fJackClient = jack_client_open ( fClientName, options, &status, NULL ) ) == NULL )
{
jack_error ( "Can't open a new jack client." );
return false;
}

jack_set_process_callback ( fJackClient, SetProcess, this );

//port registering
int i;
char name[24];
//audio
for ( i = 0; i < fParams.fSendAudioChannels; i++ )
{
sprintf ( name, "to_slave_%d", i+1 );
if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ) ) == NULL )
goto fail;
}
for ( i = 0; i < fParams.fReturnAudioChannels; i++ )
{
sprintf ( name, "from_slave_%d", i+1 );
if ( ( fAudioPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ) ) == NULL )
goto fail;
}
//midi
for ( i = 0; i < fParams.fSendMidiChannels; i++ )
{
sprintf ( name, "midi_to_slave_%d", i+1 );
if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 ) ) == NULL )
goto fail;
}
for ( i = 0; i < fParams.fReturnMidiChannels; i++ )
{
sprintf ( name, "midi_from_slave_%d", i+1 );
if ( ( fMidiPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 ) ) == NULL )
goto fail;
}

fRunning = true;

//finally activate jack client
if ( jack_activate ( fJackClient ) != 0 )
{
jack_error ( "Can't activate jack client." );
goto fail;
}

jack_info ( "NetJack new master started." );

return true;

fail:
FreePorts();
jack_client_close ( fJackClient );
fJackClient = NULL;
return false;
}

void JackNetMaster::FreePorts()
{
jack_log ( "JackNetMaster::FreePorts, ID %u", fParams.fID );
for ( int port_index = 0; port_index < fParams.fSendAudioChannels; port_index++ )
if ( fAudioCapturePorts[port_index] )
jack_port_unregister ( fJackClient, fAudioCapturePorts[port_index] );
for ( int port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++ )
if ( fAudioPlaybackPorts[port_index] )
jack_port_unregister ( fJackClient, fAudioPlaybackPorts[port_index] );
for ( int port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
if ( fMidiCapturePorts[port_index] )
jack_port_unregister ( fJackClient, fMidiCapturePorts[port_index] );
for ( int port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
if ( fMidiPlaybackPorts[port_index] )
jack_port_unregister ( fJackClient, fMidiPlaybackPorts[port_index] );
}

void JackNetMaster::Exit()
{
jack_log ( "JackNetMaster::Exit, ID %u", fParams.fID );
//stop process
fRunning = false;
//send a 'multicast euthanasia request' - new socket is required on macosx
jack_info ( "Exiting '%s'", fParams.fName );
SetPacketType ( &fParams, KILL_MASTER );
int mcast_sockfd = socket ( AF_INET, SOCK_DGRAM, 0 );
if ( mcast_sockfd < 0 )
jack_error ( "Can't create socket : %s", strerror ( errno ) );
if ( sendto ( mcast_sockfd, &fParams, sizeof ( session_params_t ), MSG_DONTWAIT,
reinterpret_cast<socket_address_t*> ( &fMcastAddr ), sizeof ( socket_address_t ) ) < 0 )
jack_error ( "Can't send suicide request : %s", strerror ( errno ) );
close ( mcast_sockfd );
}

int JackNetMaster::Send ( char* buffer, size_t size, int flags )
{
int tx_bytes;
if ( ( tx_bytes = send ( fSockfd, buffer, size, flags ) ) < 0 )
{
if ( ( errno == ECONNABORTED ) || ( errno == ECONNREFUSED ) || ( errno == ECONNRESET ) )
{
//fatal connection issue, exit
jack_error ( "'%s' : %s, please check network connection with '%s'.",
fParams.fName, strerror ( errno ), fParams.fSlaveNetName );
Exit();
return 0;
}
else
jack_error ( "Error in send : %s", strerror ( errno ) );
}
return tx_bytes;
}

int JackNetMaster::Recv ( size_t size, int flags )
{
int rx_bytes;
if ( ( rx_bytes = recv ( fSockfd, fRxBuffer, size, flags ) ) < 0 )
{
if ( errno == EAGAIN )
{
//too much receive failure, react...
if ( ++fNetJumpCnt == 100 )
{
jack_error ( "Connection lost, is %s still running ?", fParams.fName );
fNetJumpCnt = 0;
}
return 0;
}
else if ( ( errno == ECONNABORTED ) || ( errno == ECONNREFUSED ) || ( errno == ECONNRESET ) )
{
//fatal connection issue, exit
jack_error ( "'%s' : %s, please check network connection with '%s'.",
fParams.fName, strerror ( errno ), fParams.fSlaveNetName );
Exit();
return 0;
}
else if ( errno != EAGAIN )
jack_error ( "Error in receive : %s", strerror ( errno ) );
}
return rx_bytes;
}

int JackNetMaster::SetProcess ( jack_nframes_t nframes, void* arg )
{
JackNetMaster* master = static_cast<JackNetMaster*> ( arg ); ;
return master->Process();
}

int JackNetMaster::Process()
{
if ( !fRunning )
return 0;

int tx_bytes, rx_bytes, copy_size;
size_t midi_recvd_pckt = 0;
fTxHeader.fCycle++;
fTxHeader.fSubCycle = 0;
fTxHeader.fIsLastPckt = 'n';
packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer );

//buffers
for ( int port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
fNetMidiCaptureBuffer->fPortBuffer[port_index] =
static_cast<JackMidiBuffer*> ( jack_port_get_buffer ( fMidiCapturePorts[port_index], fParams.fPeriodSize ) );
for ( int port_index = 0; port_index < fParams.fSendAudioChannels; port_index++ )
fNetAudioCaptureBuffer->fPortBuffer[port_index] =
static_cast<sample_t*> ( jack_port_get_buffer ( fAudioCapturePorts[port_index], fParams.fPeriodSize ) );
for ( int port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
fNetMidiPlaybackBuffer->fPortBuffer[port_index] =
static_cast<JackMidiBuffer*> ( jack_port_get_buffer ( fMidiPlaybackPorts[port_index], fParams.fPeriodSize ) );
for ( int port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++ )
fNetAudioPlaybackBuffer->fPortBuffer[port_index] =
static_cast<sample_t*> ( jack_port_get_buffer ( fAudioPlaybackPorts[port_index], fParams.fPeriodSize ) );

//send ------------------------------------------------------------------------------------------------------------------
//sync
fTxHeader.fDataType = 's';
if ( !fParams.fSendMidiChannels && !fParams.fSendAudioChannels )
fTxHeader.fIsLastPckt = 'y';
tx_bytes = Send ( reinterpret_cast<char*> ( &fTxHeader ), sizeof ( packet_header_t ), MSG_DONTWAIT );
if ( tx_bytes < 1 )
return tx_bytes;

//midi
if ( fParams.fSendMidiChannels )
{
fTxHeader.fDataType = 'm';
fTxHeader.fMidiDataSize = fNetMidiCaptureBuffer->RenderFromJackPorts();
fTxHeader.fNMidiPckt = GetNMidiPckt ( &fParams, fTxHeader.fMidiDataSize );
for ( size_t subproc = 0; subproc < fTxHeader.fNMidiPckt; subproc++ )
{
fTxHeader.fSubCycle = subproc;
if ( ( subproc == ( fTxHeader.fNMidiPckt - 1 ) ) && !fParams.fSendAudioChannels )
fTxHeader.fIsLastPckt = 'y';
memcpy ( fTxBuffer, &fTxHeader, sizeof ( packet_header_t ) );
copy_size = fNetMidiCaptureBuffer->RenderToNetwork ( subproc, fTxHeader.fMidiDataSize );
tx_bytes = Send ( fTxBuffer, sizeof ( packet_header_t ) + copy_size, MSG_DONTWAIT );
if ( tx_bytes < 1 )
return tx_bytes;
}
}

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

//receive ( if there is stg to receive...)-------------------------------------------------------------------------------------
if ( fParams.fReturnMidiChannels || fParams.fReturnAudioChannels )
{
do
{
rx_bytes = Recv ( fParams.fMtu, MSG_PEEK );
if ( rx_bytes < 1 )
return rx_bytes;
if ( rx_bytes && ( rx_head->fDataStream == 'r' ) && ( rx_head->fID == fParams.fID ) )
{
switch ( rx_head->fDataType )
{
case 'm': //midi
rx_bytes = Recv ( rx_bytes, MSG_DONTWAIT );
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();
fNetJumpCnt = 0;
break;
case 'a': //audio
rx_bytes = Recv ( fAudioRxLen, MSG_DONTWAIT );
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 );
fNetJumpCnt = 0;
break;
}
}
}
while ( fRxHeader.fIsLastPckt != 'y' );
}
return 0;
}

//JackNetMasterManager***********************************************************************************************

JackNetMasterManager::JackNetMasterManager ( jack_client_t* client )
{
jack_log ( "JackNetMasterManager::JackNetMasterManager" );
fManagerClient = client;
fManagerName = jack_get_client_name ( fManagerClient );
fMCastIP = DEFAULT_MULTICAST_IP;
fPort = DEFAULT_PORT;
fGlobalID = 0;
fRunning = true;

//launch the manager thread
if ( jack_client_create_thread ( fManagerClient, &fManagerThread, 0, 0, NetManagerThread, this ) )
jack_error ( "Can't create the network manager control thread." );
}

JackNetMasterManager::~JackNetMasterManager()
{
jack_log ( "JackNetMasterManager::~JackNetMasterManager" );
Exit();
master_list_t::iterator it;
for ( it = fMasterList.begin(); it != fMasterList.end(); it++ )
delete ( *it );
}

void* JackNetMasterManager::NetManagerThread ( void* arg )
{
jack_info ( "Starting Jack Network Manager." );
JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*> ( arg );
master_manager->Run();
return NULL;
}

void JackNetMasterManager::Run()
{
jack_log ( "JackNetMasterManager::Run" );
//utility variables
socklen_t addr_len = sizeof ( socket_address_t );
char disable = 0;
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
size_t attempt = 0;

//network
int mcast_sockfd;
struct ip_mreq multicast_req;
struct sockaddr_in mcast_addr;
struct sockaddr_in response_addr;

//data
session_params_t params;
int rx_bytes = 0;
JackNetMaster* net_master;

//socket
if ( ( mcast_sockfd = socket ( AF_INET, SOCK_DGRAM, 0 ) ) < 0 )
{
jack_error ( "Can't create the network management input socket : %s", strerror ( errno ) );
return;
}

//set the multicast address
mcast_addr.sin_family = AF_INET;
mcast_addr.sin_port = htons ( fPort );
if ( inet_aton ( fMCastIP, &mcast_addr.sin_addr ) < 0 )
{
jack_error ( "Cant set multicast address : %s", strerror ( errno ) );
close ( mcast_sockfd );
return;
}
memset ( &mcast_addr.sin_zero, 0, 8 );

//bind the socket to the multicast address
if ( bind ( mcast_sockfd, reinterpret_cast<socket_address_t *> ( &mcast_addr ), addr_len ) < 0 )
{
jack_error ( "Can't bind the network manager socket : %s", strerror ( errno ) );
close ( mcast_sockfd );
return;
}

//join multicast group
inet_aton ( fMCastIP, &multicast_req.imr_multiaddr );
multicast_req.imr_interface.s_addr = htonl ( INADDR_ANY );
if ( setsockopt ( mcast_sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof ( multicast_req ) ) < 0 )
{
jack_error ( "Can't join multicast group : %s", strerror ( errno ) );
close ( mcast_sockfd );
return;
}

//disable local loop
if ( setsockopt ( mcast_sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof ( disable ) ) < 0 )
jack_error ( "Can't set multicast loop option : %s", strerror ( errno ) );

//set a timeout on the multicast receive (the thread can now be cancelled)
if ( setsockopt ( mcast_sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof ( timeout ) ) < 0 )
jack_error ( "Can't set timeout : %s", strerror ( errno ) );

jack_info ( "Waiting for a slave..." );

//main loop, wait for data, deal with it and wait again
do
{
rx_bytes = recvfrom ( mcast_sockfd, &params, sizeof ( session_params_t ), 0,
reinterpret_cast<socket_address_t*> ( &response_addr ), &addr_len );
if ( ( rx_bytes < 0 ) && ( errno != EAGAIN ) )
{
jack_error ( "Error in receive : %s", strerror ( errno ) );
if ( ++attempt == 10 )
{
jack_error ( "Can't receive on the socket, exiting net manager." );
return;
}
}
if ( rx_bytes == sizeof ( session_params_t ) )
{
switch ( GetPacketType ( &params ) )
{
case SLAVE_AVAILABLE:
if ( ( net_master = MasterInit ( params, response_addr, mcast_addr ) ) )
SessionParamsDisplay ( &net_master->fParams );
else
jack_error ( "Can't init new net master..." );
jack_info ( "Waiting for a slave..." );
break;
case KILL_MASTER:
KillMaster ( &params );
jack_info ( "Waiting for a slave..." );
break;
default:
break;
}
}
}
while ( fRunning );
close ( mcast_sockfd );
}

void JackNetMasterManager::Exit()
{
jack_log ( "JackNetMasterManager::Exit" );
fRunning = false;
pthread_join ( fManagerThread, NULL );
jack_info ( "Exiting net manager..." );
}

JackNetMaster* JackNetMasterManager::MasterInit ( session_params_t& params, struct sockaddr_in& address, struct sockaddr_in& mcast_addr )
{
jack_log ( "JackNetMasterManager::MasterInit, Slave : %s", params.fName );
//settings
gethostname ( params.fMasterNetName, 255 );
params.fMtu = 1500;
params.fID = ++fGlobalID;
params.fSampleRate = jack_get_sample_rate ( fManagerClient );
params.fPeriodSize = jack_get_buffer_size ( fManagerClient );
params.fBitdepth = 0;
SetFramesPerPacket ( &params );
SetSlaveName ( params );

//create a new master and add it to the list
JackNetMaster* master = new JackNetMaster ( this, params, address, mcast_addr );
if ( master->Init() )
{
fMasterList.push_back ( master );
return master;
}
delete master;
return NULL;
}

void JackNetMasterManager::SetSlaveName ( session_params_t& params )
{
jack_log ( "JackNetMasterManager::SetSlaveName" );
master_list_it_t it;
for ( it = fMasterList.begin(); it != fMasterList.end(); it++ )
if ( strcmp ( ( *it )->fParams.fName, params.fName ) == 0 )
sprintf ( params.fName, "%s-%u", params.fName, params.fID );
}

master_list_it_t JackNetMasterManager::FindMaster ( size_t id )
{
jack_log ( "JackNetMasterManager::FindMaster, ID %u.", id );
master_list_it_t it;
for ( it = fMasterList.begin(); it != fMasterList.end(); it++ )
if ( ( *it )->fParams.fID == id )
return it;
return it;
}

void JackNetMasterManager::KillMaster ( session_params_t* params )
{
jack_log ( "JackNetMasterManager::KillMaster, ID %u.", params->fID );
master_list_it_t master = FindMaster ( params->fID );
if ( master != fMasterList.end() )
{
fMasterList.erase ( master );
delete *master;
}
}
}//namespace

static Jack::JackNetMasterManager* master_manager = NULL;

#ifdef __cplusplus
extern "C"
{
#endif
int jack_initialize ( jack_client_t* jack_client, const char* load_init )
{
if ( master_manager )
{
jack_error ( "Master Manager already loaded" );
return 1;
}
else
{
jack_log ( "Loading Master Manager" );
master_manager = new Jack::JackNetMasterManager ( jack_client );
return ( master_manager ) ? 0 : 1;
}
}

void jack_finish ( void* arg )
{
if ( master_manager )
{
jack_log ( "Unloading Master Manager" );
delete master_manager;
master_manager = NULL;
}
}
#ifdef __cplusplus
}
#endif

+ 118
- 0
common/JackNetManager.h View File

@@ -0,0 +1,118 @@
/***************************************************************************
* Copyright (C) 2008 by Romain Moret *
* moret@grame.fr *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __JACKNETMASTER_H__
#define __JACKNETMASTER_H__

#include "JackNetTool.h"
#include <list>
#include <algorithm>
#include "thread.h"
#include <unistd.h>
#include "jack.h"

namespace Jack
{
class JackNetMasterManager;

class JackNetMaster
{
friend class JackNetMasterManager;
private:
static int SetProcess ( jack_nframes_t nframes, void* arg );

JackNetMasterManager* fMasterManager;
session_params_t fParams;
struct sockaddr_in fAddr;
struct sockaddr_in fMcastAddr;
int fSockfd;
size_t fNSubProcess;
size_t fNetJumpCnt;
bool fRunning;

jack_client_t* fJackClient;
const char* fClientName;

jack_port_t** fAudioCapturePorts;
jack_port_t** fAudioPlaybackPorts;
jack_port_t** fMidiCapturePorts;
jack_port_t** fMidiPlaybackPorts;

packet_header_t fTxHeader;
packet_header_t fRxHeader;

char* fTxBuffer;
char* fRxBuffer;
char* fTxData;
char* fRxData;

NetAudioBuffer* fNetAudioCaptureBuffer;
NetAudioBuffer* fNetAudioPlaybackBuffer;
NetMidiBuffer* fNetMidiCaptureBuffer;
NetMidiBuffer* fNetMidiPlaybackBuffer;

int fAudioTxLen;
int fAudioRxLen;

bool Init();
void FreePorts();
void Exit();

int Send ( char* buffer, size_t size, int flags );
int Recv ( size_t size, int flags );
int Process();
public:
JackNetMaster ( JackNetMasterManager* manager, session_params_t& params, struct sockaddr_in& address, struct sockaddr_in& mcast_addr );
~JackNetMaster ();
};

typedef std::list<JackNetMaster*> master_list_t;
typedef master_list_t::iterator master_list_it_t;

class JackNetMasterManager
{
private:
static void* NetManagerThread ( void* arg );
static int SetProcess ( jack_nframes_t nframes, void* arg );

jack_client_t* fManagerClient;
char* fManagerName;
char* fMCastIP;
pthread_t fManagerThread;
master_list_t fMasterList;
size_t fGlobalID;
bool fRunning;
size_t fPort;

void Run();
JackNetMaster* MasterInit ( session_params_t& params, struct sockaddr_in& address, struct sockaddr_in& mcast_addr );
master_list_it_t FindMaster ( size_t client_id );
void KillMaster ( session_params_t* params );
void SetSlaveName ( session_params_t& params );
int Process();
public:
JackNetMasterManager ( jack_client_t* jack_client );
~JackNetMasterManager();

void Exit();
};
}

#endif

+ 312
- 0
common/JackNetTool.cpp View File

@@ -0,0 +1,312 @@

#include "JackNetTool.h"
#include "JackError.h"

using namespace std;

namespace Jack
{
// NetMidiBuffer**********************************************************************************

NetMidiBuffer::NetMidiBuffer ( session_params_t* params, size_t nports, char* net_buffer )
{
fNPorts = nports;
fMaxBufsize = fNPorts * sizeof ( sample_t ) * params->fPeriodSize ;
fMaxPcktSize = params->fMtu - sizeof ( packet_header_t );
fBuffer = new char[fMaxBufsize];
fPortBuffer = new JackMidiBuffer* [fNPorts];
for ( int port_index = 0; port_index < fNPorts; port_index++ )
fPortBuffer[port_index] = NULL;
fNetBuffer = net_buffer;
}

NetMidiBuffer::~NetMidiBuffer()
{
delete[] fBuffer;
delete[] fPortBuffer;
}

size_t NetMidiBuffer::GetSize()
{
return fMaxBufsize;
}

void NetMidiBuffer::DisplayEvents()
{
for ( int port_index = 0; port_index < fNPorts; port_index++ )
{
for ( size_t event = 0; event < fPortBuffer[port_index]->event_count; event++ )
if ( fPortBuffer[port_index]->IsValid() )
jack_info ( "port %d : midi event %u/%u -> time : %u, size : %u",
port_index + 1, event + 1, fPortBuffer[port_index]->event_count,
fPortBuffer[port_index]->events[event].time, fPortBuffer[port_index]->events[event].size );
}
}

int NetMidiBuffer::RenderFromJackPorts()
{
int pos = 0;
int copy_size;
for ( int port_index = 0; port_index < fNPorts; port_index++ )
{
copy_size = sizeof ( JackMidiBuffer ) + fPortBuffer[port_index]->event_count * sizeof ( JackMidiEvent );
memcpy ( fBuffer + pos, fPortBuffer[port_index], copy_size );
pos += copy_size;
memcpy ( fBuffer + pos, fPortBuffer[port_index] + ( fPortBuffer[port_index]->buffer_size - fPortBuffer[port_index]->write_pos ),
fPortBuffer[port_index]->write_pos );
pos += fPortBuffer[port_index]->write_pos;
}
return pos;
}

int NetMidiBuffer::RenderToJackPorts()
{
int pos = 0;
int copy_size;
for ( int port_index = 0; port_index < fNPorts; port_index++ )
{
copy_size = sizeof ( JackMidiBuffer ) + reinterpret_cast<JackMidiBuffer*>(fBuffer + pos)->event_count * sizeof ( JackMidiEvent );
memcpy ( fPortBuffer[port_index], fBuffer + pos, copy_size );
pos += copy_size;
memcpy ( fPortBuffer[port_index] + ( fPortBuffer[port_index]->buffer_size - fPortBuffer[port_index]->write_pos ),
fBuffer + pos, fPortBuffer[port_index]->write_pos );
pos += fPortBuffer[port_index]->write_pos;
}
return pos;
}

int NetMidiBuffer::RenderFromNetwork ( size_t subcycle, size_t copy_size )
{
memcpy ( fBuffer + subcycle * fMaxPcktSize, fNetBuffer, copy_size );
return copy_size;
}

int NetMidiBuffer::RenderToNetwork ( size_t subcycle, size_t total_size )
{
int size = total_size - subcycle * fMaxPcktSize;
int copy_size = ( size <= fMaxPcktSize ) ? size : fMaxPcktSize;
memcpy ( fNetBuffer, fBuffer + subcycle * fMaxPcktSize, copy_size );
return copy_size;
}

// net audio buffer *********************************************************************************

NetAudioBuffer::NetAudioBuffer ( session_params_t* params, size_t nports, char* net_buffer )
{
fNPorts = nports;
fPeriodSize = params->fPeriodSize;
fSubPeriodSize = params->fFramesPerPacket;
fSubPeriodBytesSize = fSubPeriodSize * sizeof ( sample_t );
fPortBuffer = new sample_t* [fNPorts];
for ( int port_index = 0; port_index < fNPorts; port_index++ )
fPortBuffer[port_index] = NULL;
fNetBuffer = net_buffer;
}

NetAudioBuffer::~NetAudioBuffer()
{
delete[] fPortBuffer;
}

size_t NetAudioBuffer::GetSize()
{
return fNPorts * fSubPeriodBytesSize;
}

void NetAudioBuffer::RenderFromJackPorts ( size_t subcycle )
{
for ( int port_index = 0; port_index < fNPorts; port_index++ )
memcpy ( fNetBuffer + port_index * fSubPeriodBytesSize, fPortBuffer[port_index] + subcycle * fSubPeriodSize, fSubPeriodBytesSize );
}

void NetAudioBuffer::RenderToJackPorts ( size_t subcycle )
{
for ( int port_index = 0; port_index < fNPorts; port_index++ )
memcpy ( fPortBuffer[port_index] + subcycle * fSubPeriodSize, fNetBuffer + port_index * fSubPeriodBytesSize, fSubPeriodBytesSize );
}

// SessionParams ************************************************************************************

void SessionParamsHToN ( session_params_t* params )
{
params->fPacketID = htonl ( params->fPacketID );
params->fMtu = htonl ( params->fMtu );
params->fID = htonl ( params->fID );
params->fSendAudioChannels = htonl ( params->fSendAudioChannels );
params->fReturnAudioChannels = htonl ( params->fReturnAudioChannels );
params->fSendMidiChannels = htonl ( params->fSendMidiChannels );
params->fReturnMidiChannels = htonl ( params->fReturnMidiChannels );
params->fSampleRate = htonl ( params->fSampleRate );
params->fPeriodSize = htonl ( params->fPeriodSize );
params->fFramesPerPacket = htonl ( params->fFramesPerPacket );
params->fBitdepth = htonl ( params->fBitdepth );
}

void SessionParamsNToH ( session_params_t* params )
{
params->fPacketID = ntohl ( params->fPacketID );
params->fMtu = ntohl ( params->fMtu );
params->fID = ntohl ( params->fID );
params->fSendAudioChannels = ntohl ( params->fSendAudioChannels );
params->fReturnAudioChannels = ntohl ( params->fReturnAudioChannels );
params->fSendMidiChannels = ntohl ( params->fSendMidiChannels );
params->fReturnMidiChannels = ntohl ( params->fReturnMidiChannels );
params->fSampleRate = ntohl ( params->fSampleRate );
params->fPeriodSize = ntohl ( params->fPeriodSize );
params->fFramesPerPacket = ntohl ( params->fFramesPerPacket );
params->fBitdepth = ntohl ( params->fBitdepth );
}

void SessionParamsDisplay ( session_params_t* params )
{
jack_info ( "********************Params********************" );
jack_info ( "Protocol revision : %c", params->fProtocolVersion );
jack_info ( "MTU : %u", params->fMtu );
jack_info ( "Master name : %s", params->fMasterNetName );
jack_info ( "Slave name : %s", params->fSlaveNetName );
jack_info ( "ID : %u", params->fID );
jack_info ( "Send channels (audio - midi) : %d - %d", params->fSendAudioChannels, params->fSendMidiChannels );
jack_info ( "Return channels (audio - midi) : %d - %d", params->fReturnAudioChannels, params->fReturnMidiChannels );
jack_info ( "Sample rate : %u frames per second", params->fSampleRate );
jack_info ( "Period size : %u frames per period", params->fPeriodSize );
jack_info ( "Frames per packet : %u", params->fFramesPerPacket );
jack_info ( "Packet per period : %u", params->fPeriodSize / params->fFramesPerPacket );
jack_info ( "Bitdepth (0 for float) : %u", params->fBitdepth );
jack_info ( "Name : %s", params->fName );
jack_info ( "**********************************************" );
}

sync_packet_type_t GetPacketType ( session_params_t* params )
{
switch ( params->fPacketID )
{
case 0:
return SLAVE_AVAILABLE;
case 1:
return SLAVE_SETUP;
case 2:
return START_MASTER;
case 3:
return START_SLAVE;
case 4:
return KILL_MASTER;
}
return INVALID;
}

int SetPacketType ( session_params_t* params, sync_packet_type_t packet_type )
{
switch ( packet_type )
{
case INVALID:
return -1;
case SLAVE_AVAILABLE:
params->fPacketID = 0;
break;
case SLAVE_SETUP:
params->fPacketID = 1;
break;
case START_MASTER:
params->fPacketID = 2;
break;
case START_SLAVE:
params->fPacketID = 3;
break;
case KILL_MASTER:
params->fPacketID = 4;
}
return 0;
}

// Packet header **********************************************************************************

void PacketHeaderHToN ( packet_header_t* header )
{
header->fID = htonl ( header->fID );
header->fMidiDataSize = htonl ( header->fMidiDataSize );
header->fBitdepth = htonl ( header->fBitdepth );
header->fNMidiPckt = htonl ( header->fNMidiPckt );
header->fCycle = ntohl ( header->fCycle );
header->fSubCycle = htonl ( header->fSubCycle );
}

void PacketHeaderNToH ( packet_header_t* header )
{
header->fID = ntohl ( header->fID );
header->fMidiDataSize = ntohl ( header->fMidiDataSize );
header->fBitdepth = ntohl ( header->fBitdepth );
header->fNMidiPckt = ntohl ( header->fNMidiPckt );
header->fCycle = ntohl ( header->fCycle );
header->fSubCycle = ntohl ( header->fSubCycle );
}

void PacketHeaderDisplay ( packet_header_t* header )
{
jack_info ( "********************Header********************" );
jack_info ( "Data type : %c", header->fDataType );
jack_info ( "Data stream : %c", header->fDataStream );
jack_info ( "ID : %u", header->fID );
jack_info ( "Cycle : %u", header->fCycle );
jack_info ( "SubCycle : %u", header->fSubCycle );
jack_info ( "Midi packets : %u", header->fNMidiPckt );
jack_info ( "Midi data size : %u", header->fMidiDataSize );
jack_info ( "Last packet : '%c'", header->fIsLastPckt );
jack_info ( "Bitdepth : %u (0 for float)", header->fBitdepth );
jack_info ( "**********************************************" );
}

// Utility *******************************************************************************************************

size_t SetFramesPerPacket ( session_params_t* params )
{
if ( !params->fSendAudioChannels && !params->fReturnAudioChannels )
return ( params->fFramesPerPacket = params->fPeriodSize );
size_t period = ( int ) powf ( 2.f, ( int ) log2 ( ( params->fMtu - sizeof ( packet_header_t ) )
/ ( max ( params->fReturnAudioChannels, params->fSendAudioChannels ) * sizeof ( sample_t ) ) ) );
( period > params->fPeriodSize ) ? params->fFramesPerPacket = params->fPeriodSize : params->fFramesPerPacket = period;
return params->fFramesPerPacket;
}

size_t 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
//99% of the cases : all data in one packet
if ( data_size <= ( params->fMtu - sizeof ( packet_header_t ) ) )
return 1;
//else, get the number of needed packets (simply slice the biiig buffer)
size_t npckt = data_size / ( params->fMtu - sizeof ( packet_header_t ) );
if ( data_size % ( params->fMtu - sizeof ( packet_header_t ) ) )
return ++npckt;
return npckt;
}

int SetRxTimeout ( int* sockfd, session_params_t* params )
{
int ret;
struct timeval timeout;
float time = static_cast<float> ( params->fFramesPerPacket ) / static_cast<float> ( params->fSampleRate );
timeout.tv_sec = ( int ) time;
float usec = 1.25 * ( time - timeout.tv_sec ) * 1000000;
timeout.tv_usec = ( int ) usec;
if ( ( ret = setsockopt ( *sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof ( timeout ) ) ) < 0 )
return ret;
return timeout.tv_usec;
}

// Packet *******************************************************************************************************

bool IsNextPacket ( packet_header_t* previous, packet_header_t* next, size_t subcycles )
{
//ignore first cycle
if ( previous->fCycle <= 1 )
return true;
//same PcktID (cycle), next SubPcktID (subcycle)
if ( ( previous->fSubCycle < ( subcycles - 1 ) ) && ( next->fCycle == previous->fCycle ) && ( next->fSubCycle == ( previous->fSubCycle + 1 ) ) )
return true;
//next PcktID (cycle), SubPcktID reset to 1 (first subcyle)
if ( ( next->fCycle == ( previous->fCycle + 1 ) ) && ( previous->fSubCycle == ( subcycles - 1 ) ) && ( next->fSubCycle == 0 ) )
return true;
//else, next is'nt next, return false
return false;
}
}

+ 174
- 0
common/JackNetTool.h View File

@@ -0,0 +1,174 @@

#include "types.h"
#include "JackConstants.h"
#include "JackMidiPort.h"

#include <string>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <iostream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

namespace Jack
{
typedef struct _session_params session_params_t;
typedef struct _packet_header packet_header_t;
typedef struct _midi_portbuf_desc midi_portbuf_desc_t;
typedef struct sockaddr socket_address_t;
typedef struct in_addr address_t;
typedef jack_default_audio_sample_t sample_t;


//session params ******************************************************************************

struct _session_params
{
char fPacketType[7]; //packet type ('param')
char fProtocolVersion; //version
int fPacketID; //indicates the packet type
char fMasterNetName[256]; //master hostname (network)
char fSlaveNetName[256]; //slave hostname (network)
size_t fMtu; //connection mtu
size_t fID; //slave's ID
int fSendAudioChannels; //number of master->slave channels
int fReturnAudioChannels; //number of slave->master channels
int fSendMidiChannels; //number of master->slave midi channels
int fReturnMidiChannels; //number of slave->master midi channels
size_t fSampleRate; //session sample rate
size_t fPeriodSize; //period size
size_t fFramesPerPacket; //complete frames per packet
size_t fBitdepth; //samples bitdepth (unused)
char fName[JACK_CLIENT_NAME_SIZE]; //slave's name
};


//net status **********************************************************************************

enum _net_status
{
SOCKET_ERROR,
CONNECT_ERROR,
RECV_ERROR,
CONNECTED,
ROLLING
};

typedef enum _net_status net_status_t;


//sync packet type ****************************************************************************

enum _sync_packet_type
{
INVALID, //...
SLAVE_AVAILABLE, //a slave is available
SLAVE_SETUP, //slave configuration
START_MASTER, //slave is ready, start master
START_SLAVE, //master is ready, activate slave
KILL_MASTER //master must stop
};

typedef enum _sync_packet_type sync_packet_type_t;


//packet header *******************************************************************************

struct _packet_header
{
char fPacketType[7]; //packet type ( 'headr' )
char fDataType; //a for audio, m for midi
char fDataStream; //s for send, r for return
size_t fID; //to identify the slave
size_t fBitdepth; //bitdepth of the data samples
size_t fMidiDataSize; //size of midi data (if packet is 'midi typed') in bytes
size_t fNMidiPckt; //number of midi packets of the cycle
size_t fCycle; //process cycle counter
size_t fSubCycle; //midi/audio subcycle counter
char fIsLastPckt; //is it the last packet of a given cycle ('y' or 'n')
char fFree[13]; //unused
};

//midi data ***********************************************************************************

class NetMidiBuffer
{
private:
int fNPorts;
size_t fMaxBufsize;
int fMaxPcktSize;
//data
char* fBuffer;
char* fNetBuffer;
public:
NetMidiBuffer ( session_params_t* params, size_t nports, char* net_buffer );
~NetMidiBuffer();

JackMidiBuffer** fPortBuffer;

void Reset();
size_t GetSize();
//utility
void DisplayEvents();
//jack<->buffer
int RenderFromJackPorts();
int RenderToJackPorts();
//network<->buffer
int RenderFromNetwork ( size_t subcycle, size_t copy_size );
int RenderToNetwork ( size_t subcycle, size_t copy_size );
};

// audio data *********************************************************************************

class NetAudioBuffer
{
private:
int fNPorts;
jack_nframes_t fPeriodSize;
jack_nframes_t fSubPeriodSize;
size_t fSubPeriodBytesSize;
char* fNetBuffer;
public:
NetAudioBuffer ( session_params_t* params, size_t nports, char* net_buffer );
~NetAudioBuffer();

sample_t** fPortBuffer;

size_t GetSize();
//jack<->buffer
void RenderFromJackPorts ( size_t subcycle );
void RenderToJackPorts ( size_t subcycle );
};

//utility *************************************************************************************

//n<-->h functions
void SessionParamsHToN ( session_params_t* params );
void SessionParamsNToH ( session_params_t* params );
void PacketHeaderHToN ( packet_header_t* header );
void PacketHeaderNToH ( packet_header_t* header );
//display session parameters
void SessionParamsDisplay ( session_params_t* params );
//display packet header
void PacketHeaderDisplay ( packet_header_t* header );
//get the packet type from a sesion parameters
sync_packet_type_t GetPacketType ( session_params_t* params );
//set the packet type in a session parameters
int SetPacketType ( session_params_t* params, sync_packet_type_t packet_type );
//step of network initialization
size_t SetFramesPerPacket ( session_params_t* params );
//get the midi packet number for a given cycle
size_t GetNMidiPckt ( session_params_t* params, size_t data_size );
//set the recv timeout on a socket
int SetRxTimeout ( int* sockfd, session_params_t* params );
//check if 'next' packet is really the next after 'previous'
bool IsNextPacket ( packet_header_t* previous, packet_header_t* next, size_t subcycles );
}

+ 2
- 0
common/SConscript View File

@@ -74,6 +74,7 @@ srcfiles_common_serverlib = [
'JackClient.cpp',
'JackConnectionManager.cpp',
'JackDriver.cpp',
'JackNetTool.cpp',
'JackEngine.cpp',
'JackEngineControl.cpp',
'JackError.cpp',
@@ -179,6 +180,7 @@ if env['PLATFORM'] == 'posix':

clientlib = libenv.SharedLibrary(env['CLIENTLIB'], srcfiles_common_clientlib)
serverlib = libenv.SharedLibrary(env['SERVERLIB'], srcfiles_common_serverlib)
netmanagerlib = libenv.SharedLibrary(env['NETMANAGERLIB'], 'JackNetManager.cpp')
env.Install( env['INSTALL_LIBDIR'], [clientlib, serverlib])
env.Alias('install', env['INSTALL_LIBDIR'])



+ 9
- 1
common/wscript View File

@@ -30,7 +30,7 @@ def build(bld):
'timestamps.c',
'JackTools.cpp',
'JackMessageBuffer.cpp',
'JackProcessSync.cpp'
'JackProcessSync.cpp',
]
serverlib = bld.create_obj('cpp', 'shlib')
@@ -58,6 +58,7 @@ def build(bld):
'JackDriverLoader.cpp',
'JackServerGlobals.cpp',
'JackControl.cpp',
'JackNetTool.cpp',
]
serverlib.vnum = bld.env()['JACK_API_VERSION']

@@ -79,4 +80,11 @@ def build(bld):
]
clientlib.vnum = bld.env()['JACK_API_VERSION']

netmanager_lib = bld.create_obj('cpp', 'shlib')
netmanager_lib.env['shlib_PATTERN'] = '%s.so'
netmanager_lib.includes = ['./jack', '.']
netmanager_lib.name = 'netmanager'
netmanager_lib.target = 'netmanager'
netmanager_lib.source = 'JackNetManager.cpp'

install_files('PREFIX', 'jack', 'jack/*.h')

+ 4
- 0
linux/SConscript View File

@@ -51,6 +51,7 @@ for i in range(len(srcfiles_linux_alsa)):
srcfiles_linux_freebob = ['freebob/JackFreebobDriver.cpp']
srcfiles_linux_ffado = ['firewire/JackFFADODriver.cpp']
srcfiles_linux_dummy = ['#/common/JackDummyDriver.cpp']
srcfiles_linux_net = ['#/common/JackNetDriver.cpp']

#
# Start building
@@ -69,6 +70,9 @@ driver_dir = env['INSTALL_ADDON_DIR'] + "/"
drv = serverenv.SharedLibrary( 'jack_dummy', srcfiles_linux_dummy )
serverenv.InstallAs( driver_dir + "jack_dummy.so", drv )

drv = serverenv.SharedLibrary( 'jack_net', srcfiles_linux_net )
serverenv.InstallAs( driver_dir + "jack_net.so", drv )

if env['ENABLE_ALSA']:
if not env.GetOption('clean'):
serverenv.MergeFlags( env['ALSA_FLAGS'] )


+ 3
- 0
linux/wscript View File

@@ -53,3 +53,6 @@ def build(bld):

if bld.env()['BUILD_DRIVER_FFADO'] == True:
create_jack_driver_obj(bld, 'firewire', 'firewire/JackFFADODriver.cpp', "LIBFFADO")

create_jack_driver_obj(bld, 'net', '../common/JackNetDriver.cpp')


+ 439
- 0
macosx/Jackdmp.xcodeproj/project.pbxproj View File

@@ -90,6 +90,8 @@
4B363F530DEB0CFE001F72D9 /* PBXTargetDependency */,
4B363F780DEB0D85001F72D9 /* PBXTargetDependency */,
4B978E800A31D8B7009E2DD1 /* PBXTargetDependency */,
BA222AF00DC883EF001A17F4 /* PBXTargetDependency */,
BA222AF20DC883F3001A17F4 /* PBXTargetDependency */,
);
name = "All Universal 32 bits";
productName = All;
@@ -549,6 +551,14 @@
4BFA82BC0DF6A9E40087B4E1 /* showtime.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B363F3D0DEB0C31001F72D9 /* showtime.c */; };
4BFA82C80DF6A9E40087B4E1 /* impulse_grabber.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B363F750DEB0D7D001F72D9 /* impulse_grabber.c */; };
4BFA99AA0AAAF40C009E916C /* jdelay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFA99A90AAAF40C009E916C /* jdelay.cpp */; };
BA222AD80DC88268001A17F4 /* JackNetTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BA222AD60DC88268001A17F4 /* JackNetTool.cpp */; };
BA222AD90DC88269001A17F4 /* JackNetTool.h in Headers */ = {isa = PBXBuildFile; fileRef = BA222AD70DC88268001A17F4 /* JackNetTool.h */; };
BA222ADA0DC88269001A17F4 /* JackNetTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BA222AD60DC88268001A17F4 /* JackNetTool.cpp */; };
BA222ADB0DC88269001A17F4 /* JackNetTool.h in Headers */ = {isa = PBXBuildFile; fileRef = BA222AD70DC88268001A17F4 /* JackNetTool.h */; };
BA222ADE0DC882A5001A17F4 /* JackNetDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BA222ADC0DC882A5001A17F4 /* JackNetDriver.cpp */; };
BA222ADF0DC882A5001A17F4 /* JackNetDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = BA222ADD0DC882A5001A17F4 /* JackNetDriver.h */; };
BA222AED0DC883B3001A17F4 /* JackNetManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BA222AEB0DC883B3001A17F4 /* JackNetManager.cpp */; };
BA222AEE0DC883B3001A17F4 /* JackNetManager.h in Headers */ = {isa = PBXBuildFile; fileRef = BA222AEC0DC883B3001A17F4 /* JackNetManager.h */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
@@ -1035,6 +1045,20 @@
remoteGlobalIDString = 4BFA99980AAAF3B0009E916C;
remoteInfo = "jdelay Universal";
};
BA222AEF0DC883EF001A17F4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = BA222AE00DC882DB001A17F4;
remoteInfo = netmanager;
};
BA222AF10DC883F3001A17F4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = BA222AC50DC88132001A17F4;
remoteInfo = "jack_net Universal";
};
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
@@ -1097,6 +1121,7 @@
4B4F9C8B0DC20C0400706CB0 /* JackMessageBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMessageBuffer.h; path = ../common/JackMessageBuffer.h; sourceTree = SOURCE_ROOT; };
4B56880F08B5C8620022B32D /* JackFifo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackFifo.cpp; path = ../common/JackFifo.cpp; sourceTree = SOURCE_ROOT; };
4B56881008B5C8620022B32D /* JackFifo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackFifo.h; path = ../common/JackFifo.h; sourceTree = SOURCE_ROOT; };
4B57F5950D72C27900B4E719 /* jack_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; };
4B5A1BBB0CD1CB9E0005BF74 /* jack_midiseq */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_midiseq; sourceTree = BUILT_PRODUCTS_DIR; };
4B5A1BBD0CD1CC110005BF74 /* midiseq.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = midiseq.c; path = "../example-clients/midiseq.c"; sourceTree = SOURCE_ROOT; };
4B5A1BDA0CD1CCE10005BF74 /* jack_midisine */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_midisine; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1288,6 +1313,14 @@
4BFB73F608AD291A00DB99B8 /* JackGlobals.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackGlobals.h; path = ../common/JackGlobals.h; sourceTree = SOURCE_ROOT; };
4BFB741E08AD2B9900DB99B8 /* JackMachThread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JackMachThread.cpp; sourceTree = SOURCE_ROOT; };
4BFB741F08AD2B9900DB99B8 /* JackMachThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JackMachThread.h; sourceTree = SOURCE_ROOT; };
BA222ACF0DC88132001A17F4 /* jack_net.so */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = jack_net.so; sourceTree = BUILT_PRODUCTS_DIR; };
BA222AD60DC88268001A17F4 /* JackNetTool.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackNetTool.cpp; path = ../common/JackNetTool.cpp; sourceTree = SOURCE_ROOT; };
BA222AD70DC88268001A17F4 /* JackNetTool.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackNetTool.h; path = ../common/JackNetTool.h; sourceTree = SOURCE_ROOT; };
BA222ADC0DC882A5001A17F4 /* JackNetDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackNetDriver.cpp; path = ../common/JackNetDriver.cpp; sourceTree = SOURCE_ROOT; };
BA222ADD0DC882A5001A17F4 /* JackNetDriver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackNetDriver.h; path = ../common/JackNetDriver.h; sourceTree = SOURCE_ROOT; };
BA222AE90DC882DB001A17F4 /* netmanager.so */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = netmanager.so; sourceTree = BUILT_PRODUCTS_DIR; };
BA222AEB0DC883B3001A17F4 /* JackNetManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackNetManager.cpp; path = ../common/JackNetManager.cpp; sourceTree = SOURCE_ROOT; };
BA222AEC0DC883B3001A17F4 /* JackNetManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackNetManager.h; path = ../common/JackNetManager.h; sourceTree = SOURCE_ROOT; };
C6859E8B029090EE04C91782 /* JackServer.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = JackServer.1; sourceTree = "<group>"; };
/* End PBXFileReference section */

@@ -1792,6 +1825,20 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
BA222ACA0DC88132001A17F4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
BA222AE40DC882DB001A17F4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
@@ -1820,6 +1867,7 @@
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
BA222AEA0DC88379001A17F4 /* Net */,
4B6BEB4A07A6CCDC00A5DBDA /* Tests */,
4B37C20006DF1F900016E567 /* Latency */,
4B03383E0797E19900686131 /* Simple clients */,
@@ -1895,6 +1943,10 @@
4B35C63E0D4731D3000DE7AE /* inprocess.so */,
4B0A28E60D52073D002EFF74 /* jack_thread_wait */,
4B0A292D0D52108E002EFF74 /* jack_thread_wait */,
4B57F5950D72C27900B4E719 /* jack_thread_wait */,
4BA7FEC30D8E76270017FF73 /* jack_server_control */,
BA222ACF0DC88132001A17F4 /* jack_net.so */,
BA222AE90DC882DB001A17F4 /* netmanager.so */,
4BA7FEC30D8E76270017FF73 /* jack_server_control */,
4B363DD80DEB02F6001F72D9 /* jack_alias */,
4B363E1A0DEB03C5001F72D9 /* jack_evmon */,
@@ -2089,6 +2141,8 @@
4BA550F605E241B800569492 /* Driver */ = {
isa = PBXGroup;
children = (
BA222ADC0DC882A5001A17F4 /* JackNetDriver.cpp */,
BA222ADD0DC882A5001A17F4 /* JackNetDriver.h */,
4B869B3D08C8D21C001CF041 /* driver_interface.h */,
4B869B4208C8D22F001CF041 /* JackDriverLoader.h */,
4B869D7F08C9CB00001CF041 /* JackDriverLoader.cpp */,
@@ -2270,6 +2324,17 @@
name = Socket;
sourceTree = "<group>";
};
BA222AEA0DC88379001A17F4 /* Net */ = {
isa = PBXGroup;
children = (
BA222AEB0DC883B3001A17F4 /* JackNetManager.cpp */,
BA222AEC0DC883B3001A17F4 /* JackNetManager.h */,
BA222AD60DC88268001A17F4 /* JackNetTool.cpp */,
BA222AD70DC88268001A17F4 /* JackNetTool.h */,
);
name = Net;
sourceTree = "<group>";
};
C6859E8C029090F304C91782 /* Documentation */ = {
isa = PBXGroup;
children = (
@@ -2405,6 +2470,7 @@
4B35C4BF0D4731D1000DE7AE /* midiport.h in Headers */,
4B35C4C00D4731D1000DE7AE /* JackDebugClient.h in Headers */,
4B35C4C10D4731D1000DE7AE /* JackTools.h in Headers */,
BA222ADB0DC88269001A17F4 /* JackNetTool.h in Headers */,
4B9A26060DBF8584006E9FBC /* jslist.h in Headers */,
4B4F9C930DC20C0400706CB0 /* JackMessageBuffer.h in Headers */,
);
@@ -2749,6 +2815,7 @@
4B6B9EF70CD095970051EE5A /* midiport.h in Headers */,
4B5DB9840CD2429B00EBA5EE /* JackDebugClient.h in Headers */,
4BE4CC040CDA153500CCF5BB /* JackTools.h in Headers */,
BA222AD90DC88269001A17F4 /* JackNetTool.h in Headers */,
4B95BCAE0D913073000F7695 /* control.h in Headers */,
4B9A26020DBF8584006E9FBC /* jslist.h in Headers */,
4B4F9C8D0DC20C0400706CB0 /* JackMessageBuffer.h in Headers */,
@@ -2962,6 +3029,22 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
BA222AC60DC88132001A17F4 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
BA222ADF0DC882A5001A17F4 /* JackNetDriver.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
BA222AE10DC882DB001A17F4 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
BA222AEE0DC883B3001A17F4 /* JackNetManager.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */

/* Begin PBXNativeTarget section */
@@ -4262,6 +4345,40 @@
productReference = 4BFA99A20AAAF3B0009E916C /* jdelay */;
productType = "com.apple.product-type.tool";
};
BA222AC50DC88132001A17F4 /* jack_net Universal */ = {
isa = PBXNativeTarget;
buildConfigurationList = BA222ACB0DC88132001A17F4 /* Build configuration list for PBXNativeTarget "jack_net Universal" */;
buildPhases = (
BA222AC60DC88132001A17F4 /* Headers */,
BA222AC80DC88132001A17F4 /* Sources */,
BA222ACA0DC88132001A17F4 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "jack_net Universal";
productName = jack_coreaudio;
productReference = BA222ACF0DC88132001A17F4 /* jack_net.so */;
productType = "com.apple.product-type.library.dynamic";
};
BA222AE00DC882DB001A17F4 /* netmanager */ = {
isa = PBXNativeTarget;
buildConfigurationList = BA222AE50DC882DB001A17F4 /* Build configuration list for PBXNativeTarget "netmanager" */;
buildPhases = (
BA222AE10DC882DB001A17F4 /* Headers */,
BA222AE20DC882DB001A17F4 /* Sources */,
BA222AE40DC882DB001A17F4 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = netmanager;
productName = jack_coreaudio;
productReference = BA222AE90DC882DB001A17F4 /* netmanager.so */;
productType = "com.apple.product-type.library.dynamic";
};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
@@ -4311,7 +4428,9 @@
4B699D97097D421700A18468 /* jack_coreaudio Universal */,
4B978DB10A31CF4A009E2DD1 /* jack_portaudio Universal */,
4B699DA6097D421700A18468 /* jack_dummy Universal */,
BA222AC50DC88132001A17F4 /* jack_net Universal */,
4BD623ED0CBCF0F000DE782F /* inprocess */,
BA222AE00DC882DB001A17F4 /* netmanager */,
4B35C41B0D4731D1000DE7AE /* jackdmp framework 64bits */,
4B35C4270D4731D1000DE7AE /* Jackmp.framework 64 bits */,
4B35C4850D4731D1000DE7AE /* Jackservermp.framework 64 bits */,
@@ -4922,6 +5041,7 @@
4B35C4F30D4731D1000DE7AE /* JackEngineControl.cpp in Sources */,
4B35C4F40D4731D1000DE7AE /* JackDebugClient.cpp in Sources */,
4B35C4F50D4731D1000DE7AE /* JackTools.cpp in Sources */,
BA222ADA0DC88269001A17F4 /* JackNetTool.cpp in Sources */,
4B9A26640DBF8B14006E9FBC /* JackError.cpp in Sources */,
4B9A26680DBF8B23006E9FBC /* JackControl.cpp in Sources */,
4B0206A10DC0BAB400319AF1 /* JackProcessSync.cpp in Sources */,
@@ -5290,6 +5410,7 @@
4B6F7AEE0CD0CDBD00F48A9D /* JackEngineControl.cpp in Sources */,
4B5DB9830CD2429A00EBA5EE /* JackDebugClient.cpp in Sources */,
4BE4CC030CDA153500CCF5BB /* JackTools.cpp in Sources */,
BA222AD80DC88268001A17F4 /* JackNetTool.cpp in Sources */,
4B95BCAC0D913064000F7695 /* JackControl.cpp in Sources */,
4B9A25B60DBF8330006E9FBC /* JackError.cpp in Sources */,
4B02069E0DC0BAB400319AF1 /* JackProcessSync.cpp in Sources */,
@@ -5531,6 +5652,22 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
BA222AC80DC88132001A17F4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BA222ADE0DC882A5001A17F4 /* JackNetDriver.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
BA222AE20DC882DB001A17F4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BA222AED0DC883B3001A17F4 /* JackNetManager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
@@ -5879,6 +6016,16 @@
target = 4BFA99980AAAF3B0009E916C /* jdelay Universal */;
targetProxy = 4BFA99AB0AAAF41D009E916C /* PBXContainerItemProxy */;
};
BA222AF00DC883EF001A17F4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = BA222AE00DC882DB001A17F4 /* netmanager */;
targetProxy = BA222AEF0DC883EF001A17F4 /* PBXContainerItemProxy */;
};
BA222AF20DC883F3001A17F4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = BA222AC50DC88132001A17F4 /* jack_net Universal */;
targetProxy = BA222AF10DC883F3001A17F4 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */

/* Begin XCBuildConfiguration section */
@@ -13673,6 +13820,278 @@
};
name = Default;
};
BA222ACC0DC88132001A17F4 /* Development */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = NO;
DEBUGGING_SYMBOLS = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_MODEL_TUNING = G4;
GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
OPTIMIZATION_CFLAGS = "-O0";
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackservermp,
"-framework",
CoreAudio,
"-framework",
CoreServices,
"-framework",
AudioUnit,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = jack_net;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = YES;
};
name = Development;
};
BA222ACD0DC88132001A17F4 /* Deployment */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G4;
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
MACOSX_DEPLOYMENT_TARGET = 10.4;
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackservermp,
"-framework",
CoreAudio,
"-framework",
CoreServices,
"-framework",
AudioUnit,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = jack_net;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = NO;
};
name = Deployment;
};
BA222ACE0DC88132001A17F4 /* Default */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G4;
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackdmp,
"-framework",
AudioToolBox,
"-framework",
CoreAudio,
"-framework",
CoreServices,
"-framework",
AudioUnit,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = jack_dummy;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
};
name = Default;
};
BA222AE60DC882DB001A17F4 /* Development */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = NO;
DEBUGGING_SYMBOLS = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_MODEL_TUNING = G4;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "";
HEADER_SEARCH_PATHS = ../common;
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
OPTIMIZATION_CFLAGS = "-O0";
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-framework",
Jackservermp,
"-framework",
CoreAudio,
"-framework",
CoreServices,
"-framework",
AudioUnit,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = netmanager;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = YES;
};
name = Development;
};
BA222AE70DC882DB001A17F4 /* Deployment */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G4;
GCC_PREPROCESSOR_DEFINITIONS = "";
HEADER_SEARCH_PATHS = ../common;
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
MACOSX_DEPLOYMENT_TARGET = 10.4;
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-framework",
Jackservermp,
"-framework",
CoreAudio,
"-framework",
CoreServices,
"-framework",
AudioUnit,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = netmanager;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = NO;
};
name = Deployment;
};
BA222AE80DC882DB001A17F4 /* Default */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G4;
GCC_PREPROCESSOR_DEFINITIONS = "";
HEADER_SEARCH_PATHS = ../common;
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-framework",
Jackdmp,
"-framework",
AudioToolBox,
"-framework",
CoreAudio,
"-framework",
CoreServices,
"-framework",
AudioUnit,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = inprocess;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
};
name = Default;
};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
@@ -14396,6 +14815,26 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
BA222ACB0DC88132001A17F4 /* Build configuration list for PBXNativeTarget "jack_net Universal" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BA222ACC0DC88132001A17F4 /* Development */,
BA222ACD0DC88132001A17F4 /* Deployment */,
BA222ACE0DC88132001A17F4 /* Default */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
BA222AE50DC882DB001A17F4 /* Build configuration list for PBXNativeTarget "netmanager" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BA222AE60DC882DB001A17F4 /* Development */,
BA222AE70DC882DB001A17F4 /* Deployment */,
BA222AE80DC882DB001A17F4 /* Default */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;


+ 4
- 0
macosx/install_jackdmp View File

@@ -14,6 +14,10 @@ sudo cp jackdmp /usr/local/bin
sudo install -d /usr/local/lib/jackmp
sudo cp jack_coreaudio.so /usr/local/lib/jackmp
sudo cp jack_dummy.so /usr/local/lib/jackmp
sudo cp jack_net.so /usr/local/lib/jackmp

# Copy tools
sudo cp netmanager.so /usr/local/lib/jackmp

# Create links to jackmp ressources
cd /usr/local/lib && [ -f libjack.0.dylib ] && sudo mv -f libjack.0.dylib tmp_libjack.0.dylib


Loading…
Cancel
Save