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
FillSound(void * device,void * stream,size_t len,const media_raw_audio_format & format)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
HAIKUAUDIO_CloseDevice(_THIS)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
MaskSignals(sigset_t * omask)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
UnmaskSignals(sigset_t * omask)103 UnmaskSignals(sigset_t * omask)
104 {
105 sigprocmask(SIG_SETMASK, omask, NULL);
106 }
107
108
109 static int
HAIKUAUDIO_OpenDevice(_THIS,void * handle,const char * devname,int iscapture)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_zerop(_this->hidden);
122
123 /* Parse the audio format and fill the Be raw audio format */
124 SDL_zero(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
HAIKUAUDIO_Deinitialize(void)201 HAIKUAUDIO_Deinitialize(void)
202 {
203 SDL_QuitBeApp();
204 }
205
206 static int
HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl)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: */
235