JackAudioDriver.cpp 13.4 KB
Newer Older
sletz's avatar
sletz committed
1
/*
sletz's avatar
sletz committed
2
Copyright (C) 2001 Paul Davis
sletz's avatar
sletz committed
3
Copyright (C) 2004-2008 Grame.
sletz's avatar
sletz committed
4
5
6
7
8
9
10

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
sletz's avatar
sletz committed
11
12
(at your option) any later version.

sletz's avatar
sletz committed
13
14
15
16
17
18
19
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
sletz's avatar
Cleanup    
sletz committed
20

21
#include "JackSystemDeps.h"
sletz's avatar
sletz committed
22
23
24
25
26
27
#include "JackAudioDriver.h"
#include "JackTime.h"
#include "JackError.h"
#include "JackEngineControl.h"
#include "JackPort.h"
#include "JackGraphManager.h"
sletz's avatar
sletz committed
28
#include "JackLockedEngine.h"
29
#include "JackException.h"
sletz's avatar
sletz committed
30
31
32
33
34
#include <assert.h>

namespace Jack
{

sletz's avatar
sletz committed
35
JackAudioDriver::JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
36
        : JackDriver(name, alias, engine, table),
sletz's avatar
sletz committed
37
38
39
40
41
42
43
44
        fCaptureChannels(0),
        fPlaybackChannels(0),
        fWithMonitorPorts(false)
{}

JackAudioDriver::~JackAudioDriver()
{}

sletz's avatar
sletz committed
45
46
47
int JackAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
{
    fEngineControl->fBufferSize = buffer_size;
sletz's avatar
sletz committed
48
49
50
51
    fGraphManager->SetBufferSize(buffer_size);
    fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize);	// in microsec
    if (!fEngineControl->fTimeOut)
        fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs);
sletz's avatar
sletz committed
52
53
54
    return 0;
}

55
56
57
int JackAudioDriver::SetSampleRate(jack_nframes_t sample_rate)
{
    fEngineControl->fSampleRate = sample_rate;
sletz's avatar
sletz committed
58
59
60
    fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize);	// in microsec
    if (!fEngineControl->fTimeOut)
        fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs);
61
62
63
    return 0;
}

sletz's avatar
sletz committed
64
int JackAudioDriver::Open(jack_nframes_t buffer_size,
sletz's avatar
sletz committed
65
                          jack_nframes_t samplerate,
sletz's avatar
sletz committed
66
67
                          bool capturing,
                          bool playing,
sletz's avatar
sletz committed
68
69
70
71
72
73
74
75
76
77
78
                          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)
{
    fCaptureChannels = inchannels;
    fPlaybackChannels = outchannels;
    fWithMonitorPorts = monitor;
sletz's avatar
sletz committed
79
    return JackDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency);
sletz's avatar
sletz committed
80
81
}

sletz's avatar
sletz committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
int JackAudioDriver::Open(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)
{
    fCaptureChannels = inchannels;
    fPlaybackChannels = outchannels;
    fWithMonitorPorts = monitor;
    return JackDriver::Open(capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency);
}

sletz's avatar
sletz committed
98
99
100
101
int JackAudioDriver::Attach()
{
    JackPort* port;
    jack_port_id_t port_index;
102
    char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
sletz's avatar
sletz committed
103
    char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
sletz's avatar
sletz committed
104
    jack_latency_range_t range;
sletz's avatar
sletz committed
105
106
    int i;

sletz's avatar
sletz committed
107
    jack_log("JackAudioDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
sletz's avatar
sletz committed
108
109

    for (i = 0; i < fCaptureChannels; i++) {
110
        snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
111
        snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
sletz's avatar
sletz committed
112
        if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
113
            jack_error("driver: cannot register port for %s", name);
sletz's avatar
sletz committed
114
115
            return -1;
        }
sletz's avatar
sletz committed
116
117
        port = fGraphManager->GetPort(port_index);
        port->SetAlias(alias);
sletz's avatar
sletz committed
118
119
        range.min = range.max = fEngineControl->fBufferSize + fCaptureLatency;
        port->SetLatencyRange(JackCaptureLatency, &range);
sletz's avatar
sletz committed
120
        fCapturePortList[i] = port_index;
sletz's avatar
sletz committed
121
        jack_log("JackAudioDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
sletz's avatar
sletz committed
122
123
124
    }

    for (i = 0; i < fPlaybackChannels; i++) {
125
        snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1);
126
        snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
sletz's avatar
sletz committed
127
        if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
128
            jack_error("driver: cannot register port for %s", name);
sletz's avatar
sletz committed
129
130
            return -1;
        }
sletz's avatar
sletz committed
131
132
        port = fGraphManager->GetPort(port_index);
        port->SetAlias(alias);
133
        // Add more latency if "async" mode is used...
sletz's avatar
sletz committed
134
135
        range.min = range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency;
        port->SetLatencyRange(JackPlaybackLatency, &range);
sletz's avatar
sletz committed
136
        fPlaybackPortList[i] = port_index;
sletz's avatar
sletz committed
137
        jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
sletz's avatar
sletz committed
138

sletz's avatar
sletz committed
139
140
        // Monitor ports
        if (fWithMonitorPorts) {
sletz's avatar
sletz committed
141
            jack_log("Create monitor port");
sletz's avatar
sletz committed
142
            snprintf(name, sizeof(name) - 1, "%s:monitor_%u", fClientControl.fName, i + 1);
143
            if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, fEngineControl->fBufferSize)) == NO_PORT) {
144
                jack_error("Cannot register monitor port for %s", name);
sletz's avatar
sletz committed
145
146
147
                return -1;
            } else {
                port = fGraphManager->GetPort(port_index);
sletz's avatar
sletz committed
148
149
                range.min = range.max = fEngineControl->fBufferSize;
                port->SetLatencyRange(JackCaptureLatency, &range);
sletz's avatar
sletz committed
150
151
152
153
154
155
156
157
158
159
160
                fMonitorPortList[i] = port_index;
            }
        }
    }

    return 0;
}

int JackAudioDriver::Detach()
{
    int i;
sletz's avatar
sletz committed
161
    jack_log("JackAudioDriver::Detach");
sletz's avatar
sletz committed
162
163

    for (i = 0; i < fCaptureChannels; i++) {
164
        fGraphManager->ReleasePort(fClientControl.fRefNum, fCapturePortList[i]);
sletz's avatar
sletz committed
165
166
167
    }

    for (i = 0; i < fPlaybackChannels; i++) {
168
        fGraphManager->ReleasePort(fClientControl.fRefNum, fPlaybackPortList[i]);
sletz's avatar
sletz committed
169
        if (fWithMonitorPorts)
170
            fGraphManager->ReleasePort(fClientControl.fRefNum, fMonitorPortList[i]);
sletz's avatar
sletz committed
171
172
173
174
175
176
177
178
179
    }

    return 0;
}

int JackAudioDriver::Write()
{
    for (int i = 0; i < fPlaybackChannels; i++) {
        if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
sletz's avatar
sletz committed
180
181
            jack_default_audio_sample_t* buffer = GetOutputBuffer(i);
            int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize;
sletz's avatar
sletz committed
182
183
            // Monitor ports
            if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0)
sletz's avatar
sletz committed
184
                memcpy(GetMonitorBuffer(i), buffer, size);
sletz's avatar
sletz committed
185
186
187
188
189
        }
    }
    return 0;
}

190
191
int JackAudioDriver::ProcessNull()
{
sletz's avatar
sletz committed
192
    // Keep begin cycle time
sletz's avatar
sletz committed
193
    JackDriver::CycleTakeBeginTime();
sletz's avatar
sletz committed
194

sletz's avatar
sletz committed
195
196
197
198
199
    if (fEngineControl->fSyncMode) {
        ProcessGraphSync();
    } else {
        ProcessGraphAsync();
    }
sletz's avatar
sletz committed
200

sletz's avatar
sletz committed
201
    // Keep end cycle time
sletz's avatar
sletz committed
202
    JackDriver::CycleTakeEndTime();
sletz's avatar
sletz committed
203
    WaitUntilNextCycle();
204
    return 0;
sletz's avatar
sletz committed
205
206
}

sletz's avatar
sletz committed
207
208
209
210
211
int JackAudioDriver::Process()
{
    return (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync();
}

sletz's avatar
sletz committed
212
213
214
215
216
217
218
/*
The driver ASYNC mode: output buffers computed at the *previous cycle* are used, the server does not
synchronize to the end of client graph execution.
*/

int JackAudioDriver::ProcessAsync()
{
219
    // Read input buffers for the current cycle
sletz's avatar
sletz committed
220
    if (Read() < 0) {
sletz's avatar
sletz committed
221
        jack_error("JackAudioDriver::ProcessAsync: read error, stopping...");
sletz's avatar
sletz committed
222
        return -1;
sletz's avatar
sletz committed
223
224
    }

225
226
    // Write output buffers from the previous cycle
    if (Write() < 0) {
sletz's avatar
sletz committed
227
        jack_error("JackAudioDriver::ProcessAsync: write error, stopping...");
sletz's avatar
sletz committed
228
        return -1;
sletz's avatar
sletz committed
229
230
    }

sletz's avatar
sletz committed
231
    // Process graph
sletz's avatar
sletz committed
232
    if (fIsMaster) {
sletz's avatar
sletz committed
233
        ProcessGraphAsync();
sletz's avatar
sletz committed
234
    } else {
235
        fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
sletz's avatar
sletz committed
236
    }
sletz's avatar
sletz committed
237

sletz's avatar
sletz committed
238
    // Keep end cycle time
sletz's avatar
sletz committed
239
    JackDriver::CycleTakeEndTime();
sletz's avatar
sletz committed
240
241
242
243
244
    return 0;
}

/*
The driver SYNC mode: the server does synchronize to the end of client graph execution,
sletz's avatar
sletz committed
245
if graph process succeed, output buffers computed at the *current cycle* are used.
sletz's avatar
sletz committed
246
247
248
249
*/

int JackAudioDriver::ProcessSync()
{
250
    // Read input buffers for the current cycle
sletz's avatar
sletz committed
251
    if (Read() < 0) {
sletz's avatar
sletz committed
252
        jack_error("JackAudioDriver::ProcessSync: read error, stopping...");
sletz's avatar
sletz committed
253
        return -1;
sletz's avatar
sletz committed
254
255
    }

sletz's avatar
sletz committed
256
    // Process graph
sletz's avatar
Cleanup    
sletz committed
257
    if (fIsMaster) {
sletz's avatar
sletz committed
258
259
260
261
        if (ProcessGraphSync() < 0) {
            jack_error("JackAudioDriver::ProcessSync: process error, skip cycle...");
            goto end;
        }
sletz's avatar
sletz committed
262
    } else {
sletz's avatar
sletz committed
263
264
265
266
        if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) {
            jack_error("JackAudioDriver::ProcessSync: process error, skip cycle...");
            goto end;
        }
sletz's avatar
sletz committed
267
    }
sletz's avatar
sletz committed
268

sletz's avatar
sletz committed
269
270
271
    // Write output buffers from the current cycle
    if (Write() < 0) {
        jack_error("JackAudioDriver::ProcessSync: write error, stopping...");
sletz's avatar
sletz committed
272
        return -1;
sletz's avatar
sletz committed
273
    }
sletz's avatar
sletz committed
274
275
276

end:

sletz's avatar
sletz committed
277
    // Keep end cycle time
sletz's avatar
sletz committed
278
    JackDriver::CycleTakeEndTime();
sletz's avatar
sletz committed
279
280
281
    return 0;
}

sletz's avatar
sletz committed
282
283
284
void JackAudioDriver::ProcessGraphAsync()
{
    // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle
sletz's avatar
sletz committed
285
    if (!fEngine->Process(fBeginDateUst, fEndDateUst))
sletz's avatar
sletz committed
286
        jack_error("JackAudioDriver::ProcessGraphAsync: Process error");
sletz's avatar
sletz committed
287
288
    fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
    if (ProcessSlaves() < 0)
sletz's avatar
sletz committed
289
        jack_error("JackAudioDriver::ProcessGraphAsync: ProcessSlaves error");
sletz's avatar
sletz committed
290
291
}

sletz's avatar
sletz committed
292
int JackAudioDriver::ProcessGraphSync()
sletz's avatar
sletz committed
293
{
sletz's avatar
sletz committed
294
295
    int res = 0;

sletz's avatar
sletz committed
296
    // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle
sletz's avatar
sletz committed
297
    if (fEngine->Process(fBeginDateUst, fEndDateUst)) {
sletz's avatar
sletz committed
298
        fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
sletz's avatar
sletz committed
299
        if (ProcessSlaves() < 0) {
sletz's avatar
sletz committed
300
            jack_error("JackAudioDriver::ProcessGraphSync: ProcessSlaves error, engine may now behave abnormally!!");
sletz's avatar
sletz committed
301
302
303
            res = -1;
        }
        if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) {
sletz's avatar
sletz committed
304
            jack_error("JackAudioDriver::ProcessGraphSync: SuspendRefNum error, engine may now behave abnormally!!");
sletz's avatar
sletz committed
305
306
            res = -1;
        }
sletz's avatar
sletz committed
307
    } else { // Graph not finished: do not activate it
sletz's avatar
sletz committed
308
        jack_error("JackAudioDriver::ProcessGraphSync: Process error");
sletz's avatar
sletz committed
309
        res = -1;
sletz's avatar
sletz committed
310
    }
sletz's avatar
sletz committed
311
312

    return res;
sletz's avatar
sletz committed
313
314
}

sletz's avatar
sletz committed
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
int JackAudioDriver::Start()
{
    int res = JackDriver::Start();
    if ((res >= 0) && fIsMaster) {
        res = StartSlaves();
    }
    return res;
}

int JackAudioDriver::Stop()
{
    int res = JackDriver::Stop();
    if (fIsMaster) {
        if (StopSlaves() < 0) {
            res = -1;
        }
    }
    return res;
}

sletz's avatar
sletz committed
335
336
337
338
339
340
341
342
void JackAudioDriver::WaitUntilNextCycle()
{
    int wait_time_usec = (int((float(fEngineControl->fBufferSize) / (float(fEngineControl->fSampleRate))) * 1000000.0f));
    wait_time_usec = int(wait_time_usec - (GetMicroSeconds() - fBeginDateUst));
	if (wait_time_usec > 0)
		JackSleep(wait_time_usec);
}

sletz's avatar
sletz committed
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
jack_default_audio_sample_t* JackAudioDriver::GetInputBuffer(int port_index)
{
    assert(fCapturePortList[port_index]);
    return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[port_index], fEngineControl->fBufferSize);
}

jack_default_audio_sample_t* JackAudioDriver::GetOutputBuffer(int port_index)
{
    assert(fPlaybackPortList[port_index]);
    return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[port_index], fEngineControl->fBufferSize);
}

jack_default_audio_sample_t* JackAudioDriver::GetMonitorBuffer(int port_index)
{
    assert(fPlaybackPortList[port_index]);
    return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize);
}

sletz's avatar
sletz committed
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
int JackAudioDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
{
    switch (notify) {

        case kLatencyCallback:
            HandleLatencyCallback(value1);
            break;

        default:
            JackDriver::ClientNotify(refnum, name, notify, sync, message, value1, value2);
            break;
    }

    return 0;
}

void JackAudioDriver::HandleLatencyCallback(int status)
{
    jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency;

    for (int i = 0; i < fCaptureChannels; i++) {
        if (mode == JackPlaybackLatency) {
           fGraphManager->RecalculateLatency(fCapturePortList[i], mode);
		}
	}

    for (int i = 0; i < fPlaybackChannels; i++) {
        if (mode == JackCaptureLatency) {
            fGraphManager->RecalculateLatency(fPlaybackPortList[i], mode);
		}
	}
}

sletz's avatar
sletz committed
394
} // end of namespace