src/audio/paudio/SDL_paudio.c
author Sam Lantinga
Sat, 06 Oct 2012 11:23:47 -0700
changeset 6565 1f3c0df426dc
parent 6138 4c64952a58fb
child 6885 700f1b25f77f
permissions -rw-r--r--
When using Xinerama, XVidMode always works on screen 0. Otherwise use the real X11 screen.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
slouken@1402
    21
#include "SDL_config.h"
slouken@0
    22
slouken@6044
    23
#if SDL_AUDIO_DRIVER_PAUDIO
slouken@6044
    24
slouken@0
    25
/* Allow access to a raw mixing buffer */
slouken@0
    26
slouken@0
    27
#include <errno.h>
slouken@0
    28
#include <unistd.h>
slouken@0
    29
#include <fcntl.h>
slouken@0
    30
#include <sys/time.h>
slouken@0
    31
#include <sys/ioctl.h>
icculus@2049
    32
#include <sys/types.h>
slouken@0
    33
#include <sys/stat.h>
slouken@0
    34
slouken@1358
    35
#include "SDL_timer.h"
slouken@0
    36
#include "SDL_audio.h"
icculus@2049
    37
#include "SDL_stdinc.h"
slouken@1361
    38
#include "../SDL_audiomem.h"
slouken@1361
    39
#include "../SDL_audio_c.h"
slouken@0
    40
#include "SDL_paudio.h"
slouken@0
    41
icculus@2049
    42
#define DEBUG_AUDIO 0
slouken@0
    43
slouken@0
    44
/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
slouken@0
    45
 * I guess nobody ever uses audio... Shame over AIX header files.  */
slouken@0
    46
#include <sys/machine.h>
slouken@0
    47
#undef BIG_ENDIAN
slouken@0
    48
#include <sys/audio.h>
slouken@0
    49
slouken@0
    50
/* Open the audio device for playback, and don't block if busy */
slouken@0
    51
/* #define OPEN_FLAGS	(O_WRONLY|O_NONBLOCK) */
slouken@0
    52
#define OPEN_FLAGS	O_WRONLY
slouken@0
    53
icculus@2049
    54
/* Get the name of the audio device we use for output */
icculus@2049
    55
icculus@2049
    56
#ifndef _PATH_DEV_DSP
icculus@2049
    57
#define _PATH_DEV_DSP	"/dev/%caud%c/%c"
icculus@2049
    58
#endif
slouken@0
    59
icculus@2049
    60
static char devsettings[][3] = {
icculus@2049
    61
    {'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
icculus@2049
    62
    {'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
icculus@2049
    63
    {'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
icculus@2049
    64
    {'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
icculus@2049
    65
    {'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
icculus@2049
    66
    {'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
icculus@2049
    67
    {'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
icculus@2049
    68
    {'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
icculus@2049
    69
    {'\0', '\0', '\0'}
icculus@2049
    70
};
slouken@0
    71
slouken@1895
    72
static int
icculus@2049
    73
OpenUserDefinedDevice(char *path, int maxlen, int flags)
slouken@0
    74
{
icculus@2049
    75
    const char *audiodev;
slouken@1895
    76
    int fd;
slouken@0
    77
icculus@2049
    78
    /* Figure out what our audio device is */
icculus@2049
    79
    if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
icculus@2049
    80
        audiodev = SDL_getenv("AUDIODEV");
icculus@2049
    81
    }
icculus@2049
    82
    if (audiodev == NULL) {
icculus@2049
    83
        return -1;
slouken@1895
    84
    }
icculus@2049
    85
    fd = open(audiodev, flags, 0);
icculus@2049
    86
    if (path != NULL) {
icculus@2049
    87
        SDL_strlcpy(path, audiodev, maxlen);
icculus@2049
    88
        path[maxlen - 1] = '\0';
icculus@2049
    89
    }
icculus@2049
    90
    return fd;
slouken@0
    91
}
slouken@0
    92
icculus@2049
    93
static int
icculus@2049
    94
OpenAudioPath(char *path, int maxlen, int flags, int classic)
slouken@0
    95
{
icculus@2049
    96
    struct stat sb;
icculus@2049
    97
    int cycle = 0;
icculus@2049
    98
    int fd = OpenUserDefinedDevice(path, maxlen, flags);
slouken@0
    99
icculus@2049
   100
    if (fd != -1) {
icculus@2049
   101
        return fd;
slouken@1895
   102
    }
slouken@0
   103
icculus@2049
   104
    /* !!! FIXME: do we really need a table here? */
icculus@2049
   105
    while (devsettings[cycle][0] != '\0') {
icculus@2049
   106
        char audiopath[1024];
icculus@2049
   107
        SDL_snprintf(audiopath, SDL_arraysize(audiopath),
icculus@2049
   108
                     _PATH_DEV_DSP,
icculus@2049
   109
                     devsettings[cycle][0],
icculus@2049
   110
                     devsettings[cycle][1], devsettings[cycle][2]);
slouken@0
   111
icculus@2049
   112
        if (stat(audiopath, &sb) == 0) {
icculus@2049
   113
            fd = open(audiopath, flags, 0);
icculus@2049
   114
            if (fd > 0) {
icculus@2049
   115
                if (path != NULL) {
icculus@2049
   116
                    SDL_strlcpy(path, audiopath, maxlen);
icculus@2049
   117
                }
icculus@2049
   118
                return fd;
icculus@2049
   119
            }
icculus@2049
   120
        }
icculus@2049
   121
    }
icculus@2049
   122
    return -1;
slouken@0
   123
}
slouken@0
   124
slouken@0
   125
/* This function waits until it is possible to write a full sound buffer */
slouken@1895
   126
static void
icculus@2049
   127
PAUDIO_WaitDevice(_THIS)
slouken@0
   128
{
slouken@0
   129
    fd_set fdset;
slouken@0
   130
slouken@0
   131
    /* See if we need to use timed audio synchronization */
icculus@2049
   132
    if (this->hidden->frame_ticks) {
slouken@0
   133
        /* Use timer for general audio synchronization */
slouken@0
   134
        Sint32 ticks;
slouken@0
   135
slouken@2060
   136
        ticks =
slouken@2060
   137
            ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) -
slouken@2060
   138
            FUDGE_TICKS;
slouken@1895
   139
        if (ticks > 0) {
slouken@1895
   140
            SDL_Delay(ticks);
slouken@0
   141
        }
slouken@0
   142
    } else {
slouken@1895
   143
        audio_buffer paud_bufinfo;
slouken@0
   144
slouken@0
   145
        /* Use select() for audio synchronization */
slouken@0
   146
        struct timeval timeout;
slouken@0
   147
        FD_ZERO(&fdset);
icculus@2049
   148
        FD_SET(this->hidden->audio_fd, &fdset);
slouken@0
   149
icculus@2049
   150
        if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
slouken@0
   151
#ifdef DEBUG_AUDIO
slouken@0
   152
            fprintf(stderr, "Couldn't get audio buffer information\n");
slouken@0
   153
#endif
slouken@1895
   154
            timeout.tv_sec = 10;
slouken@0
   155
            timeout.tv_usec = 0;
slouken@0
   156
        } else {
slouken@1895
   157
            long ms_in_buf = paud_bufinfo.write_buf_time;
slouken@1895
   158
            timeout.tv_sec = ms_in_buf / 1000;
slouken@1895
   159
            ms_in_buf = ms_in_buf - timeout.tv_sec * 1000;
slouken@1895
   160
            timeout.tv_usec = ms_in_buf * 1000;
slouken@0
   161
#ifdef DEBUG_AUDIO
slouken@1895
   162
            fprintf(stderr,
slouken@1895
   163
                    "Waiting for write_buf_time=%ld,%ld\n",
slouken@1895
   164
                    timeout.tv_sec, timeout.tv_usec);
slouken@0
   165
#endif
slouken@1895
   166
        }
slouken@0
   167
slouken@0
   168
#ifdef DEBUG_AUDIO
slouken@0
   169
        fprintf(stderr, "Waiting for audio to get ready\n");
slouken@0
   170
#endif
slouken@2060
   171
        if (select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, &timeout)
slouken@2060
   172
            <= 0) {
slouken@1895
   173
            const char *message =
slouken@1895
   174
                "Audio timeout - buggy audio driver? (disabled)";
slouken@0
   175
            /*
slouken@1895
   176
             * In general we should never print to the screen,
slouken@0
   177
             * but in this case we have no other way of letting
slouken@0
   178
             * the user know what happened.
slouken@0
   179
             */
slouken@0
   180
            fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
slouken@0
   181
            this->enabled = 0;
slouken@0
   182
            /* Don't try to close - may hang */
icculus@2049
   183
            this->hidden->audio_fd = -1;
slouken@0
   184
#ifdef DEBUG_AUDIO
slouken@0
   185
            fprintf(stderr, "Done disabling audio\n");
slouken@0
   186
#endif
slouken@0
   187
        }
slouken@0
   188
#ifdef DEBUG_AUDIO
slouken@0
   189
        fprintf(stderr, "Ready!\n");
slouken@0
   190
#endif
slouken@0
   191
    }
slouken@0
   192
}
slouken@0
   193
slouken@1895
   194
static void
icculus@2049
   195
PAUDIO_PlayDevice(_THIS)
slouken@0
   196
{
icculus@2049
   197
    int written = 0;
icculus@2049
   198
    const Uint8 *mixbuf = this->hidden->mixbuf;
icculus@2049
   199
    const size_t mixlen = this->hidden->mixlen;
slouken@0
   200
slouken@1895
   201
    /* Write the audio data, checking for EAGAIN on broken audio drivers */
slouken@1895
   202
    do {
icculus@2049
   203
        written = write(this->hidden->audio_fd, mixbuf, mixlen);
slouken@1895
   204
        if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
slouken@1895
   205
            SDL_Delay(1);       /* Let a little CPU time go by */
slouken@1895
   206
        }
slouken@2735
   207
    } while ((written < 0) &&
slouken@2735
   208
             ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
slouken@0
   209
slouken@1895
   210
    /* If timer synchronization is enabled, set the next write frame */
icculus@2049
   211
    if (this->hidden->frame_ticks) {
icculus@2049
   212
        this->hidden->next_frame += this->hidden->frame_ticks;
slouken@1895
   213
    }
slouken@0
   214
slouken@1895
   215
    /* If we couldn't write, assume fatal error for now */
slouken@1895
   216
    if (written < 0) {
slouken@1895
   217
        this->enabled = 0;
slouken@1895
   218
    }
slouken@0
   219
#ifdef DEBUG_AUDIO
slouken@1895
   220
    fprintf(stderr, "Wrote %d bytes of audio data\n", written);
slouken@0
   221
#endif
slouken@0
   222
}
slouken@0
   223
slouken@1895
   224
static Uint8 *
icculus@2049
   225
PAUDIO_GetDeviceBuf(_THIS)
slouken@0
   226
{
icculus@2049
   227
    return this->hidden->mixbuf;
slouken@0
   228
}
slouken@0
   229
slouken@1895
   230
static void
icculus@2049
   231
PAUDIO_CloseDevice(_THIS)
slouken@0
   232
{
icculus@2049
   233
    if (this->hidden != NULL) {
icculus@2049
   234
        if (this->hidden->mixbuf != NULL) {
icculus@2049
   235
            SDL_FreeAudioMem(this->hidden->mixbuf);
icculus@2049
   236
            this->hidden->mixbuf = NULL;
icculus@2049
   237
        }
icculus@2049
   238
        if (this->hidden->audio_fd >= 0) {
icculus@2049
   239
            close(this->hidden->audio_fd);
icculus@2049
   240
            this->hidden->audio_fd = -1;
icculus@2049
   241
        }
icculus@2049
   242
        SDL_free(this->hidden);
icculus@2049
   243
        this->hidden = NULL;
slouken@1895
   244
    }
slouken@0
   245
}
slouken@0
   246
slouken@1895
   247
static int
icculus@2049
   248
PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
slouken@0
   249
{
icculus@2049
   250
    const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
slouken@1895
   251
    char audiodev[1024];
icculus@2049
   252
    const char *err = NULL;
slouken@1895
   253
    int format;
slouken@1895
   254
    int bytes_per_sample;
icculus@1982
   255
    SDL_AudioFormat test_format;
slouken@1895
   256
    audio_init paud_init;
slouken@1895
   257
    audio_buffer paud_bufinfo;
slouken@1895
   258
    audio_status paud_status;
slouken@1895
   259
    audio_control paud_control;
slouken@1895
   260
    audio_change paud_change;
icculus@2049
   261
    int fd = -1;
slouken@0
   262
icculus@2049
   263
    /* Initialize all variables that we clean on shutdown */
icculus@2049
   264
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2060
   265
        SDL_malloc((sizeof *this->hidden));
icculus@2049
   266
    if (this->hidden == NULL) {
icculus@2049
   267
        SDL_OutOfMemory();
icculus@2049
   268
        return 0;
icculus@2049
   269
    }
icculus@2049
   270
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
slouken@0
   271
slouken@1895
   272
    /* Open the audio device */
icculus@2049
   273
    fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
icculus@2049
   274
    this->hidden->audio_fd = fd;
icculus@2049
   275
    if (fd < 0) {
icculus@2049
   276
        PAUDIO_CloseDevice(this);
slouken@1895
   277
        SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
icculus@2049
   278
        return 0;
slouken@1895
   279
    }
slouken@0
   280
slouken@1895
   281
    /*
slouken@1895
   282
     * We can't set the buffer size - just ask the device for the maximum
slouken@1895
   283
     * that we can have.
slouken@1895
   284
     */
icculus@2049
   285
    if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
icculus@2049
   286
        PAUDIO_CloseDevice(this);
slouken@1895
   287
        SDL_SetError("Couldn't get audio buffer information");
icculus@2049
   288
        return 0;
slouken@1895
   289
    }
slouken@0
   290
icculus@2049
   291
    if (this->spec.channels > 1)
icculus@2049
   292
        this->spec.channels = 2;
slouken@1895
   293
    else
icculus@2049
   294
        this->spec.channels = 1;
slouken@0
   295
slouken@1895
   296
    /*
slouken@1895
   297
     * Fields in the audio_init structure:
slouken@1895
   298
     *
slouken@1895
   299
     * Ignored by us:
slouken@1895
   300
     *
slouken@1895
   301
     * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
slouken@1895
   302
     * paud.slot_number;         * slot number of the adapter
slouken@1895
   303
     * paud.device_id;           * adapter identification number
slouken@1895
   304
     *
slouken@1895
   305
     * Input:
slouken@1895
   306
     *
slouken@1895
   307
     * paud.srate;           * the sampling rate in Hz
slouken@1895
   308
     * paud.bits_per_sample; * 8, 16, 32, ...
slouken@1895
   309
     * paud.bsize;           * block size for this rate
slouken@1895
   310
     * paud.mode;            * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
slouken@1895
   311
     * paud.channels;        * 1=mono, 2=stereo
slouken@1895
   312
     * paud.flags;           * FIXED - fixed length data
slouken@1895
   313
     *                       * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
slouken@1895
   314
     *                       * TWOS_COMPLEMENT - 2's complement data
slouken@1895
   315
     *                       * SIGNED - signed? comment seems wrong in sys/audio.h
slouken@1895
   316
     *                       * BIG_ENDIAN
slouken@1895
   317
     * paud.operation;       * PLAY, RECORD
slouken@1895
   318
     *
slouken@1895
   319
     * Output:
slouken@1895
   320
     *
slouken@1895
   321
     * paud.flags;           * PITCH            - pitch is supported
slouken@1895
   322
     *                       * INPUT            - input is supported
slouken@1895
   323
     *                       * OUTPUT           - output is supported
slouken@1895
   324
     *                       * MONITOR          - monitor is supported
slouken@1895
   325
     *                       * VOLUME           - volume is supported
slouken@1895
   326
     *                       * VOLUME_DELAY     - volume delay is supported
slouken@1895
   327
     *                       * BALANCE          - balance is supported
slouken@1895
   328
     *                       * BALANCE_DELAY    - balance delay is supported
slouken@1895
   329
     *                       * TREBLE           - treble control is supported
slouken@1895
   330
     *                       * BASS             - bass control is supported
slouken@1895
   331
     *                       * BESTFIT_PROVIDED - best fit returned
slouken@1895
   332
     *                       * LOAD_CODE        - DSP load needed
slouken@1895
   333
     * paud.rc;              * NO_PLAY         - DSP code can't do play requests
slouken@1895
   334
     *                       * NO_RECORD       - DSP code can't do record requests
slouken@1895
   335
     *                       * INVALID_REQUEST - request was invalid
slouken@1895
   336
     *                       * CONFLICT        - conflict with open's flags
slouken@1895
   337
     *                       * OVERLOADED      - out of DSP MIPS or memory
slouken@1895
   338
     * paud.position_resolution; * smallest increment for position
slouken@1895
   339
     */
slouken@0
   340
icculus@2049
   341
    paud_init.srate = this->spec.freq;
slouken@1895
   342
    paud_init.mode = PCM;
slouken@1895
   343
    paud_init.operation = PLAY;
icculus@2049
   344
    paud_init.channels = this->spec.channels;
slouken@0
   345
slouken@1895
   346
    /* Try for a closest match on audio format */
slouken@1895
   347
    format = 0;
icculus@2049
   348
    for (test_format = SDL_FirstAudioFormat(this->spec.format);
slouken@1895
   349
         !format && test_format;) {
slouken@0
   350
#ifdef DEBUG_AUDIO
slouken@1895
   351
        fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
slouken@0
   352
#endif
slouken@1895
   353
        switch (test_format) {
slouken@1895
   354
        case AUDIO_U8:
slouken@1895
   355
            bytes_per_sample = 1;
slouken@1895
   356
            paud_init.bits_per_sample = 8;
slouken@1895
   357
            paud_init.flags = TWOS_COMPLEMENT | FIXED;
slouken@1895
   358
            format = 1;
slouken@1895
   359
            break;
slouken@1895
   360
        case AUDIO_S8:
slouken@1895
   361
            bytes_per_sample = 1;
slouken@1895
   362
            paud_init.bits_per_sample = 8;
slouken@1895
   363
            paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
slouken@1895
   364
            format = 1;
slouken@1895
   365
            break;
slouken@1895
   366
        case AUDIO_S16LSB:
slouken@1895
   367
            bytes_per_sample = 2;
slouken@1895
   368
            paud_init.bits_per_sample = 16;
slouken@1895
   369
            paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
slouken@1895
   370
            format = 1;
slouken@1895
   371
            break;
slouken@1895
   372
        case AUDIO_S16MSB:
slouken@1895
   373
            bytes_per_sample = 2;
slouken@1895
   374
            paud_init.bits_per_sample = 16;
slouken@1895
   375
            paud_init.flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED;
slouken@1895
   376
            format = 1;
slouken@1895
   377
            break;
slouken@1895
   378
        case AUDIO_U16LSB:
slouken@1895
   379
            bytes_per_sample = 2;
slouken@1895
   380
            paud_init.bits_per_sample = 16;
slouken@1895
   381
            paud_init.flags = TWOS_COMPLEMENT | FIXED;
slouken@1895
   382
            format = 1;
slouken@1895
   383
            break;
slouken@1895
   384
        case AUDIO_U16MSB:
slouken@1895
   385
            bytes_per_sample = 2;
slouken@1895
   386
            paud_init.bits_per_sample = 16;
slouken@1895
   387
            paud_init.flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED;
slouken@1895
   388
            format = 1;
slouken@1895
   389
            break;
slouken@1895
   390
        default:
slouken@1895
   391
            break;
slouken@1895
   392
        }
slouken@1895
   393
        if (!format) {
slouken@1895
   394
            test_format = SDL_NextAudioFormat();
slouken@1895
   395
        }
slouken@1895
   396
    }
slouken@1895
   397
    if (format == 0) {
slouken@0
   398
#ifdef DEBUG_AUDIO
slouken@1895
   399
        fprintf(stderr, "Couldn't find any hardware audio formats\n");
slouken@0
   400
#endif
icculus@2049
   401
        PAUDIO_CloseDevice(this);
slouken@1895
   402
        SDL_SetError("Couldn't find any hardware audio formats");
icculus@2049
   403
        return 0;
slouken@1895
   404
    }
icculus@2049
   405
    this->spec.format = test_format;
slouken@0
   406
slouken@1895
   407
    /*
slouken@1895
   408
     * We know the buffer size and the max number of subsequent writes
icculus@2049
   409
     *  that can be pending. If more than one can pend, allow the application
icculus@2049
   410
     *  to do something like double buffering between our write buffer and
icculus@2049
   411
     *  the device's own buffer that we are filling with write() anyway.
slouken@1895
   412
     *
icculus@2049
   413
     * We calculate this->spec.samples like this because
icculus@2049
   414
     *  SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
icculus@2049
   415
     *  (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
slouken@1895
   416
     */
slouken@1895
   417
    if (paud_bufinfo.request_buf_cap == 1) {
icculus@2049
   418
        this->spec.samples = paud_bufinfo.write_buf_cap
icculus@2049
   419
            / bytes_per_sample / this->spec.channels;
slouken@1895
   420
    } else {
icculus@2049
   421
        this->spec.samples = paud_bufinfo.write_buf_cap
icculus@2049
   422
            / bytes_per_sample / this->spec.channels / 2;
slouken@1895
   423
    }
icculus@2049
   424
    paud_init.bsize = bytes_per_sample * this->spec.channels;
slouken@0
   425
icculus@2049
   426
    SDL_CalculateAudioSpec(&this->spec);
slouken@0
   427
slouken@1895
   428
    /*
slouken@1895
   429
     * The AIX paud device init can't modify the values of the audio_init
slouken@1895
   430
     * structure that we pass to it. So we don't need any recalculation
icculus@5586
   431
     * of this stuff and no reinit call as in linux dsp code.
slouken@1895
   432
     *
slouken@1895
   433
     * /dev/paud supports all of the encoding formats, so we don't need
slouken@1895
   434
     * to do anything like reopening the device, either.
slouken@1895
   435
     */
icculus@2049
   436
    if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) {
slouken@1895
   437
        switch (paud_init.rc) {
slouken@1895
   438
        case 1:
icculus@2049
   439
            err = "Couldn't set audio format: DSP can't do play requests";
slouken@1895
   440
            break;
slouken@1895
   441
        case 2:
icculus@2049
   442
            err = "Couldn't set audio format: DSP can't do record requests";
slouken@1895
   443
            break;
slouken@1895
   444
        case 4:
icculus@2049
   445
            err = "Couldn't set audio format: request was invalid";
slouken@1895
   446
            break;
slouken@1895
   447
        case 5:
icculus@2049
   448
            err = "Couldn't set audio format: conflict with open's flags";
slouken@1895
   449
            break;
slouken@1895
   450
        case 6:
icculus@2049
   451
            err = "Couldn't set audio format: out of DSP MIPS or memory";
slouken@1895
   452
            break;
slouken@1895
   453
        default:
icculus@2049
   454
            err = "Couldn't set audio format: not documented in sys/audio.h";
slouken@1895
   455
            break;
slouken@1895
   456
        }
slouken@1895
   457
    }
slouken@0
   458
icculus@2049
   459
    if (err != NULL) {
icculus@2049
   460
        PAUDIO_CloseDevice(this);
icculus@2049
   461
        SDL_SetError("Paudio: %s", err);
icculus@2049
   462
        return 0;
icculus@2049
   463
    }
icculus@2049
   464
slouken@1895
   465
    /* Allocate mixing buffer */
icculus@2049
   466
    this->hidden->mixlen = this->spec.size;
icculus@2049
   467
    this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
icculus@2049
   468
    if (this->hidden->mixbuf == NULL) {
icculus@2049
   469
        PAUDIO_CloseDevice(this);
icculus@2049
   470
        SDL_OutOfMemory();
icculus@2049
   471
        return 0;
slouken@1895
   472
    }
icculus@2049
   473
    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
slouken@0
   474
slouken@1895
   475
    /*
slouken@1895
   476
     * Set some paramters: full volume, first speaker that we can find.
slouken@1895
   477
     * Ignore the other settings for now.
slouken@1895
   478
     */
slouken@1895
   479
    paud_change.input = AUDIO_IGNORE;   /* the new input source */
slouken@1895
   480
    paud_change.output = OUTPUT_1;      /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
slouken@1895
   481
    paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
slouken@1895
   482
    paud_change.volume = 0x7fffffff;    /* volume level [0-0x7fffffff] */
slouken@1895
   483
    paud_change.volume_delay = AUDIO_IGNORE;    /* the new volume delay */
slouken@1895
   484
    paud_change.balance = 0x3fffffff;   /* the new balance */
slouken@1895
   485
    paud_change.balance_delay = AUDIO_IGNORE;   /* the new balance delay */
slouken@1895
   486
    paud_change.treble = AUDIO_IGNORE;  /* the new treble state */
slouken@1895
   487
    paud_change.bass = AUDIO_IGNORE;    /* the new bass state */
slouken@1895
   488
    paud_change.pitch = AUDIO_IGNORE;   /* the new pitch state */
slouken@0
   489
slouken@1895
   490
    paud_control.ioctl_request = AUDIO_CHANGE;
slouken@1895
   491
    paud_control.request_info = (char *) &paud_change;
icculus@2049
   492
    if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
slouken@0
   493
#ifdef DEBUG_AUDIO
slouken@1895
   494
        fprintf(stderr, "Can't change audio display settings\n");
slouken@0
   495
#endif
slouken@1895
   496
    }
slouken@0
   497
slouken@1895
   498
    /*
slouken@1895
   499
     * Tell the device to expect data. Actual start will wait for
slouken@1895
   500
     * the first write() call.
slouken@1895
   501
     */
slouken@1895
   502
    paud_control.ioctl_request = AUDIO_START;
slouken@1895
   503
    paud_control.position = 0;
icculus@2049
   504
    if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
icculus@2049
   505
        PAUDIO_CloseDevice(this);
slouken@0
   506
#ifdef DEBUG_AUDIO
slouken@1895
   507
        fprintf(stderr, "Can't start audio play\n");
slouken@0
   508
#endif
slouken@1895
   509
        SDL_SetError("Can't start audio play");
icculus@2049
   510
        return 0;
slouken@1895
   511
    }
slouken@0
   512
slouken@1895
   513
    /* Check to see if we need to use select() workaround */
icculus@2049
   514
    if (workaround != NULL) {
icculus@2049
   515
        this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
slouken@2060
   516
            this->spec.freq;
icculus@2049
   517
        this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
slouken@1895
   518
    }
slouken@0
   519
slouken@1895
   520
    /* We're ready to rock and roll. :-) */
icculus@2049
   521
    return 1;
slouken@0
   522
}
slouken@0
   523
icculus@2049
   524
static int
slouken@2060
   525
PAUDIO_Init(SDL_AudioDriverImpl * impl)
icculus@2049
   526
{
icculus@2938
   527
    /* !!! FIXME: not right for device enum? */
icculus@2049
   528
    int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
icculus@2049
   529
    if (fd < 0) {
icculus@2049
   530
        SDL_SetError("PAUDIO: Couldn't open audio device");
icculus@2049
   531
        return 0;
icculus@2049
   532
    }
icculus@2049
   533
    close(fd);
icculus@2049
   534
icculus@2049
   535
    /* Set the function pointers */
icculus@2049
   536
    impl->OpenDevice = DSP_OpenDevice;
icculus@2049
   537
    impl->PlayDevice = DSP_PlayDevice;
icculus@2049
   538
    impl->PlayDevice = DSP_WaitDevice;
icculus@2049
   539
    impl->GetDeviceBuf = DSP_GetDeviceBuf;
icculus@2049
   540
    impl->CloseDevice = DSP_CloseDevice;
slouken@2060
   541
    impl->OnlyHasDefaultOutputDevice = 1;       /* !!! FIXME: add device enum! */
icculus@2049
   542
icculus@3699
   543
    return 1;   /* this audio target is available. */
icculus@2049
   544
}
icculus@2049
   545
icculus@2049
   546
AudioBootStrap PAUDIO_bootstrap = {
icculus@5594
   547
    "paud", "AIX Paudio", PAUDIO_Init, 0
icculus@2049
   548
};
icculus@2049
   549
slouken@6044
   550
#endif /* SDL_AUDIO_DRIVER_PAUDIO */
slouken@6044
   551
slouken@1895
   552
/* vi: set ts=4 sw=4 expandtab: */