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