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