JackNetAdapter.cpp 18.5 KB
Newer Older
sletz's avatar
sletz committed
1
/*
sletz's avatar
sletz committed
2
Copyright (C) 2008-2011 Romain Moret at Grame
sletz's avatar
sletz committed
3
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.
*/

#include "JackNetAdapter.h"
moret's avatar
moret committed
20
#include "JackException.h"
21
#include "JackServerGlobals.h"
22
#include "JackEngineControl.h"
23
#include "JackArgParser.h"
sletz's avatar
sletz committed
24
#include <assert.h>
25

26
27
namespace Jack
{
sletz's avatar
sletz committed
28
29
    JackNetAdapter::JackNetAdapter(jack_client_t* jack_client, jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
            : JackAudioAdapterInterface(buffer_size, sample_rate), JackNetSlaveInterface(), fThread(this)
30
    {
sletz's avatar
sletz committed
31
        jack_log("JackNetAdapter::JackNetAdapter");
sletz's avatar
sletz committed
32

sletz's avatar
sletz committed
33
34
35
36
37
        /*
        Global parameter setting : we can't call JackNetSlaveInterface constructor with some parameters before,
        because we don't have full parametering right now, parameters will be parsed from the param list,
        and then JackNetSlaveInterface will be filled with proper values.
        */
Stephane Letz's avatar
Stephane Letz committed
38
39
        char multicast_ip[32];
        uint udp_port;
sletz's avatar
sletz committed
40
41
        GetHostName(fParams.fName, JACK_CLIENT_NAME_SIZE);
        fSocket.GetName(fParams.fSlaveNetName);
42
        fParams.fMtu = DEFAULT_MTU;
sletz's avatar
sletz committed
43
        // Desactivated for now...
moret's avatar
moret committed
44
        fParams.fTransportSync = 0;
45
46
        int send_audio = -1;
        int return_audio = -1;
47
48
        fParams.fSendMidiChannels = 0;
        fParams.fReturnMidiChannels = 0;
moret's avatar
moret committed
49
50
        fParams.fSampleRate = sample_rate;
        fParams.fPeriodSize = buffer_size;
moret's avatar
Cleanup    
moret committed
51
        fParams.fSlaveSyncMode = 1;
52
        fParams.fNetworkLatency = 2;
sletz's avatar
sletz committed
53
        fParams.fSampleEncoder = JackFloatEncoder;
Stephane Letz's avatar
Stephane Letz committed
54
        fClient = jack_client;
55
    
Stephane Letz's avatar
Stephane Letz committed
56
57
58
59
60
61
62
63
64
65
        // Possibly use env variable
        const char* default_udp_port = getenv("JACK_NETJACK_PORT");
        udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;

        const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
        if (default_multicast_ip) {
            strcpy(multicast_ip, default_multicast_ip);
        } else {
            strcpy(multicast_ip, DEFAULT_MULTICAST_IP);
        }
sletz's avatar
sletz committed
66

moret's avatar
moret committed
67
        //options parsing
68
69
        const JSList* node;
        const jack_driver_param_t* param;
sletz's avatar
sletz committed
70
        for (node = params; node; node = jack_slist_next(node))
71
        {
sletz's avatar
sletz committed
72
            param = (const jack_driver_param_t*) node->data;
73
74

            switch (param->character) {
moret's avatar
moret committed
75
                case 'a' :
Stephane Letz's avatar
Stephane Letz committed
76
77
                    assert(strlen(param->value.str) < 32);
                    strcpy(multicast_ip, param->value.str);
moret's avatar
moret committed
78
79
                    break;
                case 'p' :
Stephane Letz's avatar
Stephane Letz committed
80
                    udp_port = param->value.ui;
moret's avatar
moret committed
81
82
83
84
85
                    break;
                case 'M' :
                    fParams.fMtu = param->value.i;
                    break;
                case 'C' :
86
                    send_audio = param->value.i;
moret's avatar
moret committed
87
88
                    break;
                case 'P' :
89
                    return_audio = param->value.i;
moret's avatar
moret committed
90
91
                    break;
                case 'n' :
sletz's avatar
sletz committed
92
                    strncpy(fParams.fName, param->value.str, JACK_CLIENT_NAME_SIZE);
moret's avatar
moret committed
93
94
                    break;
                case 't' :
Stephane Letz's avatar
Stephane Letz committed
95
                    fParams.fTransportSync = param->value.ui;
moret's avatar
moret committed
96
                    break;
sletz's avatar
sletz committed
97
98
99
100
101
102
103
            #if HAVE_CELT
                case 'c':
                    if (param->value.i > 0) {
                        fParams.fSampleEncoder = JackCeltEncoder;
                        fParams.fKBps = param->value.i;
                    }
                    break;
Robin Gareus's avatar
Robin Gareus committed
104
105
106
107
108
109
110
111
            #endif
            #if HAVE_OPUS
                case 'O':
                    if (param->value.i > 0) {
                        fParams.fSampleEncoder = JackOpusEncoder;
                        fParams.fKBps = param->value.i;
                    }
                    break;
sletz's avatar
sletz committed
112
            #endif
113
114
                case 'l' :
                    fParams.fNetworkLatency = param->value.i;
sletz's avatar
sletz committed
115
116
117
118
                    if (fParams.fNetworkLatency > NETWORK_MAX_LATENCY) {
                        jack_error("Error : network latency is limited to %d\n", NETWORK_MAX_LATENCY);
                        throw std::bad_alloc();
                    }
moret's avatar
moret committed
119
                    break;
120
121
122
                case 'q':
                    fQuality = param->value.ui;
                    break;
sletz's avatar
sletz committed
123
                case 'g':
sletz's avatar
sletz committed
124
125
                    fRingbufferCurSize = param->value.ui;
                    fAdaptative = false;
sletz's avatar
sletz committed
126
                    break;
127
             }
128
        }
moret's avatar
moret committed
129

Stephane Letz's avatar
Stephane Letz committed
130
131
        strcpy(fMulticastIP, multicast_ip);

sletz's avatar
sletz committed
132
        // Set the socket parameters
Stephane Letz's avatar
Stephane Letz committed
133
134
        fSocket.SetPort(udp_port);
        fSocket.SetAddress(fMulticastIP, udp_port);
sletz's avatar
sletz committed
135

sletz's avatar
sletz committed
136
        // If not set, takes default
137
        fParams.fSendAudioChannels = (send_audio == -1) ? 2 : send_audio;
sletz's avatar
sletz committed
138

sletz's avatar
sletz committed
139
        // If not set, takes default
140
        fParams.fReturnAudioChannels = (return_audio == -1) ? 2 : return_audio;
sletz's avatar
sletz committed
141

sletz's avatar
sletz committed
142
        // Set the audio adapter interface channel values
sletz's avatar
sletz committed
143
144
        SetInputs(fParams.fSendAudioChannels);
        SetOutputs(fParams.fReturnAudioChannels);
moret's avatar
moret committed
145

sletz's avatar
sletz committed
146
        // Soft buffers will be allocated later (once network initialization done)
147
148
149
        fSoftCaptureBuffer = NULL;
        fSoftPlaybackBuffer = NULL;
    }
sletz's avatar
sletz committed
150

151
152
    JackNetAdapter::~JackNetAdapter()
    {
sletz's avatar
sletz committed
153
        jack_log("JackNetAdapter::~JackNetAdapter");
moret's avatar
moret committed
154

sletz's avatar
sletz committed
155
        if (fSoftCaptureBuffer) {
Stephane Letz's avatar
Stephane Letz committed
156
            for (int port_index = 0; port_index < fCaptureChannels; port_index++) {
157
                delete[] fSoftCaptureBuffer[port_index];
Stephane Letz's avatar
Stephane Letz committed
158
            }
159
160
            delete[] fSoftCaptureBuffer;
        }
sletz's avatar
sletz committed
161
        if (fSoftPlaybackBuffer) {
Stephane Letz's avatar
Stephane Letz committed
162
            for (int port_index = 0; port_index < fPlaybackChannels; port_index++) {
163
                delete[] fSoftPlaybackBuffer[port_index];
Stephane Letz's avatar
Stephane Letz committed
164
            }
165
166
            delete[] fSoftPlaybackBuffer;
        }
moret's avatar
moret committed
167
    }
sletz's avatar
sletz committed
168

moret's avatar
moret committed
169
//open/close--------------------------------------------------------------------------
170
171
    int JackNetAdapter::Open()
    {
sletz's avatar
sletz committed
172
173
        jack_info("NetAdapter started in %s mode %s Master's transport sync.",
                    (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
174

sletz's avatar
sletz committed
175
176
        if (fThread.StartSync() < 0) {
            jack_error("Cannot start netadapter thread");
177
178
            return -1;
        }
moret's avatar
moret committed
179

180
        return 0;
moret's avatar
moret committed
181
    }
182
183
184

    int JackNetAdapter::Close()
    {
sletz's avatar
sletz committed
185
        int res = 0;
sletz's avatar
sletz committed
186
        jack_log("JackNetAdapter::Close");
moret's avatar
moret committed
187

sletz's avatar
sletz committed
188
189
190
191
#ifdef JACK_MONITOR
        fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
#endif

sletz's avatar
sletz committed
192
193
194
        if (fThread.Kill() < 0) {
            jack_error("Cannot kill thread");
            res = -1;
195
        }
sletz's avatar
sletz committed
196

sletz's avatar
sletz committed
197
198
199
        fSocket.Close();
        return res;
   }
200

sletz's avatar
sletz committed
201
    int JackNetAdapter::SetBufferSize(jack_nframes_t buffer_size)
202
    {
sletz's avatar
sletz committed
203
        JackAudioAdapterInterface::SetHostBufferSize(buffer_size);
204
205
206
        return 0;
    }

moret's avatar
moret committed
207
//thread------------------------------------------------------------------------------
sletz's avatar
sletz committed
208
    // TODO : if failure, thread exist... need to restart ?
sletz's avatar
sletz committed
209

210
211
    bool JackNetAdapter::Init()
    {
sletz's avatar
sletz committed
212
        jack_log("JackNetAdapter::Init");
213

moret's avatar
moret committed
214
        //init network connection
sletz's avatar
sletz committed
215
        if (!JackNetSlaveInterface::Init()) {
sletz's avatar
sletz committed
216
            jack_error("JackNetSlaveInterface::Init() error...");
moret's avatar
moret committed
217
            return false;
sletz's avatar
sletz committed
218
        }
moret's avatar
moret committed
219
220

        //then set global parameters
sletz's avatar
sletz committed
221
        if (!SetParams()) {
sletz's avatar
sletz committed
222
            jack_error("SetParams error...");
sletz's avatar
sletz committed
223
224
            return false;
        }
moret's avatar
moret committed
225
226

        //set buffers
227
228
        if (fCaptureChannels > 0) {
            fSoftCaptureBuffer = new sample_t*[fCaptureChannels];
sletz's avatar
sletz committed
229
            for (int port_index = 0; port_index < fCaptureChannels; port_index++) {
230
                fSoftCaptureBuffer[port_index] = new sample_t[fParams.fPeriodSize];
sletz's avatar
sletz committed
231
                fNetAudioCaptureBuffer->SetBuffer(port_index, fSoftCaptureBuffer[port_index]);
232
            }
moret's avatar
moret committed
233
        }
sletz's avatar
sletz committed
234

235
236
        if (fPlaybackChannels > 0) {
            fSoftPlaybackBuffer = new sample_t*[fPlaybackChannels];
sletz's avatar
sletz committed
237
            for (int port_index = 0; port_index < fPlaybackChannels; port_index++) {
238
                fSoftPlaybackBuffer[port_index] = new sample_t[fParams.fPeriodSize];
sletz's avatar
sletz committed
239
                fNetAudioPlaybackBuffer->SetBuffer(port_index, fSoftPlaybackBuffer[port_index]);
240
            }
moret's avatar
moret committed
241
242
        }

243
        //set audio adapter parameters
sletz's avatar
sletz committed
244
245
        SetAdaptedBufferSize(fParams.fPeriodSize);
        SetAdaptedSampleRate(fParams.fSampleRate);
sletz's avatar
sletz committed
246

247
        // Will do "something" on OSX only...
sletz's avatar
sletz committed
248
        fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
sletz's avatar
sletz committed
249

sletz's avatar
sletz committed
250
251
        if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) {
            jack_error("AcquireSelfRealTime error");
252
253
254
        } else {
            set_threaded_log_function();
        }
sletz's avatar
sletz committed
255

moret's avatar
moret committed
256
        //init done, display parameters
sletz's avatar
sletz committed
257
        SessionParamsDisplay(&fParams);
moret's avatar
moret committed
258
        return true;
259
260
    }

moret's avatar
moret committed
261
    bool JackNetAdapter::Execute()
moret's avatar
moret committed
262
    {
sletz's avatar
sletz committed
263
        try {
moret's avatar
moret committed
264
            // Keep running even in case of error
265
            while (fThread.GetStatus() == JackThread::kRunning) {
Stephane Letz's avatar
Stephane Letz committed
266
                if (Process() == SOCKET_ERROR) {
moret's avatar
moret committed
267
                    return false;
Stephane Letz's avatar
Stephane Letz committed
268
                }
269
            }
moret's avatar
moret committed
270
            return false;
sletz's avatar
sletz committed
271
        } catch (JackNetException& e) {
Stephane Letz's avatar
Stephane Letz committed
272
            // Otherwise just restart...
moret's avatar
moret committed
273
            e.PrintMessage();
sletz's avatar
sletz committed
274
            jack_info("NetAdapter is restarted");
sletz's avatar
sletz committed
275
            Reset();
sletz's avatar
sletz committed
276
            fThread.DropSelfRealTime();
sletz's avatar
sletz committed
277
278
279
            fThread.SetStatus(JackThread::kIniting);
            if (Init()) {
                fThread.SetStatus(JackThread::kRunning);
moret's avatar
moret committed
280
                return true;
sletz's avatar
sletz committed
281
            } else {
moret's avatar
moret committed
282
                return false;
sletz's avatar
sletz committed
283
            }
moret's avatar
moret committed
284
285
286
        }
    }

moret's avatar
moret committed
287
//transport---------------------------------------------------------------------------
sletz's avatar
sletz committed
288
    void JackNetAdapter::DecodeTransportData()
moret's avatar
moret committed
289
290
291
292
    {
        //TODO : we need here to get the actual timebase master to eventually release it from its duty (see JackNetDriver)

        //is there a new transport state ?
Stephane Letz's avatar
Stephane Letz committed
293
        if (fSendTransportData.fNewState &&(fSendTransportData.fState != jack_transport_query(fClient, NULL))) {
sletz's avatar
sletz committed
294
            switch (fSendTransportData.fState)
moret's avatar
moret committed
295
296
            {
                case JackTransportStopped :
Stephane Letz's avatar
Stephane Letz committed
297
                    jack_transport_stop(fClient);
sletz's avatar
sletz committed
298
                    jack_info("NetMaster : transport stops");
moret's avatar
moret committed
299
                    break;
sletz's avatar
sletz committed
300

moret's avatar
moret committed
301
                case JackTransportStarting :
Stephane Letz's avatar
Stephane Letz committed
302
303
                    jack_transport_reposition(fClient, &fSendTransportData.fPosition);
                    jack_transport_start(fClient);
sletz's avatar
sletz committed
304
                    jack_info("NetMaster : transport starts");
moret's avatar
moret committed
305
                    break;
sletz's avatar
sletz committed
306

moret's avatar
moret committed
307
                case JackTransportRolling :
sletz's avatar
sletz committed
308
                    // TODO, we need to :
moret's avatar
moret committed
309
310
                    // - find a way to call TransportEngine->SetNetworkSync()
                    // - turn the transport state to JackTransportRolling
sletz's avatar
sletz committed
311
                    jack_info("NetMaster : transport rolls");
moret's avatar
moret committed
312
313
314
315
316
                    break;
            }
        }
    }

sletz's avatar
sletz committed
317
    void JackNetAdapter::EncodeTransportData()
moret's avatar
moret committed
318
319
320
321
322
    {
        //is there a timebase master change ?
        int refnum = -1;
        bool conditional = 0;
        //TODO : get the actual timebase master
sletz's avatar
sletz committed
323
        if (refnum != fLastTimebaseMaster) {
moret's avatar
moret committed
324
            //timebase master has released its function
sletz's avatar
sletz committed
325
            if (refnum == -1) {
moret's avatar
moret committed
326
                fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
sletz's avatar
sletz committed
327
328
329
330
331
                jack_info("Sending a timebase master release request.");
            } else {
                //there is a new timebase master
                fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
                jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
moret's avatar
moret committed
332
333
            }
            fLastTimebaseMaster = refnum;
sletz's avatar
sletz committed
334
        } else {
moret's avatar
moret committed
335
            fReturnTransportData.fTimebaseMaster = NO_CHANGE;
sletz's avatar
sletz committed
336
        }
moret's avatar
moret committed
337
338

        //update transport state and position
Stephane Letz's avatar
Stephane Letz committed
339
        fReturnTransportData.fState = jack_transport_query(fClient, &fReturnTransportData.fPosition);
moret's avatar
moret committed
340
341

        //is it a new state (that the master need to know...) ?
sletz's avatar
sletz committed
342
343
        fReturnTransportData.fNewState = ((fReturnTransportData.fState != fLastTransportState) &&
                                           (fReturnTransportData.fState != fSendTransportData.fState));
Stephane Letz's avatar
Stephane Letz committed
344
        if (fReturnTransportData.fNewState) {
sletz's avatar
sletz committed
345
            jack_info("Sending transport state '%s'.", GetTransportState(fReturnTransportData.fState));
Stephane Letz's avatar
Stephane Letz committed
346
        }
moret's avatar
moret committed
347
348
349
350
        fLastTransportState = fReturnTransportData.fState;
    }

//read/write operations---------------------------------------------------------------
moret's avatar
moret committed
351
    int JackNetAdapter::Read()
352
    {
353
354
355
356
357
        switch (SyncRecv()) {
        
            case SOCKET_ERROR:
                return 0;
                
358
            case SYNC_PACKET_ERROR:
359
360
361
362
363
364
365
366
367
                // Since sync packet is incorrect, don't decode it and continue with data
                break;
                
            default:
                //decode sync
                DecodeSyncPacket();
                break;
        }
        
moret's avatar
moret committed
368
369
370
371
372
        return DataRecv();
    }

    int JackNetAdapter::Write()
    {
sletz's avatar
sletz committed
373
        EncodeSyncPacket();
sletz's avatar
sletz committed
374

Stephane Letz's avatar
Stephane Letz committed
375
        if (SyncSend() == SOCKET_ERROR) {
moret's avatar
moret committed
376
            return SOCKET_ERROR;
Stephane Letz's avatar
Stephane Letz committed
377
        }
moret's avatar
moret committed
378

moret's avatar
moret committed
379
380
        return DataSend();
    }
moret's avatar
moret committed
381

moret's avatar
moret committed
382
//process-----------------------------------------------------------------------------
moret's avatar
moret committed
383
384
385
    int JackNetAdapter::Process()
    {
        //read data from the network
386
        //in case of fatal network error, stop the process
Stephane Letz's avatar
Stephane Letz committed
387
        if (Read() == SOCKET_ERROR) {
moret's avatar
moret committed
388
            return SOCKET_ERROR;
Stephane Letz's avatar
Stephane Letz committed
389
        }
sletz's avatar
sletz committed
390

sletz's avatar
sletz committed
391
        PushAndPull(fSoftCaptureBuffer, fSoftPlaybackBuffer, fAdaptedBufferSize);
moret's avatar
moret committed
392

moret's avatar
moret committed
393
        //then write data to network
394
        //in case of failure, stop process
Stephane Letz's avatar
Stephane Letz committed
395
        if (Write() == SOCKET_ERROR) {
moret's avatar
moret committed
396
            return SOCKET_ERROR;
Stephane Letz's avatar
Stephane Letz committed
397
        }
moret's avatar
moret committed
398

399
        return 0;
400
    }
sletz's avatar
sletz committed
401

402
} // namespace Jack
sletz's avatar
sletz committed
403

moret's avatar
moret committed
404
//loader------------------------------------------------------------------------------
sletz's avatar
sletz committed
405
406
407
408
409
410
#ifdef __cplusplus
extern "C"
{
#endif

#include "driver_interface.h"
411
412
#include "JackAudioAdapter.h"

moret's avatar
moret committed
413
    using namespace Jack;
sletz's avatar
sletz committed
414

415
    SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
sletz's avatar
sletz committed
416
    {
417
418
419
420
        jack_driver_desc_t * desc;
        jack_driver_desc_filler_t filler;
        jack_driver_param_value_t value;

421
        desc = jack_driver_descriptor_construct("netadapter", JackDriverNone, "netjack net <==> audio backend adapter", &filler);
422
423

        strcpy(value.str, DEFAULT_MULTICAST_IP);
424
        jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address, or explicit IP of the master", NULL);
425
426

        value.i = DEFAULT_PORT;
Stephane Letz's avatar
Stephane Letz committed
427
        jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
428
429
430
431
432
433

        value.i = DEFAULT_MTU;
        jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);

        value.i = 2;
        jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", NULL);
434
        jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", NULL);
435

sletz's avatar
sletz committed
436
    #if HAVE_CELT
437
438
        value.i = -1;
        jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
sletz's avatar
sletz committed
439
440
    #endif

Robin Gareus's avatar
Robin Gareus committed
441
442
443
444
445
    #if HAVE_OPUS
        value.i = -1;
        jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'O', JackDriverParamInt, &value, NULL, "Set Opus encoding and number of kBits per channel", NULL);
    #endif

446
447
448
        strcpy(value.str, "'hostname'");
        jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);

Stephane Letz's avatar
Stephane Letz committed
449
        value.ui = 0U;
450
451
        jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);

sletz's avatar
sletz committed
452
        value.ui = 5U;
sletz's avatar
sletz committed
453
        jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
454
455
456
457
458
459
460
461

        value.i = 0;
        jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);

        value.i = 32768;
        jack_driver_descriptor_add_parameter(desc, &filler, "ring-buffer", 'g', JackDriverParamInt, &value, NULL, "Fixed ringbuffer size", "Fixed ringbuffer size (if not set => automatic adaptative)");

        value.i = false;
462
        jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netadapter to system ports", NULL);
nedko's avatar
nedko committed
463

sletz's avatar
sletz committed
464
465
466
        return desc;
    }

Stephane Letz's avatar
Stephane Letz committed
467
    SERVER_EXPORT int jack_internal_initialize(jack_client_t* client, const JSList* params)
sletz's avatar
sletz committed
468
    {
sletz's avatar
sletz committed
469
        jack_log("Loading netadapter");
sletz's avatar
sletz committed
470
471

        Jack::JackAudioAdapter* adapter;
Stephane Letz's avatar
Stephane Letz committed
472
473
        jack_nframes_t buffer_size = jack_get_buffer_size(client);
        jack_nframes_t sample_rate = jack_get_sample_rate(client);
sletz's avatar
sletz committed
474

475
        try {
sletz's avatar
sletz committed
476

Stephane Letz's avatar
Stephane Letz committed
477
            adapter = new Jack::JackAudioAdapter(client, new Jack::JackNetAdapter(client, buffer_size, sample_rate, params), params);
sletz's avatar
sletz committed
478
            assert(adapter);
sletz's avatar
sletz committed
479

sletz's avatar
sletz committed
480
            if (adapter->Open() == 0) {
481
                return 0;
sletz's avatar
sletz committed
482
            } else {
483
484
485
                delete adapter;
                return 1;
            }
sletz's avatar
sletz committed
486

487
        } catch (...) {
488
            jack_info("netadapter allocation error");
sletz's avatar
sletz committed
489
490
491
492
            return 1;
        }
    }

sletz's avatar
sletz committed
493
    SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
sletz's avatar
sletz committed
494
495
    {
        JSList* params = NULL;
496
497
498
499
        bool parse_params = true;
        int res = 1;
        jack_driver_desc_t* desc = jack_get_descriptor();

sletz's avatar
sletz committed
500
        Jack::JackArgParser parser(load_init);
Stephane Letz's avatar
Stephane Letz committed
501
        if (parser.GetArgc() > 0) {
sletz's avatar
sletz committed
502
            parse_params = parser.ParseParams(desc, &params);
Stephane Letz's avatar
Stephane Letz committed
503
        }
504
505

        if (parse_params) {
sletz's avatar
sletz committed
506
507
            res = jack_internal_initialize(jack_client, params);
            parser.FreeParams(params);
508
        }
sletz's avatar
sletz committed
509
        return res;
sletz's avatar
sletz committed
510
511
    }

sletz's avatar
sletz committed
512
    SERVER_EXPORT void jack_finish(void* arg)
sletz's avatar
sletz committed
513
    {
sletz's avatar
sletz committed
514
        Jack::JackAudioAdapter* adapter = static_cast<Jack::JackAudioAdapter*>(arg);
sletz's avatar
sletz committed
515

516
        if (adapter) {
sletz's avatar
sletz committed
517
            jack_log("Unloading netadapter");
sletz's avatar
sletz committed
518
519
520
521
522
523
524
525
            adapter->Close();
            delete adapter;
        }
    }

#ifdef __cplusplus
}
#endif