| @@ -369,29 +369,33 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| void FreePorts() | |||
| { | |||
| if (fAudioPlaybackBuffer) { | |||
| for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) | |||
| for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) { | |||
| delete[] fAudioPlaybackBuffer[audio_port_index]; | |||
| } | |||
| delete[] fAudioPlaybackBuffer; | |||
| fAudioPlaybackBuffer = NULL; | |||
| } | |||
| if (fMidiPlaybackBuffer) { | |||
| for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) | |||
| for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) { | |||
| delete[] (fMidiPlaybackBuffer[midi_port_index]); | |||
| } | |||
| delete[] fMidiPlaybackBuffer; | |||
| fMidiPlaybackBuffer = NULL; | |||
| } | |||
| if (fAudioCaptureBuffer) { | |||
| for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) | |||
| for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) { | |||
| delete[] fAudioCaptureBuffer[audio_port_index]; | |||
| } | |||
| delete[] fAudioCaptureBuffer; | |||
| fAudioCaptureBuffer = NULL; | |||
| } | |||
| if (fMidiCaptureBuffer) { | |||
| for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) | |||
| for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) { | |||
| delete[] fMidiCaptureBuffer[midi_port_index]; | |||
| } | |||
| delete[] fMidiCaptureBuffer; | |||
| fMidiCaptureBuffer = NULL; | |||
| } | |||
| @@ -399,7 +403,6 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| int Read(int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer) | |||
| { | |||
| try { | |||
| assert(audio_input == fParams.fReturnAudioChannels); | |||
| @@ -412,23 +415,44 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_input_buffer)[midi_port_index]); | |||
| } | |||
| /* | |||
| // TODO : use with netmaster/netdriver code | |||
| //receive sync | |||
| int res = SyncRecv(); | |||
| if ((res == 0) || (res == SOCKET_ERROR)) { | |||
| return res; | |||
| } | |||
| DecodeSyncPacket(); | |||
| */ | |||
| int res = SyncRecv(); | |||
| switch (res) { | |||
| case 0: | |||
| case SOCKET_ERROR: | |||
| return res; | |||
| case NET_PACKET_ERROR: | |||
| // Since sync packet is incorrect, don't decode it and continue with data | |||
| break; | |||
| default: | |||
| //decode sync | |||
| DecodeSyncPacket(); | |||
| break; | |||
| } | |||
| return DataRecv(); | |||
| } catch (JackNetException& e) { | |||
| jack_error("Connection lost."); | |||
| jack_error("Lost connection"); | |||
| return -1; | |||
| } | |||
| } | |||
| } | |||
| int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer) | |||
| { | |||
| int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer) | |||
| { | |||
| try { | |||
| assert(audio_output == fParams.fSendAudioChannels); | |||
| @@ -441,11 +465,11 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| fNetMidiCaptureBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_output_buffer)[midi_port_index]); | |||
| } | |||
| if (IsSynched()) { // only send if connection is "synched" | |||
| EncodeSyncPacket(); | |||
| // send sync | |||
| if (SyncSend() == SOCKET_ERROR) { | |||
| return SOCKET_ERROR; | |||
| } | |||
| @@ -462,7 +486,7 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| return 0; | |||
| } catch (JackNetException& e) { | |||
| jack_error("Connection lost."); | |||
| jack_error("Lost connection"); | |||
| return -1; | |||
| } | |||
| } | |||
| @@ -749,13 +773,34 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf | |||
| int Read() | |||
| { | |||
| // TODO : use with netmaster/netdriver code | |||
| //receive sync (launch the cycle) | |||
| /* | |||
| if (SyncRecv() == SOCKET_ERROR) { | |||
| return SOCKET_ERROR; | |||
| } | |||
| DecodeSyncPacket(); | |||
| return DataRecv(); | |||
| */ | |||
| switch (SyncRecv()) { | |||
| case SOCKET_ERROR: | |||
| return SOCKET_ERROR; | |||
| case NET_PACKET_ERROR: | |||
| // Since sync packet is incorrect, don't decode it and continue with data | |||
| break; | |||
| default: | |||
| //decode sync | |||
| //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified | |||
| DecodeSyncPacket(); | |||
| break; | |||
| } | |||
| return DataRecv(); | |||
| } | |||
| int Write() | |||
| @@ -351,11 +351,31 @@ namespace Jack | |||
| { | |||
| //don't return -1 in case of sync recv failure | |||
| //we need the process to continue for network error detection | |||
| /* | |||
| if (SyncRecv() == SOCKET_ERROR) { | |||
| return 0; | |||
| } | |||
| DecodeSyncPacket(); | |||
| */ | |||
| //don't return -1 in case of sync recv failure | |||
| //we need the process to continue for network error detection | |||
| switch (SyncRecv()) { | |||
| case SOCKET_ERROR: | |||
| return 0; | |||
| case NET_PACKET_ERROR: | |||
| // Since sync packet is incorrect, don't decode it and continue with data | |||
| break; | |||
| default: | |||
| //decode sync | |||
| DecodeSyncPacket(); | |||
| break; | |||
| } | |||
| return DataRecv(); | |||
| } | |||
| @@ -507,10 +507,25 @@ namespace Jack | |||
| fNetTimeMon->New(); | |||
| #endif | |||
| //receive sync (launch the cycle) | |||
| switch (SyncRecv()) { | |||
| case SOCKET_ERROR: | |||
| return SOCKET_ERROR; | |||
| case NET_PACKET_ERROR: | |||
| // Since sync packet is incorrect, don't decode it and continue with data | |||
| break; | |||
| default: | |||
| //decode sync | |||
| DecodeSyncPacket(); | |||
| break; | |||
| } | |||
| /* | |||
| if (SyncRecv() == SOCKET_ERROR) { | |||
| return SOCKET_ERROR; | |||
| } | |||
| */ | |||
| #ifdef JACK_MONITOR | |||
| // For timing | |||
| @@ -519,19 +534,30 @@ namespace Jack | |||
| //decode sync | |||
| //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified | |||
| DecodeSyncPacket(); | |||
| //DecodeSyncPacket(); | |||
| #ifdef JACK_MONITOR | |||
| fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f); | |||
| #endif | |||
| //audio, midi or sync if driver is late | |||
| int res = DataRecv(); | |||
| switch (DataRecv()) { | |||
| case SOCKET_ERROR: | |||
| return SOCKET_ERROR; | |||
| case NET_PACKET_ERROR: | |||
| jack_time_t cur_time = GetMicroSeconds(); | |||
| NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... | |||
| break; | |||
| } | |||
| /* | |||
| if (res == SOCKET_ERROR) { | |||
| return SOCKET_ERROR; | |||
| } else if (res == NET_PACKET_ERROR) { | |||
| jack_time_t cur_time = GetMicroSeconds(); | |||
| NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... | |||
| } | |||
| */ | |||
| //take the time at the beginning of the cycle | |||
| JackDriver::CycleTakeBeginTime(); | |||
| @@ -553,12 +579,9 @@ namespace Jack | |||
| for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) { | |||
| #ifdef OPTIMIZED_PROTOCOL | |||
| // Port is connected on other side... | |||
| if (fNetAudioPlaybackBuffer->GetConnected(audio_port_index)) { | |||
| if (fGraphManager->GetConnectionsNum(fPlaybackPortList[audio_port_index]) > 0) { | |||
| fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index)); | |||
| } else { | |||
| fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL); | |||
| } | |||
| if (fNetAudioPlaybackBuffer->GetConnected(audio_port_index) | |||
| && (fGraphManager->GetConnectionsNum(fPlaybackPortList[audio_port_index]) > 0)) { | |||
| fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index)); | |||
| } else { | |||
| fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL); | |||
| } | |||
| @@ -381,7 +381,7 @@ namespace Jack | |||
| fRunning = false; | |||
| // send a 'multicast euthanasia request' - new socket is required on macosx | |||
| jack_info("Exiting '%s'", fParams.fName); | |||
| jack_info("Exiting '%s' %s", fParams.fName, fMulticastIP); | |||
| SetPacketType(&fParams, KILL_MASTER); | |||
| JackNetSocket mcast_socket(fMulticastIP, fSocket.GetPort()); | |||
| @@ -488,8 +488,8 @@ namespace Jack | |||
| while (strcmp(rx_head->fPacketType, "header") != 0); | |||
| if (rx_head->fDataType != 's') { | |||
| jack_error("Wrong packet type : %c\n", rx_head->fDataType); | |||
| return -1; | |||
| jack_error("Wrong packet type : %c", rx_head->fDataType); | |||
| return NET_PACKET_ERROR; | |||
| } | |||
| fCurrentCycleOffset = fTxHeader.fCycle - rx_head->fCycle; | |||
| @@ -532,7 +532,7 @@ namespace Jack | |||
| break; | |||
| case 's': // sync | |||
| jack_info("NetMaster : overloaded, skipping receive from '%s'", fParams.fName); | |||
| jack_info("NetMaster : missing last data packet from '%s'", fParams.fName); | |||
| return FinishRecv(fNetAudioPlaybackBuffer); | |||
| } | |||
| } | |||
| @@ -866,7 +866,7 @@ namespace Jack | |||
| // receive sync (launch the cycle) | |||
| do { | |||
| rx_bytes = Recv(fParams.fMtu, 0); | |||
| // connection issue, send will detect it, so don't skip the cycle (return 0) | |||
| // connection issue (return -1) | |||
| if (rx_bytes == SOCKET_ERROR) { | |||
| return rx_bytes; | |||
| } | |||
| @@ -874,8 +874,8 @@ namespace Jack | |||
| while (strcmp(rx_head->fPacketType, "header") != 0); | |||
| if (rx_head->fDataType != 's') { | |||
| jack_error("Wrong packet type : %c\n", rx_head->fDataType); | |||
| return -1; | |||
| jack_error("Wrong packet type : %c", rx_head->fDataType); | |||
| return NET_PACKET_ERROR; | |||
| } | |||
| fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; | |||
| @@ -894,7 +894,7 @@ namespace Jack | |||
| // how much data is queued on the rx buffer ? | |||
| rx_bytes = Recv(fParams.fMtu, MSG_PEEK); | |||
| // error here, problem with recv, just skip the cycle (return -1) | |||
| // error here, just skip the cycle (return -1) | |||
| if (rx_bytes == SOCKET_ERROR) { | |||
| return rx_bytes; | |||
| } | |||
| @@ -912,7 +912,7 @@ namespace Jack | |||
| break; | |||
| case 's': // sync | |||
| jack_info("NetSlave : overloaded, skipping receive"); | |||
| jack_info("NetSlave : missing last data packet"); | |||
| return FinishRecv(fNetAudioCaptureBuffer); | |||
| } | |||
| } | |||
| @@ -510,19 +510,39 @@ namespace Jack | |||
| } | |||
| //receive sync | |||
| /* | |||
| int res = SyncRecv(); | |||
| if ((res == 0) || (res == SOCKET_ERROR)) { | |||
| return res; | |||
| } | |||
| */ | |||
| int res = SyncRecv(); | |||
| switch (res) { | |||
| case 0: | |||
| case SOCKET_ERROR: | |||
| return res; | |||
| case NET_PACKET_ERROR: | |||
| // Since sync packet is incorrect, don't decode it and continue with data | |||
| break; | |||
| default: | |||
| //decode sync | |||
| DecodeSyncPacket(); | |||
| break; | |||
| } | |||
| #ifdef JACK_MONITOR | |||
| fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f); | |||
| #endif | |||
| //decode sync | |||
| DecodeSyncPacket(); | |||
| //DecodeSyncPacket(); | |||
| //receive data | |||
| /* | |||
| res = DataRecv(); | |||
| if ((res == 0) || (res == SOCKET_ERROR)) { | |||
| return res; | |||
| @@ -530,6 +550,21 @@ namespace Jack | |||
| // Well not a real XRun... | |||
| JackServerGlobals::fInstance->GetEngine()->NotifyClientXRun(ALL_CLIENTS); | |||
| } | |||
| */ | |||
| //receive data | |||
| res = DataRecv(); | |||
| switch (res) { | |||
| case 0: | |||
| case SOCKET_ERROR: | |||
| return res; | |||
| case NET_PACKET_ERROR: | |||
| // Well not a real XRun... | |||
| JackServerGlobals::fInstance->GetEngine()->NotifyClientXRun(ALL_CLIENTS); | |||
| break; | |||
| } | |||
| #ifdef JACK_MONITOR | |||
| fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f); | |||
| @@ -59,6 +59,15 @@ JackCoreMidiVirtualInputPort(const char *alias_name, const char *client_name, | |||
| MIDIEndpointRef destination; | |||
| OSStatus status = MIDIDestinationCreate(client, name, HandleInputEvent, | |||
| this, &destination); | |||
| /* | |||
| SInt32 value; | |||
| status = MIDIObjectGetIntegerProperty(destination, kMIDIPropertyUniqueID, &value); | |||
| if (status == noErr) { | |||
| jack_info("kMIDIPropertyUniqueID %d", value); | |||
| } | |||
| */ | |||
| CFRelease(name); | |||
| if (status != noErr) { | |||
| throw std::runtime_error(GetMacOSErrorString(status)); | |||
| @@ -44,6 +44,15 @@ JackCoreMidiVirtualOutputPort(const char *alias_name, const char *client_name, | |||
| } | |||
| MIDIEndpointRef source; | |||
| OSStatus status = MIDISourceCreate(client, name, &source); | |||
| /* | |||
| SInt32 value; | |||
| status = MIDIObjectGetIntegerProperty(source, kMIDIPropertyUniqueID, &value); | |||
| if (status == noErr) { | |||
| jack_info("kMIDIPropertyUniqueID %d", value); | |||
| } | |||
| */ | |||
| CFRelease(name); | |||
| if (status != noErr) { | |||
| throw std::runtime_error(GetMacOSErrorString(status)); | |||
| @@ -335,12 +335,12 @@ namespace Jack | |||
| jack_log("JackNetUnixSocket::SetTimeout %d usecs", us); | |||
| struct timeval timeout; | |||
| //less than 1sec | |||
| //less than 1 sec | |||
| if (us < 1000000) { | |||
| timeout.tv_sec = 0; | |||
| timeout.tv_usec = us; | |||
| } else { | |||
| //more than 1sec | |||
| //more than 1 sec | |||
| float sec = float(us) / 1000000.f; | |||
| timeout.tv_sec = (int)sec; | |||
| float usec = (sec - float(timeout.tv_sec)) * 1000000; | |||