src/audio/nto/SDL_nto_audio.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
permissions -rw-r--r--
more tweaking indent options
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@769
     3
    Copyright (C) 1997-2004 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@0
     6
    modify it under the terms of the GNU Library General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@0
     8
    version 2 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@0
    13
    Library General Public License for more details.
slouken@0
    14
slouken@0
    15
    You should have received a copy of the GNU Library General Public
slouken@0
    16
    License along with this library; if not, write to the Free
slouken@0
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
#include <errno.h>
slouken@0
    25
#include <unistd.h>
slouken@0
    26
#include <fcntl.h>
slouken@0
    27
#include <signal.h>
slouken@0
    28
#include <sys/types.h>
slouken@0
    29
#include <sys/time.h>
slouken@0
    30
#include <sched.h>
slouken@718
    31
#include <sys/select.h>
slouken@718
    32
#include <sys/neutrino.h>
slouken@0
    33
#include <sys/asoundlib.h>
slouken@0
    34
slouken@1358
    35
#include "SDL_timer.h"
slouken@0
    36
#include "SDL_audio.h"
slouken@1361
    37
#include "../SDL_audiomem.h"
slouken@1361
    38
#include "../SDL_audio_c.h"
slouken@0
    39
#include "SDL_nto_audio.h"
slouken@0
    40
slouken@0
    41
/* The tag name used by NTO audio */
slouken@718
    42
#define DRIVER_NAME "qsa-nto"
slouken@0
    43
slouken@0
    44
/* default channel communication parameters */
slouken@0
    45
#define DEFAULT_CPARAMS_RATE 22050
slouken@0
    46
#define DEFAULT_CPARAMS_VOICES 1
slouken@718
    47
/* FIXME: need to add in the near future flexible logic with frag_size and frags count */
slouken@418
    48
#define DEFAULT_CPARAMS_FRAG_SIZE 4096
slouken@0
    49
#define DEFAULT_CPARAMS_FRAGS_MIN 1
slouken@283
    50
#define DEFAULT_CPARAMS_FRAGS_MAX 1
slouken@0
    51
slouken@0
    52
/* Open the audio device for playback, and don't block if busy */
slouken@418
    53
#define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK
slouken@0
    54
slouken@718
    55
#define QSA_NO_WORKAROUNDS  0x00000000
slouken@718
    56
#define QSA_MMAP_WORKAROUND 0x00000001
slouken@718
    57
slouken@718
    58
struct BuggyCards
slouken@718
    59
{
slouken@1662
    60
    char *cardname;
slouken@1662
    61
    unsigned long bugtype;
slouken@718
    62
};
slouken@718
    63
slouken@718
    64
#define QSA_WA_CARDS 3
slouken@718
    65
slouken@1662
    66
struct BuggyCards buggycards[QSA_WA_CARDS] = {
slouken@1662
    67
    {"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
slouken@1662
    68
    {"Vortex 8820", QSA_MMAP_WORKAROUND},
slouken@1662
    69
    {"Vortex 8830", QSA_MMAP_WORKAROUND},
slouken@718
    70
};
slouken@718
    71
slouken@0
    72
/* Audio driver functions */
slouken@1668
    73
static void NTO_ThreadInit(_THIS);
slouken@1668
    74
static int NTO_OpenAudio(_THIS, SDL_AudioSpec * spec);
slouken@1668
    75
static void NTO_WaitAudio(_THIS);
slouken@1668
    76
static void NTO_PlayAudio(_THIS);
slouken@1668
    77
static Uint8 *NTO_GetAudioBuf(_THIS);
slouken@1668
    78
static void NTO_CloseAudio(_THIS);
slouken@0
    79
slouken@718
    80
/* card names check to apply the workarounds */
slouken@1662
    81
static int
slouken@1668
    82
NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
slouken@718
    83
{
slouken@718
    84
    char scardname[33];
slouken@718
    85
    int it;
slouken@1662
    86
slouken@1668
    87
    if (snd_card_get_name(cardno, scardname, 32) < 0) {
slouken@718
    88
        return 0;
slouken@718
    89
    }
slouken@718
    90
slouken@1662
    91
    for (it = 0; it < QSA_WA_CARDS; it++) {
slouken@1668
    92
        if (SDL_strcmp(buggycards[it].cardname, scardname) == 0) {
slouken@1662
    93
            if (buggycards[it].bugtype == checkfor) {
slouken@1662
    94
                return 1;
slouken@1662
    95
            }
slouken@1662
    96
        }
slouken@718
    97
    }
slouken@718
    98
slouken@718
    99
    return 0;
slouken@718
   100
}
slouken@718
   101
slouken@1662
   102
static void
slouken@1668
   103
NTO_ThreadInit(_THIS)
slouken@718
   104
{
slouken@1662
   105
    int status;
slouken@1662
   106
    struct sched_param param;
slouken@718
   107
slouken@1662
   108
    /* increasing default 10 priority to 25 to avoid jerky sound */
slouken@1668
   109
    status = SchedGet(0, 0, &param);
slouken@1662
   110
    param.sched_priority = param.sched_curpriority + 15;
slouken@1668
   111
    status = SchedSet(0, 0, SCHED_NOCHANGE, &param);
slouken@718
   112
}
slouken@0
   113
slouken@0
   114
/* PCM transfer channel parameters initialize function */
slouken@1662
   115
static void
slouken@1668
   116
NTO_InitAudioParams(snd_pcm_channel_params_t * cpars)
slouken@0
   117
{
slouken@1668
   118
    SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
slouken@0
   119
slouken@718
   120
    cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
slouken@718
   121
    cpars->mode = SND_PCM_MODE_BLOCK;
slouken@718
   122
    cpars->start_mode = SND_PCM_START_DATA;
slouken@1662
   123
    cpars->stop_mode = SND_PCM_STOP_STOP;
slouken@718
   124
    cpars->format.format = SND_PCM_SFMT_S16_LE;
slouken@718
   125
    cpars->format.interleave = 1;
slouken@718
   126
    cpars->format.rate = DEFAULT_CPARAMS_RATE;
slouken@718
   127
    cpars->format.voices = DEFAULT_CPARAMS_VOICES;
slouken@718
   128
    cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
slouken@718
   129
    cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
slouken@718
   130
    cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
slouken@0
   131
}
slouken@0
   132
slouken@1662
   133
static int
slouken@1668
   134
NTO_AudioAvailable(void)
slouken@418
   135
{
slouken@718
   136
    /*  See if we can open a nonblocking channel.
slouken@1662
   137
       Return value '1' means we can.
slouken@1662
   138
       Return value '0' means we cannot. */
slouken@0
   139
slouken@718
   140
    int available;
slouken@718
   141
    int rval;
slouken@1662
   142
    snd_pcm_t *handle;
slouken@0
   143
slouken@718
   144
    available = 0;
slouken@718
   145
    handle = NULL;
slouken@0
   146
slouken@1668
   147
    rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
slouken@0
   148
slouken@1662
   149
    if (rval >= 0) {
slouken@718
   150
        available = 1;
slouken@718
   151
slouken@1668
   152
        if ((rval = snd_pcm_close(handle)) < 0) {
slouken@1662
   153
            SDL_SetError
slouken@1662
   154
                ("NTO_AudioAvailable(): snd_pcm_close failed: %s\n",
slouken@1668
   155
                 snd_strerror(rval));
slouken@718
   156
            available = 0;
slouken@718
   157
        }
slouken@1662
   158
    } else {
slouken@1662
   159
        SDL_SetError
slouken@1662
   160
            ("NTO_AudioAvailable(): there are no available audio devices.\n");
slouken@718
   161
    }
slouken@718
   162
slouken@718
   163
    return (available);
slouken@0
   164
}
slouken@0
   165
slouken@1662
   166
static void
slouken@1668
   167
NTO_DeleteAudioDevice(SDL_AudioDevice * device)
slouken@0
   168
{
slouken@1662
   169
    if ((device) && (device->hidden)) {
slouken@1668
   170
        SDL_free(device->hidden);
slouken@718
   171
    }
slouken@1662
   172
    if (device) {
slouken@1668
   173
        SDL_free(device);
slouken@718
   174
    }
slouken@0
   175
}
slouken@0
   176
slouken@1662
   177
static SDL_AudioDevice *
slouken@1668
   178
NTO_CreateAudioDevice(int devindex)
slouken@0
   179
{
slouken@718
   180
    SDL_AudioDevice *this;
slouken@718
   181
slouken@718
   182
    /* Initialize all variables that we clean on shutdown */
slouken@1668
   183
    this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
slouken@1662
   184
    if (this) {
slouken@1668
   185
        SDL_memset(this, 0, sizeof(SDL_AudioDevice));
slouken@1662
   186
        this->hidden = (struct SDL_PrivateAudioData *)
slouken@1668
   187
            SDL_malloc(sizeof(struct SDL_PrivateAudioData));
slouken@718
   188
    }
slouken@1662
   189
    if ((this == NULL) || (this->hidden == NULL)) {
slouken@1668
   190
        SDL_OutOfMemory();
slouken@1662
   191
        if (this) {
slouken@1668
   192
            SDL_free(this);
slouken@1662
   193
        }
slouken@718
   194
        return (0);
slouken@718
   195
    }
slouken@1668
   196
    SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
slouken@718
   197
    audio_handle = NULL;
slouken@0
   198
slouken@718
   199
    /* Set the function pointers */
slouken@718
   200
    this->ThreadInit = NTO_ThreadInit;
slouken@718
   201
    this->OpenAudio = NTO_OpenAudio;
slouken@718
   202
    this->WaitAudio = NTO_WaitAudio;
slouken@718
   203
    this->PlayAudio = NTO_PlayAudio;
slouken@718
   204
    this->GetAudioBuf = NTO_GetAudioBuf;
slouken@718
   205
    this->CloseAudio = NTO_CloseAudio;
slouken@0
   206
slouken@718
   207
    this->free = NTO_DeleteAudioDevice;
slouken@0
   208
slouken@718
   209
    return this;
slouken@0
   210
}
slouken@0
   211
slouken@1662
   212
AudioBootStrap QNXNTOAUDIO_bootstrap = {
slouken@718
   213
    DRIVER_NAME, "QNX6 QSA-NTO Audio",
slouken@718
   214
    NTO_AudioAvailable,
slouken@718
   215
    NTO_CreateAudioDevice
slouken@0
   216
};
slouken@0
   217
slouken@0
   218
/* This function waits until it is possible to write a full sound buffer */
slouken@1662
   219
static void
slouken@1668
   220
NTO_WaitAudio(_THIS)
slouken@0
   221
{
slouken@718
   222
    fd_set wfds;
slouken@718
   223
    int selectret;
slouken@0
   224
slouken@1668
   225
    FD_ZERO(&wfds);
slouken@1668
   226
    FD_SET(audio_fd, &wfds);
slouken@718
   227
slouken@718
   228
    do {
slouken@1668
   229
        selectret = select(audio_fd + 1, NULL, &wfds, NULL, NULL);
slouken@1662
   230
        switch (selectret) {
slouken@1662
   231
        case -1:
slouken@1662
   232
        case 0:
slouken@1668
   233
            SDL_SetError("NTO_WaitAudio(): select() failed: %s\n",
slouken@1668
   234
                         strerror(errno));
slouken@1662
   235
            return;
slouken@1662
   236
        default:
slouken@1668
   237
            if (FD_ISSET(audio_fd, &wfds)) {
slouken@1662
   238
                return;
slouken@1662
   239
            }
slouken@1662
   240
            break;
slouken@718
   241
        }
slouken@1662
   242
    }
slouken@1662
   243
    while (1);
slouken@0
   244
}
slouken@0
   245
slouken@1662
   246
static void
slouken@1668
   247
NTO_PlayAudio(_THIS)
slouken@0
   248
{
slouken@718
   249
    int written, rval;
slouken@718
   250
    int towrite;
slouken@1662
   251
    void *pcmbuffer;
slouken@0
   252
slouken@1662
   253
    if (!this->enabled) {
slouken@718
   254
        return;
slouken@718
   255
    }
slouken@1662
   256
slouken@718
   257
    towrite = this->spec.size;
slouken@718
   258
    pcmbuffer = pcm_buf;
slouken@0
   259
slouken@718
   260
    /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
slouken@718
   261
    do {
slouken@1668
   262
        written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
slouken@1662
   263
        if (written != towrite) {
slouken@1662
   264
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
slouken@718
   265
                /* Let a little CPU time go by and try to write again */
slouken@1668
   266
                SDL_Delay(1);
slouken@718
   267
                /* if we wrote some data */
slouken@718
   268
                towrite -= written;
slouken@718
   269
                pcmbuffer += written * this->spec.channels;
slouken@718
   270
                continue;
slouken@1662
   271
            } else {
slouken@1662
   272
                if ((errno == EINVAL) || (errno == EIO)) {
slouken@1668
   273
                    SDL_memset(&cstatus, 0, sizeof(cstatus));
slouken@718
   274
                    cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
slouken@1662
   275
                    if ((rval =
slouken@1668
   276
                         snd_pcm_plugin_status(audio_handle, &cstatus)) < 0) {
slouken@1662
   277
                        SDL_SetError
slouken@1662
   278
                            ("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n",
slouken@1668
   279
                             snd_strerror(rval));
slouken@718
   280
                        return;
slouken@1662
   281
                    }
slouken@1662
   282
                    if ((cstatus.status == SND_PCM_STATUS_UNDERRUN)
slouken@1662
   283
                        || (cstatus.status == SND_PCM_STATUS_READY)) {
slouken@1662
   284
                        if ((rval =
slouken@1668
   285
                             snd_pcm_plugin_prepare(audio_handle,
slouken@1668
   286
                                                    SND_PCM_CHANNEL_PLAYBACK))
slouken@1662
   287
                            < 0) {
slouken@1662
   288
                            SDL_SetError
slouken@1662
   289
                                ("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n",
slouken@1668
   290
                                 snd_strerror(rval));
slouken@718
   291
                            return;
slouken@718
   292
                        }
slouken@1662
   293
                    }
slouken@718
   294
                    continue;
slouken@1662
   295
                } else {
slouken@718
   296
                    return;
slouken@718
   297
                }
slouken@718
   298
            }
slouken@1662
   299
        } else {
slouken@718
   300
            /* we wrote all remaining data */
slouken@718
   301
            towrite -= written;
slouken@718
   302
            pcmbuffer += written * this->spec.channels;
slouken@718
   303
        }
slouken@1662
   304
    }
slouken@1662
   305
    while ((towrite > 0) && (this->enabled));
slouken@0
   306
slouken@718
   307
    /* If we couldn't write, assume fatal error for now */
slouken@1662
   308
    if (towrite != 0) {
slouken@718
   309
        this->enabled = 0;
slouken@718
   310
    }
slouken@0
   311
slouken@718
   312
    return;
slouken@0
   313
}
slouken@0
   314
slouken@1662
   315
static Uint8 *
slouken@1668
   316
NTO_GetAudioBuf(_THIS)
slouken@0
   317
{
slouken@718
   318
    return pcm_buf;
slouken@0
   319
}
slouken@0
   320
slouken@1662
   321
static void
slouken@1668
   322
NTO_CloseAudio(_THIS)
slouken@0
   323
{
slouken@718
   324
    int rval;
slouken@0
   325
slouken@718
   326
    this->enabled = 0;
slouken@418
   327
slouken@1662
   328
    if (audio_handle != NULL) {
slouken@1662
   329
        if ((rval =
slouken@1668
   330
             snd_pcm_plugin_flush(audio_handle,
slouken@1668
   331
                                  SND_PCM_CHANNEL_PLAYBACK)) < 0) {
slouken@1662
   332
            SDL_SetError
slouken@1662
   333
                ("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n",
slouken@1668
   334
                 snd_strerror(rval));
slouken@718
   335
            return;
slouken@718
   336
        }
slouken@1668
   337
        if ((rval = snd_pcm_close(audio_handle)) < 0) {
slouken@1668
   338
            SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",
slouken@1668
   339
                         snd_strerror(rval));
slouken@718
   340
            return;
slouken@718
   341
        }
slouken@718
   342
        audio_handle = NULL;
slouken@718
   343
    }
slouken@0
   344
}
slouken@0
   345
slouken@1662
   346
static int
slouken@1668
   347
NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
slouken@0
   348
{
slouken@718
   349
    int rval;
slouken@718
   350
    int format;
slouken@718
   351
    Uint16 test_format;
slouken@718
   352
    int found;
slouken@0
   353
slouken@718
   354
    audio_handle = NULL;
slouken@718
   355
    this->enabled = 0;
slouken@718
   356
slouken@1662
   357
    if (pcm_buf != NULL) {
slouken@1668
   358
        SDL_FreeAudioMem(pcm_buf);
slouken@718
   359
        pcm_buf = NULL;
slouken@718
   360
    }
slouken@718
   361
slouken@718
   362
    /* initialize channel transfer parameters to default */
slouken@1668
   363
    NTO_InitAudioParams(&cparams);
slouken@718
   364
slouken@718
   365
    /* Open the audio device */
slouken@1662
   366
    rval =
slouken@1668
   367
        snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS);
slouken@1662
   368
    if (rval < 0) {
slouken@1668
   369
        SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n",
slouken@1668
   370
                     snd_strerror(rval));
slouken@718
   371
        return (-1);
slouken@718
   372
    }
slouken@718
   373
slouken@1668
   374
    if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
slouken@718
   375
        /* enable count status parameter */
slouken@1662
   376
        if ((rval =
slouken@1668
   377
             snd_pcm_plugin_set_disable(audio_handle,
slouken@1668
   378
                                        PLUGIN_DISABLE_MMAP)) < 0) {
slouken@1668
   379
            SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n",
slouken@1668
   380
                         snd_strerror(rval));
slouken@718
   381
            return (-1);
slouken@718
   382
        }
slouken@718
   383
    }
slouken@718
   384
slouken@718
   385
    /* Try for a closest match on audio format */
slouken@718
   386
    format = 0;
slouken@718
   387
    /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
slouken@718
   388
    found = 0;
slouken@718
   389
slouken@1668
   390
    for (test_format = SDL_FirstAudioFormat(spec->format); !found;) {
slouken@718
   391
        /* if match found set format to equivalent ALSA format */
slouken@1662
   392
        switch (test_format) {
slouken@1662
   393
        case AUDIO_U8:
slouken@1662
   394
            format = SND_PCM_SFMT_U8;
slouken@1662
   395
            found = 1;
slouken@1662
   396
            break;
slouken@1662
   397
        case AUDIO_S8:
slouken@1662
   398
            format = SND_PCM_SFMT_S8;
slouken@1662
   399
            found = 1;
slouken@1662
   400
            break;
slouken@1662
   401
        case AUDIO_S16LSB:
slouken@1662
   402
            format = SND_PCM_SFMT_S16_LE;
slouken@1662
   403
            found = 1;
slouken@1662
   404
            break;
slouken@1662
   405
        case AUDIO_S16MSB:
slouken@1662
   406
            format = SND_PCM_SFMT_S16_BE;
slouken@1662
   407
            found = 1;
slouken@1662
   408
            break;
slouken@1662
   409
        case AUDIO_U16LSB:
slouken@1662
   410
            format = SND_PCM_SFMT_U16_LE;
slouken@1662
   411
            found = 1;
slouken@1662
   412
            break;
slouken@1662
   413
        case AUDIO_U16MSB:
slouken@1662
   414
            format = SND_PCM_SFMT_U16_BE;
slouken@1662
   415
            found = 1;
slouken@1662
   416
            break;
slouken@1662
   417
        default:
slouken@1662
   418
            break;
slouken@718
   419
        }
slouken@718
   420
slouken@1662
   421
        if (!found) {
slouken@1668
   422
            test_format = SDL_NextAudioFormat();
slouken@718
   423
        }
slouken@718
   424
    }
slouken@718
   425
slouken@718
   426
    /* assumes test_format not 0 on success */
slouken@1662
   427
    if (test_format == 0) {
slouken@1662
   428
        SDL_SetError
slouken@1662
   429
            ("NTO_OpenAudio(): Couldn't find any hardware audio formats");
slouken@718
   430
        return (-1);
slouken@718
   431
    }
slouken@718
   432
slouken@718
   433
    spec->format = test_format;
slouken@718
   434
slouken@718
   435
    /* Set the audio format */
slouken@718
   436
    cparams.format.format = format;
slouken@718
   437
slouken@718
   438
    /* Set mono or stereo audio (currently only two channels supported) */
slouken@718
   439
    cparams.format.voices = spec->channels;
slouken@1662
   440
slouken@718
   441
    /* Set rate */
slouken@718
   442
    cparams.format.rate = spec->freq;
slouken@0
   443
slouken@718
   444
    /* Setup the transfer parameters according to cparams */
slouken@1668
   445
    rval = snd_pcm_plugin_params(audio_handle, &cparams);
slouken@1662
   446
    if (rval < 0) {
slouken@1662
   447
        SDL_SetError
slouken@1662
   448
            ("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n",
slouken@1668
   449
             snd_strerror(rval));
slouken@718
   450
        return (-1);
slouken@718
   451
    }
slouken@0
   452
slouken@718
   453
    /* Make sure channel is setup right one last time */
slouken@1668
   454
    SDL_memset(&csetup, 0x00, sizeof(csetup));
slouken@718
   455
    csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
slouken@1668
   456
    if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0) {
slouken@1668
   457
        SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n");
slouken@718
   458
        return -1;
slouken@718
   459
    }
slouken@0
   460
slouken@0
   461
slouken@718
   462
    /* Calculate the final parameters for this audio specification */
slouken@1668
   463
    SDL_CalculateAudioSpec(spec);
slouken@418
   464
slouken@718
   465
    pcm_len = spec->size;
slouken@418
   466
slouken@1662
   467
    if (pcm_len == 0) {
slouken@1662
   468
        pcm_len =
slouken@1662
   469
            csetup.buf.block.frag_size * spec->channels *
slouken@1668
   470
            (snd_pcm_format_width(format) / 8);
slouken@718
   471
    }
slouken@0
   472
slouken@718
   473
    /* Allocate memory to the audio buffer and initialize with silence (Note that
slouken@718
   474
       buffer size must be a multiple of fragment size, so find closest multiple)
slouken@1662
   475
     */
slouken@1668
   476
    pcm_buf = (Uint8 *) SDL_AllocAudioMem(pcm_len);
slouken@1662
   477
    if (pcm_buf == NULL) {
slouken@1668
   478
        SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n");
slouken@718
   479
        return (-1);
slouken@718
   480
    }
slouken@1668
   481
    SDL_memset(pcm_buf, spec->silence, pcm_len);
slouken@0
   482
slouken@718
   483
    /* get the file descriptor */
slouken@1662
   484
    if ((audio_fd =
slouken@1668
   485
         snd_pcm_file_descriptor(audio_handle,
slouken@1668
   486
                                 SND_PCM_CHANNEL_PLAYBACK)) < 0) {
slouken@1662
   487
        SDL_SetError
slouken@1662
   488
            ("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n",
slouken@1668
   489
             snd_strerror(rval));
slouken@718
   490
        return (-1);
slouken@718
   491
    }
slouken@0
   492
slouken@718
   493
    /* Trigger audio playback */
slouken@1668
   494
    rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK);
slouken@1662
   495
    if (rval < 0) {
slouken@1668
   496
        SDL_SetError("snd_pcm_plugin_prepare failed: %s\n",
slouken@1668
   497
                     snd_strerror(rval));
slouken@718
   498
        return (-1);
slouken@718
   499
    }
slouken@0
   500
slouken@718
   501
    this->enabled = 1;
slouken@0
   502
slouken@718
   503
    /* Get the parent process id (we're the parent of the audio thread) */
slouken@1668
   504
    parent = getpid();
slouken@0
   505
slouken@718
   506
    /* We're really ready to rock and roll. :-) */
slouken@718
   507
    return (0);
slouken@0
   508
}
slouken@1662
   509
slouken@1662
   510
/* vi: set ts=4 sw=4 expandtab: */