src/audio/jack/SDL_jackaudio.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 01 Jun 2018 19:43:53 -0700
changeset 12005 94f3f018d3eb
parent 11811 5d94cb6b24d3
child 12503 806492103856
permissions -rw-r--r--
Fixed bug 4184 - jack audio driver fails in presence of midi ports

Martin Širokov

Launching an SDL application with SDL_AUDIODRIVER=jack, and then calling SDL_OpenAudioDevice() with whatever parameters fails with an error like this one:

SDL_OpenAudioDevice: Couldn't connect JACK ports: SDL:sdl_jack_output_0 => system:midi_playback_1

This happens because JACK_OpenDevice in src/audio/jack/SDL_jackaudio.c blindly tries to connect to all input ports without checking whether they are for audio or midi.

The fix is to check port types and ignore all non audio ports. Also I removed devports field from struct SDL_PrivateAudioData, because it's never really used and removing unused ports from it would be PITA.
icculus@11081
     1
/*
icculus@11081
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
icculus@11081
     4
icculus@11081
     5
  This software is provided 'as-is', without any express or implied
icculus@11081
     6
  warranty.  In no event will the authors be held liable for any damages
icculus@11081
     7
  arising from the use of this software.
icculus@11081
     8
icculus@11081
     9
  Permission is granted to anyone to use this software for any purpose,
icculus@11081
    10
  including commercial applications, and to alter it and redistribute it
icculus@11081
    11
  freely, subject to the following restrictions:
icculus@11081
    12
icculus@11081
    13
  1. The origin of this software must not be misrepresented; you must not
icculus@11081
    14
     claim that you wrote the original software. If you use this software
icculus@11081
    15
     in a product, an acknowledgment in the product documentation would be
icculus@11081
    16
     appreciated but is not required.
icculus@11081
    17
  2. Altered source versions must be plainly marked as such, and must not be
icculus@11081
    18
     misrepresented as being the original software.
icculus@11081
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@11081
    20
*/
icculus@11081
    21
icculus@11081
    22
#include "../../SDL_internal.h"
icculus@11081
    23
icculus@11081
    24
#if SDL_AUDIO_DRIVER_JACK
icculus@11081
    25
icculus@11081
    26
#include "SDL_assert.h"
icculus@11081
    27
#include "SDL_timer.h"
icculus@11081
    28
#include "SDL_audio.h"
icculus@11081
    29
#include "../SDL_audio_c.h"
icculus@11081
    30
#include "SDL_jackaudio.h"
icculus@11081
    31
#include "SDL_loadso.h"
icculus@11081
    32
#include "../../thread/SDL_systhread.h"
icculus@11081
    33
icculus@11081
    34
icculus@11081
    35
static jack_client_t * (*JACK_jack_client_open) (const char *, jack_options_t, jack_status_t *, ...);
icculus@11081
    36
static int (*JACK_jack_client_close) (jack_client_t *);
icculus@11081
    37
static void (*JACK_jack_on_shutdown) (jack_client_t *, JackShutdownCallback, void *);
icculus@11081
    38
static int (*JACK_jack_activate) (jack_client_t *);
icculus@11083
    39
static int (*JACK_jack_deactivate) (jack_client_t *);
icculus@11081
    40
static void * (*JACK_jack_port_get_buffer) (jack_port_t *, jack_nframes_t);
icculus@11081
    41
static int (*JACK_jack_port_unregister) (jack_client_t *, jack_port_t *);
icculus@11081
    42
static void (*JACK_jack_free) (void *);
icculus@11081
    43
static const char ** (*JACK_jack_get_ports) (jack_client_t *, const char *, const char *, unsigned long);
icculus@11081
    44
static jack_nframes_t (*JACK_jack_get_sample_rate) (jack_client_t *);
icculus@11081
    45
static jack_nframes_t (*JACK_jack_get_buffer_size) (jack_client_t *);
icculus@11081
    46
static jack_port_t * (*JACK_jack_port_register) (jack_client_t *, const char *, const char *, unsigned long, unsigned long);
slouken@12005
    47
static jack_port_t * (*JACK_jack_port_by_name) (jack_client_t *, const char *);
icculus@11081
    48
static const char * (*JACK_jack_port_name) (const jack_port_t *);
slouken@12005
    49
static const char * (*JACK_jack_port_type) (const jack_port_t *);
icculus@11081
    50
static int (*JACK_jack_connect) (jack_client_t *, const char *, const char *);
icculus@11081
    51
static int (*JACK_jack_set_process_callback) (jack_client_t *, JackProcessCallback, void *);
icculus@11081
    52
icculus@11081
    53
static int load_jack_syms(void);
icculus@11081
    54
icculus@11081
    55
icculus@11081
    56
#ifdef SDL_AUDIO_DRIVER_JACK_DYNAMIC
icculus@11081
    57
icculus@11081
    58
static const char *jack_library = SDL_AUDIO_DRIVER_JACK_DYNAMIC;
icculus@11081
    59
static void *jack_handle = NULL;
icculus@11081
    60
icculus@11081
    61
/* !!! FIXME: this is copy/pasted in several places now */
icculus@11081
    62
static int
icculus@11081
    63
load_jack_sym(const char *fn, void **addr)
icculus@11081
    64
{
icculus@11081
    65
    *addr = SDL_LoadFunction(jack_handle, fn);
icculus@11081
    66
    if (*addr == NULL) {
icculus@11081
    67
        /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
icculus@11081
    68
        return 0;
icculus@11081
    69
    }
icculus@11081
    70
icculus@11081
    71
    return 1;
icculus@11081
    72
}
icculus@11081
    73
icculus@11081
    74
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
icculus@11081
    75
#define SDL_JACK_SYM(x) \
icculus@11081
    76
    if (!load_jack_sym(#x, (void **) (char *) &JACK_##x)) return -1
icculus@11081
    77
icculus@11081
    78
static void
icculus@11081
    79
UnloadJackLibrary(void)
icculus@11081
    80
{
icculus@11081
    81
    if (jack_handle != NULL) {
icculus@11081
    82
        SDL_UnloadObject(jack_handle);
icculus@11081
    83
        jack_handle = NULL;
icculus@11081
    84
    }
icculus@11081
    85
}
icculus@11081
    86
icculus@11081
    87
static int
icculus@11081
    88
LoadJackLibrary(void)
icculus@11081
    89
{
icculus@11081
    90
    int retval = 0;
icculus@11081
    91
    if (jack_handle == NULL) {
icculus@11081
    92
        jack_handle = SDL_LoadObject(jack_library);
icculus@11081
    93
        if (jack_handle == NULL) {
icculus@11081
    94
            retval = -1;
icculus@11081
    95
            /* Don't call SDL_SetError(): SDL_LoadObject already did. */
icculus@11081
    96
        } else {
icculus@11081
    97
            retval = load_jack_syms();
icculus@11081
    98
            if (retval < 0) {
icculus@11081
    99
                UnloadJackLibrary();
icculus@11081
   100
            }
icculus@11081
   101
        }
icculus@11081
   102
    }
icculus@11081
   103
    return retval;
icculus@11081
   104
}
icculus@11081
   105
icculus@11081
   106
#else
icculus@11081
   107
icculus@11081
   108
#define SDL_JACK_SYM(x) JACK_##x = x
icculus@11081
   109
icculus@11081
   110
static void
icculus@11081
   111
UnloadJackLibrary(void)
icculus@11081
   112
{
icculus@11081
   113
}
icculus@11081
   114
icculus@11081
   115
static int
icculus@11081
   116
LoadJackLibrary(void)
icculus@11081
   117
{
icculus@11081
   118
    load_jack_syms();
icculus@11081
   119
    return 0;
icculus@11081
   120
}
icculus@11081
   121
icculus@11081
   122
#endif /* SDL_AUDIO_DRIVER_JACK_DYNAMIC */
icculus@11081
   123
icculus@11081
   124
icculus@11081
   125
static int
icculus@11081
   126
load_jack_syms(void)
icculus@11081
   127
{
icculus@11081
   128
    SDL_JACK_SYM(jack_client_open);
icculus@11081
   129
    SDL_JACK_SYM(jack_client_close);
icculus@11081
   130
    SDL_JACK_SYM(jack_on_shutdown);
icculus@11081
   131
    SDL_JACK_SYM(jack_activate);
icculus@11083
   132
    SDL_JACK_SYM(jack_deactivate);
icculus@11081
   133
    SDL_JACK_SYM(jack_port_get_buffer);
icculus@11081
   134
    SDL_JACK_SYM(jack_port_unregister);
icculus@11081
   135
    SDL_JACK_SYM(jack_free);
icculus@11081
   136
    SDL_JACK_SYM(jack_get_ports);
icculus@11081
   137
    SDL_JACK_SYM(jack_get_sample_rate);
icculus@11081
   138
    SDL_JACK_SYM(jack_get_buffer_size);
icculus@11081
   139
    SDL_JACK_SYM(jack_port_register);
slouken@12005
   140
    SDL_JACK_SYM(jack_port_by_name);
icculus@11081
   141
    SDL_JACK_SYM(jack_port_name);
slouken@12005
   142
    SDL_JACK_SYM(jack_port_type);
icculus@11081
   143
    SDL_JACK_SYM(jack_connect);
icculus@11081
   144
    SDL_JACK_SYM(jack_set_process_callback);
icculus@11081
   145
    return 0;
icculus@11081
   146
}
icculus@11081
   147
icculus@11081
   148
icculus@11081
   149
static void
icculus@11083
   150
jackShutdownCallback(void *arg)  /* JACK went away; device is lost. */
icculus@11081
   151
{
icculus@11083
   152
    SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
icculus@11083
   153
    SDL_OpenedAudioDeviceDisconnected(this);
icculus@11083
   154
    SDL_SemPost(this->hidden->iosem);  /* unblock the SDL thread. */
icculus@11081
   155
}
icculus@11081
   156
icculus@11081
   157
// !!! FIXME: implement and register these!
icculus@11081
   158
//typedef int(* JackSampleRateCallback)(jack_nframes_t nframes, void *arg)
icculus@11081
   159
//typedef int(* JackBufferSizeCallback)(jack_nframes_t nframes, void *arg)
icculus@11081
   160
icculus@11081
   161
static int
icculus@11081
   162
jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
icculus@11081
   163
{
icculus@11081
   164
    SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
icculus@11081
   165
    jack_port_t **ports = this->hidden->sdlports;
icculus@11081
   166
    const int total_channels = this->spec.channels;
icculus@11081
   167
    const int total_frames = this->spec.samples;
icculus@11081
   168
    int channelsi;
icculus@11081
   169
icculus@11081
   170
    if (!SDL_AtomicGet(&this->enabled)) {
icculus@11081
   171
        /* silence the buffer to avoid repeats and corruption. */
icculus@11081
   172
        SDL_memset(this->hidden->iobuffer, '\0', this->spec.size);
icculus@11081
   173
    }
icculus@11081
   174
icculus@11081
   175
    for (channelsi = 0; channelsi < total_channels; channelsi++) {
icculus@11081
   176
        float *dst = (float *) JACK_jack_port_get_buffer(ports[channelsi], nframes);
icculus@11081
   177
        if (dst) {
icculus@11081
   178
            const float *src = ((float *) this->hidden->iobuffer) + channelsi;
icculus@11081
   179
            int framesi;
icculus@11081
   180
            for (framesi = 0; framesi < total_frames; framesi++) {
icculus@11081
   181
                *(dst++) = *src;
icculus@11081
   182
                src += total_channels;
icculus@11081
   183
            }
icculus@11081
   184
        }
icculus@11081
   185
    }
icculus@11081
   186
icculus@11081
   187
    SDL_SemPost(this->hidden->iosem);  /* tell SDL thread we're done; refill the buffer. */
icculus@11081
   188
    return 0;  /* success */
icculus@11081
   189
}
icculus@11081
   190
icculus@11081
   191
icculus@11081
   192
/* This function waits until it is possible to write a full sound buffer */
icculus@11081
   193
static void
icculus@11081
   194
JACK_WaitDevice(_THIS)
icculus@11081
   195
{
icculus@11081
   196
    if (SDL_AtomicGet(&this->enabled)) {
icculus@11081
   197
        if (SDL_SemWait(this->hidden->iosem) == -1) {
icculus@11081
   198
            SDL_OpenedAudioDeviceDisconnected(this);
icculus@11081
   199
        }
icculus@11081
   200
    }
icculus@11081
   201
}
icculus@11081
   202
icculus@11081
   203
static Uint8 *
icculus@11081
   204
JACK_GetDeviceBuf(_THIS)
icculus@11081
   205
{
icculus@11081
   206
    return (Uint8 *) this->hidden->iobuffer;
icculus@11081
   207
}
icculus@11081
   208
icculus@11081
   209
icculus@11081
   210
static int
icculus@11081
   211
jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
icculus@11081
   212
{
icculus@11084
   213
    SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
icculus@11084
   214
    if (SDL_AtomicGet(&this->enabled)) {
icculus@11084
   215
        jack_port_t **ports = this->hidden->sdlports;
icculus@11084
   216
        const int total_channels = this->spec.channels;
icculus@11084
   217
        const int total_frames = this->spec.samples;
icculus@11084
   218
        int channelsi;
icculus@11084
   219
    
icculus@11084
   220
        for (channelsi = 0; channelsi < total_channels; channelsi++) {
icculus@11084
   221
            const float *src = (const float *) JACK_jack_port_get_buffer(ports[channelsi], nframes);
icculus@11084
   222
            if (src) {
icculus@11084
   223
                float *dst = ((float *) this->hidden->iobuffer) + channelsi;
icculus@11084
   224
                int framesi;
icculus@11084
   225
                for (framesi = 0; framesi < total_frames; framesi++) {
icculus@11084
   226
                    *dst = *(src++);
icculus@11084
   227
                    dst += total_channels;
icculus@11084
   228
                }
icculus@11084
   229
            }
icculus@11084
   230
        }
icculus@11084
   231
    }
icculus@11084
   232
icculus@11084
   233
    SDL_SemPost(this->hidden->iosem);  /* tell SDL thread we're done; new buffer is ready! */
icculus@11084
   234
    return 0;  /* success */
icculus@11081
   235
}
icculus@11081
   236
icculus@11081
   237
static int
icculus@11081
   238
JACK_CaptureFromDevice(_THIS, void *buffer, int buflen)
icculus@11081
   239
{
icculus@11084
   240
    SDL_assert(buflen == this->spec.size);  /* we always fill a full buffer. */
icculus@11084
   241
icculus@11084
   242
    /* Wait for JACK to fill the iobuffer */
icculus@11084
   243
    if (SDL_SemWait(this->hidden->iosem) == -1) {
icculus@11084
   244
        return -1;
icculus@11084
   245
    }
icculus@11084
   246
icculus@11084
   247
    SDL_memcpy(buffer, this->hidden->iobuffer, buflen);
icculus@11084
   248
    return buflen;
icculus@11081
   249
}
icculus@11084
   250
icculus@11084
   251
static void
icculus@11084
   252
JACK_FlushCapture(_THIS)
icculus@11084
   253
{
icculus@11084
   254
    SDL_SemWait(this->hidden->iosem);
icculus@11084
   255
}
icculus@11084
   256
icculus@11081
   257
icculus@11081
   258
static void
icculus@11081
   259
JACK_CloseDevice(_THIS)
icculus@11081
   260
{
icculus@11083
   261
    if (this->hidden->client) {
icculus@11083
   262
        JACK_jack_deactivate(this->hidden->client);
icculus@11083
   263
icculus@11083
   264
        if (this->hidden->sdlports) {
icculus@11083
   265
            const int channels = this->spec.channels;
icculus@11083
   266
            int i;
icculus@11083
   267
            for (i = 0; i < channels; i++) {
icculus@11083
   268
                JACK_jack_port_unregister(this->hidden->client, this->hidden->sdlports[i]);
icculus@11083
   269
            }
icculus@11083
   270
            SDL_free(this->hidden->sdlports);
icculus@11081
   271
        }
icculus@11083
   272
icculus@11083
   273
        JACK_jack_client_close(this->hidden->client);
icculus@11081
   274
    }
icculus@11081
   275
icculus@11081
   276
    if (this->hidden->iosem) {
icculus@11081
   277
        SDL_DestroySemaphore(this->hidden->iosem);
icculus@11081
   278
    }
icculus@11081
   279
icculus@11081
   280
    SDL_free(this->hidden->iobuffer);
icculus@11081
   281
}
icculus@11081
   282
icculus@11081
   283
static int
icculus@11081
   284
JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
icculus@11081
   285
{
icculus@11081
   286
    /* Note that JACK uses "output" for capture devices (they output audio
icculus@11081
   287
        data to us) and "input" for playback (we input audio data to them).
icculus@11081
   288
        Likewise, SDL's playback port will be "output" (we write data out)
icculus@11081
   289
        and capture will be "input" (we read data in). */
icculus@11081
   290
    const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput;
icculus@11081
   291
    const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput;
icculus@11084
   292
    const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback;
icculus@11081
   293
    const char *sdlportstr = iscapture ? "input" : "output";
icculus@11081
   294
    const char **devports = NULL;
slouken@12005
   295
    int *audio_ports;
icculus@11083
   296
    jack_client_t *client = NULL;
icculus@11083
   297
    jack_status_t status;
icculus@11081
   298
    int channels = 0;
slouken@12005
   299
    int ports = 0;
icculus@11081
   300
    int i;
icculus@11081
   301
icculus@11081
   302
    /* Initialize all variables that we clean on shutdown */
icculus@11081
   303
    this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof (*this->hidden));
icculus@11081
   304
    if (this->hidden == NULL) {
icculus@11081
   305
        return SDL_OutOfMemory();
icculus@11081
   306
    }
icculus@11081
   307
icculus@11083
   308
    /* !!! FIXME: we _still_ need an API to specify an app name */
icculus@11083
   309
    client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
icculus@11083
   310
    this->hidden->client = client;
icculus@11083
   311
    if (client == NULL) {
icculus@11083
   312
        return SDL_SetError("Can't open JACK client");
icculus@11083
   313
    }
icculus@11083
   314
icculus@11083
   315
    devports = JACK_jack_get_ports(client, NULL, NULL, JackPortIsPhysical | sysportflags);
icculus@11081
   316
    if (!devports || !devports[0]) {
icculus@11081
   317
        return SDL_SetError("No physical JACK ports available");
icculus@11081
   318
    }
icculus@11081
   319
slouken@12005
   320
    while (devports[++ports]) {
icculus@11081
   321
        /* spin to count devports */
icculus@11081
   322
    }
icculus@11081
   323
slouken@12005
   324
    /* Filter out non-audio ports */
slouken@12005
   325
    audio_ports = SDL_calloc(ports, sizeof *audio_ports);
slouken@12005
   326
    for (i = 0; i < ports; i++) {
slouken@12005
   327
        const jack_port_t *dport = JACK_jack_port_by_name(client, devports[i]);
slouken@12005
   328
        const char *type = JACK_jack_port_type(dport);
slouken@12005
   329
        const int len = SDL_strlen(type);
slouken@12005
   330
        /* See if type ends with "audio" */
slouken@12005
   331
        if (len >= 5 && !SDL_memcmp(type+len-5, "audio", 5)) {
slouken@12005
   332
            audio_ports[channels++] = i;
slouken@12005
   333
        }
slouken@12005
   334
    }
slouken@12005
   335
    if (channels == 0) {
slouken@12005
   336
        return SDL_SetError("No physical JACK ports available");
slouken@12005
   337
    }
slouken@12005
   338
slouken@12005
   339
icculus@11081
   340
    /* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
icculus@11081
   341
icculus@11081
   342
    /* Jack pretty much demands what it wants. */
icculus@11081
   343
    this->spec.format = AUDIO_F32SYS;
icculus@11083
   344
    this->spec.freq = JACK_jack_get_sample_rate(client);
icculus@11081
   345
    this->spec.channels = channels;
icculus@11083
   346
    this->spec.samples = JACK_jack_get_buffer_size(client);
icculus@11081
   347
icculus@11081
   348
    SDL_CalculateAudioSpec(&this->spec);
icculus@11081
   349
icculus@11081
   350
    this->hidden->iosem = SDL_CreateSemaphore(0);
icculus@11081
   351
    if (!this->hidden->iosem) {
icculus@11081
   352
        return -1;  /* error was set by SDL_CreateSemaphore */
icculus@11081
   353
    }
icculus@11081
   354
icculus@11081
   355
    this->hidden->iobuffer = (float *) SDL_calloc(1, this->spec.size);
icculus@11081
   356
    if (!this->hidden->iobuffer) {
icculus@11081
   357
        return SDL_OutOfMemory();
icculus@11081
   358
    }
icculus@11081
   359
icculus@11081
   360
    /* Build SDL's ports, which we will connect to the device ports. */
icculus@11081
   361
    this->hidden->sdlports = (jack_port_t **) SDL_calloc(channels, sizeof (jack_port_t *));
icculus@11081
   362
    if (this->hidden->sdlports == NULL) {
icculus@11081
   363
        return SDL_OutOfMemory();
icculus@11081
   364
    }
icculus@11081
   365
icculus@11081
   366
    for (i = 0; i < channels; i++) {
icculus@11081
   367
        char portname[32];
icculus@11081
   368
        SDL_snprintf(portname, sizeof (portname), "sdl_jack_%s_%d", sdlportstr, i);
icculus@11083
   369
        this->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
icculus@11081
   370
        if (this->hidden->sdlports[i] == NULL) {
icculus@11081
   371
            return SDL_SetError("jack_port_register failed");
icculus@11081
   372
        }
icculus@11081
   373
    }
icculus@11081
   374
icculus@11084
   375
    if (JACK_jack_set_process_callback(client, callback, this) != 0) {
icculus@11083
   376
        return SDL_SetError("JACK: Couldn't set process callback");
icculus@11083
   377
    }
icculus@11083
   378
icculus@11083
   379
    JACK_jack_on_shutdown(client, jackShutdownCallback, this);
icculus@11083
   380
icculus@11083
   381
    if (JACK_jack_activate(client) != 0) {
icculus@11083
   382
        return SDL_SetError("Failed to activate JACK client");
icculus@11081
   383
    }
icculus@11081
   384
icculus@11081
   385
    /* once activated, we can connect all the ports. */
icculus@11081
   386
    for (i = 0; i < channels; i++) {
icculus@11081
   387
        const char *sdlport = JACK_jack_port_name(this->hidden->sdlports[i]);
slouken@12005
   388
        const char *srcport = iscapture ? devports[audio_ports[i]] : sdlport;
slouken@12005
   389
        const char *dstport = iscapture ? sdlport : devports[audio_ports[i]];
icculus@11083
   390
        if (JACK_jack_connect(client, srcport, dstport) != 0) {
icculus@11081
   391
            return SDL_SetError("Couldn't connect JACK ports: %s => %s", srcport, dstport);
icculus@11081
   392
        }
icculus@11081
   393
    }
icculus@11081
   394
icculus@11081
   395
    /* don't need these anymore. */
icculus@11081
   396
    JACK_jack_free(devports);
slouken@12005
   397
    SDL_free(audio_ports);
icculus@11081
   398
icculus@11081
   399
    /* We're ready to rock and roll. :-) */
icculus@11081
   400
    return 0;
icculus@11081
   401
}
icculus@11081
   402
icculus@11081
   403
static void
icculus@11081
   404
JACK_Deinitialize(void)
icculus@11081
   405
{
icculus@11081
   406
    UnloadJackLibrary();
icculus@11081
   407
}
icculus@11081
   408
icculus@11081
   409
static int
icculus@11081
   410
JACK_Init(SDL_AudioDriverImpl * impl)
icculus@11081
   411
{
icculus@11081
   412
    if (LoadJackLibrary() < 0) {
icculus@11081
   413
        return 0;
icculus@11083
   414
    } else {
icculus@11083
   415
        /* Make sure a JACK server is running and available. */
icculus@11083
   416
        jack_status_t status;
icculus@11083
   417
        jack_client_t *client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
icculus@11083
   418
        if (client == NULL) {
icculus@11083
   419
            UnloadJackLibrary();
icculus@11083
   420
            return 0;
icculus@11083
   421
        }
icculus@11083
   422
        JACK_jack_client_close(client);
icculus@11081
   423
    }
icculus@11081
   424
icculus@11081
   425
    /* Set the function pointers */
icculus@11081
   426
    impl->OpenDevice = JACK_OpenDevice;
icculus@11081
   427
    impl->WaitDevice = JACK_WaitDevice;
icculus@11081
   428
    impl->GetDeviceBuf = JACK_GetDeviceBuf;
icculus@11081
   429
    impl->CloseDevice = JACK_CloseDevice;
icculus@11081
   430
    impl->Deinitialize = JACK_Deinitialize;
icculus@11084
   431
    impl->CaptureFromDevice = JACK_CaptureFromDevice;
icculus@11084
   432
    impl->FlushCapture = JACK_FlushCapture;
icculus@11084
   433
    impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
icculus@11084
   434
    impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
icculus@11084
   435
    impl->HasCaptureSupport = SDL_TRUE;
icculus@11081
   436
icculus@11081
   437
    return 1;   /* this audio target is available. */
icculus@11081
   438
}
icculus@11081
   439
icculus@11081
   440
AudioBootStrap JACK_bootstrap = {
icculus@11081
   441
    "jack", "JACK Audio Connection Kit", JACK_Init, 0
icculus@11081
   442
};
icculus@11081
   443
icculus@11081
   444
#endif /* SDL_AUDIO_DRIVER_JACK */
icculus@11081
   445
icculus@11081
   446
/* vi: set ts=4 sw=4 expandtab: */