src/audio/haiku/SDL_haikuaudio.cc
author Ryan C. Gordon <icculus@icculus.org>
Fri, 05 Aug 2016 01:44:41 -0400
changeset 10255 9530fc07da6c
parent 10238 6fa358b97f4b
child 10257 f17581d00c26
permissions -rw-r--r--
audio: Clean up some CloseDevice() interface details.

- It's now always called if device->hidden isn't NULL, even if OpenDevice()
failed halfway through. This lets implementation code not have to clean up
itself on every possible failure point; just return an error and SDL will
handle it for you.

- Implementations can assume this->hidden != NULL and not check for it.

- implementations don't have to set this->hidden = NULL when done, because
the caller is always about to free(this).

- Don't reset other fields that are in a block of memory about to be free()'d.

- Implementations all now free things like internal mix buffers last, after
closing devices and such, to guarantee they definitely aren't in use anymore
at the point of deallocation.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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_HAIKU
    24 
    25 /* Allow access to the audio stream on Haiku */
    26 
    27 #include <SoundPlayer.h>
    28 #include <signal.h>
    29 
    30 #include "../../main/haiku/SDL_BeApp.h"
    31 
    32 extern "C"
    33 {
    34 
    35 #include "SDL_audio.h"
    36 #include "../SDL_audio_c.h"
    37 #include "../SDL_sysaudio.h"
    38 #include "SDL_haikuaudio.h"
    39 
    40 }
    41 
    42 
    43 /* !!! FIXME: have the callback call the higher level to avoid code dupe. */
    44 /* The Haiku callback for handling the audio buffer */
    45 static void
    46 FillSound(void *device, void *stream, size_t len,
    47           const media_raw_audio_format & format)
    48 {
    49     SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
    50 
    51     /* Only do soemthing if audio is enabled */
    52     if (!SDL_AtomicGet(&audio->enabled)) {
    53         return;
    54     }
    55 
    56     if (!SDL_AtomicGet(&audio->paused)) {
    57         if (audio->convert.needed) {
    58             SDL_LockMutex(audio->mixer_lock);
    59             (*audio->spec.callback) (audio->spec.userdata,
    60                                      (Uint8 *) audio->convert.buf,
    61                                      audio->convert.len);
    62             SDL_UnlockMutex(audio->mixer_lock);
    63             SDL_ConvertAudio(&audio->convert);
    64             SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
    65         } else {
    66             SDL_LockMutex(audio->mixer_lock);
    67             (*audio->spec.callback) (audio->spec.userdata,
    68                                      (Uint8 *) stream, len);
    69             SDL_UnlockMutex(audio->mixer_lock);
    70         }
    71     }
    72 }
    73 
    74 static void
    75 HAIKUAUDIO_CloseDevice(_THIS)
    76 {
    77     if (_this->hidden->audio_obj) {
    78         _this->hidden->audio_obj->Stop();
    79         delete _this->hidden->audio_obj;
    80     }
    81     delete _this->hidden;
    82 }
    83 
    84 
    85 static const int sig_list[] = {
    86     SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGWINCH, 0
    87 };
    88 
    89 static inline void
    90 MaskSignals(sigset_t * omask)
    91 {
    92     sigset_t mask;
    93     int i;
    94 
    95     sigemptyset(&mask);
    96     for (i = 0; sig_list[i]; ++i) {
    97         sigaddset(&mask, sig_list[i]);
    98     }
    99     sigprocmask(SIG_BLOCK, &mask, omask);
   100 }
   101 
   102 static inline void
   103 UnmaskSignals(sigset_t * omask)
   104 {
   105     sigprocmask(SIG_SETMASK, omask, NULL);
   106 }
   107 
   108 
   109 static int
   110 HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
   111 {
   112     int valid_datatype = 0;
   113     media_raw_audio_format format;
   114     SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
   115 
   116     /* Initialize all variables that we clean on shutdown */
   117     _this->hidden = new SDL_PrivateAudioData;
   118     if (_this->hidden == NULL) {
   119         return SDL_OutOfMemory();
   120     }
   121     SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
   122 
   123     /* Parse the audio format and fill the Be raw audio format */
   124     SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
   125     format.byte_order = B_MEDIA_LITTLE_ENDIAN;
   126     format.frame_rate = (float) _this->spec.freq;
   127     format.channel_count = _this->spec.channels;        /* !!! FIXME: support > 2? */
   128     while ((!valid_datatype) && (test_format)) {
   129         valid_datatype = 1;
   130         _this->spec.format = test_format;
   131         switch (test_format) {
   132         case AUDIO_S8:
   133             format.format = media_raw_audio_format::B_AUDIO_CHAR;
   134             break;
   135 
   136         case AUDIO_U8:
   137             format.format = media_raw_audio_format::B_AUDIO_UCHAR;
   138             break;
   139 
   140         case AUDIO_S16LSB:
   141             format.format = media_raw_audio_format::B_AUDIO_SHORT;
   142             break;
   143 
   144         case AUDIO_S16MSB:
   145             format.format = media_raw_audio_format::B_AUDIO_SHORT;
   146             format.byte_order = B_MEDIA_BIG_ENDIAN;
   147             break;
   148 
   149         case AUDIO_S32LSB:
   150             format.format = media_raw_audio_format::B_AUDIO_INT;
   151             break;
   152 
   153         case AUDIO_S32MSB:
   154             format.format = media_raw_audio_format::B_AUDIO_INT;
   155             format.byte_order = B_MEDIA_BIG_ENDIAN;
   156             break;
   157 
   158         case AUDIO_F32LSB:
   159             format.format = media_raw_audio_format::B_AUDIO_FLOAT;
   160             break;
   161 
   162         case AUDIO_F32MSB:
   163             format.format = media_raw_audio_format::B_AUDIO_FLOAT;
   164             format.byte_order = B_MEDIA_BIG_ENDIAN;
   165             break;
   166 
   167         default:
   168             valid_datatype = 0;
   169             test_format = SDL_NextAudioFormat();
   170             break;
   171         }
   172     }
   173 
   174     if (!valid_datatype) {      /* shouldn't happen, but just in case... */
   175         return SDL_SetError("Unsupported audio format");
   176     }
   177 
   178     /* Calculate the final parameters for this audio specification */
   179     SDL_CalculateAudioSpec(&_this->spec);
   180 
   181     format.buffer_size = _this->spec.size;
   182 
   183     /* Subscribe to the audio stream (creates a new thread) */
   184     sigset_t omask;
   185     MaskSignals(&omask);
   186     _this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
   187                                                 FillSound, NULL, _this);
   188     UnmaskSignals(&omask);
   189 
   190     if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
   191         _this->hidden->audio_obj->SetHasData(true);
   192     } else {
   193         return SDL_SetError("Unable to start Be audio");
   194     }
   195 
   196     /* We're running! */
   197     return 0;
   198 }
   199 
   200 static void
   201 HAIKUAUDIO_Deinitialize(void)
   202 {
   203     SDL_QuitBeApp();
   204 }
   205 
   206 static int
   207 HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl)
   208 {
   209     /* Initialize the Be Application, if it's not already started */
   210     if (SDL_InitBeApp() < 0) {
   211         return 0;
   212     }
   213 
   214     /* Set the function pointers */
   215     impl->OpenDevice = HAIKUAUDIO_OpenDevice;
   216     impl->CloseDevice = HAIKUAUDIO_CloseDevice;
   217     impl->Deinitialize = HAIKUAUDIO_Deinitialize;
   218     impl->ProvidesOwnCallbackThread = 1;
   219     impl->OnlyHasDefaultOutputDevice = 1;
   220 
   221     return 1;   /* this audio target is available. */
   222 }
   223 
   224 extern "C"
   225 {
   226     extern AudioBootStrap HAIKUAUDIO_bootstrap;
   227 }
   228 AudioBootStrap HAIKUAUDIO_bootstrap = {
   229     "haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, 0
   230 };
   231 
   232 #endif /* SDL_AUDIO_DRIVER_HAIKU */
   233 
   234 /* vi: set ts=4 sw=4 expandtab: */