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"
24 #include "JackError.h"
26 #include "JackGraphManager.h"
27 #include "JackGlobals.h"
28 #include "JackEngineControl.h"
29 #include "JackClientControl.h"
30 #include "JackLockedEngine.h"
39 JackDriver::JackDriver(const char* name
, const char* alias
, JackLockedEngine
* engine
, JackSynchro
* table
)
43 fWithMonitorPorts(false)
45 assert(strlen(name
) < JACK_CLIENT_NAME_SIZE
);
46 fSynchroTable
= table
;
47 strcpy(fAliasName
, alias
);
56 JackDriver::JackDriver()
66 fPlaybackChannels
= 0;
67 fWithMonitorPorts
= false;
70 JackDriver::~JackDriver()
72 jack_log("~JackDriver");
75 int JackDriver::Open()
79 if (fEngine
->ClientInternalOpen(fClientControl
.fName
, &refnum
, &fEngineControl
, &fGraphManager
, this, false) != 0) {
80 jack_error("Cannot allocate internal client for driver");
84 fClientControl
.fRefNum
= refnum
;
85 fClientControl
.fActive
= true;
86 fEngineControl
->fDriverNum
++;
87 fGraphManager
->DirectConnect(fClientControl
.fRefNum
, fClientControl
.fRefNum
); // Connect driver to itself for "sync" mode
88 SetupDriverSync(fClientControl
.fRefNum
, false);
92 int JackDriver::Open(bool capturing
,
97 const char* capture_driver_name
,
98 const char* playback_driver_name
,
99 jack_nframes_t capture_latency
,
100 jack_nframes_t playback_latency
)
102 jack_log("JackDriver::Open capture_driver_name = %s", capture_driver_name
);
103 jack_log("JackDriver::Open playback_driver_name = %s", playback_driver_name
);
105 char name_res
[JACK_CLIENT_NAME_SIZE
+ 1];
108 // Check name and possibly rename
109 if (fEngine
->ClientCheck(fClientControl
.fName
, -1, name_res
, JACK_PROTOCOL_VERSION
, (int)JackNullOption
, (int*)&status
) < 0) {
110 jack_error("Client name = %s conflits with another running client", fClientControl
.fName
);
113 strcpy(fClientControl
.fName
, name_res
);
115 if (fEngine
->ClientInternalOpen(fClientControl
.fName
, &refnum
, &fEngineControl
, &fGraphManager
, this, false) != 0) {
116 jack_error("Cannot allocate internal client for driver");
120 fClientControl
.fRefNum
= refnum
;
121 fClientControl
.fActive
= true;
122 fEngineControl
->fDriverNum
++;
123 fCaptureLatency
= capture_latency
;
124 fPlaybackLatency
= playback_latency
;
126 assert(strlen(capture_driver_name
) < JACK_CLIENT_NAME_SIZE
);
127 assert(strlen(playback_driver_name
) < JACK_CLIENT_NAME_SIZE
);
129 strcpy(fCaptureDriverName
, capture_driver_name
);
130 strcpy(fPlaybackDriverName
, playback_driver_name
);
132 fEngineControl
->UpdateTimeOut();
134 fGraphManager
->DirectConnect(fClientControl
.fRefNum
, fClientControl
.fRefNum
); // Connect driver to itself for "sync" mode
135 SetupDriverSync(fClientControl
.fRefNum
, false);
139 int JackDriver::Open(jack_nframes_t buffer_size
,
140 jack_nframes_t samplerate
,
146 const char* capture_driver_name
,
147 const char* playback_driver_name
,
148 jack_nframes_t capture_latency
,
149 jack_nframes_t playback_latency
)
151 jack_log("JackDriver::Open capture_driver_name = %s", capture_driver_name
);
152 jack_log("JackDriver::Open playback_driver_name = %s", playback_driver_name
);
154 char name_res
[JACK_CLIENT_NAME_SIZE
+ 1];
157 // Check name and possibly rename
158 if (fEngine
->ClientCheck(fClientControl
.fName
, -1, name_res
, JACK_PROTOCOL_VERSION
, (int)JackNullOption
, (int*)&status
) < 0) {
159 jack_error("Client name = %s conflits with another running client", fClientControl
.fName
);
162 strcpy(fClientControl
.fName
, name_res
);
164 if (fEngine
->ClientInternalOpen(fClientControl
.fName
, &refnum
, &fEngineControl
, &fGraphManager
, this, false) != 0) {
165 jack_error("Cannot allocate internal client for driver");
169 fClientControl
.fRefNum
= refnum
;
170 fClientControl
.fActive
= true;
171 fEngineControl
->fDriverNum
++;
172 fEngineControl
->fBufferSize
= buffer_size
;
173 fEngineControl
->fSampleRate
= samplerate
;
174 fCaptureLatency
= capture_latency
;
175 fPlaybackLatency
= playback_latency
;
177 assert(strlen(capture_driver_name
) < JACK_CLIENT_NAME_SIZE
);
178 assert(strlen(playback_driver_name
) < JACK_CLIENT_NAME_SIZE
);
180 strcpy(fCaptureDriverName
, capture_driver_name
);
181 strcpy(fPlaybackDriverName
, playback_driver_name
);
183 fEngineControl
->UpdateTimeOut();
185 fGraphManager
->SetBufferSize(buffer_size
);
186 fGraphManager
->DirectConnect(fClientControl
.fRefNum
, fClientControl
.fRefNum
); // Connect driver to itself for "sync" mode
187 SetupDriverSync(fClientControl
.fRefNum
, false);
191 int JackDriver::Close()
193 if (fClientControl
.fRefNum
>= 0) {
194 jack_log("JackDriver::Close");
195 fGraphManager
->DirectDisconnect(fClientControl
.fRefNum
, fClientControl
.fRefNum
); // Disconnect driver from itself for sync
196 fClientControl
.fActive
= false;
197 fEngineControl
->fDriverNum
--;
198 return fEngine
->ClientInternalClose(fClientControl
.fRefNum
, false);
205 In "async" mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
206 The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
207 Drivers synchro are setup in "flush" mode if server is "async" and NOT freewheel.
209 void JackDriver::SetupDriverSync(int ref
, bool freewheel
)
211 if (!freewheel
&& !fEngineControl
->fSyncMode
) {
212 jack_log("JackDriver::SetupDriverSync driver sem in flush mode");
213 fSynchroTable
[ref
].SetFlush(true);
215 jack_log("JackDriver::SetupDriverSync driver sem in normal mode");
216 fSynchroTable
[ref
].SetFlush(false);
220 int JackDriver::ClientNotify(int refnum
, const char* name
, int notify
, int sync
, const char* message
, int value1
, int value2
)
222 jack_log("JackDriver::ClientNotify ref = %ld driver = %s name = %s notify = %ld", refnum
, fClientControl
.fName
, name
, notify
);
226 case kStartFreewheelCallback
:
227 jack_log("JackDriver::kStartFreewheel");
228 SetupDriverSync(fClientControl
.fRefNum
, true);
231 case kStopFreewheelCallback
:
232 jack_log("JackDriver::kStopFreewheel");
233 SetupDriverSync(fClientControl
.fRefNum
, false);
240 bool JackDriver::IsRealTime() const
242 return fEngineControl
->fRealTime
;
245 void JackDriver::CycleIncTime()
247 fEngineControl
->CycleIncTime(fBeginDateUst
);
250 void JackDriver::CycleTakeBeginTime()
252 fBeginDateUst
= GetMicroSeconds(); // Take callback date here
253 fEngineControl
->CycleIncTime(fBeginDateUst
);
256 void JackDriver::CycleTakeEndTime()
258 fEndDateUst
= GetMicroSeconds(); // Take end date here
261 JackClientControl
* JackDriver::GetClientControl() const
263 return (JackClientControl
*)&fClientControl
;
266 void JackDriver::NotifyXRun(jack_time_t cur_cycle_begin
, float delayed_usecs
)
268 fEngine
->NotifyXRun(cur_cycle_begin
, delayed_usecs
);
271 void JackDriver::NotifyBufferSize(jack_nframes_t buffer_size
)
273 fEngine
->NotifyBufferSize(buffer_size
);
274 fEngineControl
->InitFrameTime();
277 void JackDriver::NotifySampleRate(jack_nframes_t sample_rate
)
279 fEngine
->NotifySampleRate(sample_rate
);
280 fEngineControl
->InitFrameTime();
283 void JackDriver::NotifyFailure(int code
, const char* reason
)
285 fEngine
->NotifyFailure(code
, reason
);
288 void JackDriver::SetMaster(bool onoff
)
293 bool JackDriver::GetMaster()
298 void JackDriver::AddSlave(JackDriverInterface
* slave
)
300 fSlaveList
.push_back(slave
);
303 void JackDriver::RemoveSlave(JackDriverInterface
* slave
)
305 fSlaveList
.remove(slave
);
308 int JackDriver::ProcessReadSlaves()
311 list
<JackDriverInterface
*>::const_iterator it
;
312 for (it
= fSlaveList
.begin(); it
!= fSlaveList
.end(); it
++) {
313 JackDriverInterface
* slave
= *it
;
314 if (slave
->IsRunning()) {
315 if (slave
->ProcessRead() < 0) {
323 int JackDriver::ProcessWriteSlaves()
326 list
<JackDriverInterface
*>::const_iterator it
;
327 for (it
= fSlaveList
.begin(); it
!= fSlaveList
.end(); it
++) {
328 JackDriverInterface
* slave
= *it
;
329 if (slave
->IsRunning()) {
330 if (slave
->ProcessWrite() < 0) {
338 int JackDriver::ProcessRead()
340 return (fEngineControl
->fSyncMode
) ? ProcessReadSync() : ProcessReadAsync();
343 int JackDriver::ProcessWrite()
345 return (fEngineControl
->fSyncMode
) ? ProcessWriteSync() : ProcessWriteAsync();
348 int JackDriver::ProcessReadSync()
353 int JackDriver::ProcessWriteSync()
358 int JackDriver::ProcessReadAsync()
363 int JackDriver::ProcessWriteAsync()
368 int JackDriver::Process()
373 int JackDriver::Attach()
378 int JackDriver::Detach()
383 int JackDriver::Read()
388 int JackDriver::Write()
393 int JackDriver::Start()
396 fEngineControl
->InitFrameTime();
399 return StartSlaves();
402 int JackDriver::Stop()
408 int JackDriver::StartSlaves()
411 list
<JackDriverInterface
*>::const_iterator it
;
412 for (it
= fSlaveList
.begin(); it
!= fSlaveList
.end(); it
++) {
413 JackDriverInterface
* slave
= *it
;
414 if (slave
->Start() < 0) {
416 // XXX: We should attempt to stop all of the slaves that we've
424 int JackDriver::StopSlaves()
427 list
<JackDriverInterface
*>::const_iterator it
;
428 for (it
= fSlaveList
.begin(); it
!= fSlaveList
.end(); it
++) {
429 JackDriverInterface
* slave
= *it
;
430 if (slave
->Stop() < 0) {
437 bool JackDriver::IsFixedBufferSize()
442 int JackDriver::SetBufferSize(jack_nframes_t buffer_size
)
445 list
<JackDriverInterface
*>::const_iterator it
;
446 for (it
= fSlaveList
.begin(); it
!= fSlaveList
.end(); it
++) {
447 JackDriverInterface
* slave
= *it
;
448 if (slave
->SetBufferSize(buffer_size
) < 0) {
455 int JackDriver::SetSampleRate(jack_nframes_t sample_rate
)
458 list
<JackDriverInterface
*>::const_iterator it
;
459 for (it
= fSlaveList
.begin(); it
!= fSlaveList
.end(); it
++) {
460 JackDriverInterface
* slave
= *it
;
461 if (slave
->SetSampleRate(sample_rate
) < 0) {
468 bool JackDriver::Initialize()
473 void JackDriver::SaveConnections()
475 const char** connections
;
476 fConnections
.clear();
477 char alias1
[REAL_JACK_PORT_NAME_SIZE
];
478 char alias2
[REAL_JACK_PORT_NAME_SIZE
];
484 for (int i
= 0; i
< fCaptureChannels
; ++i
) {
485 if (fCapturePortList
[i
] && (connections
= fGraphManager
->GetConnections(fCapturePortList
[i
])) != 0) {
486 for (int j
= 0; connections
[j
]; j
++) {
488 fGraphManager->GetPort(fCapturePortList[i])->GetAliases(aliases);
489 fConnections.push_back(make_pair(aliases[0], connections[j]));
490 jack_info("Save connection: %s %s", aliases[0], connections[j]);
492 fConnections
.push_back(make_pair(string(fGraphManager
->GetPort(fCapturePortList
[i
])->GetName()), string(connections
[j
])));
493 jack_info("Save connection: %s %s", fGraphManager
->GetPort(fCapturePortList
[i
])->GetName(), connections
[j
]);
499 for (int i
= 0; i
< fPlaybackChannels
; ++i
) {
500 if (fPlaybackPortList
[i
] && (connections
= fGraphManager
->GetConnections(fPlaybackPortList
[i
])) != 0) {
501 for (int j
= 0; connections
[j
]; j
++) {
503 fGraphManager->GetPort(fPlaybackPortList[i])->GetAliases(aliases);
504 fConnections.push_back(make_pair(connections[j], aliases[0]));
505 jack_info("Save connection: %s %s", connections[j], aliases[0]);
507 fConnections
.push_back(make_pair(string(connections
[j
]), string(fGraphManager
->GetPort(fPlaybackPortList
[i
])->GetName())));
508 jack_info("Save connection: %s %s", connections
[j
], fGraphManager
->GetPort(fPlaybackPortList
[i
])->GetName());
515 void JackDriver::RestoreConnections()
517 list
<pair
<string
, string
> >::const_iterator it
;
519 for (it
= fConnections
.begin(); it
!= fConnections
.end(); it
++) {
520 pair
<string
, string
> connection
= *it
;
521 jack_info("Restore connection: %s %s", connection
.first
.c_str(), connection
.second
.c_str());
522 fEngine
->PortConnect(fClientControl
.fRefNum
, connection
.first
.c_str(), connection
.second
.c_str());
526 int JackDriver::ResumeRefNum()
528 return fGraphManager
->ResumeRefNum(&fClientControl
, fSynchroTable
);
531 int JackDriver::SuspendRefNum()
533 return fGraphManager
->SuspendRefNum(&fClientControl
, fSynchroTable
, DRIVER_TIMEOUT_FACTOR
* fEngineControl
->fTimeOutUsecs
);
537 } // end of namespace