git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3402 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
| @@ -23,6 +23,19 @@ Michael Voigt | |||
| Jackdmp changes log | |||
| --------------------------- | |||
| 2009-03-05 Stephane Letz <letz@grame.fr> | |||
| * 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> | |||
| * More robust profiling tools when clients come and go. | |||
| 2009-03-01 Stephane Letz <letz@grame.fr> | |||
| * Raise default port number to 1024. | |||
| 2009-02-27 Stephane Letz <letz@grame.fr> | |||
| * Improve generated gnuplot files for adapting code. | |||
| @@ -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(); | |||
| @@ -34,7 +34,7 @@ | |||
| #define JACK_CLIENT_NAME_SIZE 64 | |||
| #ifndef PORT_NUM | |||
| #define PORT_NUM 512 | |||
| #define PORT_NUM 1024 | |||
| #endif | |||
| #define DRIVER_PORT_NUM 256 | |||
| @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| namespace Jack | |||
| { | |||
| JackEngineProfiling::JackEngineProfiling():fAudioCycle(0) | |||
| JackEngineProfiling::JackEngineProfiling():fAudioCycle(0),fMeasuredClient(0) | |||
| { | |||
| jack_info("Engine profiling activated, beware %ld MBytes are needed to record profiling points...", sizeof(fProfileTable) / (1024 * 1024)); | |||
| @@ -36,66 +36,59 @@ JackEngineProfiling::JackEngineProfiling():fAudioCycle(0) | |||
| JackEngineProfiling::~JackEngineProfiling() | |||
| { | |||
| // Window monitoring | |||
| int max_client = 0; | |||
| char buffer[1024]; | |||
| char* nameTable[CLIENT_NUM]; | |||
| FILE* file = fopen("JackEngineProfiling.log", "w"); | |||
| char buffer[1024]; | |||
| jack_info("Write server and clients timing data..."); | |||
| if (file == NULL) { | |||
| jack_error("JackEngineProfiling::Save cannot open JackEngineProfiling.log file"); | |||
| } else { | |||
| // For each measured point | |||
| for (int i = 2; i < TIME_POINTS; i++) { | |||
| bool header = true; | |||
| bool printed = false; | |||
| int count = 0; | |||
| for (int j = REAL_REFNUM; j < CLIENT_NUM; j++) { | |||
| if (fProfileTable[i].fClientTable[j].fRefNum > 0) { | |||
| long d1 = long(fProfileTable[i - 1].fCurCycleBegin - fProfileTable[i - 2].fCurCycleBegin); | |||
| long d2 = long(fProfileTable[i].fPrevCycleEnd - fProfileTable[i - 1].fCurCycleBegin); | |||
| if (d1 > 0 && fProfileTable[i].fClientTable[j].fStatus != NotTriggered) { // Valid cycle | |||
| count++; | |||
| nameTable[count] = fNameTable[fProfileTable[i].fClientTable[j].fRefNum]; | |||
| // driver delta and end cycle | |||
| if (header) { | |||
| fprintf(file, "%ld \t %ld \t", d1, d2); | |||
| header = false; | |||
| } | |||
| long d5 = long(fProfileTable[i].fClientTable[j].fSignaledAt - fProfileTable[i - 1].fCurCycleBegin); | |||
| long d6 = long(fProfileTable[i].fClientTable[j].fAwakeAt - fProfileTable[i - 1].fCurCycleBegin); | |||
| long d7 = long(fProfileTable[i].fClientTable[j].fFinishedAt - fProfileTable[i - 1].fCurCycleBegin); | |||
| // ref, signal, start, end, scheduling, duration, status | |||
| fprintf(file, "%d \t %ld \t %ld \t %ld \t %ld \t %ld \t %d \t", | |||
| fProfileTable[i].fClientTable[j].fRefNum, | |||
| ((d5 > 0) ? d5 : 0), | |||
| ((d6 > 0) ? d6 : 0), | |||
| ((d7 > 0) ? d7 : 0), | |||
| ((d6 > 0 && d5 > 0) ? (d6 - d5) : 0), | |||
| ((d7 > 0 && d6 > 0) ? (d7 - d6) : 0), | |||
| fProfileTable[i].fClientTable[j].fStatus); | |||
| printed = true; | |||
| } | |||
| } | |||
| max_client = (count > max_client) ? count : max_client; | |||
| } | |||
| if (printed) { | |||
| fprintf(file, "\n"); | |||
| } else if (fProfileTable[i].fAudioCycle > 0) { // Driver timing only | |||
| long d1 = long(fProfileTable[i].fCurCycleBegin - fProfileTable[i - 1].fCurCycleBegin); | |||
| long d2 = long(fProfileTable[i].fPrevCycleEnd - fProfileTable[i - 1].fCurCycleBegin); | |||
| if (d1 > 0) { // Valid cycle | |||
| fprintf(file, "%ld \t %ld \n", d1, d2); | |||
| // Driver timing values | |||
| long d1 = long(fProfileTable[i].fCurCycleBegin - fProfileTable[i - 1].fCurCycleBegin); | |||
| long d2 = long(fProfileTable[i].fPrevCycleEnd - fProfileTable[i - 1].fCurCycleBegin); | |||
| if (d1 <= 0 || fProfileTable[i].fAudioCycle <= 0) | |||
| continue; // Skip non valid cycles | |||
| // Print driver delta and end cycle | |||
| fprintf(file, "%ld \t %ld \t", d1, d2); | |||
| // For each measured client | |||
| for (unsigned int j = 0; j < fMeasuredClient; j++) { | |||
| int ref = fIntervalTable[j].fRefNum; | |||
| // Is valid client cycle | |||
| if (fProfileTable[i].fClientTable[ref].fStatus != NotTriggered) { | |||
| long d5 = long(fProfileTable[i].fClientTable[ref].fSignaledAt - fProfileTable[i - 1].fCurCycleBegin); | |||
| long d6 = long(fProfileTable[i].fClientTable[ref].fAwakeAt - fProfileTable[i - 1].fCurCycleBegin); | |||
| long d7 = long(fProfileTable[i].fClientTable[ref].fFinishedAt - fProfileTable[i - 1].fCurCycleBegin); | |||
| // Print ref, signal, start, end, scheduling, duration, status | |||
| fprintf(file, "%d \t %ld \t %ld \t %ld \t %ld \t %ld \t %d \t", | |||
| ref, | |||
| ((d5 > 0) ? d5 : 0), | |||
| ((d6 > 0) ? d6 : 0), | |||
| ((d7 > 0) ? d7 : 0), | |||
| ((d6 > 0 && d5 > 0) ? (d6 - d5) : 0), | |||
| ((d7 > 0 && d6 > 0) ? (d7 - d6) : 0), | |||
| fProfileTable[i].fClientTable[ref].fStatus); | |||
| } else { // Print tabs | |||
| fprintf(file, "\t \t \t \t \t \t \t"); | |||
| } | |||
| } | |||
| // Terminate line | |||
| fprintf(file, "\n"); | |||
| } | |||
| fclose(file); | |||
| } | |||
| // Driver period | |||
| file = fopen("Timing1.plot", "w"); | |||
| @@ -145,9 +138,9 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| fclose(file); | |||
| } | |||
| // Clients end date | |||
| if (max_client > 0) { | |||
| if (fMeasuredClient > 0) { | |||
| file = fopen("Timing3.plot", "w"); | |||
| if (file == NULL) { | |||
| jack_error("JackEngineProfiling::Save cannot open Timing3.log file"); | |||
| @@ -158,21 +151,20 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| fprintf(file, "set title \"Clients end date\"\n"); | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"usec\"\n"); | |||
| fprintf(file, "plot "); | |||
| for (int i = 0; i < max_client; i++) { | |||
| for (unsigned int i = 0; i < fMeasuredClient; i++) { | |||
| if (i == 0) { | |||
| if ((i + 1) == max_client) { | |||
| if (i + 1 == fMeasuredClient) { // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines", | |||
| ((i + 1) * 7) - 1 , nameTable[(i + 1)]); | |||
| ((i + 1) * 7) - 1 , fIntervalTable[i].fName); | |||
| } else { | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", | |||
| ((i + 1) * 7) - 1 , nameTable[(i + 1)]); | |||
| ((i + 1) * 7) - 1 , fIntervalTable[i].fName); | |||
| } | |||
| } else if ((i + 1) == max_client) { // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) - 1 , nameTable[(i + 1)]); | |||
| } else if (i + 1 == fMeasuredClient) { // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) - 1 , fIntervalTable[i].fName); | |||
| } else { | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) - 1, nameTable[(i + 1)]); | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) - 1, fIntervalTable[i].fName); | |||
| } | |||
| fprintf(file, buffer); | |||
| } | |||
| @@ -187,28 +179,29 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"usec\"\n"); | |||
| fprintf(file, "plot "); | |||
| for (int i = 0; i < max_client; i++) { | |||
| for (unsigned int i = 0; i < fMeasuredClient; i++) { | |||
| if (i == 0) { | |||
| if ((i + 1) == max_client) { | |||
| if ((i + 1) == fMeasuredClient) { // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines", | |||
| ((i + 1) * 7) - 1 , nameTable[(i + 1)]); | |||
| ((i + 1) * 7) - 1 , fIntervalTable[i].fName); | |||
| } else { | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", | |||
| ((i + 1) * 7) - 1 , nameTable[(i + 1)]); | |||
| ((i + 1) * 7) - 1 , fIntervalTable[i].fName); | |||
| } | |||
| } else if ((i + 1) == max_client) { // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) - 1 , nameTable[(i + 1)]); | |||
| } else if ((i + 1) == fMeasuredClient) { // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) - 1 , fIntervalTable[i].fName); | |||
| } else { | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) - 1, nameTable[(i + 1)]); | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) - 1, fIntervalTable[i].fName); | |||
| } | |||
| fprintf(file, buffer); | |||
| } | |||
| fclose(file); | |||
| } | |||
| } | |||
| // Clients scheduling | |||
| if (max_client > 0) { | |||
| if (fMeasuredClient > 0) { | |||
| file = fopen("Timing4.plot", "w"); | |||
| if (file == NULL) { | |||
| @@ -221,11 +214,11 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"usec\"\n"); | |||
| fprintf(file, "plot "); | |||
| for (int i = 0; i < max_client; i++) { | |||
| if ((i + 1) == max_client) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7), nameTable[(i + 1)]); | |||
| for (unsigned int i = 0; i < fMeasuredClient; i++) { | |||
| if ((i + 1) == fMeasuredClient) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7), fIntervalTable[i].fName); | |||
| else | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7), nameTable[(i + 1)]); | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7), fIntervalTable[i].fName); | |||
| fprintf(file, buffer); | |||
| } | |||
| @@ -239,11 +232,11 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"usec\"\n"); | |||
| fprintf(file, "plot "); | |||
| for (int i = 0; i < max_client; i++) { | |||
| if ((i + 1) == max_client) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7), nameTable[(i + 1)]); | |||
| for (unsigned int i = 0; i < fMeasuredClient; i++) { | |||
| if ((i + 1) == fMeasuredClient) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7), fIntervalTable[i].fName); | |||
| else | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7), nameTable[(i + 1)]); | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7), fIntervalTable[i].fName); | |||
| fprintf(file, buffer); | |||
| } | |||
| fclose(file); | |||
| @@ -251,7 +244,7 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| } | |||
| // Clients duration | |||
| if (max_client > 0) { | |||
| if (fMeasuredClient > 0) { | |||
| file = fopen("Timing5.plot", "w"); | |||
| if (file == NULL) { | |||
| @@ -264,11 +257,11 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"usec\"\n"); | |||
| fprintf(file, "plot "); | |||
| for (int i = 0; i < max_client; i++) { | |||
| if ((i + 1) == max_client) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) + 1, nameTable[(i + 1)]); | |||
| for (unsigned int i = 0; i < fMeasuredClient; i++) { | |||
| if ((i + 1) == fMeasuredClient) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) + 1, fIntervalTable[i].fName); | |||
| else | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) + 1, nameTable[(i + 1)]); | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) + 1, fIntervalTable[i].fName); | |||
| fprintf(file, buffer); | |||
| } | |||
| @@ -282,11 +275,11 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"usec\"\n"); | |||
| fprintf(file, "plot "); | |||
| for (int i = 0; i < max_client; i++) { | |||
| if ((i + 1) == max_client) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) + 1, nameTable[(i + 1)]); | |||
| for (unsigned int i = 0; i < fMeasuredClient; i++) { | |||
| if ((i + 1) == fMeasuredClient) // Last client | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) + 1, fIntervalTable[i].fName); | |||
| else | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) + 1, nameTable[(i + 1)]); | |||
| sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) + 1, fIntervalTable[i].fName); | |||
| fprintf(file, buffer); | |||
| } | |||
| fclose(file); | |||
| @@ -294,6 +287,17 @@ JackEngineProfiling::~JackEngineProfiling() | |||
| } | |||
| } | |||
| bool JackEngineProfiling::CheckClient(const char* name, int cur_point) | |||
| { | |||
| for (int i = 0; i < MEASURED_CLIENTS; i++) { | |||
| if (strcmp(fIntervalTable[i].fName, name) == 0) { | |||
| fIntervalTable[i].fEndInterval = cur_point; | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void JackEngineProfiling::Profile(JackClientInterface** table, | |||
| JackGraphManager* manager, | |||
| jack_time_t period_usecs, | |||
| @@ -311,8 +315,16 @@ void JackEngineProfiling::Profile(JackClientInterface** table, | |||
| for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||
| JackClientInterface* client = table[i]; | |||
| JackClientTiming* timing = manager->GetClientTiming(i); | |||
| if (client && client->GetClientControl()->fActive) { | |||
| strcpy(fNameTable[i], client->GetClientControl()->fName); | |||
| if (client && client->GetClientControl()->fActive && client->GetClientControl()->fCallback[kRealTimeCallback]) { | |||
| if (!CheckClient(client->GetClientControl()->fName, fAudioCycle)) { | |||
| // Keep new measured client | |||
| fIntervalTable[fMeasuredClient].fRefNum = i; | |||
| strcpy(fIntervalTable[fMeasuredClient].fName, client->GetClientControl()->fName); | |||
| fIntervalTable[fMeasuredClient].fBeginInterval = fAudioCycle; | |||
| fIntervalTable[fMeasuredClient].fEndInterval = fAudioCycle; | |||
| fMeasuredClient++; | |||
| } | |||
| fProfileTable[fAudioCycle].fClientTable[i].fRefNum = i; | |||
| fProfileTable[fAudioCycle].fClientTable[i].fSignaledAt = timing->fSignaledAt; | |||
| fProfileTable[fAudioCycle].fClientTable[i].fAwakeAt = timing->fAwakeAt; | |||
| @@ -31,6 +31,7 @@ namespace Jack | |||
| #define TIME_POINTS 250000 | |||
| #define FAILURE_TIME_POINTS 10000 | |||
| #define FAILURE_WINDOW 10 | |||
| #define MEASURED_CLIENTS 32 | |||
| /*! | |||
| \brief Timing stucture for a client. | |||
| @@ -43,6 +44,32 @@ struct JackTimingMeasureClient | |||
| jack_time_t fAwakeAt; | |||
| jack_time_t fFinishedAt; | |||
| jack_client_state_t fStatus; | |||
| JackTimingMeasureClient() | |||
| :fRefNum(-1), | |||
| fSignaledAt(0), | |||
| fAwakeAt(0), | |||
| fFinishedAt(0), | |||
| fStatus((jack_client_state_t)0) | |||
| {} | |||
| }; | |||
| /*! | |||
| \brief Timing interval in the global table for a given client | |||
| */ | |||
| struct JackTimingClientInterval | |||
| { | |||
| int fRefNum; | |||
| char fName[JACK_CLIENT_NAME_SIZE + 1]; | |||
| int fBeginInterval; | |||
| int fEndInterval; | |||
| JackTimingClientInterval() | |||
| :fRefNum(-1), | |||
| fBeginInterval(-1), | |||
| fEndInterval(-1) | |||
| {} | |||
| }; | |||
| /*! | |||
| @@ -56,6 +83,13 @@ struct JackTimingMeasure | |||
| jack_time_t fCurCycleBegin; | |||
| jack_time_t fPrevCycleEnd; | |||
| JackTimingMeasureClient fClientTable[CLIENT_NUM]; | |||
| JackTimingMeasure() | |||
| :fAudioCycle(0), | |||
| fPeriodUsecs(0), | |||
| fCurCycleBegin(0), | |||
| fPrevCycleEnd(0) | |||
| {} | |||
| }; | |||
| /*! | |||
| @@ -71,9 +105,13 @@ class SERVER_EXPORT JackEngineProfiling | |||
| private: | |||
| JackTimingMeasure fProfileTable[TIME_POINTS]; | |||
| char fNameTable[CLIENT_NUM][JACK_CLIENT_NAME_SIZE + 1]; | |||
| JackTimingClientInterval fIntervalTable[MEASURED_CLIENTS]; | |||
| unsigned int fAudioCycle; | |||
| unsigned int fMeasuredClient; | |||
| bool CheckClient(const char* name, int cur_point); | |||
| public: | |||
| JackEngineProfiling(); | |||
| @@ -354,9 +354,8 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| if (SyncRecv() == SOCKET_ERROR) | |||
| return 0; | |||
| if (DecodeSyncPacket() < 0) | |||
| return 0; | |||
| DecodeSyncPacket(); | |||
| return DataRecv(); | |||
| } | |||
| @@ -373,9 +372,8 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| fNetMidiCaptureBuffer->SetBuffer(port_index, ((JackMidiBuffer**)midi_output_buffer)[port_index]); | |||
| } | |||
| if (EncodeSyncPacket() < 0) | |||
| return 0; | |||
| EncodeSyncPacket(); | |||
| if (SyncSend() == SOCKET_ERROR) | |||
| return SOCKET_ERROR; | |||
| @@ -383,15 +381,11 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
| } | |||
| // Transport | |||
| int EncodeTransportData() | |||
| { | |||
| return 0; | |||
| } | |||
| void EncodeTransportData() | |||
| {} | |||
| int DecodeTransportData() | |||
| { | |||
| return 0; | |||
| } | |||
| void DecodeTransportData() | |||
| {} | |||
| }; | |||
| @@ -574,15 +568,11 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf | |||
| } | |||
| // Transport | |||
| int EncodeTransportData() | |||
| { | |||
| return 0; | |||
| } | |||
| void EncodeTransportData() | |||
| {} | |||
| int DecodeTransportData() | |||
| { | |||
| return 0; | |||
| } | |||
| void DecodeTransportData() | |||
| {} | |||
| bool Init() | |||
| { | |||
| @@ -624,17 +614,15 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf | |||
| if (SyncRecv() == SOCKET_ERROR) | |||
| return 0; | |||
| if (DecodeSyncPacket() < 0) | |||
| return 0; | |||
| DecodeSyncPacket(); | |||
| return DataRecv(); | |||
| } | |||
| int Write() | |||
| { | |||
| if (EncodeSyncPacket() < 0) | |||
| return 0; | |||
| EncodeSyncPacket(); | |||
| if (SyncSend() == SOCKET_ERROR) | |||
| return SOCKET_ERROR; | |||
| @@ -260,7 +260,7 @@ namespace Jack | |||
| } | |||
| //transport--------------------------------------------------------------------------- | |||
| int JackNetAdapter::DecodeTransportData() | |||
| void JackNetAdapter::DecodeTransportData() | |||
| { | |||
| //TODO : we need here to get the actual timebase master to eventually release it from its duty (see JackNetDriver) | |||
| @@ -288,11 +288,9 @@ namespace Jack | |||
| break; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| int JackNetAdapter::EncodeTransportData() | |||
| void JackNetAdapter::EncodeTransportData() | |||
| { | |||
| //is there a timebase master change ? | |||
| int refnum = -1; | |||
| @@ -326,8 +324,6 @@ namespace Jack | |||
| if ( fReturnTransportData.fNewState ) | |||
| jack_info ( "Sending transport state '%s'.", GetTransportState ( fReturnTransportData.fState ) ); | |||
| fLastTransportState = fReturnTransportData.fState; | |||
| return 0; | |||
| } | |||
| //read/write operations--------------------------------------------------------------- | |||
| @@ -338,17 +334,14 @@ namespace Jack | |||
| if ( SyncRecv() == SOCKET_ERROR ) | |||
| return 0; | |||
| if ( DecodeSyncPacket() < 0 ) | |||
| return 0; | |||
| DecodeSyncPacket(); | |||
| return DataRecv(); | |||
| } | |||
| int JackNetAdapter::Write() | |||
| { | |||
| if ( EncodeSyncPacket() < 0 ) | |||
| return 0; | |||
| EncodeSyncPacket(); | |||
| if ( SyncSend() == SOCKET_ERROR ) | |||
| return SOCKET_ERROR; | |||
| @@ -358,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------------------------------------------------------------------------------ | |||
| @@ -420,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; | |||
| @@ -494,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; | |||
| } | |||
| @@ -508,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 ) | |||
| @@ -48,8 +48,8 @@ namespace Jack | |||
| JackThread fThread; | |||
| //transport | |||
| int EncodeTransportData(); | |||
| int DecodeTransportData(); | |||
| void EncodeTransportData(); | |||
| void DecodeTransportData(); | |||
| public: | |||
| @@ -381,7 +381,7 @@ namespace Jack | |||
| } | |||
| //transport--------------------------------------------------------------------------- | |||
| int JackNetDriver::DecodeTransportData() | |||
| void JackNetDriver::DecodeTransportData() | |||
| { | |||
| //is there a new timebase master on the net master ? | |||
| // - release timebase master only if it's a non-conditional request | |||
| @@ -397,9 +397,10 @@ namespace Jack | |||
| jack_info ( "The NetMaster is now the new timebase master." ); | |||
| } | |||
| //is there a tranport state change to handle ? | |||
| //is there a transport state change to handle ? | |||
| if ( fSendTransportData.fNewState && ( fSendTransportData.fState != fEngineControl->fTransport.GetState() ) ) | |||
| { | |||
| switch ( fSendTransportData.fState ) | |||
| { | |||
| case JackTransportStopped : | |||
| @@ -419,11 +420,9 @@ namespace Jack | |||
| break; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| int JackNetDriver::EncodeTransportData() | |||
| void JackNetDriver::EncodeTransportData() | |||
| { | |||
| //is there a timebase master change ? | |||
| int refnum; | |||
| @@ -457,8 +456,6 @@ namespace Jack | |||
| if ( fReturnTransportData.fNewState ) | |||
| jack_info ( "Sending '%s'.", GetTransportState ( fReturnTransportData.fState ) ); | |||
| fLastTransportState = fReturnTransportData.fState; | |||
| return 0; | |||
| } | |||
| //driver processes-------------------------------------------------------------------- | |||
| @@ -486,9 +483,8 @@ 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 | |||
| if ( DecodeSyncPacket() < 0 ) | |||
| return 0; | |||
| DecodeSyncPacket(); | |||
| #ifdef JACK_MONITOR | |||
| fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - JackDriver::fBeginDateUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f ); | |||
| #endif | |||
| @@ -519,9 +515,8 @@ namespace Jack | |||
| #endif | |||
| //sync | |||
| if ( EncodeSyncPacket() < 0 ) | |||
| return 0; | |||
| EncodeSyncPacket(); | |||
| //send sync | |||
| if ( SyncSend() == SOCKET_ERROR ) | |||
| return SOCKET_ERROR; | |||
| @@ -57,8 +57,8 @@ namespace Jack | |||
| int FreePorts(); | |||
| //transport | |||
| int EncodeTransportData(); | |||
| int DecodeTransportData(); | |||
| void EncodeTransportData(); | |||
| void DecodeTransportData(); | |||
| JackMidiBuffer* GetMidiInputBuffer ( int port_index ); | |||
| JackMidiBuffer* GetMidiOutputBuffer ( int port_index ); | |||
| @@ -565,39 +565,35 @@ namespace Jack | |||
| return rx_bytes; | |||
| } | |||
| int JackNetMasterInterface::EncodeSyncPacket() | |||
| void JackNetMasterInterface::EncodeSyncPacket() | |||
| { | |||
| //this method contains every step of sync packet informations coding | |||
| //first of all, reset sync packet | |||
| memset ( fTxData, 0, fPayloadSize ); | |||
| //then, first step : transport | |||
| if ( fParams.fTransportSync ) | |||
| { | |||
| if ( EncodeTransportData() < 0 ) | |||
| return -1; | |||
| if (fParams.fTransportSync) { | |||
| EncodeTransportData(); | |||
| TransportDataHToN( &fSendTransportData, &fSendTransportData); | |||
| //copy to TxBuffer | |||
| memcpy ( fTxData, &fSendTransportData, sizeof ( net_transport_data_t ) ); | |||
| } | |||
| //then others (freewheel etc.) | |||
| //... | |||
| return 0; | |||
| } | |||
| int JackNetMasterInterface::DecodeSyncPacket() | |||
| void JackNetMasterInterface::DecodeSyncPacket() | |||
| { | |||
| //this method contains every step of sync packet informations decoding process | |||
| //first : transport | |||
| if ( fParams.fTransportSync ) | |||
| { | |||
| if (fParams.fTransportSync) { | |||
| //copy received transport data to transport data structure | |||
| memcpy ( &fReturnTransportData, fRxData, sizeof ( net_transport_data_t ) ); | |||
| if ( DecodeTransportData() < 0 ) | |||
| return -1; | |||
| TransportDataNToH( &fReturnTransportData, &fReturnTransportData); | |||
| DecodeTransportData(); | |||
| } | |||
| //then others | |||
| //... | |||
| return 0; | |||
| } | |||
| // JackNetSlaveInterface ************************************************************************************************ | |||
| @@ -955,38 +951,34 @@ namespace Jack | |||
| } | |||
| //network sync------------------------------------------------------------------------ | |||
| int JackNetSlaveInterface::DecodeSyncPacket() | |||
| { | |||
| //this method contains every step of sync packet informations decoding process | |||
| //first : transport | |||
| if ( fParams.fTransportSync ) | |||
| { | |||
| //copy received transport data to transport data structure | |||
| memcpy ( &fSendTransportData, fRxData, sizeof ( net_transport_data_t ) ); | |||
| if ( DecodeTransportData() < 0 ) | |||
| return -1; | |||
| } | |||
| //then others | |||
| //... | |||
| return 0; | |||
| } | |||
| int JackNetSlaveInterface::EncodeSyncPacket() | |||
| void JackNetSlaveInterface::EncodeSyncPacket() | |||
| { | |||
| //this method contains every step of sync packet informations coding | |||
| //first of all, reset sync packet | |||
| memset ( fTxData, 0, fPayloadSize ); | |||
| //then first step : transport | |||
| if ( fParams.fTransportSync ) | |||
| { | |||
| if ( EncodeTransportData() < 0 ) | |||
| return -1; | |||
| if (fParams.fTransportSync) { | |||
| EncodeTransportData(); | |||
| TransportDataHToN( &fReturnTransportData, &fReturnTransportData); | |||
| //copy to TxBuffer | |||
| memcpy ( fTxData, &fReturnTransportData, sizeof ( net_transport_data_t ) ); | |||
| } | |||
| //then others | |||
| //... | |||
| return 0; | |||
| } | |||
| void JackNetSlaveInterface::DecodeSyncPacket() | |||
| { | |||
| //this method contains every step of sync packet informations decoding process | |||
| //first : transport | |||
| if (fParams.fTransportSync) { | |||
| //copy received transport data to transport data structure | |||
| memcpy ( &fSendTransportData, fRxData, sizeof ( net_transport_data_t ) ); | |||
| TransportDataNToH( &fSendTransportData, &fSendTransportData); | |||
| DecodeTransportData(); | |||
| } | |||
| //then others | |||
| //... | |||
| } | |||
| } | |||
| @@ -73,12 +73,12 @@ namespace Jack | |||
| virtual bool Init() = 0; | |||
| //transport | |||
| virtual int EncodeTransportData() = 0; | |||
| virtual int DecodeTransportData() = 0; | |||
| virtual void EncodeTransportData() = 0; | |||
| virtual void DecodeTransportData() = 0; | |||
| //sync packet | |||
| virtual int EncodeSyncPacket() = 0; | |||
| virtual int DecodeSyncPacket() = 0; | |||
| virtual void EncodeSyncPacket() = 0; | |||
| virtual void DecodeSyncPacket() = 0; | |||
| virtual int SyncRecv() = 0; | |||
| virtual int SyncSend() = 0; | |||
| @@ -119,8 +119,8 @@ namespace Jack | |||
| int DataSend(); | |||
| //sync packet | |||
| int EncodeSyncPacket(); | |||
| int DecodeSyncPacket(); | |||
| void EncodeSyncPacket(); | |||
| void DecodeSyncPacket(); | |||
| int Send ( size_t size, int flags ); | |||
| int Recv ( size_t size, int flags ); | |||
| @@ -163,8 +163,8 @@ namespace Jack | |||
| int DataSend(); | |||
| //sync packet | |||
| int EncodeSyncPacket(); | |||
| int DecodeSyncPacket(); | |||
| void EncodeSyncPacket(); | |||
| void DecodeSyncPacket(); | |||
| int Recv ( size_t size, int flags ); | |||
| int Send ( size_t size, int flags ); | |||
| @@ -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() | |||
| { | |||
| @@ -245,7 +266,7 @@ namespace Jack | |||
| } | |||
| //transport--------------------------------------------------------------------------- | |||
| int JackNetMaster::EncodeTransportData() | |||
| void JackNetMaster::EncodeTransportData() | |||
| { | |||
| //is there a new timebase master ? | |||
| //TODO : check if any timebase callback has been called (and if it's conditional or not) and set correct value... | |||
| @@ -260,11 +281,9 @@ namespace Jack | |||
| if ( fSendTransportData.fNewState ) | |||
| jack_info ( "Sending '%s' to '%s'.", GetTransportState ( fSendTransportData.fState ), fParams.fName ); | |||
| fLastTransportState = fSendTransportData.fState; | |||
| } | |||
| return 0; | |||
| } | |||
| int JackNetMaster::DecodeTransportData() | |||
| void JackNetMaster::DecodeTransportData() | |||
| { | |||
| //is there timebase master change ? | |||
| if ( fReturnTransportData.fTimebaseMaster != NO_CHANGE ) | |||
| @@ -322,7 +341,6 @@ namespace Jack | |||
| break; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| void JackNetMaster::SetTimebaseCallback ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg ) | |||
| @@ -385,9 +403,8 @@ namespace Jack | |||
| if (IsSynched()) { // only send if connection is "synched" | |||
| //encode the first packet | |||
| if ( EncodeSyncPacket() < 0 ) | |||
| return 0; | |||
| EncodeSyncPacket(); | |||
| //send sync | |||
| if ( SyncSend() == SOCKET_ERROR ) | |||
| return SOCKET_ERROR; | |||
| @@ -418,9 +435,8 @@ namespace Jack | |||
| #endif | |||
| //decode sync | |||
| if ( DecodeSyncPacket() < 0 ) | |||
| return 0; | |||
| DecodeSyncPacket(); | |||
| //receive data | |||
| res = DataRecv(); | |||
| if ( ( res == 0 ) || ( res == SOCKET_ERROR ) ) | |||
| @@ -444,6 +460,7 @@ namespace Jack | |||
| fSocket.SetPort ( DEFAULT_PORT ); | |||
| fGlobalID = 0; | |||
| fRunning = true; | |||
| fAutoConnect = false; | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| @@ -458,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; | |||
| } | |||
| } | |||
| @@ -618,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; | |||
| @@ -679,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; | |||
| @@ -697,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,29 +53,28 @@ namespace Jack | |||
| //sync and transport | |||
| int fLastTransportState; | |||
| net_transport_data_t fSendTransportData; | |||
| net_transport_data_t fReturnTransportData; | |||
| //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(); | |||
| //transport | |||
| int EncodeTransportData(); | |||
| int DecodeTransportData(); | |||
| void EncodeTransportData(); | |||
| void DecodeTransportData(); | |||
| 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(); | |||
| @@ -103,6 +102,7 @@ namespace Jack | |||
| master_list_t fMasterList; | |||
| uint32_t fGlobalID; | |||
| bool fRunning; | |||
| bool fAutoConnect; | |||
| void Run(); | |||
| JackNetMaster* MasterInit ( session_params_t& params ); | |||
| @@ -112,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(); | |||
| }; | |||
| } | |||
| @@ -377,6 +377,15 @@ namespace Jack | |||
| jack_info ( "**********************************************" ); | |||
| } | |||
| SERVER_EXPORT void NetTransportDataDisplay ( net_transport_data_t* data ) | |||
| { | |||
| jack_info ( "********************Network Transport********************" ); | |||
| jack_info ( "Transport new state : %u", data->fNewState ); | |||
| jack_info ( "Transport timebase master : %u", data->fTimebaseMaster ); | |||
| jack_info ( "Transport cycle state : %u", data->fState ); | |||
| jack_info ( "**********************************************" ); | |||
| } | |||
| SERVER_EXPORT void MidiBufferHToN ( JackMidiBuffer* src_buffer, JackMidiBuffer* dst_buffer ) | |||
| { | |||
| dst_buffer->magic = htonl(src_buffer->magic); | |||
| @@ -398,6 +407,56 @@ namespace Jack | |||
| dst_buffer->lost_events = ntohl(src_buffer->lost_events); | |||
| dst_buffer->mix_index = ntohl(src_buffer->mix_index); | |||
| } | |||
| SERVER_EXPORT void TransportDataHToN ( net_transport_data_t* src_params, net_transport_data_t* dst_params ) | |||
| { | |||
| dst_params->fNewState = htonl(src_params->fNewState); | |||
| dst_params->fTimebaseMaster = htonl(src_params->fTimebaseMaster); | |||
| dst_params->fState = htonl(src_params->fState); | |||
| dst_params->fPosition.unique_1 = htonll(src_params->fPosition.unique_1); | |||
| dst_params->fPosition.usecs = htonl(src_params->fPosition.usecs); | |||
| dst_params->fPosition.frame_rate = htonl(src_params->fPosition.frame_rate); | |||
| dst_params->fPosition.frame = htonl(src_params->fPosition.frame); | |||
| dst_params->fPosition.bar = htonl(src_params->fPosition.bar); | |||
| dst_params->fPosition.beat = htonl(src_params->fPosition.beat); | |||
| dst_params->fPosition.tick = htonl(src_params->fPosition.tick); | |||
| dst_params->fPosition.bar_start_tick = htonll((uint64_t)src_params->fPosition.bar_start_tick); | |||
| dst_params->fPosition.beats_per_bar = htonl(src_params->fPosition.beats_per_bar); | |||
| dst_params->fPosition.beat_type = htonl(src_params->fPosition.beat_type); | |||
| dst_params->fPosition.ticks_per_beat = htonll((uint64_t)src_params->fPosition.ticks_per_beat); | |||
| dst_params->fPosition.beats_per_minute = htonll((uint64_t)src_params->fPosition.beats_per_minute); | |||
| dst_params->fPosition.frame_time = htonll((uint64_t)src_params->fPosition.frame_time); | |||
| dst_params->fPosition.next_time = htonll((uint64_t)src_params->fPosition.next_time); | |||
| dst_params->fPosition.bbt_offset = htonl(src_params->fPosition.bbt_offset); | |||
| dst_params->fPosition.audio_frames_per_video_frame = htonl(src_params->fPosition.audio_frames_per_video_frame); | |||
| dst_params->fPosition.video_offset = htonl(src_params->fPosition.video_offset); | |||
| dst_params->fPosition.unique_2 = htonll(src_params->fPosition.unique_2); | |||
| } | |||
| SERVER_EXPORT void TransportDataNToH ( net_transport_data_t* src_params, net_transport_data_t* dst_params ) | |||
| { | |||
| dst_params->fNewState = ntohl(src_params->fNewState); | |||
| dst_params->fTimebaseMaster = ntohl(src_params->fTimebaseMaster); | |||
| dst_params->fState = ntohl(src_params->fState); | |||
| dst_params->fPosition.unique_1 = ntohll(src_params->fPosition.unique_1); | |||
| dst_params->fPosition.usecs = ntohl(src_params->fPosition.usecs); | |||
| dst_params->fPosition.frame_rate = ntohl(src_params->fPosition.frame_rate); | |||
| dst_params->fPosition.frame = ntohl(src_params->fPosition.frame); | |||
| dst_params->fPosition.bar = ntohl(src_params->fPosition.bar); | |||
| dst_params->fPosition.beat = ntohl(src_params->fPosition.beat); | |||
| dst_params->fPosition.tick = ntohl(src_params->fPosition.tick); | |||
| dst_params->fPosition.bar_start_tick = ntohll((uint64_t)src_params->fPosition.bar_start_tick); | |||
| dst_params->fPosition.beats_per_bar = ntohl(src_params->fPosition.beats_per_bar); | |||
| dst_params->fPosition.beat_type = ntohl(src_params->fPosition.beat_type); | |||
| dst_params->fPosition.ticks_per_beat = ntohll((uint64_t)src_params->fPosition.ticks_per_beat); | |||
| dst_params->fPosition.beats_per_minute = ntohll((uint64_t)src_params->fPosition.beats_per_minute); | |||
| dst_params->fPosition.frame_time = ntohll((uint64_t)src_params->fPosition.frame_time); | |||
| dst_params->fPosition.next_time = ntohll((uint64_t)src_params->fPosition.next_time); | |||
| dst_params->fPosition.bbt_offset = ntohl(src_params->fPosition.bbt_offset); | |||
| dst_params->fPosition.audio_frames_per_video_frame = ntohl(src_params->fPosition.audio_frames_per_video_frame); | |||
| dst_params->fPosition.video_offset = ntohl(src_params->fPosition.video_offset); | |||
| dst_params->fPosition.unique_2 = ntohll(src_params->fPosition.unique_2); | |||
| } | |||
| // Utility ******************************************************************************************************* | |||
| @@ -29,6 +29,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| using namespace std; | |||
| #ifndef htonll | |||
| #ifdef __BIG_ENDIAN__ | |||
| #define htonll(x) (x) | |||
| #define ntohll(x) (x) | |||
| #else | |||
| #define htonll(x) ((((uint64_t)htonl(x)) << 32) + htonl(x >> 32)) | |||
| #define ntohll(x) ((((uint64_t)ntohl(x)) << 32) + ntohl(x >> 32)) | |||
| #endif | |||
| #endif | |||
| namespace Jack | |||
| { | |||
| typedef struct _session_params session_params_t; | |||
| @@ -282,6 +292,8 @@ namespace Jack | |||
| SERVER_EXPORT void PacketHeaderNToH ( packet_header_t* src_header, packet_header_t* dst_header ); | |||
| SERVER_EXPORT void MidiBufferHToN ( JackMidiBuffer* src_buffer, JackMidiBuffer* dst_buffer ); | |||
| SERVER_EXPORT void MidiBufferNToH ( JackMidiBuffer* src_buffer, JackMidiBuffer* dst_buffer ); | |||
| SERVER_EXPORT void TransportDataHToN ( net_transport_data_t* src_params, net_transport_data_t* dst_params ); | |||
| SERVER_EXPORT void TransportDataNToH ( net_transport_data_t* src_params, net_transport_data_t* dst_params ); | |||
| //display session parameters | |||
| SERVER_EXPORT void SessionParamsDisplay ( session_params_t* params ); | |||
| //display packet header | |||
| @@ -292,4 +304,5 @@ namespace Jack | |||
| SERVER_EXPORT int SetPacketType ( session_params_t* params, sync_packet_type_t packet_type ); | |||
| //transport utility | |||
| SERVER_EXPORT const char* GetTransportState ( int transport_state ); | |||
| SERVER_EXPORT void NetTransportDataDisplay ( net_transport_data_t* data ); | |||
| } | |||
| @@ -218,7 +218,7 @@ extern "C" | |||
| strcpy(desc->params[i].name, "cpu-load"); | |||
| desc->params[i].character = 'c'; | |||
| desc->params[i].type = JackDriverParamBool; | |||
| desc->params[i].value.i = TRUE; | |||
| desc->params[i].value.i = FALSE; | |||
| strcpy(desc->params[i].short_desc, "Show DSP CPU load"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| @@ -226,7 +226,7 @@ extern "C" | |||
| strcpy(desc->params[i].name, "driver-period"); | |||
| desc->params[i].character = 'p'; | |||
| desc->params[i].type = JackDriverParamBool; | |||
| desc->params[i].value.i = TRUE; | |||
| desc->params[i].value.i = FALSE; | |||
| strcpy(desc->params[i].short_desc, "Show driver period"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| @@ -234,7 +234,7 @@ extern "C" | |||
| strcpy(desc->params[i].name, "driver-end-time"); | |||
| desc->params[i].character = 'e'; | |||
| desc->params[i].type = JackDriverParamBool; | |||
| desc->params[i].value.i = TRUE; | |||
| desc->params[i].value.i = FALSE; | |||
| strcpy(desc->params[i].short_desc, "Show driver end time"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| @@ -223,34 +223,7 @@ void JackOSSDriver::DisplayDeviceInfo() | |||
| if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); | |||
| } | |||
| } | |||
| /* | |||
| TODO | |||
| ai_in.dev = fInFD; | |||
| jack_log("JackOSSDriver::DisplayDeviceInfo input fInFD = %d", ai_in.dev); | |||
| if (ioctl(fInFD, SNDCTL_AUDIOINFO, &ai_in) != -1) { | |||
| jack_info("Using audio engine %d = %s for input", ai_in.dev, ai_in.name); | |||
| if (ai_in.iformats & AFMT_S24_NE) | |||
| jack_info("Available input format : AFMT_S24_NE"); | |||
| if (ai_in.iformats & AFMT_S16_NE) | |||
| jack_info("Available input format : AFMT_S16_NE"); | |||
| if (ai_in.iformats & AFMT_S32_NE) | |||
| jack_info("Available input format : AFMT_S32_NE"); | |||
| } | |||
| ai_out.dev = fOutFD; | |||
| jack_log("JackOSSDriver::DisplayDeviceInfo output fOutFD = %d", ai_out.dev); | |||
| if (ioctl(fOutFD, SNDCTL_AUDIOINFO, &ai_out) != -1) { | |||
| jack_info("Using audio engine %d = %s for output", ai_out.dev, ai_out.name); | |||
| if (ai_out.oformats & AFMT_S24_NE) | |||
| jack_info("Available output format : AFMT_S24_NE"); | |||
| if (ai_out.oformats & AFMT_S16_NE) | |||
| jack_info("Available output format : AFMT_S16_NE"); | |||
| if (ai_out.oformats & AFMT_S32_NE) | |||
| jack_info("Available output format : AFMT_S32_NE"); | |||
| } | |||
| */ | |||
| if (ai_in.rate_source != ai_out.rate_source) { | |||
| jack_info("Warning : input and output are not necessarily driven by the same clock!"); | |||
| } | |||
| @@ -541,7 +514,7 @@ int JackOSSDriver::OpenAux() | |||
| // In duplex mode, check that input and output use the same buffer size | |||
| /* | |||
| // 10/02/09 : desactivated for now, needs more check (only needed when *same* device is used for input and output ??) | |||
| 10/02/09 : desactivated for now, needs more check (only needed when *same* device is used for input and output ??) | |||
| if ((fRWMode & kRead) && (fRWMode & kWrite) && (fInputBufferSize != fOutputBufferSize)) { | |||
| jack_error("JackOSSDriver::OpenAux input and output buffer size are not the same!!"); | |||
| @@ -583,32 +556,6 @@ int JackOSSDriver::Read() | |||
| } | |||
| ssize_t count; | |||
| /* | |||
| // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html | |||
| if (fFirstCycle) { | |||
| fFirstCycle = false; | |||
| memset(fOutputBuffer, 0, fOutputBufferSize); | |||
| // Prefill ouput buffer | |||
| for (int i = 0; i < fNperiods; i++) { | |||
| count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize); | |||
| if (count < fOutputBufferSize) { | |||
| jack_error("JackOSSDriver::Write error bytes written = %ld", count); | |||
| return -1; | |||
| } | |||
| } | |||
| int delay; | |||
| if (ioctl(fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) { | |||
| jack_error("JackOSSDriver::Write error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno); | |||
| return -1; | |||
| } | |||
| delay /= fSampleSize * fPlaybackChannels; | |||
| jack_info("JackOSSDriver::Write output latency frames = %ld", delay); | |||
| } | |||
| */ | |||
| #ifdef JACK_MONITOR | |||
| gCycleTable.fTable[gCycleCount].fBeforeRead = GetMicroSeconds(); | |||
| @@ -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'. | |||
| @@ -66,8 +66,8 @@ | |||
| <_><src>..\Release\bin\jack_metro.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\jack_unload.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\jackd.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\libjack.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\libjackserver.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\libjack.dll</><dest>sys</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\libjackserver.dll</><dest>sys</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\libsamplerate-0.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\portaudio_x86.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></> | |||
| <_><src>..\Release\bin\jack\jack_net.dll</><dest>inst</><custom>jack</><ifexist>overnewer</><recurs>0</></> | |||
| @@ -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) | |||
| @@ -65,9 +65,9 @@ def set_options(opt): | |||
| opt.add_option('--doxygen', action='store_true', default=False, help='Enable build of doxygen documentation') | |||
| opt.add_option('--profile', action='store_true', default=False, help='Build with engine profiling') | |||
| opt.add_option('--clients', default=64, type="int", dest="clients", help='Maximum number of JACK clients') | |||
| opt.add_option('--ports', default=512, type="int", dest="ports", help='Maximum number of ports') | |||
| opt.add_option('--ports', default=1024, type="int", dest="ports", help='Maximum number of ports') | |||
| opt.add_option('--clients', default=64, type="int", dest="clients", help='Maximum number of JACK clients') | |||
| opt.add_option('--ports', default=512, type="int", dest="ports", help='Maximum number of ports') | |||
| opt.add_option('--ports', default=1024, type="int", dest="ports", help='Maximum number of ports') | |||
| opt.sub_options('dbus') | |||
| def configure(conf): | |||