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