src/audio/haiku/SDL_haikuaudio.cc
author Ryan C. Gordon <icculus@icculus.org>
Mon, 21 May 2018 12:00:21 -0400
changeset 11994 8e094f91ddab
parent 11811 5d94cb6b24d3
child 12503 806492103856
permissions -rw-r--r--
thread: fixed compiler warnings on non-Linux systems that use pthread.

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