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