git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3401 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.2
| @@ -25,7 +25,8 @@ Michael Voigt | |||
| 2009-03-05 Stephane Letz <letz@grame.fr> | |||
| * Support for BIG_ENDIAN machines in NetJack2 for transport data. | |||
| * Support for BIG_ENDIAN machines in NetJack2 for transport data. | |||
| * Add auto_connect parameter in netmanager and netadapter. | |||
| 2009-03-03 Stephane Letz <letz@grame.fr> | |||
| @@ -69,6 +69,24 @@ namespace Jack | |||
| } | |||
| //JackAudioAdapter ********************************************************* | |||
| JackAudioAdapter::JackAudioAdapter (jack_client_t* jack_client, JackAudioAdapterInterface* audio_io, const JSList* params, bool system) | |||
| :fJackClient(jack_client), fAudioAdapter(audio_io) | |||
| { | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| fAutoConnect = false; | |||
| for (node = params; node; node = jack_slist_next(node)) { | |||
| param = (const jack_driver_param_t*) node->data; | |||
| switch (param->character) { | |||
| case 'c': | |||
| fAutoConnect = param->value.i; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| JackAudioAdapter::~JackAudioAdapter() | |||
| { | |||
| // When called, Close has already been used for the client, thus ports are already unregistered. | |||
| @@ -87,6 +105,27 @@ namespace Jack | |||
| delete[] fCapturePortList; | |||
| delete[] fPlaybackPortList; | |||
| } | |||
| void JackAudioAdapter::ConnectPorts() | |||
| { | |||
| const char **ports; | |||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | |||
| if (ports != NULL) { | |||
| for (int i = 0; i < fAudioAdapter->GetInputs() && ports[i]; i++) { | |||
| jack_connect(fJackClient,jack_port_name(fCapturePortList[i]), ports[i]); | |||
| } | |||
| free(ports); | |||
| } | |||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | |||
| if (ports != NULL) { | |||
| for (int i = 0; i < fAudioAdapter->GetOutputs() && ports[i]; i++) { | |||
| jack_connect(fJackClient, ports[i], jack_port_name(fPlaybackPortList[i])); | |||
| } | |||
| free(ports); | |||
| } | |||
| } | |||
| void JackAudioAdapter::Reset() | |||
| { | |||
| @@ -126,6 +165,9 @@ namespace Jack | |||
| goto fail; | |||
| if ( jack_activate ( fJackClient ) < 0 ) | |||
| goto fail; | |||
| if (fAutoConnect) | |||
| ConnectPorts(); | |||
| // Ring buffer are now allocated.. | |||
| return fAudioAdapter->Open(); | |||
| @@ -21,6 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #define __JackAudioAdapter__ | |||
| #include "JackAudioAdapterInterface.h" | |||
| #include "driver_interface.h" | |||
| namespace Jack | |||
| { | |||
| @@ -42,15 +43,15 @@ namespace Jack | |||
| jack_client_t* fJackClient; | |||
| JackAudioAdapterInterface* fAudioAdapter; | |||
| bool fAutoConnect; | |||
| void FreePorts(); | |||
| void ConnectPorts(); | |||
| void Reset(); | |||
| public: | |||
| JackAudioAdapter ( jack_client_t* jack_client, JackAudioAdapterInterface* audio_io ) : | |||
| fJackClient ( jack_client ), fAudioAdapter ( audio_io ) | |||
| {} | |||
| JackAudioAdapter(jack_client_t* jack_client, JackAudioAdapterInterface* audio_io, const JSList* params = NULL, bool system = false); | |||
| ~JackAudioAdapter(); | |||
| int Open(); | |||
| @@ -351,48 +351,21 @@ namespace Jack | |||
| //process----------------------------------------------------------------------------- | |||
| int JackNetAdapter::Process() | |||
| { | |||
| bool failure = false; | |||
| int port_index; | |||
| //read data from the network | |||
| //in case of fatal network error, stop the process | |||
| if ( Read() == SOCKET_ERROR ) | |||
| if (Read() == SOCKET_ERROR) | |||
| return SOCKET_ERROR; | |||
| //get the resample factor, | |||
| jack_time_t time1, time2; | |||
| ResampleFactor ( time1, time2 ); | |||
| //resample input data, | |||
| for ( port_index = 0; port_index < fCaptureChannels; port_index++ ) | |||
| { | |||
| fCaptureRingBuffer[port_index]->SetRatio ( time1, time2 ); | |||
| if ( fCaptureRingBuffer[port_index]->WriteResample ( fSoftCaptureBuffer[port_index], fAdaptedBufferSize ) < fAdaptedBufferSize ) | |||
| failure = true; | |||
| } | |||
| //and output data, | |||
| for ( port_index = 0; port_index < fPlaybackChannels; port_index++ ) | |||
| { | |||
| fPlaybackRingBuffer[port_index]->SetRatio ( time2, time1 ); | |||
| if ( fPlaybackRingBuffer[port_index]->ReadResample ( fSoftPlaybackBuffer[port_index], fAdaptedBufferSize ) < fAdaptedBufferSize ) | |||
| failure = true; | |||
| } | |||
| PushAndPull(fSoftCaptureBuffer, fSoftPlaybackBuffer, fAdaptedBufferSize); | |||
| //then write data to network | |||
| //in case of failure, stop process | |||
| if ( Write() == SOCKET_ERROR ) | |||
| if (Write() == SOCKET_ERROR) | |||
| return SOCKET_ERROR; | |||
| //if there was any ringbuffer failure during resampling, reset | |||
| if ( failure ) | |||
| { | |||
| jack_error ( "JackNetAdapter::Execute ringbuffer failure...reset." ); | |||
| ResetRingBuffers(); | |||
| } | |||
| return 0; | |||
| } | |||
| } // namespace Jack | |||
| //loader------------------------------------------------------------------------------ | |||
| @@ -413,7 +386,7 @@ extern "C" | |||
| strcpy(desc->name, "netadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
| strcpy(desc->desc, "netjack net <==> audio backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
| desc->nparams = 9; | |||
| desc->nparams = 10; | |||
| desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) ); | |||
| int i = 0; | |||
| @@ -487,6 +460,14 @@ extern "C" | |||
| desc->params[i].value.ui = 0; | |||
| strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy ( desc->params[i].name, "auto_connect" ); | |||
| desc->params[i].character = 'c'; | |||
| desc->params[i].type = JackDriverParamBool; | |||
| desc->params[i].value.i = false; | |||
| strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" ); | |||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | |||
| return desc; | |||
| } | |||
| @@ -501,7 +482,7 @@ extern "C" | |||
| try { | |||
| adapter = new Jack::JackAudioAdapter ( jack_client, new Jack::JackNetAdapter ( jack_client, buffer_size, sample_rate, params ) ); | |||
| adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackNetAdapter(jack_client, buffer_size, sample_rate, params), params, false); | |||
| assert ( adapter ); | |||
| if ( adapter->Open() == 0 ) | |||
| @@ -26,7 +26,7 @@ namespace Jack | |||
| { | |||
| //JackNetMaster****************************************************************************************************** | |||
| JackNetMaster::JackNetMaster ( JackNetSocket& socket, session_params_t& params, const char* multicast_ip ) | |||
| JackNetMaster::JackNetMaster ( JackNetSocket& socket, session_params_t& params, const char* multicast_ip) | |||
| : JackNetMasterInterface ( params, socket, multicast_ip ) | |||
| { | |||
| jack_log ( "JackNetMaster::JackNetMaster" ); | |||
| @@ -107,7 +107,7 @@ namespace Jack | |||
| #endif | |||
| } | |||
| //init-------------------------------------------------------------------------------- | |||
| bool JackNetMaster::Init() | |||
| bool JackNetMaster::Init(bool auto_connect) | |||
| { | |||
| //network init | |||
| if ( !JackNetMasterInterface::Init() ) | |||
| @@ -141,9 +141,10 @@ namespace Jack | |||
| jack_error ( "Can't activate jack client." ); | |||
| goto fail; | |||
| } | |||
| if (auto_connect) | |||
| ConnectPorts(); | |||
| jack_info ( "New NetMaster started." ); | |||
| return true; | |||
| fail: | |||
| @@ -156,27 +157,26 @@ namespace Jack | |||
| //jack ports-------------------------------------------------------------------------- | |||
| int JackNetMaster::AllocPorts() | |||
| { | |||
| jack_log ( "JackNetMaster::AllocPorts" ); | |||
| uint i; | |||
| char name[24]; | |||
| jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient ); | |||
| unsigned long port_flags; | |||
| jack_log ( "JackNetMaster::AllocPorts" ); | |||
| //audio | |||
| port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal; | |||
| 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, port_flags, 0 ) ) == NULL ) | |||
| if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
| return -1; | |||
| //port latency | |||
| jack_port_set_latency ( fAudioCapturePorts[i], 0 ); | |||
| } | |||
| port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; | |||
| 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, port_flags, 0 ) ) == NULL ) | |||
| if ( ( fAudioPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
| return -1; | |||
| //port latency | |||
| switch ( fParams.fNetworkMode ) | |||
| @@ -192,21 +192,21 @@ namespace Jack | |||
| break; | |||
| } | |||
| } | |||
| //midi | |||
| port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal; | |||
| 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, port_flags, 0 ) ) == NULL ) | |||
| if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
| return -1; | |||
| //port latency | |||
| jack_port_set_latency ( fMidiCapturePorts[i], 0 ); | |||
| } | |||
| port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; | |||
| 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, port_flags, 0 ) ) == NULL ) | |||
| if ( ( fMidiPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
| return -1; | |||
| //port latency | |||
| switch ( fParams.fNetworkMode ) | |||
| @@ -224,6 +224,27 @@ namespace Jack | |||
| } | |||
| return 0; | |||
| } | |||
| void JackNetMaster::ConnectPorts() | |||
| { | |||
| const char **ports; | |||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | |||
| if (ports != NULL) { | |||
| for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { | |||
| jack_connect(fJackClient, ports[i], jack_port_name(fAudioCapturePorts[i])); | |||
| } | |||
| free(ports); | |||
| } | |||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | |||
| if (ports != NULL) { | |||
| for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { | |||
| jack_connect(fJackClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]); | |||
| } | |||
| free(ports); | |||
| } | |||
| } | |||
| void JackNetMaster::FreePorts() | |||
| { | |||
| @@ -439,6 +460,7 @@ namespace Jack | |||
| fSocket.SetPort ( DEFAULT_PORT ); | |||
| fGlobalID = 0; | |||
| fRunning = true; | |||
| fAutoConnect = false; | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| @@ -453,8 +475,14 @@ namespace Jack | |||
| else | |||
| jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP); | |||
| break; | |||
| case 'p': | |||
| fSocket.SetPort ( param->value.ui ); | |||
| break; | |||
| case 'c': | |||
| fAutoConnect = param->value.i; | |||
| break; | |||
| } | |||
| } | |||
| @@ -613,8 +641,8 @@ namespace Jack | |||
| SetSlaveName ( params ); | |||
| //create a new master and add it to the list | |||
| JackNetMaster* master = new JackNetMaster ( fSocket, params, fMulticastIP ); | |||
| if ( master->Init() ) | |||
| JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP); | |||
| if ( master->Init(fAutoConnect) ) | |||
| { | |||
| fMasterList.push_back ( master ); | |||
| return master; | |||
| @@ -674,7 +702,7 @@ extern "C" | |||
| strcpy ( desc->name, "netmanager" ); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
| strcpy ( desc->desc, "netjack multi-cast master component" ); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
| desc->nparams = 2; | |||
| desc->nparams = 3; | |||
| desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) ); | |||
| int i = 0; | |||
| @@ -692,6 +720,14 @@ extern "C" | |||
| desc->params[i].value.i = DEFAULT_PORT; | |||
| 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, "auto_connect" ); | |||
| desc->params[i].character = 'c'; | |||
| desc->params[i].type = JackDriverParamBool; | |||
| desc->params[i].value.i = false; | |||
| strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" ); | |||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | |||
| return desc; | |||
| } | |||
| @@ -53,14 +53,14 @@ namespace Jack | |||
| //sync and transport | |||
| int fLastTransportState; | |||
| //monitoring | |||
| #ifdef JACK_MONITOR | |||
| jack_time_t fPeriodUsecs; | |||
| JackGnuPlotMonitor<float>* fNetTimeMon; | |||
| #endif | |||
| bool Init(); | |||
| bool Init(bool auto_connect); | |||
| int AllocPorts(); | |||
| void FreePorts(); | |||
| void Exit(); | |||
| @@ -71,9 +71,10 @@ namespace Jack | |||
| int Process(); | |||
| void TimebaseCallback ( jack_position_t* pos ); | |||
| void ConnectPorts(); | |||
| public: | |||
| JackNetMaster ( JackNetSocket& socket, session_params_t& params, const char* multicast_ip ); | |||
| JackNetMaster ( JackNetSocket& socket, session_params_t& params, const char* multicast_ip); | |||
| ~JackNetMaster (); | |||
| bool IsSlaveReadyToRoll(); | |||
| @@ -101,6 +102,7 @@ namespace Jack | |||
| master_list_t fMasterList; | |||
| uint32_t fGlobalID; | |||
| bool fRunning; | |||
| bool fAutoConnect; | |||
| void Run(); | |||
| JackNetMaster* MasterInit ( session_params_t& params ); | |||
| @@ -110,7 +112,7 @@ namespace Jack | |||
| int SyncCallback ( jack_transport_state_t state, jack_position_t* pos ); | |||
| public: | |||
| JackNetMasterManager ( jack_client_t* jack_client, const JSList* params ); | |||
| JackNetMasterManager ( jack_client_t* jack_client, const JSList* params); | |||
| ~JackNetMasterManager(); | |||
| }; | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| ------------------------------- | |||
| Jackmp on windows | |||
| Jackmp on Windows | |||
| ------------------------------- | |||
| This folder contains all the windows specific sources. | |||
| @@ -34,11 +34,11 @@ You can make a small installer ('setup.exe') with CreateInstallFree, a little fr | |||
| A binary version of qjackctl is also included. | |||
| ------------------------------- | |||
| Running Jack on windows | |||
| Running Jack on Windows | |||
| ------------------------------- | |||
| You can use two drivers : PortAudio and NetDriver. | |||
| The PortAudio backend allow the use of many soundcards, using ASIO or WMME drivers (any ASIO driver can be seen by PortAudio). | |||
| The PortAudio backend allow the use of many soundcards, using ASIO, DirectSound or WMME drivers (any ASIO driver can be seen by PortAudio). | |||
| The NetDriver allow you to use NetJack2 on windows. Thus you can easily exchange midi and audio streams bitween computers (Linux, MacOSX or Windows). | |||
| In both cases, you have to use the minimalist : | |||
| 'jackd -R -d ...' | |||
| @@ -46,7 +46,11 @@ In both cases, you have to use the minimalist : | |||
| 'jackd -R -S -d portaudio -l' | |||
| Other options still stay the same. | |||
| You can also pick a binary of Qjackctl, but this is still in development. | |||
| You can also pick a binary of Qjackctl, but this is still in development. | |||
| ------------------------------- | |||
| Running Jack on windows | |||
| ------------------------------- | |||
| More information at : 'http://www.grame.fr/~letz/jackdmp.html'. | |||
| @@ -28,7 +28,7 @@ It is compiled from the latest CVS version which is using QT4 framework. To uses | |||
| - quit qjackctl.exe and start is again, it should now launch the jack server. Quitting the qjackctl.exe will now close the jack server. | |||
| Starting the jack server with another audio device installed on the machine (like an ASIO card) can now be done directly in qjackctl. | |||
| A ">" button at the right of the interface button allows to list the name of all available devices, driven either by "MME", "Direct Sound", or "ASIO". | |||
| A ">" button at the right of the interface button allows to list the name of all available devices, driven either by "MME", "DirectSound", or "ASIO". | |||
| Alternatively using the following command allows to display the names of available devices: | |||
| - jackd -d portaudio -l to display the entire list of available audio devices. (jackd -d portaudio -h will display all portaudio driver features) | |||