src/audio/paudio/SDL_paudio.c
author Sam Lantinga
Mon, 09 Jan 2017 11:58:01 -0800
changeset 10802 6afc9b833867
parent 10737 3406a0f8b041
child 11117 ea02b6aa1679
permissions -rw-r--r--
We only need the first few keymaps corresponding to the following constants:
K_NORMTAB, K_SHIFTTAB, K_ALTTAB, K_ALTSHIFTTAB

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