JackServer.cpp 11.9 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
11
12
13
14
15
16
17
18
19

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
(at your option) any later version.

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
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
sletz committed
20

21
#include "JackSystemDeps.h"
22
#include "JackServerGlobals.h"
sletz's avatar
sletz committed
23
24
#include "JackTime.h"
#include "JackFreewheelDriver.h"
25
#include "JackDummyDriver.h"
sletz's avatar
sletz committed
26
27
#include "JackThreadedDriver.h"
#include "JackGlobals.h"
28
#include "JackLockedEngine.h"
sletz's avatar
sletz committed
29
30
31
32
33
#include "JackAudioDriver.h"
#include "JackChannel.h"
#include "JackClientControl.h"
#include "JackEngineControl.h"
#include "JackGraphManager.h"
34
#include "JackInternalClient.h"
sletz's avatar
sletz committed
35
36
#include "JackError.h"
#include "JackMessageBuffer.h"
sletz's avatar
sletz committed
37
38
39
40

namespace Jack
{

sletz's avatar
sletz committed
41
JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, const char* server_name)
sletz's avatar
sletz committed
42
{
43
    if (rt) {
44
        jack_info("JACK server starting in realtime mode with priority %ld", priority);
45
    } else {
46
47
        jack_info("JACK server starting in non-realtime mode");
    }
48

sletz's avatar
sletz committed
49
    fGraphManager = JackGraphManager::Allocate(port_max);
50
    fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name);
51
    fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl);
52
53
54
55
56
57
58
59
60

    // A distinction is made between the threaded freewheel driver and the
    // regular freewheel driver because the freewheel driver needs to run in
    // threaded mode when freewheel mode is active and needs to run as a slave
    // when freewheel mode isn't active.
    JackFreewheelDriver *freewheelDriver =
        new JackFreewheelDriver(fEngine, GetSynchroTable());
    fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver);

sletz's avatar
sletz committed
61
    fFreewheelDriver = freewheelDriver;
62
    fDriverInfo = new JackDriverInfo();
63
    fAudioDriver = NULL;
sletz's avatar
sletz committed
64
    fFreewheel = false;
65
66
    JackServerGlobals::fInstance = this;   // Unique instance
    JackServerGlobals::fUserCount = 1;     // One user
67
    JackGlobals::fVerbose = verbose;
sletz's avatar
sletz committed
68
69
70
71
}

JackServer::~JackServer()
{
sletz's avatar
sletz committed
72
    JackGraphManager::Destroy(fGraphManager);
73
    delete fDriverInfo;
74
    delete fThreadedFreewheelDriver;
sletz's avatar
sletz committed
75
76
77
78
79
80
    delete fEngine;
    delete fEngineControl;
}

int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
{
sletz's avatar
sletz committed
81
82
    // TODO: move that in reworked JackServerGlobals::Init()
    JackMessageBuffer::Create();
83

84
85
86
87
     if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
        jack_error("Cannot initialize driver");
        goto fail_close1;
    }
88

89
    if (fChannel.Open(fEngineControl->fServerName, this) < 0) {
sletz's avatar
sletz committed
90
        jack_error("Server channel open error");
91
        goto fail_close2;
sletz's avatar
sletz committed
92
    }
93

94
    if (fEngine->Open() < 0) {
sletz's avatar
sletz committed
95
        jack_error("Cannot open engine");
96
        goto fail_close3;
sletz's avatar
sletz committed
97
    }
98

99
100
101
102
103
    if (fFreewheelDriver->Open() < 0) {
        jack_error("Cannot open freewheel driver");
        goto fail_close4;
    }

104
    if (fAudioDriver->Attach() < 0) {
sletz's avatar
sletz committed
105
        jack_error("Cannot attach audio driver");
106
        goto fail_close5;
107
    }
108

sletz's avatar
sletz committed
109
110
    fFreewheelDriver->SetMaster(false);
    fAudioDriver->SetMaster(true);
111
    fAudioDriver->AddSlave(fFreewheelDriver);
sletz's avatar
sletz committed
112
    InitTime();
113
    SetClockSource(fEngineControl->fClockSource);
sletz's avatar
sletz committed
114
    return 0;
115

116
117
118
fail_close5:
    fFreewheelDriver->Close();

119
fail_close4:
120
    fEngine->Close();
121
122

fail_close3:
123
    fChannel.Close();
124
125

fail_close2:
126
    fAudioDriver->Close();
127

128
fail_close1:
sletz's avatar
Typo.    
sletz committed
129
130
    JackMessageBuffer::Destroy();
    return -1;
sletz's avatar
sletz committed
131
132
133
134
}

int JackServer::Close()
{
sletz's avatar
sletz committed
135
    jack_log("JackServer::Close");
136
    fEngine->NotifyQuit();
137
    fChannel.Close();
sletz's avatar
sletz committed
138
139
140
    fAudioDriver->Detach();
    fAudioDriver->Close();
    fEngine->Close();
sletz's avatar
sletz committed
141
142
    // TODO: move that in reworked JackServerGlobals::Destroy()
    JackMessageBuffer::Destroy();
sletz's avatar
sletz committed
143
144
145
    return 0;
}

146
int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status)
147
{
sletz's avatar
sletz committed
148
    JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
149
    assert(client);
Stéphane LETZ's avatar
Stéphane LETZ committed
150
    return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
151
 }
152

153
int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status)
154
{
sletz's avatar
sletz committed
155
    JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
156
    assert(client);
Stéphane LETZ's avatar
Stéphane LETZ committed
157
    return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
158
159
}

Stéphane LETZ's avatar
Stéphane LETZ committed
160
int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status)
161
{
162
163
    // Clear status
    *status = 0;
164
165

    // Client object is internally kept in JackEngine
Stéphane LETZ's avatar
Stéphane LETZ committed
166
    if ((client->Init(so_name) < 0) || (client->Open(JACK_DEFAULT_SERVER_NAME, client_name,  uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) {
167
        delete client;
sletz's avatar
sletz committed
168
169
170
        int my_status1 = *status | JackFailure;
        *status = (jack_status_t)my_status1;
        *int_ref = 0;
171
172
173
174
        return -1;
    } else {
        *int_ref = client->GetClientControl()->fRefNum;
        return 0;
sletz's avatar
sletz committed
175
    }
176
 }
177

sletz's avatar
sletz committed
178
179
int JackServer::Start()
{
sletz's avatar
sletz committed
180
    jack_log("JackServer::Start");
181
182
183
184
    if (fAudioDriver->Start() < 0) {
        return -1;
    }
    return fChannel.Start();
sletz's avatar
sletz committed
185
186
187
188
}

int JackServer::Stop()
{
sletz's avatar
sletz committed
189
    jack_log("JackServer::Stop");
190
191
192
193
194
195
196
197
198
199
200
201
    if (fFreewheel) {
        return fThreadedFreewheelDriver->Stop();
    } else {
        return fAudioDriver->Stop();
    }
}

bool JackServer::IsRunning()
{
    jack_log("JackServer::IsRunning");
    assert(fAudioDriver);
    return fAudioDriver->IsRunning();
sletz's avatar
sletz committed
202
203
}

204
205
int JackServer::SetBufferSize(jack_nframes_t buffer_size)
{
sletz's avatar
sletz committed
206
    jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
sletz's avatar
sletz committed
207
    jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
208

209
210
211
212
    if (current_buffer_size == buffer_size) {
        jack_log("SetBufferSize: requirement for new buffer size equals current value");
        return 0;
    }
213

214
215
    if (fAudioDriver->IsFixedBufferSize()) {
        jack_log("SetBufferSize: driver only supports a fixed buffer size");
216
        return -1;
217
    }
218

219
220
221
222
223
224
    if (fAudioDriver->Stop() != 0) {
        jack_error("Cannot stop audio driver");
        return -1;
    }

    if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
sletz's avatar
sletz committed
225
226
227
228
        fEngine->NotifyBufferSize(buffer_size);
        return fAudioDriver->Start();
    } else { // Failure: try to restore current value
        jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
sletz's avatar
sletz committed
229
        fAudioDriver->SetBufferSize(current_buffer_size);
230
231
232
        fAudioDriver->Start();
        // SetBufferSize actually failed, so return an error...
        return -1;
sletz's avatar
sletz committed
233
    }
234
}
sletz's avatar
sletz committed
235
236
237

/*
Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
sletz's avatar
sletz committed
238

sletz's avatar
sletz committed
239
240
241
242
    - "global" connection state is saved
    - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
    - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
    - the freewheel driver becomes the "master"
sletz's avatar
sletz committed
243
244

Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
sletz's avatar
sletz committed
245
246
247
248
249
no graph state change can be done during freewheel mode.
*/

int JackServer::SetFreewheel(bool onoff)
{
250
    jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
sletz's avatar
sletz committed
251
252
253
254
255
256

    if (fFreewheel) {
        if (onoff) {
            return -1;
        } else {
            fFreewheel = false;
257
            fThreadedFreewheelDriver->Stop();
sletz's avatar
Cleanup    
sletz committed
258
            fGraphManager->Restore(&fConnectionState);   // Restore previous connection state
sletz's avatar
sletz committed
259
260
            fEngine->NotifyFreewheel(onoff);
            fFreewheelDriver->SetMaster(false);
261
            fAudioDriver->SetMaster(true);
sletz's avatar
sletz committed
262
            return fAudioDriver->Start();
sletz's avatar
sletz committed
263
264
265
266
267
        }
    } else {
        if (onoff) {
            fFreewheel = true;
            fAudioDriver->Stop();
sletz's avatar
Cleanup    
sletz committed
268
            fGraphManager->Save(&fConnectionState);     // Save connection state
sletz's avatar
sletz committed
269
270
            fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
            fEngine->NotifyFreewheel(onoff);
271
            fAudioDriver->SetMaster(false);
sletz's avatar
sletz committed
272
            fFreewheelDriver->SetMaster(true);
273
            return fThreadedFreewheelDriver->Start();
sletz's avatar
sletz committed
274
275
276
277
278
279
        } else {
            return -1;
        }
    }
}

sletz's avatar
Cleanup    
sletz committed
280
// Coming from the RT thread
sletz's avatar
sletz committed
281
282
283
284
void JackServer::Notify(int refnum, int notify, int value)
{
    switch (notify) {

285
        case kGraphOrderCallback:
sletz's avatar
sletz committed
286
287
288
            fEngine->NotifyGraphReorder();
            break;

289
        case kXRunCallback:
sletz's avatar
sletz committed
290
291
            fEngine->NotifyXRun(refnum);
            break;
sletz's avatar
Cleanup    
sletz committed
292
293
294
    }
}

295
void JackServer::ClientKill(int refnum)
sletz's avatar
Cleanup    
sletz committed
296
{
297
    jack_log("JackServer::ClientKill ref = %ld", refnum);
sletz's avatar
Cleanup    
sletz committed
298
    if (fEngine->ClientDeactivate(refnum) < 0) {
299
        jack_error("JackServer::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
sletz's avatar
sletz committed
300
301
    }
    if (fEngine->ClientExternalClose(refnum) < 0) {
302
        jack_error("JackServer::ClientKill ref = %ld cannot be closed", refnum);
sletz's avatar
sletz committed
303
304
305
    }
}

306
307
308
309
310
311
312
//----------------------
// Backend management
//----------------------

JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
{
    JackDriverInfo* info = new JackDriverInfo();
313
314
    JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
    if (slave == NULL) {
315
316
317
        delete info;
        return NULL;
    }
318
319
320
321
    slave->Attach();
    slave->SetMaster(false);
    fAudioDriver->AddSlave(slave);
    return info;
322
323
324
325
}

void JackServer::RemoveSlave(JackDriverInfo* info)
{
326
327
328
329
330
331
332
333
334
335
336
337
    JackDriverClientInterface* slave = info->GetBackend();
    fAudioDriver->RemoveSlave(slave);
    slave->Detach();
    slave->Close();
}

int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
{
    /// Remove current master
    fAudioDriver->Stop();
    fAudioDriver->Detach();
    fAudioDriver->Close();
338

339
340
341
    // Open new master
    JackDriverInfo* info = new JackDriverInfo();
    JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
342

343
    if (master == NULL) {
sletz's avatar
sletz committed
344
        delete info;
345
        return -1;
346
    }
347

348
349
350
    // Get slaves list
    std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
    std::list<JackDriverInterface*>::const_iterator it;
351

352
353
354
355
356
    // Move slaves in new master
    for (it = slave_list.begin(); it != slave_list.end(); it++) {
        JackDriverInterface* slave = *it;
        master->AddSlave(slave);
    }
357

358
359
    // Delete old master
    delete fDriverInfo;
360

361
362
363
364
365
366
    // Activate master
    fAudioDriver = master;
    fDriverInfo = info;
    fAudioDriver->Attach();
    fAudioDriver->SetMaster(true);
    return fAudioDriver->Start();
367
368
}

369
370
371
372
373
374
375
376
377
378
379
//----------------------
// Transport management
//----------------------

int JackServer::ReleaseTimebase(int refnum)
{
    return fEngineControl->fTransport.ResetTimebase(refnum);
}

int JackServer::SetTimebaseCallback(int refnum, int conditional)
{
380
    return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
381
382
}

sletz's avatar
sletz committed
383
JackLockedEngine* JackServer::GetEngine()
sletz's avatar
sletz committed
384
385
386
387
{
    return fEngine;
}

388
JackSynchro* JackServer::GetSynchroTable()
sletz's avatar
sletz committed
389
390
391
392
393
394
395
396
397
398
399
400
401
{
    return fSynchroTable;
}

JackEngineControl* JackServer::GetEngineControl()
{
    return fEngineControl;
}

JackGraphManager* JackServer::GetGraphManager()
{
    return fGraphManager;
}
402

sletz's avatar
sletz committed
403
404
405

} // end of namespace