1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include "JackSystemDeps.h"
22 #include "JackDriver.h"
23 #include "JackTime.h"
24 #include "JackError.h"
25 #include "JackPort.h"
26 #include "JackGraphManager.h"
27 #include "JackGlobals.h"
28 #include "JackEngineControl.h"
29 #include "JackClientControl.h"
30 #include "JackLockedEngine.h"
31 #include "JackTime.h"
32 #include <math.h>
33 #include <assert.h>
34 
35 using namespace std;
36 
37 namespace Jack
38 {
39 
JackDriver(const char * name,const char * alias,JackLockedEngine * engine,JackSynchro * table)40 JackDriver::JackDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
41     :fCaptureChannels(0),
42     fPlaybackChannels(0),
43     fClientControl(name, jack_client_uuid_generate()),
44     fWithMonitorPorts(false)
45 {
46     assert(strlen(name) < JACK_CLIENT_NAME_SIZE);
47     fSynchroTable = table;
48     strcpy(fAliasName, alias);
49     fEngine = engine;
50     fGraphManager = NULL;
51     fBeginDateUst = 0;
52     fEndDateUst = 0;
53     fDelayedUsecs = 0.f;
54     fIsMaster = true;
55     fIsRunning = false;
56 }
57 
~JackDriver()58 JackDriver::~JackDriver()
59 {
60     jack_log("~JackDriver");
61 }
62 
Open()63 int JackDriver::Open()
64 {
65     int refnum = -1;
66 
67     if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) {
68         jack_error("Cannot allocate internal client for driver");
69         return -1;
70     }
71 
72     fClientControl.fRefNum = refnum;
73     fClientControl.fActive = true;
74     fEngineControl->fDriverNum++;
75     fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode
76     SetupDriverSync(fClientControl.fRefNum, false);
77     return 0;
78 }
79 
Open(jack_nframes_t buffer_size,jack_nframes_t sample_rate,bool capturing,bool playing,int inchannels,int outchannels,bool monitor,const char * capture_driver_name,const char * playback_driver_name,jack_nframes_t capture_latency,jack_nframes_t playback_latency)80 int JackDriver::Open(jack_nframes_t buffer_size,
81                      jack_nframes_t sample_rate,
82                      bool capturing,
83                      bool playing,
84                      int inchannels,
85                      int outchannels,
86                      bool monitor,
87                      const char* capture_driver_name,
88                      const char* playback_driver_name,
89                      jack_nframes_t capture_latency,
90                      jack_nframes_t playback_latency)
91 {
92     jack_log("JackDriver::Open capture_driver_name = %s", capture_driver_name);
93     jack_log("JackDriver::Open playback_driver_name = %s", playback_driver_name);
94     int refnum = -1;
95     char name_res[JACK_CLIENT_NAME_SIZE + 1];
96     int status;
97 
98     // Check name and possibly rename
99     if (fEngine->ClientCheck(fClientControl.fName, -1, name_res, JACK_PROTOCOL_VERSION, (int)JackNullOption, (int*)&status) < 0) {
100         jack_error("Client name = %s conflits with another running client", fClientControl.fName);
101         return -1;
102     }
103     strcpy(fClientControl.fName, name_res);
104 
105     if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) {
106         jack_error("Cannot allocate internal client for driver");
107         return -1;
108     }
109 
110     fClientControl.fRefNum = refnum;
111     fClientControl.fActive = true;
112     fEngineControl->fDriverNum++;
113     if (buffer_size > 0) {
114         fEngineControl->fBufferSize = buffer_size;
115     }
116     if (sample_rate > 0) {
117         fEngineControl->fSampleRate = sample_rate;
118     }
119     fCaptureLatency = capture_latency;
120     fPlaybackLatency = playback_latency;
121 
122     assert(strlen(capture_driver_name) < JACK_CLIENT_NAME_SIZE);
123     assert(strlen(playback_driver_name) < JACK_CLIENT_NAME_SIZE);
124 
125     strcpy(fCaptureDriverName, capture_driver_name);
126     strcpy(fPlaybackDriverName, playback_driver_name);
127 
128     fEngineControl->UpdateTimeOut();
129 
130     fGraphManager->SetBufferSize(fEngineControl->fBufferSize);
131     fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode
132     SetupDriverSync(fClientControl.fRefNum, false);
133     return 0;
134 }
135 
Close()136 int JackDriver::Close()
137 {
138     if (fClientControl.fRefNum >= 0) {
139         jack_log("JackDriver::Close");
140         fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync
141         fClientControl.fActive = false;
142         fEngineControl->fDriverNum--;
143         return fEngine->ClientInternalClose(fClientControl.fRefNum, false);
144     } else {
145         return -1;
146     }
147 }
148 
149 /*!
150 	In "async" mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
151 	The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
152 	Drivers synchro are setup in "flush" mode if server is "async" and NOT freewheel.
153 */
SetupDriverSync(int ref,bool freewheel)154 void JackDriver::SetupDriverSync(int ref, bool freewheel)
155 {
156     if (!freewheel && !fEngineControl->fSyncMode) {
157         jack_log("JackDriver::SetupDriverSync driver sem in flush mode");
158         fSynchroTable[ref].SetFlush(true);
159     } else {
160         jack_log("JackDriver::SetupDriverSync driver sem in normal mode");
161         fSynchroTable[ref].SetFlush(false);
162     }
163 }
164 
ClientNotify(int refnum,const char * name,int notify,int sync,const char * message,int value1,int value2)165 int JackDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
166 {
167     jack_log("JackDriver::ClientNotify ref = %ld driver = %s name = %s notify = %ld", refnum, fClientControl.fName, name, notify);
168 
169     switch (notify) {
170 
171         case kStartFreewheelCallback:
172             jack_log("JackDriver::kStartFreewheel");
173             SetupDriverSync(fClientControl.fRefNum, true);
174             break;
175 
176         case kStopFreewheelCallback:
177             jack_log("JackDriver::kStopFreewheel");
178             SetupDriverSync(fClientControl.fRefNum, false);
179             break;
180     }
181 
182     return 0;
183 }
184 
IsRealTime() const185 bool JackDriver::IsRealTime() const
186 {
187     return fEngineControl->fRealTime;
188 }
189 
CycleIncTime()190 void JackDriver::CycleIncTime()
191 {
192     fEngineControl->CycleIncTime(fBeginDateUst);
193 }
194 
CycleTakeBeginTime()195 void JackDriver::CycleTakeBeginTime()
196 {
197     fBeginDateUst = GetMicroSeconds();  // Take callback date here
198     fEngineControl->CycleIncTime(fBeginDateUst);
199 }
200 
CycleTakeEndTime()201 void JackDriver::CycleTakeEndTime()
202 {
203     fEndDateUst = GetMicroSeconds();    // Take end date here
204 }
205 
GetClientControl() const206 JackClientControl* JackDriver::GetClientControl() const
207 {
208     return (JackClientControl*)&fClientControl;
209 }
210 
NotifyXRun(jack_time_t cur_cycle_begin,float delayed_usecs)211 void JackDriver::NotifyXRun(jack_time_t cur_cycle_begin, float delayed_usecs)
212 {
213     fEngineControl->NotifyXRun(cur_cycle_begin, delayed_usecs);
214     fEngine->NotifyDriverXRun();
215 }
216 
NotifyBufferSize(jack_nframes_t buffer_size)217 void JackDriver::NotifyBufferSize(jack_nframes_t buffer_size)
218 {
219     fEngine->NotifyBufferSize(buffer_size);
220     fEngineControl->InitFrameTime();
221 }
222 
NotifySampleRate(jack_nframes_t sample_rate)223 void JackDriver::NotifySampleRate(jack_nframes_t sample_rate)
224 {
225     fEngine->NotifySampleRate(sample_rate);
226     fEngineControl->InitFrameTime();
227 }
228 
NotifyFailure(int code,const char * reason)229 void JackDriver::NotifyFailure(int code, const char* reason)
230 {
231     fEngine->NotifyFailure(code, reason);
232 }
233 
SetMaster(bool onoff)234 void JackDriver::SetMaster(bool onoff)
235 {
236     fIsMaster = onoff;
237 }
238 
GetMaster()239 bool JackDriver::GetMaster()
240 {
241     return fIsMaster;
242 }
243 
AddSlave(JackDriverInterface * slave)244 void JackDriver::AddSlave(JackDriverInterface* slave)
245 {
246     fSlaveList.push_back(slave);
247 }
248 
RemoveSlave(JackDriverInterface * slave)249 void JackDriver::RemoveSlave(JackDriverInterface* slave)
250 {
251     fSlaveList.remove(slave);
252 }
253 
ProcessReadSlaves()254 int JackDriver::ProcessReadSlaves()
255 {
256     int res = 0;
257     list<JackDriverInterface*>::const_iterator it;
258     for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
259         JackDriverInterface* slave = *it;
260         if (slave->IsRunning()) {
261             if (slave->ProcessRead() < 0) {
262                 res = -1;
263             }
264         }
265     }
266     return res;
267 }
268 
ProcessWriteSlaves()269 int JackDriver::ProcessWriteSlaves()
270 {
271     int res = 0;
272     list<JackDriverInterface*>::const_iterator it;
273     for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
274         JackDriverInterface* slave = *it;
275         if (slave->IsRunning()) {
276             if (slave->ProcessWrite() < 0) {
277                 res = -1;
278             }
279         }
280     }
281     return res;
282 }
283 
ProcessRead()284 int JackDriver::ProcessRead()
285 {
286     return (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
287 }
288 
ProcessWrite()289 int JackDriver::ProcessWrite()
290 {
291     return (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
292 }
293 
ProcessReadSync()294 int JackDriver::ProcessReadSync()
295 {
296     return 0;
297 }
298 
ProcessWriteSync()299 int JackDriver::ProcessWriteSync()
300 {
301     return 0;
302 }
303 
ProcessReadAsync()304 int JackDriver::ProcessReadAsync()
305 {
306     return 0;
307 }
308 
ProcessWriteAsync()309 int JackDriver::ProcessWriteAsync()
310 {
311     return 0;
312 }
313 
Process()314 int JackDriver::Process()
315 {
316     return 0;
317 }
318 
Attach()319 int JackDriver::Attach()
320 {
321     return 0;
322 }
323 
Detach()324 int JackDriver::Detach()
325 {
326     return 0;
327 }
328 
Read()329 int JackDriver::Read()
330 {
331     return 0;
332 }
333 
Write()334 int JackDriver::Write()
335 {
336     return 0;
337 }
338 
Start()339 int JackDriver::Start()
340 {
341     if (fIsMaster) {
342         fEngineControl->InitFrameTime();
343     }
344     fIsRunning = true;
345     return StartSlaves();
346 }
347 
Stop()348 int JackDriver::Stop()
349 {
350     fIsRunning = false;
351     return StopSlaves();
352 }
353 
StartSlaves()354 int JackDriver::StartSlaves()
355 {
356     int res = 0;
357     list<JackDriverInterface*>::const_iterator it;
358     for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
359         JackDriverInterface* slave = *it;
360         if (slave->Start() < 0) {
361             res = -1;
362             // XXX: We should attempt to stop all of the slaves that we've
363             // started here.
364             break;
365         }
366     }
367     return res;
368 }
369 
StopSlaves()370 int JackDriver::StopSlaves()
371 {
372     int res = 0;
373     list<JackDriverInterface*>::const_iterator it;
374     for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
375         JackDriverInterface* slave = *it;
376         if (slave->Stop() < 0) {
377             res = -1;
378         }
379     }
380     return res;
381 }
382 
IsFixedBufferSize()383 bool JackDriver::IsFixedBufferSize()
384 {
385     return true;
386 }
387 
SetBufferSize(jack_nframes_t buffer_size)388 int JackDriver::SetBufferSize(jack_nframes_t buffer_size)
389 {
390     int res = 0;
391     list<JackDriverInterface*>::const_iterator it;
392     for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
393         JackDriverInterface* slave = *it;
394         if (slave->SetBufferSize(buffer_size) < 0) {
395             res = -1;
396         }
397     }
398     return res;
399 }
400 
SetSampleRate(jack_nframes_t sample_rate)401 int JackDriver::SetSampleRate(jack_nframes_t sample_rate)
402 {
403     int res = 0;
404     list<JackDriverInterface*>::const_iterator it;
405     for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
406         JackDriverInterface* slave = *it;
407         if (slave->SetSampleRate(sample_rate) < 0) {
408             res = -1;
409         }
410     }
411     return res;
412 }
413 
Initialize()414 bool JackDriver::Initialize()
415 {
416     return true;
417 }
418 
RemoveLast(const string & name)419 static string RemoveLast(const string& name)
420 {
421     return name.substr(0, name.find_last_of(':')); // Remove end of name after last ":"
422 }
423 
SaveConnections(int alias)424 void JackDriver::SaveConnections(int alias)
425 {
426     const char** connections;
427     char alias1[REAL_JACK_PORT_NAME_SIZE+1];
428     char alias2[REAL_JACK_PORT_NAME_SIZE+1];
429     char system_alias1[REAL_JACK_PORT_NAME_SIZE+1];
430     char system_alias2[REAL_JACK_PORT_NAME_SIZE+1];
431     char* aliases[2];
432     char* system_aliases[2];
433 
434     aliases[0] = alias1;
435     aliases[1] = alias2;
436 
437     system_aliases[0] = system_alias1;
438     system_aliases[1] = system_alias2;
439 
440     fConnections.clear();
441 
442     for (int i = 0; i < fCaptureChannels; ++i) {
443         if (fCapturePortList[i] && (connections = fGraphManager->GetConnections(fCapturePortList[i])) != 0) {
444             if (alias == 0) {
445                 for (int j = 0; connections[j]; j++) {
446                     JackPort* port_id = fGraphManager->GetPort(fCapturePortList[i]);
447                     fConnections.push_back(make_pair(port_id->GetType(), make_pair(port_id->GetName(), connections[j])));
448                     jack_info("Save connection: %s %s", fGraphManager->GetPort(fCapturePortList[i])->GetName(), connections[j]);
449                 }
450             } else {
451                 int res1 = fGraphManager->GetPort(fCapturePortList[i])->GetAliases(aliases);
452                 string sub_system_name;
453                 if (res1 >= alias) {
454                     sub_system_name = aliases[alias-1];
455                 } else {
456                     sub_system_name = fGraphManager->GetPort(fCapturePortList[i])->GetName();
457                 }
458                 for (int j = 0; connections[j]; j++) {
459                     JackPort* port_id = fGraphManager->GetPort(fGraphManager->GetPort(connections[j]));
460                     int res2 = port_id->GetAliases(system_aliases);
461                     string sub_system;
462                     if (res2 >= alias) {
463                         sub_system = system_aliases[alias-1];
464                     } else {
465                         sub_system = connections[j];
466                     }
467                     fConnections.push_back(make_pair(port_id->GetType(), make_pair(sub_system_name, sub_system)));
468                     jack_info("Save connection: %s %s", sub_system_name.c_str(), sub_system.c_str());
469                }
470             }
471             free(connections);
472         }
473     }
474 
475     for (int i = 0; i < fPlaybackChannels; ++i) {
476         if (fPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fPlaybackPortList[i])) != 0) {
477             if (alias == 0) {
478                 for (int j = 0; connections[j]; j++) {
479                     JackPort* port_id = fGraphManager->GetPort(fPlaybackPortList[i]);
480                     fConnections.push_back(make_pair(port_id->GetType(), make_pair(connections[j], port_id->GetName())));
481                     jack_info("Save connection: %s %s", connections[j], fGraphManager->GetPort(fPlaybackPortList[i])->GetName());
482                 }
483             } else {
484                 int res1 = fGraphManager->GetPort(fPlaybackPortList[i])->GetAliases(aliases);
485                 string sub_system_name;
486                 if (res1 >= alias) {
487                     sub_system_name = aliases[alias-1];
488                 } else {
489                     sub_system_name = fGraphManager->GetPort(fPlaybackPortList[i])->GetName();
490                 }
491                 for (int j = 0; connections[j]; j++) {
492                     JackPort* port_id = fGraphManager->GetPort(fGraphManager->GetPort(connections[j]));
493                     int res2 = port_id->GetAliases(system_aliases);
494                     string sub_name;
495                     if (res2 >= alias) {
496                         sub_name = system_aliases[alias-1];
497                     } else {
498                         sub_name = connections[j];
499                     }
500                     fConnections.push_back(make_pair(port_id->GetType(), make_pair(sub_name, sub_system_name)));
501                     jack_info("Save connection: %s %s", sub_name.c_str(), sub_system_name.c_str());
502                }
503             }
504             free(connections);
505         }
506     }
507 }
508 
MatchPortName(const char * name,const char ** ports,int alias,const std::string & type)509 string JackDriver::MatchPortName(const char* name, const char** ports, int alias, const std::string& type)
510 {
511     char alias1[REAL_JACK_PORT_NAME_SIZE+1];
512     char alias2[REAL_JACK_PORT_NAME_SIZE+1];
513     char* aliases[2];
514 
515     aliases[0] = alias1;
516     aliases[1] = alias2;
517 
518     for (int i = 0; ports && ports[i]; ++i) {
519 
520         jack_port_id_t port_id2 = fGraphManager->GetPort(ports[i]);
521         JackPort* port2 = (port_id2 != NO_PORT) ? fGraphManager->GetPort(port_id2) : NULL;
522 
523         if (port2) {
524             int res = port2->GetAliases(aliases);
525             string name_str;
526             if (res >= alias) {
527                 name_str = string(aliases[alias-1]);
528             } else {
529                 name_str = string(ports[i]);
530             }
531             string sub_name = RemoveLast(name);
532             if ((name_str.find(sub_name) != string::npos) && (type == string(port2->GetType()))) {
533                 return name_str;
534             }
535         }
536     }
537 
538     return "";
539 }
540 
LoadConnections(int alias,bool full_name)541 void JackDriver::LoadConnections(int alias, bool full_name)
542 {
543     list<pair<string, pair<string, string> > >::const_iterator it;
544 
545     if (full_name) {
546         for (it = fConnections.begin(); it != fConnections.end(); it++) {
547             pair<string, string> connection = (*it).second;
548             jack_info("Load connection: %s %s", connection.first.c_str(), connection.second.c_str());
549             fEngine->PortConnect(fClientControl.fRefNum, connection.first.c_str(), connection.second.c_str());
550         }
551     } else {
552         const char** inputs = fGraphManager->GetPorts(NULL, NULL, JackPortIsInput);
553         const char** outputs = fGraphManager->GetPorts(NULL, NULL, JackPortIsOutput);
554 
555         for (it = fConnections.begin(); it != fConnections.end(); it++) {
556             pair<string, string> connection = (*it).second;
557             string real_input = MatchPortName(connection.first.c_str(), outputs, alias, (*it).first);
558             string real_output = MatchPortName(connection.second.c_str(), inputs, alias, (*it).first);
559             if ((real_input != "") && (real_output != "")) {
560                 jack_info("Load connection: %s %s", real_input.c_str(), real_output.c_str());
561                 fEngine->PortConnect(fClientControl.fRefNum, real_input.c_str(), real_output.c_str());
562             }
563         }
564 
565         // Wait for connection change
566         if (fGraphManager->IsPendingChange()) {
567             JackSleep(int(fEngineControl->fPeriodUsecs * 1.1f));
568         }
569 
570         if (inputs) {
571             free(inputs);
572         }
573         if (outputs) {
574             free(outputs);
575         }
576     }
577 }
578 
ResumeRefNum()579 int JackDriver::ResumeRefNum()
580 {
581     return fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
582 }
583 
SuspendRefNum()584 int JackDriver::SuspendRefNum()
585 {
586     return fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs);
587 }
588 
589 } // end of namespace
590