Merge branch 'master' into develop
[jack2.git] / common / JackDriver.cpp
blob8700b1c9d9e2605f59f9eb5f33a753e19c52e9b1
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
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.
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.
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.
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>
35 using namespace std;
37 namespace Jack
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)
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;
58 JackDriver::~JackDriver()
60 jack_log("~JackDriver");
63 int JackDriver::Open()
65 int refnum = -1;
67 if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) {
68 jack_error("Cannot allocate internal client for driver");
69 return -1;
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;
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)
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;
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;
103 strcpy(fClientControl.fName, name_res);
105 if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) {
106 jack_error("Cannot allocate internal client for driver");
107 return -1;
110 fClientControl.fRefNum = refnum;
111 fClientControl.fActive = true;
112 fEngineControl->fDriverNum++;
113 if (buffer_size > 0) {
114 fEngineControl->fBufferSize = buffer_size;
116 if (sample_rate > 0) {
117 fEngineControl->fSampleRate = sample_rate;
119 fCaptureLatency = capture_latency;
120 fPlaybackLatency = playback_latency;
122 assert(strlen(capture_driver_name) < JACK_CLIENT_NAME_SIZE);
123 assert(strlen(playback_driver_name) < JACK_CLIENT_NAME_SIZE);
125 strcpy(fCaptureDriverName, capture_driver_name);
126 strcpy(fPlaybackDriverName, playback_driver_name);
128 fEngineControl->UpdateTimeOut();
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;
136 int JackDriver::Close()
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;
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.
154 void JackDriver::SetupDriverSync(int ref, bool freewheel)
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);
165 int JackDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
167 jack_log("JackDriver::ClientNotify ref = %ld driver = %s name = %s notify = %ld", refnum, fClientControl.fName, name, notify);
169 switch (notify) {
171 case kStartFreewheelCallback:
172 jack_log("JackDriver::kStartFreewheel");
173 SetupDriverSync(fClientControl.fRefNum, true);
174 break;
176 case kStopFreewheelCallback:
177 jack_log("JackDriver::kStopFreewheel");
178 SetupDriverSync(fClientControl.fRefNum, false);
179 break;
182 return 0;
185 bool JackDriver::IsRealTime() const
187 return fEngineControl->fRealTime;
190 void JackDriver::CycleIncTime()
192 fEngineControl->CycleIncTime(fBeginDateUst);
195 void JackDriver::CycleTakeBeginTime()
197 fBeginDateUst = GetMicroSeconds(); // Take callback date here
198 fEngineControl->CycleIncTime(fBeginDateUst);
201 void JackDriver::CycleTakeEndTime()
203 fEndDateUst = GetMicroSeconds(); // Take end date here
206 JackClientControl* JackDriver::GetClientControl() const
208 return (JackClientControl*)&fClientControl;
211 void JackDriver::NotifyXRun(jack_time_t cur_cycle_begin, float delayed_usecs)
213 fEngineControl->NotifyXRun(cur_cycle_begin, delayed_usecs);
214 fEngine->NotifyDriverXRun();
217 void JackDriver::NotifyBufferSize(jack_nframes_t buffer_size)
219 fEngine->NotifyBufferSize(buffer_size);
220 fEngineControl->InitFrameTime();
223 void JackDriver::NotifySampleRate(jack_nframes_t sample_rate)
225 fEngine->NotifySampleRate(sample_rate);
226 fEngineControl->InitFrameTime();
229 void JackDriver::NotifyFailure(int code, const char* reason)
231 fEngine->NotifyFailure(code, reason);
234 void JackDriver::SetMaster(bool onoff)
236 fIsMaster = onoff;
239 bool JackDriver::GetMaster()
241 return fIsMaster;
244 void JackDriver::AddSlave(JackDriverInterface* slave)
246 fSlaveList.push_back(slave);
249 void JackDriver::RemoveSlave(JackDriverInterface* slave)
251 fSlaveList.remove(slave);
254 int JackDriver::ProcessReadSlaves()
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;
266 return res;
269 int JackDriver::ProcessWriteSlaves()
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;
281 return res;
284 int JackDriver::ProcessRead()
286 return (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
289 int JackDriver::ProcessWrite()
291 return (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
294 int JackDriver::ProcessReadSync()
296 return 0;
299 int JackDriver::ProcessWriteSync()
301 return 0;
304 int JackDriver::ProcessReadAsync()
306 return 0;
309 int JackDriver::ProcessWriteAsync()
311 return 0;
314 int JackDriver::Process()
316 return 0;
319 int JackDriver::Attach()
321 return 0;
324 int JackDriver::Detach()
326 return 0;
329 int JackDriver::Read()
331 return 0;
334 int JackDriver::Write()
336 return 0;
339 int JackDriver::Start()
341 if (fIsMaster) {
342 fEngineControl->InitFrameTime();
344 fIsRunning = true;
345 return StartSlaves();
348 int JackDriver::Stop()
350 fIsRunning = false;
351 return StopSlaves();
354 int JackDriver::StartSlaves()
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;
367 return res;
370 int JackDriver::StopSlaves()
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;
380 return res;
383 bool JackDriver::IsFixedBufferSize()
385 return true;
388 int JackDriver::SetBufferSize(jack_nframes_t buffer_size)
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;
398 return res;
401 int JackDriver::SetSampleRate(jack_nframes_t sample_rate)
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;
411 return res;
414 bool JackDriver::Initialize()
416 return true;
419 static string RemoveLast(const string& name)
421 return name.substr(0, name.find_last_of(':')); // Remove end of name after last ":"
424 void JackDriver::SaveConnections(int alias)
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];
434 aliases[0] = alias1;
435 aliases[1] = alias2;
437 system_aliases[0] = system_alias1;
438 system_aliases[1] = system_alias2;
440 fConnections.clear();
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]);
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();
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];
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());
471 free(connections);
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());
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();
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];
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());
504 free(connections);
509 string JackDriver::MatchPortName(const char* name, const char** ports, int alias, const std::string& type)
511 char alias1[REAL_JACK_PORT_NAME_SIZE+1];
512 char alias2[REAL_JACK_PORT_NAME_SIZE+1];
513 char* aliases[2];
515 aliases[0] = alias1;
516 aliases[1] = alias2;
518 for (int i = 0; ports && ports[i]; ++i) {
520 jack_port_id_t port_id2 = fGraphManager->GetPort(ports[i]);
521 JackPort* port2 = (port_id2 != NO_PORT) ? fGraphManager->GetPort(port_id2) : NULL;
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]);
531 string sub_name = RemoveLast(name);
532 if ((name_str.find(sub_name) != string::npos) && (type == string(port2->GetType()))) {
533 return name_str;
538 return "";
541 void JackDriver::LoadConnections(int alias, bool full_name)
543 list<pair<string, pair<string, string> > >::const_iterator it;
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());
551 } else {
552 const char** inputs = fGraphManager->GetPorts(NULL, NULL, JackPortIsInput);
553 const char** outputs = fGraphManager->GetPorts(NULL, NULL, JackPortIsOutput);
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());
565 // Wait for connection change
566 if (fGraphManager->IsPendingChange()) {
567 JackSleep(int(fEngineControl->fPeriodUsecs * 1.1f));
570 if (inputs) {
571 free(inputs);
573 if (outputs) {
574 free(outputs);
579 int JackDriver::ResumeRefNum()
581 return fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
584 int JackDriver::SuspendRefNum()
586 return fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs);
589 } // end of namespace