merge new MTDM code from Fons' latest release.
[jack2.git] / common / JackDebugClient.cpp
blobe5efa7da15976b4b1c7e2a7946d30719d16ce624
1 /*
2 Copyright (C) 2004-2008 Grame
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.
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.
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.
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>
32 using namespace std;
34 namespace Jack
37 JackDebugClient::JackDebugClient(JackClient * client)
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;
48 JackDebugClient::~JackDebugClient()
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;
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;
76 *fStream << "delete object JackDebugClient : end of tracing" << endl;
77 delete fStream;
78 delete fClient;
81 int JackDebugClient::Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status)
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;
101 } else {
102 jack_log("JackDebugClient::Open : cannot open log file");
104 strcpy(fClientName, name);
105 return res;
108 int JackDebugClient::Close()
110 *fStream << "Client '" << fClientName << "' was closed" << endl;
111 int res = fClient->Close();
112 fIsClosed++;
113 return res;
116 void JackDebugClient::CheckClient(const char* function_name) const
118 #ifdef WIN32
119 *fStream << "CheckClient : " << function_name << ", calling thread : " << GetCurrentThread() << endl;
120 #else
121 *fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl;
122 #endif
124 if (fIsClosed > 0) {
125 *fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl;
126 *fStream << "This is likely to cause crash !'" << endl;
127 #ifdef __APPLE__
128 // Debugger();
129 #endif
133 jack_native_thread_t JackDebugClient::GetThreadID()
135 CheckClient("GetThreadID");
136 return fClient->GetThreadID();
139 JackGraphManager* JackDebugClient::GetGraphManager() const
141 CheckClient("GetGraphManager");
142 return fClient->GetGraphManager();
144 JackEngineControl* JackDebugClient::GetEngineControl() const
146 CheckClient("GetEngineControl");
147 return fClient->GetEngineControl();
150 \brief Notification received from the server.
153 int JackDebugClient::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
155 CheckClient("ClientNotify");
156 return fClient->ClientNotify( refnum, name, notify, sync, message, value1, value2);
159 int JackDebugClient::Activate()
161 CheckClient("Activate");
162 int res = fClient->Activate();
163 fIsActivated++;
164 if (fIsDeactivated)
165 *fStream << "Client '" << fClientName << "' call activate a new time (it already call 'activate' previously)." << endl;
166 *fStream << "Client '" << fClientName << "' Activated" << endl;
167 if (res != 0)
168 *fStream << "Client '" << fClientName << "' try to activate but server return " << res << " ." << endl;
169 return res;
172 int JackDebugClient::Deactivate()
174 CheckClient("Deactivate");
175 int res = fClient->Deactivate();
176 fIsDeactivated++;
177 if (fIsActivated == 0)
178 *fStream << "Client '" << fClientName << "' deactivate while it hasn't been previoulsy activated !" << endl;
179 *fStream << "Client '" << fClientName << "' Deactivated" << endl;
180 if (res != 0)
181 *fStream << "Client '" << fClientName << "' try to deactivate but server return " << res << " ." << endl;
182 return res;
185 //-----------------
186 // Port management
187 //-----------------
189 int JackDebugClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
191 CheckClient("PortRegister");
192 int res = fClient->PortRegister(port_name, port_type, flags, buffer_size);
193 if (res <= 0) {
194 *fStream << "Client '" << fClientName << "' try port register ('" << port_name << "') and server return error " << res << " ." << endl;
195 } else {
196 if (fTotalPortNumber < MAX_PORT_HISTORY) {
197 fPortList[fTotalPortNumber].idport = res;
198 strcpy(fPortList[fTotalPortNumber].name, port_name);
199 fPortList[fTotalPortNumber].IsConnected = 0;
200 fPortList[fTotalPortNumber].IsUnregistered = 0;
201 } else {
202 *fStream << "!!! WARNING !!! History is full : no more port history will be recorded." << endl;
204 fTotalPortNumber++;
205 fOpenPortNumber++;
206 *fStream << "Client '" << fClientName << "' port register with portname '" << port_name << " port " << res << "' ." << endl;
208 return res;
211 int JackDebugClient::PortUnRegister(jack_port_id_t port_index)
213 CheckClient("PortUnRegister");
214 int res = fClient->PortUnRegister(port_index);
215 fOpenPortNumber--;
216 int i;
217 for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
218 if (fPortList[i].idport == port_index) { // We found the last record
219 if (fPortList[i].IsUnregistered != 0)
220 *fStream << "!!! ERROR !!! : '" << fClientName << "' id deregistering port '" << fPortList[i].name << "' that have already been unregistered !" << endl;
221 fPortList[i].IsUnregistered++;
222 break;
225 if (i == 0) // Port is not found
226 *fStream << "JackClientDebug : PortUnregister : port " << port_index << " was not previously registered !" << endl;
227 if (res != 0)
228 *fStream << "Client '" << fClientName << "' try to do PortUnregister and server return " << res << endl;
229 *fStream << "Client '" << fClientName << "' unregister port '" << port_index << "'." << endl;
230 return res;
233 int JackDebugClient::PortConnect(const char* src, const char* dst)
235 CheckClient("PortConnect");
236 if (!fIsActivated)
237 *fStream << "!!! ERROR !!! Trying to connect a port ( " << src << " to " << dst << ") while the client has not been activated !" << endl;
238 int i;
239 int res = fClient->PortConnect( src, dst);
240 for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
241 if (strcmp(fPortList[i].name, src) == 0) { // We found the last record in sources
242 if (fPortList[i].IsUnregistered != 0)
243 *fStream << "!!! ERROR !!! Connecting port " << src << " previoulsy unregistered !" << endl;
244 fPortList[i].IsConnected++;
245 *fStream << "Connecting port " << src << " to " << dst << ". ";
246 break;
247 } else if (strcmp(fPortList[i].name, dst) == 0 ) { // We found the record in dest
248 if (fPortList[i].IsUnregistered != 0)
249 *fStream << "!!! ERROR !!! Connecting port " << dst << " previoulsy unregistered !" << endl;
250 fPortList[i].IsConnected++;
251 *fStream << "Connecting port " << src << " to " << dst << ". ";
252 break;
255 if (i == 0) // Port is not found
256 *fStream << "JackClientDebug : PortConnect : port was not found in debug database !" << endl;
257 if (res != 0)
258 *fStream << "Client '" << fClientName << "' try to do PortConnect but server return " << res << " ." << endl;
259 //*fStream << "Client Port Connect done with names" << endl;
260 return res;
263 int JackDebugClient::PortDisconnect(const char* src, const char* dst)
265 CheckClient("PortDisconnect");
266 if (!fIsActivated)
267 *fStream << "!!! ERROR !!! Trying to disconnect a port ( " << src << " to " << dst << ") while the client has not been activated !" << endl;
268 int res = fClient->PortDisconnect( src, dst);
269 int i;
270 for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
271 if (strcmp(fPortList[i].name, src) == 0) { // We found the record in sources
272 if (fPortList[i].IsUnregistered != 0)
273 *fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl;
274 fPortList[i].IsConnected--;
275 *fStream << "disconnecting port " << src << ". ";
276 break;
277 } else if (strcmp(fPortList[i].name, dst) == 0 ) { // We found the record in dest
278 if (fPortList[i].IsUnregistered != 0)
279 *fStream << "!!! ERROR !!! : Disonnecting port " << dst << " previoulsy unregistered !" << endl;
280 fPortList[i].IsConnected--;
281 *fStream << "disconnecting port " << dst << ". ";
282 break;
285 if (i == 0) // Port is not found
286 *fStream << "JackClientDebug : PortDisConnect : port was not found in debug database !" << endl;
287 if (res != 0)
288 *fStream << "Client '" << fClientName << "' try to do PortDisconnect but server return " << res << " ." << endl;
289 //*fStream << "Client Port Disconnect done." << endl;
290 return res;
293 int JackDebugClient::PortDisconnect(jack_port_id_t src)
295 CheckClient("PortDisconnect");
296 if (!fIsActivated)
297 *fStream << "!!! ERROR !!! : Trying to disconnect port " << src << " while that client has not been activated !" << endl;
298 int res = fClient->PortDisconnect(src);
299 int i;
300 for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
301 if (fPortList[i].idport == src) { // We found the record in sources
302 if (fPortList[i].IsUnregistered != 0)
303 *fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl;
304 fPortList[i].IsConnected--;
305 *fStream << "Disconnecting port " << src << ". " << endl;
306 break;
309 if (i == 0) // Port is not found
310 *fStream << "JackClientDebug : PortDisconnect : port was not found in debug database !" << endl;
311 if (res != 0)
312 *fStream << "Client '" << fClientName << "' try to do PortDisconnect but server return " << res << " ." << endl;
313 //*fStream << "Client Port Disconnect with ID done." << endl;
314 return res;
317 int JackDebugClient::PortIsMine(jack_port_id_t port_index)
319 CheckClient("PortIsMine");
320 *fStream << "JackClientDebug : PortIsMine port_index " << port_index << endl;
321 return fClient->PortIsMine(port_index);
324 int JackDebugClient::PortRename(jack_port_id_t port_index, const char* name)
326 CheckClient("PortRename");
327 *fStream << "JackClientDebug : PortRename port_index " << port_index << "name" << name << endl;
328 return fClient->PortRename(port_index, name);
331 //--------------------
332 // Context management
333 //--------------------
335 int JackDebugClient::SetBufferSize(jack_nframes_t buffer_size)
337 CheckClient("SetBufferSize");
338 *fStream << "JackClientDebug : SetBufferSize buffer_size " << buffer_size << endl;
339 return fClient->SetBufferSize(buffer_size);
342 int JackDebugClient::SetFreeWheel(int onoff)
344 CheckClient("SetFreeWheel");
345 if (onoff && fFreewheel)
346 *fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = ON while FW is already ON " << endl;
347 if (!onoff && !fFreewheel)
348 *fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = OFF while FW is already OFF " << endl;
349 fFreewheel = onoff ? true : false;
350 return fClient->SetFreeWheel(onoff);
353 int JackDebugClient::ComputeTotalLatencies()
355 CheckClient("ComputeTotalLatencies");
356 return fClient->ComputeTotalLatencies();
360 ShutDown is called:
361 - from the RT thread when Execute method fails
362 - possibly from a "closed" notification channel
363 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
366 void JackDebugClient::ShutDown()
368 CheckClient("ShutDown");
369 fClient->ShutDown();
372 //---------------------
373 // Transport management
374 //---------------------
376 int JackDebugClient::ReleaseTimebase()
378 CheckClient("ReleaseTimebase");
379 return fClient->ReleaseTimebase();
382 int JackDebugClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg)
384 CheckClient("SetSyncCallback");
385 return fClient->SetSyncCallback(sync_callback, arg);
388 int JackDebugClient::SetSyncTimeout(jack_time_t timeout)
390 CheckClient("SetSyncTimeout");
391 *fStream << "JackClientDebug : SetSyncTimeout timeout " << timeout << endl;
392 return fClient->SetSyncTimeout(timeout);
395 int JackDebugClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg)
397 CheckClient("SetTimebaseCallback");
398 return fClient->SetTimebaseCallback( conditional, timebase_callback, arg);
401 void JackDebugClient::TransportLocate(jack_nframes_t frame)
403 CheckClient("TransportLocate");
404 *fStream << "JackClientDebug : TransportLocate frame " << frame << endl;
405 fClient->TransportLocate(frame);
408 jack_transport_state_t JackDebugClient::TransportQuery(jack_position_t* pos)
410 CheckClient("TransportQuery");
411 return fClient->TransportQuery(pos);
414 jack_nframes_t JackDebugClient::GetCurrentTransportFrame()
416 CheckClient("GetCurrentTransportFrame");
417 return fClient->GetCurrentTransportFrame();
420 int JackDebugClient::TransportReposition(jack_position_t* pos)
422 CheckClient("TransportReposition");
423 return fClient->TransportReposition(pos);
426 void JackDebugClient::TransportStart()
428 CheckClient("TransportStart");
429 fClient->TransportStart();
432 void JackDebugClient::TransportStop()
434 CheckClient("TransportStop");
435 fClient->TransportStop();
438 //---------------------
439 // Callback management
440 //---------------------
442 void JackDebugClient::OnShutdown(JackShutdownCallback callback, void *arg)
444 CheckClient("OnShutdown");
445 fClient->OnShutdown(callback, arg);
448 void JackDebugClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg)
450 CheckClient("OnInfoShutdown");
451 fClient->OnInfoShutdown(callback, arg);
454 int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg)
456 JackDebugClient* client = (JackDebugClient*)arg;
457 jack_time_t t1 = GetMicroSeconds();
458 int res = client->fProcessTimeCallback(nframes, client->fProcessTimeCallbackArg);
459 if (res == 0) {
460 jack_time_t t2 = GetMicroSeconds();
461 long delta = long((t2 - t1) - client->GetEngineControl()->fPeriodUsecs);
462 if (delta > 0 && !client->fFreewheel) {
463 *client->fStream << "!!! ERROR !!! : Process overload of " << delta << " us" << endl;
466 return res;
469 int JackDebugClient::SetProcessCallback(JackProcessCallback callback, void *arg)
471 CheckClient("SetProcessCallback");
473 fProcessTimeCallback = callback;
474 fProcessTimeCallbackArg = arg;
476 if (callback == NULL) {
477 // Clear the callback...
478 return fClient->SetProcessCallback(callback, arg);
479 } else {
480 // Setup the measuring version...
481 return fClient->SetProcessCallback(TimeCallback, this);
485 int JackDebugClient::SetXRunCallback(JackXRunCallback callback, void *arg)
487 CheckClient("SetXRunCallback");
488 return fClient->SetXRunCallback(callback, arg);
491 int JackDebugClient::SetInitCallback(JackThreadInitCallback callback, void *arg)
493 CheckClient("SetInitCallback");
494 return fClient->SetInitCallback(callback, arg);
497 int JackDebugClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
499 CheckClient("SetGraphOrderCallback");
500 return fClient->SetGraphOrderCallback(callback, arg);
503 int JackDebugClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg)
505 CheckClient("SetBufferSizeCallback");
506 return fClient->SetBufferSizeCallback(callback, arg);
509 int JackDebugClient::SetClientRegistrationCallback(JackClientRegistrationCallback callback, void* arg)
511 CheckClient("SetClientRegistrationCallback");
512 return fClient->SetClientRegistrationCallback(callback, arg);
515 int JackDebugClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg)
517 CheckClient("SetFreewheelCallback");
518 return fClient->SetFreewheelCallback(callback, arg);
521 int JackDebugClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg)
523 CheckClient("SetPortRegistrationCallback");
524 return fClient->SetPortRegistrationCallback(callback, arg);
527 int JackDebugClient::SetPortConnectCallback(JackPortConnectCallback callback, void *arg)
529 CheckClient("SetPortConnectCallback");
530 return fClient->SetPortConnectCallback(callback, arg);
533 int JackDebugClient::SetPortRenameCallback(JackPortRenameCallback callback, void *arg)
535 CheckClient("SetPortRenameCallback");
536 return fClient->SetPortRenameCallback(callback, arg);
539 int JackDebugClient::SetSessionCallback(JackSessionCallback callback, void *arg)
541 CheckClient("SetSessionCallback");
542 return fClient->SetSessionCallback(callback, arg);
545 int JackDebugClient::SetLatencyCallback(JackLatencyCallback callback, void *arg)
547 CheckClient("SetLatencyCallback");
548 return fClient->SetLatencyCallback(callback, arg);
551 int JackDebugClient::SetProcessThread(JackThreadCallback fun, void *arg)
553 CheckClient("SetProcessThread");
554 return fClient->SetProcessThread(fun, arg);
557 jack_session_command_t* JackDebugClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path)
559 CheckClient("SessionNotify");
560 *fStream << "JackClientDebug : SessionNotify target " << target << "type " << type << "path " << path << endl;
561 return fClient->SessionNotify(target, type, path);
564 int JackDebugClient::SessionReply(jack_session_event_t* ev)
566 CheckClient("SessionReply");
567 return fClient->SessionReply(ev);
570 char* JackDebugClient::GetUUIDForClientName(const char* client_name)
572 CheckClient("GetUUIDForClientName");
573 *fStream << "JackClientDebug : GetUUIDForClientName client_name " << client_name << endl;
574 return fClient->GetUUIDForClientName(client_name);
577 char* JackDebugClient::GetClientNameByUUID(const char* uuid)
579 CheckClient("GetClientNameByUUID");
580 *fStream << "JackClientDebug : GetClientNameByUUID uuid " << uuid << endl;
581 return fClient->GetClientNameByUUID(uuid);
584 int JackDebugClient::ReserveClientName(const char* client_name, const char* uuid)
586 CheckClient("ReserveClientName");
587 *fStream << "JackClientDebug : ReserveClientName client_name " << client_name << "uuid " << uuid << endl;
588 return fClient->ReserveClientName(client_name, uuid);
591 int JackDebugClient::ClientHasSessionCallback(const char* client_name)
593 CheckClient("ClientHasSessionCallback");
594 *fStream << "JackClientDebug : ClientHasSessionCallback client_name " << client_name << endl;
595 return fClient->ClientHasSessionCallback(client_name);
598 JackClientControl* JackDebugClient::GetClientControl() const
600 CheckClient("GetClientControl");
601 return fClient->GetClientControl();
604 // Internal clients
605 char* JackDebugClient::GetInternalClientName(int ref)
607 CheckClient("GetInternalClientName");
608 return fClient->GetInternalClientName(ref);
611 int JackDebugClient::InternalClientHandle(const char* client_name, jack_status_t* status)
613 CheckClient("InternalClientHandle");
614 return fClient->InternalClientHandle(client_name, status);
617 int JackDebugClient::InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va)
619 CheckClient("InternalClientLoad");
620 return fClient->InternalClientLoad(client_name, options, status, va);
623 void JackDebugClient::InternalClientUnload(int ref, jack_status_t* status)
625 CheckClient("InternalClientUnload");
626 fClient->InternalClientUnload(ref, status);
629 } // end of namespace