| @@ -594,14 +594,14 @@ string JackDriver::MatchPortName(const char* name, const char** ports, int alias | |||
| return ""; | |||
| } | |||
| void JackDriver::RestoreConnections(int alias, bool full_name) | |||
| void JackDriver::LoadConnections(int alias, bool full_name) | |||
| { | |||
| list<pair<string, pair<string, string> > >::const_iterator it; | |||
| if (full_name) { | |||
| for (it = fConnections.begin(); it != fConnections.end(); it++) { | |||
| pair<string, string> connection = (*it).second; | |||
| jack_info("Restore connection: %s %s", connection.first.c_str(), connection.second.c_str()); | |||
| jack_info("Load connection: %s %s", connection.first.c_str(), connection.second.c_str()); | |||
| fEngine->PortConnect(fClientControl.fRefNum, connection.first.c_str(), connection.second.c_str()); | |||
| } | |||
| } else { | |||
| @@ -613,7 +613,7 @@ void JackDriver::RestoreConnections(int alias, bool full_name) | |||
| string real_input = MatchPortName(connection.first.c_str(), outputs, alias, (*it).first); | |||
| string real_output = MatchPortName(connection.second.c_str(), inputs, alias, (*it).first); | |||
| if ((real_input != "") && (real_output != "")) { | |||
| jack_info("Restore connection: %s %s", real_input.c_str(), real_output.c_str()); | |||
| jack_info("Load connection: %s %s", real_input.c_str(), real_output.c_str()); | |||
| fEngine->PortConnect(fClientControl.fRefNum, real_input.c_str(), real_output.c_str()); | |||
| } | |||
| } | |||
| @@ -130,6 +130,8 @@ class SERVER_EXPORT JackDriverClientInterface : public JackDriverInterface, publ | |||
| #define PlaybackDriverFlags static_cast<JackPortFlags>(JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal) | |||
| #define MonitorDriverFlags static_cast<JackPortFlags>(JackPortIsOutput) | |||
| typedef std::list<std::pair<std::string, std::pair<std::string, std::string> > > driver_connections_list_t; // [type : (src, dst)] | |||
| class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| { | |||
| @@ -169,7 +171,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| jack_port_id_t fPlaybackPortList[DRIVER_PORT_NUM]; | |||
| jack_port_id_t fMonitorPortList[DRIVER_PORT_NUM]; | |||
| std::list<std::pair<std::string, std::pair<std::string, std::string> > > fConnections; // Connections list | |||
| driver_connections_list_t fConnections; // Connections list | |||
| void CycleIncTime(); | |||
| void CycleTakeBeginTime(); | |||
| @@ -183,7 +185,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| void NotifyFailure(int code, const char* reason); // Failure notification sent by the driver | |||
| virtual void SaveConnections(int alias); | |||
| virtual void RestoreConnections(int alias, bool full_name = true); | |||
| virtual void LoadConnections(int alias, bool full_name = true); | |||
| std::string MatchPortName(const char* name, const char** ports, int alias, const std::string& type); | |||
| virtual int StartSlaves(); | |||
| @@ -29,7 +29,8 @@ namespace Jack | |||
| { | |||
| JackNetDriver::JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, | |||
| const char* ip, int udp_port, int mtu, int midi_input_ports, int midi_output_ports, | |||
| char* net_name, uint transport_sync, int network_latency, int celt_encoding, int opus_encoding) | |||
| char* net_name, uint transport_sync, int network_latency, | |||
| int celt_encoding, int opus_encoding, bool auto_save) | |||
| : JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port) | |||
| { | |||
| jack_log("JackNetDriver::JackNetDriver ip %s, port %d", ip, udp_port); | |||
| @@ -66,6 +67,7 @@ namespace Jack | |||
| fMidiPlaybackPortList = NULL; | |||
| fWantedAudioCaptureChannels = -1; | |||
| fWantedAudioPlaybackChannels = -1; | |||
| fAutoSave = auto_save; | |||
| #ifdef JACK_MONITOR | |||
| fNetTimeMon = NULL; | |||
| fRcvSyncUst = 0; | |||
| @@ -137,7 +139,9 @@ namespace Jack | |||
| bool JackNetDriver::Initialize() | |||
| { | |||
| jack_log("JackNetDriver::Initialize"); | |||
| SaveConnections(0); | |||
| if (fAutoSave) { | |||
| SaveConnections(0); | |||
| } | |||
| FreePorts(); | |||
| // New loading, but existing socket, restart the driver | |||
| @@ -237,7 +241,9 @@ namespace Jack | |||
| // Transport engine parametering | |||
| fEngineControl->fTransport.SetNetworkSync(fParams.fTransportSync); | |||
| RestoreConnections(0); | |||
| if (fAutoSave) { | |||
| LoadConnections(0); | |||
| } | |||
| return true; | |||
| } | |||
| @@ -687,6 +693,10 @@ namespace Jack | |||
| #endif | |||
| strcpy(value.str, "'hostname'"); | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL); | |||
| value.i = false; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore connection state when restarting", NULL); | |||
| /* | |||
| Deactivated for now.. | |||
| @@ -720,6 +730,7 @@ Deactivated for now.. | |||
| int network_latency = 5; | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| bool auto_save = false; | |||
| // Possibly use env variable for UDP port | |||
| const char* default_udp_port = getenv("JACK_NETJACK_PORT"); | |||
| @@ -768,6 +779,9 @@ Deactivated for now.. | |||
| case 'n' : | |||
| strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE); | |||
| break; | |||
| case 's': | |||
| auto_save = param->value.i; | |||
| break; | |||
| /* | |||
| Deactivated for now.. | |||
| case 't' : | |||
| @@ -790,7 +804,7 @@ Deactivated for now.. | |||
| new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, mtu, | |||
| midi_input_ports, midi_output_ports, | |||
| net_name, transport_sync, | |||
| network_latency, celt_encoding, opus_encoding)); | |||
| network_latency, celt_encoding, opus_encoding, auto_save)); | |||
| 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; | |||
| } else { | |||
| @@ -50,6 +50,8 @@ namespace Jack | |||
| int fWantedMIDICaptureChannels; | |||
| int fWantedMIDIPlaybackChannels; | |||
| bool fAutoSave; | |||
| //monitoring | |||
| #ifdef JACK_MONITOR | |||
| @@ -78,7 +80,8 @@ namespace Jack | |||
| JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, | |||
| const char* ip, int port, int mtu, int midi_input_ports, int midi_output_ports, | |||
| char* net_name, uint transport_sync, int network_latency, int celt_encoding, int opus_encoding); | |||
| char* net_name, uint transport_sync, int network_latency, int celt_encoding, | |||
| int opus_encoding, bool auto_save); | |||
| virtual ~JackNetDriver(); | |||
| int Open(jack_nframes_t buffer_size, | |||
| @@ -20,6 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include "JackArgParser.h" | |||
| #include "JackServerGlobals.h" | |||
| #include "JackLockedEngine.h" | |||
| #include "thread.h" | |||
| using namespace std; | |||
| @@ -556,6 +557,65 @@ namespace Jack | |||
| #endif | |||
| return 0; | |||
| } | |||
| void JackNetMaster::SaveConnections(connections_list_t& connections) | |||
| { | |||
| // Audio | |||
| for (int i = 0; i < fParams.fSendAudioChannels; i++) { | |||
| const char** connected_port = jack_port_get_all_connections(fClient, fAudioCapturePorts[i]); | |||
| if (connected_port != NULL) { | |||
| for (int port = 0; connected_port[port]; port++) { | |||
| connections.push_back(make_pair(connected_port[port], jack_port_name(fAudioCapturePorts[i]))); | |||
| jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fAudioCapturePorts[i])); | |||
| } | |||
| jack_free(connected_port); | |||
| } | |||
| } | |||
| for (int i = 0; i < fParams.fReturnAudioChannels; i++) { | |||
| const char** connected_port = jack_port_get_all_connections(fClient, fAudioPlaybackPorts[i]); | |||
| if (connected_port != NULL) { | |||
| for (int port = 0; connected_port[port]; port++) { | |||
| connections.push_back(make_pair(jack_port_name(fAudioPlaybackPorts[i]), connected_port[port])); | |||
| jack_log("OUTPUT %s ==> %s", jack_port_name(fAudioPlaybackPorts[i]), connected_port[port]); | |||
| } | |||
| jack_free(connected_port); | |||
| } | |||
| } | |||
| // MIDI | |||
| for (int i = 0; i < fParams.fSendMidiChannels; i++) { | |||
| const char** connected_port = jack_port_get_all_connections(fClient, fMidiCapturePorts[i]); | |||
| if (connected_port != NULL) { | |||
| for (int port = 0; connected_port[port]; port++) { | |||
| connections.push_back(make_pair(connected_port[port], jack_port_name(fMidiCapturePorts[i]))); | |||
| jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fMidiCapturePorts[i])); | |||
| } | |||
| jack_free(connected_port); | |||
| } | |||
| } | |||
| for (int i = 0; i < fParams.fReturnMidiChannels; i++) { | |||
| const char** connected_port = jack_port_get_all_connections(fClient, fMidiPlaybackPorts[i]); | |||
| if (connected_port != NULL) { | |||
| for (int port = 0; connected_port[port]; port++) { | |||
| connections.push_back(make_pair(jack_port_name(fMidiPlaybackPorts[i]), connected_port[port])); | |||
| jack_log("OUTPUT %s ==> %s", jack_port_name(fMidiPlaybackPorts[i]), connected_port[port]); | |||
| } | |||
| jack_free(connected_port); | |||
| } | |||
| } | |||
| } | |||
| void JackNetMaster::LoadConnections(const connections_list_t& connections) | |||
| { | |||
| list<pair<string, string> >::const_iterator it; | |||
| for (it = connections.begin(); it != connections.end(); it++) { | |||
| pair<string, string> connection = *it; | |||
| jack_connect(fClient, connection.first.c_str(), connection.second.c_str()); | |||
| } | |||
| } | |||
| //JackNetMasterManager*********************************************************************************************** | |||
| @@ -568,6 +628,7 @@ namespace Jack | |||
| fGlobalID = 0; | |||
| fRunning = true; | |||
| fAutoConnect = false; | |||
| fAutoSave = false; | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| @@ -604,6 +665,10 @@ namespace Jack | |||
| case 'c': | |||
| fAutoConnect = param->value.i; | |||
| break; | |||
| case 's': | |||
| fAutoSave = param->value.i; | |||
| break; | |||
| } | |||
| } | |||
| @@ -652,7 +717,7 @@ namespace Jack | |||
| } | |||
| master_list_t::iterator it; | |||
| for (it = fMasterList.begin(); it != fMasterList.end(); it++) { | |||
| delete(*it); | |||
| delete (*it); | |||
| } | |||
| fMasterList.clear(); | |||
| fSocket.Close(); | |||
| @@ -811,10 +876,14 @@ namespace Jack | |||
| JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP); | |||
| if (master->Init(fAutoConnect)) { | |||
| fMasterList.push_back(master); | |||
| if (fAutoSave && fMasterConnectionList.find(params.fName) != fMasterConnectionList.end()) { | |||
| master->LoadConnections(fMasterConnectionList[params.fName]); | |||
| } | |||
| return master; | |||
| } else { | |||
| delete master; | |||
| return NULL; | |||
| } | |||
| delete master; | |||
| return NULL; | |||
| } | |||
| master_list_it_t JackNetMasterManager::FindMaster(uint32_t id) | |||
| @@ -834,10 +903,14 @@ namespace Jack | |||
| { | |||
| 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; | |||
| master_list_it_t master_it = FindMaster(params->fID); | |||
| if (master_it != fMasterList.end()) { | |||
| if (fAutoSave) { | |||
| fMasterConnectionList[params->fName].clear(); | |||
| (*master_it)->SaveConnections(fMasterConnectionList[params->fName]); | |||
| } | |||
| fMasterList.erase(master_it); | |||
| delete (*master_it); | |||
| return 1; | |||
| } | |||
| return 0; | |||
| @@ -868,6 +941,9 @@ extern "C" | |||
| value.i = false; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netmaster to system ports", NULL); | |||
| value.i = false; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore netmaster connection state when restarted", NULL); | |||
| return desc; | |||
| } | |||
| @@ -21,10 +21,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #define __JACKNETMANAGER_H__ | |||
| #include "JackNetInterface.h" | |||
| #include "thread.h" | |||
| #include "jack.h" | |||
| #include "jslist.h" | |||
| #include <list> | |||
| #include <map> | |||
| namespace Jack | |||
| { | |||
| @@ -33,6 +32,8 @@ namespace Jack | |||
| /** | |||
| \Brief This class describes a Net Master | |||
| */ | |||
| typedef std::list<std::pair<std::string, std::string> > connections_list_t; | |||
| class JackNetMaster : public JackNetMasterInterface | |||
| { | |||
| @@ -78,6 +79,9 @@ namespace Jack | |||
| void TimebaseCallback(jack_position_t* pos); | |||
| void ConnectPorts(); | |||
| void ConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect); | |||
| void SaveConnections(connections_list_t& connections); | |||
| void LoadConnections(const connections_list_t& connections); | |||
| public: | |||
| @@ -89,6 +93,7 @@ namespace Jack | |||
| typedef std::list<JackNetMaster*> master_list_t; | |||
| typedef master_list_t::iterator master_list_it_t; | |||
| typedef std::map <std::string, connections_list_t> master_connections_list_t; | |||
| /** | |||
| \Brief This class describer the Network Manager | |||
| @@ -110,9 +115,11 @@ namespace Jack | |||
| JackNetSocket fSocket; | |||
| jack_native_thread_t fThread; | |||
| master_list_t fMasterList; | |||
| master_connections_list_t fMasterConnectionList; | |||
| uint32_t fGlobalID; | |||
| bool fRunning; | |||
| bool fAutoConnect; | |||
| bool fAutoSave; | |||
| void Run(); | |||
| JackNetMaster* InitMaster(session_params_t& params); | |||
| @@ -529,7 +529,7 @@ JackCoreMidiDriver::Restart() | |||
| Attach(); | |||
| Start(); | |||
| // Use first alias and partial port naming | |||
| RestoreConnections(1, false); | |||
| LoadConnections(1, false); | |||
| } | |||
| void | |||