src/audio/paudio/SDL_paudio.c
author Ryan C. Gordon
Mon, 23 Jan 2017 12:06:10 -0500
changeset 10837 c2f241c2f6ad
parent 10737 3406a0f8b041
child 11117 ea02b6aa1679
permissions -rw-r--r--
audio: Fix same bug as last commit, but for _mm_bslli_si128 vs _mm_slli_si128.
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: */