Jack2  1.9.8
JackDebugClient.cpp
1 /*
2 Copyright (C) 2004-2008 Grame
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13 
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 */
19 
20 #include "JackDebugClient.h"
21 #include "JackEngineControl.h"
22 #include "JackException.h"
23 #include "JackError.h"
24 #include "JackTime.h"
25 #include <iostream>
26 #include <iomanip>
27 #include <sstream>
28 #include <fstream>
29 #include <string>
30 #include <time.h>
31 
32 using namespace std;
33 
34 namespace Jack
35 {
36 
37 JackDebugClient::JackDebugClient(JackClient * client)
38 {
39  fTotalPortNumber = 1; // The total number of port opened and maybe closed. Historical view.
40  fOpenPortNumber = 0; // The current number of opened port.
41  fIsActivated = 0;
42  fIsDeactivated = 0;
43  fIsClosed = 0;
44  fClient = client;
45  fFreewheel = false;
46 }
47 
48 JackDebugClient::~JackDebugClient()
49 {
50  fTotalPortNumber--; // fTotalPortNumber start at 1
51  *fStream << endl << endl << "----------------------------------- JackDebugClient summary ------------------------------- " << endl << endl;
52  *fStream << "Client flags ( 1:yes / 0:no ) :" << endl;
53  *fStream << setw(5) << "- Client call activated : " << fIsActivated << endl;
54  *fStream << setw(5) << "- Client call deactivated : " << fIsDeactivated << endl;
55  *fStream << setw(5) << "- Client call closed : " << fIsClosed << endl;
56  *fStream << setw(5) << "- Total number of instantiated port : " << fTotalPortNumber << endl;
57  *fStream << setw(5) << "- Number of port remaining open when exiting client : " << fOpenPortNumber << endl;
58  if (fOpenPortNumber != 0)
59  *fStream << "!!! WARNING !!! Some ports have not been unregistered ! Incorrect exiting !" << endl;
60  if (fIsDeactivated != fIsActivated)
61  *fStream << "!!! ERROR !!! Client seem to not perform symetric activation-deactivation ! (not the same number of activate and deactivate)" << endl;
62  if (fIsClosed == 0)
63  *fStream << "!!! ERROR !!! Client have not been closed with jack_client_close() !" << endl;
64 
65  *fStream << endl << endl << "---------------------------- JackDebugClient detailed port summary ------------------------ " << endl << endl;
66  //for (int i = 0; i < fTotalPortNumber ; i++) {
67  for (int i = 1; i <= fTotalPortNumber ; i++) {
68  *fStream << endl << "Port index (internal debug test value) : " << i << endl;
69  *fStream << setw(5) << "- Name : " << fPortList[i].name << endl;
70  *fStream << setw(5) << "- idport : " << fPortList[i].idport << endl;
71  *fStream << setw(5) << "- IsConnected : " << fPortList[i].IsConnected << endl;
72  *fStream << setw(5) << "- IsUnregistered : " << fPortList[i].IsUnregistered << endl;
73  if (fPortList[i].IsUnregistered == 0)
74  *fStream << "!!! WARNING !!! Port have not been unregistered ! Incorrect exiting !" << endl;
75  }
76  *fStream << "delete object JackDebugClient : end of tracing" << endl;
77  delete fStream;
78  delete fClient;
79 }
80 
81 int JackDebugClient::Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status)
82 {
83  int res = fClient->Open(server_name, name, uuid, options, status);
84  char provstr[256];
85  char buffer[256];
86  time_t curtime;
87  struct tm *loctime;
88  /* Get the current time. */
89  curtime = time (NULL);
90  /* Convert it to local time representation. */
91  loctime = localtime (&curtime);
92  strftime (buffer, 256, "%I-%M", loctime);
93  snprintf(provstr, sizeof(provstr), "JackClientDebug-%s-%s.log", name, buffer);
94  fStream = new ofstream(provstr, ios_base::ate);
95  if (fStream->is_open()) {
96  if (res == -1) {
97  *fStream << "Trying to open client with name '" << name << "' with bad result (client not opened)." << res << endl;
98  } else {
99  *fStream << "Open client with name '" << name << "'." << endl;
100  }
101  } else {
102  jack_log("JackDebugClient::Open : cannot open log file");
103  }
104  strcpy(fClientName, name);
105  return res;
106 }
107 
108 int JackDebugClient::Close()
109 {
110  *fStream << "Client '" << fClientName << "' was closed" << endl;
111  int res = fClient->Close();
112  fIsClosed++;
113  return res;
114 }
115 
116 void JackDebugClient::CheckClient(const char* function_name) const
117 {
118  *fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl;
119 
120  if (fIsClosed > 0) {
121  *fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl;
122  *fStream << "This is likely to cause crash !'" << endl;
123  #ifdef __APPLE__
124  // Debugger();
125  #endif
126  }
127 }
128 
129 jack_native_thread_t JackDebugClient::GetThreadID()
130 {
131  CheckClient("GetThreadID");
132  return fClient->GetThreadID();
133 }
134 
135 JackGraphManager* JackDebugClient::GetGraphManager() const
136 {
137  CheckClient("GetGraphManager");
138  return fClient->GetGraphManager();
139 }
140 JackEngineControl* JackDebugClient::GetEngineControl() const
141 {
142  CheckClient("GetEngineControl");
143  return fClient->GetEngineControl();
144 }
149 int JackDebugClient::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
150 {
151  CheckClient("ClientNotify");
152  return fClient->ClientNotify( refnum, name, notify, sync, message, value1, value2);
153 }
154 
155 int JackDebugClient::Activate()
156 {
157  CheckClient("Activate");
158  int res = fClient->Activate();
159  fIsActivated++;
160  if (fIsDeactivated)
161  *fStream << "Client '" << fClientName << "' call activate a new time (it already call 'activate' previously)." << endl;
162  *fStream << "Client '" << fClientName << "' Activated" << endl;
163  if (res != 0)
164  *fStream << "Client '" << fClientName << "' try to activate but server return " << res << " ." << endl;
165  return res;
166 }
167 
168 int JackDebugClient::Deactivate()
169 {
170  CheckClient("Deactivate");
171  int res = fClient->Deactivate();
172  fIsDeactivated++;
173  if (fIsActivated == 0)
174  *fStream << "Client '" << fClientName << "' deactivate while it hasn't been previoulsy activated !" << endl;
175  *fStream << "Client '" << fClientName << "' Deactivated" << endl;
176  if (res != 0)
177  *fStream << "Client '" << fClientName << "' try to deactivate but server return " << res << " ." << endl;
178  return res;
179 }
180 
181 //-----------------
182 // Port management
183 //-----------------
184 
185 int JackDebugClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
186 {
187  CheckClient("PortRegister");
188  int res = fClient->PortRegister(port_name, port_type, flags, buffer_size);
189  if (res <= 0) {
190  *fStream << "Client '" << fClientName << "' try port register ('" << port_name << "') and server return error " << res << " ." << endl;
191  } else {
192  if (fTotalPortNumber < MAX_PORT_HISTORY) {
193  fPortList[fTotalPortNumber].idport = res;
194  strcpy(fPortList[fTotalPortNumber].name, port_name);
195  fPortList[fTotalPortNumber].IsConnected = 0;
196  fPortList[fTotalPortNumber].IsUnregistered = 0;
197  } else {
198  *fStream << "!!! WARNING !!! History is full : no more port history will be recorded." << endl;
199  }
200  fTotalPortNumber++;
201  fOpenPortNumber++;
202  *fStream << "Client '" << fClientName << "' port register with portname '" << port_name << " port " << res << "' ." << endl;
203  }
204  return res;
205 }
206 
207 int JackDebugClient::PortUnRegister(jack_port_id_t port_index)
208 {
209  CheckClient("PortUnRegister");
210  int res = fClient->PortUnRegister(port_index);
211  fOpenPortNumber--;
212  int i;
213  for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
214  if (fPortList[i].idport == port_index) { // We found the last record
215  if (fPortList[i].IsUnregistered != 0)
216  *fStream << "!!! ERROR !!! : '" << fClientName << "' id deregistering port '" << fPortList[i].name << "' that have already been unregistered !" << endl;
217  fPortList[i].IsUnregistered++;
218  break;
219  }
220  }
221  if (i == 0) // Port is not found
222  *fStream << "JackClientDebug : PortUnregister : port " << port_index << " was not previously registered !" << endl;
223  if (res != 0)
224  *fStream << "Client '" << fClientName << "' try to do PortUnregister and server return " << res << endl;
225  *fStream << "Client '" << fClientName << "' unregister port '" << port_index << "'." << endl;
226  return res;
227 }
228 
229 int JackDebugClient::PortConnect(const char* src, const char* dst)
230 {
231  CheckClient("PortConnect");
232  if (!fIsActivated)
233  *fStream << "!!! ERROR !!! Trying to connect a port ( " << src << " to " << dst << ") while the client has not been activated !" << endl;
234  int i;
235  int res = fClient->PortConnect( src, dst);
236  for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
237  if (strcmp(fPortList[i].name, src) == 0) { // We found the last record in sources
238  if (fPortList[i].IsUnregistered != 0)
239  *fStream << "!!! ERROR !!! Connecting port " << src << " previoulsy unregistered !" << endl;
240  fPortList[i].IsConnected++;
241  *fStream << "Connecting port " << src << " to " << dst << ". ";
242  break;
243  } else if (strcmp(fPortList[i].name, dst) == 0 ) { // We found the record in dest
244  if (fPortList[i].IsUnregistered != 0)
245  *fStream << "!!! ERROR !!! Connecting port " << dst << " previoulsy unregistered !" << endl;
246  fPortList[i].IsConnected++;
247  *fStream << "Connecting port " << src << " to " << dst << ". ";
248  break;
249  }
250  }
251  if (i == 0) // Port is not found
252  *fStream << "JackClientDebug : PortConnect : port was not found in debug database !" << endl;
253  if (res != 0)
254  *fStream << "Client '" << fClientName << "' try to do PortConnect but server return " << res << " ." << endl;
255  //*fStream << "Client Port Connect done with names" << endl;
256  return res;
257 }
258 
259 int JackDebugClient::PortDisconnect(const char* src, const char* dst)
260 {
261  CheckClient("PortDisconnect");
262  if (!fIsActivated)
263  *fStream << "!!! ERROR !!! Trying to disconnect a port ( " << src << " to " << dst << ") while the client has not been activated !" << endl;
264  int res = fClient->PortDisconnect( src, dst);
265  int i;
266  for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
267  if (strcmp(fPortList[i].name, src) == 0) { // We found the record in sources
268  if (fPortList[i].IsUnregistered != 0)
269  *fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl;
270  fPortList[i].IsConnected--;
271  *fStream << "disconnecting port " << src << ". ";
272  break;
273  } else if (strcmp(fPortList[i].name, dst) == 0 ) { // We found the record in dest
274  if (fPortList[i].IsUnregistered != 0)
275  *fStream << "!!! ERROR !!! : Disonnecting port " << dst << " previoulsy unregistered !" << endl;
276  fPortList[i].IsConnected--;
277  *fStream << "disconnecting port " << dst << ". ";
278  break;
279  }
280  }
281  if (i == 0) // Port is not found
282  *fStream << "JackClientDebug : PortDisConnect : port was not found in debug database !" << endl;
283  if (res != 0)
284  *fStream << "Client '" << fClientName << "' try to do PortDisconnect but server return " << res << " ." << endl;
285  //*fStream << "Client Port Disconnect done." << endl;
286  return res;
287 }
288 
289 int JackDebugClient::PortDisconnect(jack_port_id_t src)
290 {
291  CheckClient("PortDisconnect");
292  if (!fIsActivated)
293  *fStream << "!!! ERROR !!! : Trying to disconnect port " << src << " while that client has not been activated !" << endl;
294  int res = fClient->PortDisconnect(src);
295  int i;
296  for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
297  if (fPortList[i].idport == src) { // We found the record in sources
298  if (fPortList[i].IsUnregistered != 0)
299  *fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl;
300  fPortList[i].IsConnected--;
301  *fStream << "Disconnecting port " << src << ". " << endl;
302  break;
303  }
304  }
305  if (i == 0) // Port is not found
306  *fStream << "JackClientDebug : PortDisconnect : port was not found in debug database !" << endl;
307  if (res != 0)
308  *fStream << "Client '" << fClientName << "' try to do PortDisconnect but server return " << res << " ." << endl;
309  //*fStream << "Client Port Disconnect with ID done." << endl;
310  return res;
311 }
312 
313 int JackDebugClient::PortIsMine(jack_port_id_t port_index)
314 {
315  CheckClient("PortIsMine");
316  return fClient->PortIsMine(port_index);
317 }
318 
319 //--------------------
320 // Context management
321 //--------------------
322 
323 int JackDebugClient::SetBufferSize(jack_nframes_t buffer_size)
324 {
325  CheckClient("SetBufferSize");
326  return fClient->SetBufferSize(buffer_size);
327 }
328 
329 int JackDebugClient::SetFreeWheel(int onoff)
330 {
331  CheckClient("SetFreeWheel");
332  if (onoff && fFreewheel)
333  *fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = ON while FW is already ON " << endl;
334  if (!onoff && !fFreewheel)
335  *fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = OFF while FW is already OFF " << endl;
336  fFreewheel = onoff ? true : false;
337  return fClient->SetFreeWheel(onoff);
338 }
339 
340 /*
341 ShutDown is called:
342 - from the RT thread when Execute method fails
343 - possibly from a "closed" notification channel
344 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
345 */
346 
347 void JackDebugClient::ShutDown()
348 {
349  fClient->ShutDown();
350 }
351 
352 //---------------------
353 // Transport management
354 //---------------------
355 
356 int JackDebugClient::ReleaseTimebase()
357 {
358  CheckClient("ReleaseTimebase");
359  return fClient->ReleaseTimebase();
360 }
361 
362 int JackDebugClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg)
363 {
364  CheckClient("SetSyncCallback");
365  return fClient->SetSyncCallback(sync_callback, arg);
366 }
367 
368 int JackDebugClient::SetSyncTimeout(jack_time_t timeout)
369 {
370  CheckClient("SetSyncTimeout");
371  return fClient->SetSyncTimeout(timeout);
372 }
373 
374 int JackDebugClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg)
375 {
376  CheckClient("SetTimebaseCallback");
377  return fClient->SetTimebaseCallback( conditional, timebase_callback, arg);
378 }
379 
380 void JackDebugClient::TransportLocate(jack_nframes_t frame)
381 {
382  CheckClient("TransportLocate");
383  fClient->TransportLocate(frame);
384 }
385 
386 jack_transport_state_t JackDebugClient::TransportQuery(jack_position_t* pos)
387 {
388  CheckClient("TransportQuery");
389  return fClient->TransportQuery(pos);
390 }
391 
392 jack_nframes_t JackDebugClient::GetCurrentTransportFrame()
393 {
394  CheckClient("GetCurrentTransportFrame");
395  return fClient->GetCurrentTransportFrame();
396 }
397 
398 int JackDebugClient::TransportReposition(jack_position_t* pos)
399 {
400  CheckClient("TransportReposition");
401  return fClient->TransportReposition(pos);
402 }
403 
404 void JackDebugClient::TransportStart()
405 {
406  CheckClient("TransportStart");
407  fClient->TransportStart();
408 }
409 
410 void JackDebugClient::TransportStop()
411 {
412  CheckClient("TransportStop");
413  fClient->TransportStop();
414 }
415 
416 //---------------------
417 // Callback management
418 //---------------------
419 
420 void JackDebugClient::OnShutdown(JackShutdownCallback callback, void *arg)
421 {
422  CheckClient("OnShutdown");
423  fClient->OnShutdown(callback, arg);
424 }
425 
426 void JackDebugClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg)
427 {
428  CheckClient("OnInfoShutdown");
429  fClient->OnInfoShutdown(callback, arg);
430 }
431 
432 int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg)
433 {
434  JackDebugClient* client = (JackDebugClient*)arg;
435  jack_time_t t1 = GetMicroSeconds();
436  int res = client->fProcessTimeCallback(nframes, client->fProcessTimeCallbackArg);
437  if (res == 0) {
438  jack_time_t t2 = GetMicroSeconds();
439  long delta = long((t2 - t1) - client->GetEngineControl()->fPeriodUsecs);
440  if (delta > 0 && !client->fFreewheel)
441  *client->fStream << "!!! ERROR !!! : Process overload of " << delta << " us" << endl;
442  }
443  return res;
444 }
445 
446 int JackDebugClient::SetProcessCallback(JackProcessCallback callback, void *arg)
447 {
448  CheckClient("SetProcessCallback");
449  fProcessTimeCallback = callback;
450  fProcessTimeCallbackArg = arg;
451  return fClient->SetProcessCallback(TimeCallback, this);
452 }
453 
454 int JackDebugClient::SetXRunCallback(JackXRunCallback callback, void *arg)
455 {
456  CheckClient("SetXRunCallback");
457  return fClient->SetXRunCallback(callback, arg);
458 }
459 
460 int JackDebugClient::SetInitCallback(JackThreadInitCallback callback, void *arg)
461 {
462  CheckClient("SetInitCallback");
463  return fClient->SetInitCallback(callback, arg);
464 }
465 
466 int JackDebugClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
467 {
468  CheckClient("SetGraphOrderCallback");
469  return fClient->SetGraphOrderCallback(callback, arg);
470 }
471 
472 int JackDebugClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg)
473 {
474  CheckClient("SetBufferSizeCallback");
475  return fClient->SetBufferSizeCallback(callback, arg);
476 }
477 
478 int JackDebugClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback, void* arg)
479 {
480  CheckClient("SetClientRegistrationCallback");
481  return fClient->SetClientRegistrationCallback(callback, arg);
482 }
483 
484 int JackDebugClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg)
485 {
486  CheckClient("SetFreewheelCallback");
487  return fClient->SetFreewheelCallback(callback, arg);
488 }
489 
490 int JackDebugClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg)
491 {
492  CheckClient("SetPortRegistrationCallback");
493  return fClient->SetPortRegistrationCallback(callback, arg);
494 }
495 
496 int JackDebugClient::SetPortConnectCallback(JackPortConnectCallback callback, void *arg)
497 {
498  CheckClient("SetPortConnectCallback");
499  return fClient->SetPortConnectCallback(callback, arg);
500 }
501 
502 int JackDebugClient::SetPortRenameCallback(JackPortRenameCallback callback, void *arg)
503 {
504  CheckClient("SetPortRenameCallback");
505  return fClient->SetPortRenameCallback(callback, arg);
506 }
507 
508 int JackDebugClient::SetSessionCallback(JackSessionCallback callback, void *arg)
509 {
510  CheckClient("SetSessionCallback");
511  return fClient->SetSessionCallback(callback, arg);
512 }
513 
514 int JackDebugClient::SetLatencyCallback(JackLatencyCallback callback, void *arg)
515 {
516  CheckClient("SetLatencyCallback");
517  return fClient->SetLatencyCallback(callback, arg);
518 }
519 
520 jack_session_command_t* JackDebugClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path)
521 {
522  CheckClient("SessionNotify");
523  return fClient->SessionNotify(target, type, path);
524 }
525 
526 int JackDebugClient::SessionReply(jack_session_event_t* ev)
527 {
528  CheckClient("SessionReply");
529  return fClient->SessionReply(ev);
530 }
531 
532 char* JackDebugClient::GetUUIDForClientName(const char* client_name)
533 {
534  CheckClient("GetUUIDForClientName");
535  return fClient->GetUUIDForClientName(client_name);
536 }
537 
538 char* JackDebugClient::GetClientNameByUUID(const char* uuid)
539 {
540  CheckClient("GetClientNameByUUID");
541  return fClient->GetClientNameByUUID(uuid);
542 }
543 
544 int JackDebugClient::ReserveClientName(const char* client_name, const char* uuid)
545 {
546  CheckClient("ReserveClientName");
547  return fClient->ReserveClientName(client_name, uuid);
548 }
549 
550 int JackDebugClient::ClientHasSessionCallback(const char* client_name)
551 {
552  CheckClient("ClientHasSessionCallback");
553  return fClient->ClientHasSessionCallback(client_name);
554 }
555 
556 JackClientControl* JackDebugClient::GetClientControl() const
557 {
558  CheckClient("GetClientControl");
559  return fClient->GetClientControl();
560 }
561 
562 // Internal clients
563 char* JackDebugClient::GetInternalClientName(int ref)
564 {
565  CheckClient("GetInternalClientName");
566  return fClient->GetInternalClientName(ref);
567 }
568 
569 int JackDebugClient::InternalClientHandle(const char* client_name, jack_status_t* status)
570 {
571  CheckClient("InternalClientHandle");
572  return fClient->InternalClientHandle(client_name, status);
573 }
574 
575 int JackDebugClient::InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va)
576 {
577  CheckClient("InternalClientLoad");
578  return fClient->InternalClientLoad(client_name, options, status, va);
579 }
580 
581 void JackDebugClient::InternalClientUnload(int ref, jack_status_t* status)
582 {
583  CheckClient("InternalClientUnload");
584  fClient->InternalClientUnload(ref, status);
585 }
586 
587 } // end of namespace
588