~ubuntu-branches/debian/sid/jackd2/sid

2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
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 "JackServerGlobals.h"
23
#include "JackTime.h"
24
#include "JackFreewheelDriver.h"
25
#include "JackDummyDriver.h"
26
#include "JackThreadedDriver.h"
27
#include "JackGlobals.h"
28
#include "JackLockedEngine.h"
29
#include "JackAudioDriver.h"
30
#include "JackChannel.h"
31
#include "JackClientControl.h"
32
#include "JackEngineControl.h"
33
#include "JackGraphManager.h"
34
#include "JackInternalClient.h"
35
#include "JackError.h"
36
#include "JackMessageBuffer.h"
37
38
namespace Jack
39
{
40
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)
42
{
43
    if (rt) {
44
        jack_info("JACK server starting in realtime mode with priority %ld", priority);
45
    } else {
46
        jack_info("JACK server starting in non-realtime mode");
47
    }
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
48
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
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);
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
52
53
    // A distinction is made between the threaded freewheel driver and the
54
    // regular freewheel driver because the freewheel driver needs to run in
55
    // threaded mode when freewheel mode is active and needs to run as a slave
56
    // when freewheel mode isn't active.
57
    JackFreewheelDriver *freewheelDriver =
58
        new JackFreewheelDriver(fEngine, GetSynchroTable());
59
    fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver);
60
61
   fFreewheelDriver = freewheelDriver;
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
62
    fDriverInfo = new JackDriverInfo();
63
    fAudioDriver = NULL;
64
    fFreewheel = false;
65
    JackServerGlobals::fInstance = this;   // Unique instance
66
    JackServerGlobals::fUserCount = 1;     // One user
67
    JackGlobals::fVerbose = verbose;
68
}
69
70
JackServer::~JackServer()
71
{
72
    JackGraphManager::Destroy(fGraphManager);
73
    delete fDriverInfo;
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
74
    delete fThreadedFreewheelDriver;
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
75
    delete fEngine;
76
    delete fEngineControl;
77
}
78
79
int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
80
{
81
    // TODO: move that in reworked JackServerGlobals::Init()
82
    JackMessageBuffer::Create();
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
83
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
84
     if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
85
        jack_error("Cannot initialize driver");
86
        goto fail_close1;
87
    }
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
88
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
89
    if (fChannel.Open(fEngineControl->fServerName, this) < 0) {
90
        jack_error("Server channel open error");
91
        goto fail_close2;
92
    }
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
93
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
94
    if (fEngine->Open() < 0) {
95
        jack_error("Cannot open engine");
96
        goto fail_close3;
97
    }
98
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
99
    if (fFreewheelDriver->Open() < 0) {
100
        jack_error("Cannot open freewheel driver");
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
101
        goto fail_close4;
102
    }
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
103
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
104
    if (fAudioDriver->Attach() < 0) {
105
        jack_error("Cannot attach audio driver");
106
        goto fail_close5;
107
    }
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
108
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
109
    fFreewheelDriver->SetMaster(false);
110
    fAudioDriver->SetMaster(true);
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
111
    fAudioDriver->AddSlave(fFreewheelDriver);
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
112
    InitTime();
113
    SetClockSource(fEngineControl->fClockSource);
114
    return 0;
115
116
fail_close5:
117
    fFreewheelDriver->Close();
118
119
fail_close4:
120
    fEngine->Close();
121
122
fail_close3:
123
    fChannel.Close();
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
124
125
fail_close2:
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
126
    fAudioDriver->Close();
127
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
128
fail_close1:
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
129
    JackMessageBuffer::Destroy();
130
    return -1;
131
}
132
133
int JackServer::Close()
134
{
135
    jack_log("JackServer::Close");
136
    fEngine->NotifyQuit();
137
    fChannel.Close();
138
    fAudioDriver->Detach();
139
    fAudioDriver->Close();
140
    fFreewheelDriver->Close();
141
    fEngine->Close();
142
    // TODO: move that in reworked JackServerGlobals::Destroy()
143
    JackMessageBuffer::Destroy();
144
    return 0;
145
}
146
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
147
int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status)
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
148
{
149
    JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
150
    assert(client);
151
    return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
152
 }
153
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
154
int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status)
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
155
{
156
    JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
157
    assert(client);
158
    return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
159
}
160
161
int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status)
162
{
163
    // Clear status
164
    *status = 0;
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
165
166
    // Client object is internally kept in JackEngine
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
167
    if ((client->Init(so_name) < 0) || (client->Open(JACK_DEFAULT_SERVER_NAME, client_name,  uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) {
168
        delete client;
169
        int my_status1 = *status | JackFailure;
170
        *status = (jack_status_t)my_status1;
171
        *int_ref = 0;
172
        return -1;
173
    } else {
174
        *int_ref = client->GetClientControl()->fRefNum;
175
        return 0;
176
    }
177
 }
178
179
int JackServer::Start()
180
{
181
    jack_log("JackServer::Start");
182
    if (fAudioDriver->Start() < 0) {
183
        return -1;
184
    }
185
    return fChannel.Start();
186
}
187
188
int JackServer::Stop()
189
{
190
    jack_log("JackServer::Stop");
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
191
    if (fFreewheel) {
192
        return fThreadedFreewheelDriver->Stop();
193
    } else {
194
        return fAudioDriver->Stop();
195
    }
196
}
197
198
bool JackServer::IsRunning()
199
{
200
    jack_log("JackServer::IsRunning");
201
    assert(fAudioDriver);
202
    return fAudioDriver->IsRunning();
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
203
}
204
205
int JackServer::SetBufferSize(jack_nframes_t buffer_size)
206
{
207
    jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
208
    jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
209
210
    if (current_buffer_size == buffer_size) {
211
        jack_log("SetBufferSize: requirement for new buffer size equals current value");
212
        return 0;
213
    }
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
214
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
215
    if (fAudioDriver->IsFixedBufferSize()) {
216
        jack_log("SetBufferSize: driver only supports a fixed buffer size");
217
        return -1;
218
    }
219
220
    if (fAudioDriver->Stop() != 0) {
221
        jack_error("Cannot stop audio driver");
222
        return -1;
223
    }
224
225
    if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
226
        fFreewheelDriver->SetBufferSize(buffer_size);
227
        fEngine->NotifyBufferSize(buffer_size);
228
        return fAudioDriver->Start();
229
    } else { // Failure: try to restore current value
230
        jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
231
        fAudioDriver->SetBufferSize(current_buffer_size);
232
        fFreewheelDriver->SetBufferSize(current_buffer_size);
233
        fAudioDriver->Start();
234
        // SetBufferSize actually failed, so return an error...
235
        return -1;
236
    }
237
}
238
239
/*
240
Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
241
242
    - "global" connection state is saved
243
    - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
244
    - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
245
    - the freewheel driver becomes the "master"
246
247
Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
248
no graph state change can be done during freewheel mode.
249
*/
250
251
int JackServer::SetFreewheel(bool onoff)
252
{
253
    jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
254
255
    if (fFreewheel) {
256
        if (onoff) {
257
            return -1;
258
        } else {
259
            fFreewheel = false;
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
260
            fThreadedFreewheelDriver->Stop();
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
261
            fGraphManager->Restore(&fConnectionState);   // Restore previous connection state
262
            fEngine->NotifyFreewheel(onoff);
263
            fFreewheelDriver->SetMaster(false);
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
264
            fAudioDriver->SetMaster(true);
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
265
            return fAudioDriver->Start();
266
        }
267
    } else {
268
        if (onoff) {
269
            fFreewheel = true;
270
            fAudioDriver->Stop();
271
            fGraphManager->Save(&fConnectionState);     // Save connection state
272
            fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
273
            fEngine->NotifyFreewheel(onoff);
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
274
            fAudioDriver->SetMaster(false);
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
275
            fFreewheelDriver->SetMaster(true);
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
276
            return fThreadedFreewheelDriver->Start();
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
277
        } else {
278
            return -1;
279
        }
280
    }
281
}
282
283
// Coming from the RT thread
284
void JackServer::Notify(int refnum, int notify, int value)
285
{
286
    switch (notify) {
287
288
        case kGraphOrderCallback:
289
            fEngine->NotifyGraphReorder();
290
            break;
291
292
        case kXRunCallback:
293
            fEngine->NotifyXRun(refnum);
294
            break;
295
    }
296
}
297
298
void JackServer::ClientKill(int refnum)
299
{
300
    jack_log("JackServer::ClientKill ref = %ld", refnum);
301
    if (fEngine->ClientDeactivate(refnum) < 0) {
302
        jack_error("JackServer::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
303
    }
304
    if (fEngine->ClientExternalClose(refnum) < 0) {
305
        jack_error("JackServer::ClientKill ref = %ld cannot be closed", refnum);
306
    }
307
}
308
309
//----------------------
310
// Backend management
311
//----------------------
312
313
JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
314
{
315
    JackDriverInfo* info = new JackDriverInfo();
316
    JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
317
    if (slave == NULL) {
318
        delete info;
319
        return NULL;
320
    }
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
321
    slave->Attach();
322
    slave->SetMaster(false);
323
    fAudioDriver->AddSlave(slave);
324
    return info;
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
325
}
326
327
void JackServer::RemoveSlave(JackDriverInfo* info)
328
{
329
    JackDriverClientInterface* slave = info->GetBackend();
330
    fAudioDriver->RemoveSlave(slave);
331
    slave->Detach();
332
    slave->Close();
333
}
334
335
int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
336
{
337
    /// Remove current master
338
    fAudioDriver->Stop();
339
    fAudioDriver->Detach();
340
    fAudioDriver->Close();
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
341
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
342
    // Open new master
343
    JackDriverInfo* info = new JackDriverInfo();
344
    JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
345
346
    if (master == NULL) {
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
347
        delete info;
348
        return -1;
8 by Adrian Knoth
* New upstream version 1.9.7 (ALSA resume, new latency API)
349
    }
350
351
    // Get slaves list
352
    std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
353
    std::list<JackDriverInterface*>::const_iterator it;
354
355
    // Move slaves in new master
356
    for (it = slave_list.begin(); it != slave_list.end(); it++) {
357
        JackDriverInterface* slave = *it;
358
        master->AddSlave(slave);
359
    }
360
361
    // Delete old master
362
    delete fDriverInfo;
363
364
    // Activate master
365
    fAudioDriver = master;
366
    fDriverInfo = info;
367
    fAudioDriver->Attach();
368
    fAudioDriver->SetMaster(true);
369
    return fAudioDriver->Start();
2.1.4 by Adrian Knoth
Add no-self-connect patch to provide better ladish support.
370
}
371
372
//----------------------
373
// Transport management
374
//----------------------
375
376
int JackServer::ReleaseTimebase(int refnum)
377
{
378
    return fEngineControl->fTransport.ResetTimebase(refnum);
379
}
380
381
int JackServer::SetTimebaseCallback(int refnum, int conditional)
382
{
383
    return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
384
}
385
386
JackLockedEngine* JackServer::GetEngine()
387
{
388
    return fEngine;
389
}
390
391
JackSynchro* JackServer::GetSynchroTable()
392
{
393
    return fSynchroTable;
394
}
395
396
JackEngineControl* JackServer::GetEngineControl()
397
{
398
    return fEngineControl;
399
}
400
401
JackGraphManager* JackServer::GetGraphManager()
402
{
403
    return fGraphManager;
404
}
405
406
407
} // end of namespace
408