1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* Allow access to the audio stream on BeOS */
25
26#include <SoundPlayer.h>
27
28#include "../../main/beos/SDL_BeApp.h"
29
30extern "C" {
31
32#include "SDL_audio.h"
33#include "../SDL_audio_c.h"
34#include "../SDL_sysaudio.h"
35#include "../../thread/beos/SDL_systhread_c.h"
36#include "SDL_beaudio.h"
37
38
39/* Audio driver functions */
40static int BE_OpenAudio(_THIS, SDL_AudioSpec *spec);
41static void BE_WaitAudio(_THIS);
42static void BE_PlayAudio(_THIS);
43static Uint8 *BE_GetAudioBuf(_THIS);
44static void BE_CloseAudio(_THIS);
45
46/* Audio driver bootstrap functions */
47
48static int Audio_Available(void)
49{
50	return(1);
51}
52
53static void Audio_DeleteDevice(SDL_AudioDevice *device)
54{
55	SDL_free(device->hidden);
56	SDL_free(device);
57}
58
59static SDL_AudioDevice *Audio_CreateDevice(int devindex)
60{
61	SDL_AudioDevice *device;
62
63	/* Initialize all variables that we clean on shutdown */
64	device = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
65	if ( device ) {
66		SDL_memset(device, 0, (sizeof *device));
67		device->hidden = (struct SDL_PrivateAudioData *)
68				SDL_malloc((sizeof *device->hidden));
69	}
70	if ( (device == NULL) || (device->hidden == NULL) ) {
71		SDL_OutOfMemory();
72		if ( device ) {
73			SDL_free(device);
74		}
75		return(0);
76	}
77	SDL_memset(device->hidden, 0, (sizeof *device->hidden));
78
79	/* Set the function pointers */
80	device->OpenAudio = BE_OpenAudio;
81	device->WaitAudio = BE_WaitAudio;
82	device->PlayAudio = BE_PlayAudio;
83	device->GetAudioBuf = BE_GetAudioBuf;
84	device->CloseAudio = BE_CloseAudio;
85
86	device->free = Audio_DeleteDevice;
87
88	return device;
89}
90
91AudioBootStrap BAUDIO_bootstrap = {
92	"baudio", "BeOS BSoundPlayer",
93	Audio_Available, Audio_CreateDevice
94};
95
96/* The BeOS callback for handling the audio buffer */
97static void FillSound(void *device, void *stream, size_t len,
98					const media_raw_audio_format &format)
99{
100	SDL_AudioDevice *audio = (SDL_AudioDevice *)device;
101
102	/* Silence the buffer, since it's ours */
103	SDL_memset(stream, audio->spec.silence, len);
104
105	/* Only do soemthing if audio is enabled */
106	if ( ! audio->enabled )
107		return;
108
109	if ( ! audio->paused ) {
110		if ( audio->convert.needed ) {
111			SDL_mutexP(audio->mixer_lock);
112			(*audio->spec.callback)(audio->spec.userdata,
113				(Uint8 *)audio->convert.buf,audio->convert.len);
114			SDL_mutexV(audio->mixer_lock);
115			SDL_ConvertAudio(&audio->convert);
116			SDL_memcpy(stream,audio->convert.buf,audio->convert.len_cvt);
117		} else {
118			SDL_mutexP(audio->mixer_lock);
119			(*audio->spec.callback)(audio->spec.userdata,
120						(Uint8 *)stream, len);
121			SDL_mutexV(audio->mixer_lock);
122		}
123	}
124	return;
125}
126
127/* Dummy functions -- we don't use thread-based audio */
128void BE_WaitAudio(_THIS)
129{
130	return;
131}
132void BE_PlayAudio(_THIS)
133{
134	return;
135}
136Uint8 *BE_GetAudioBuf(_THIS)
137{
138	return(NULL);
139}
140
141void BE_CloseAudio(_THIS)
142{
143	if ( audio_obj ) {
144		audio_obj->Stop();
145		delete audio_obj;
146		audio_obj = NULL;
147	}
148
149	/* Quit the Be Application, if there's nothing left to do */
150	SDL_QuitBeApp();
151}
152
153int BE_OpenAudio(_THIS, SDL_AudioSpec *spec)
154{
155    int valid_datatype = 0;
156    media_raw_audio_format format;
157    Uint16 test_format = SDL_FirstAudioFormat(spec->format);
158
159    /* Parse the audio format and fill the Be raw audio format */
160    memset(&format, '\0', sizeof (media_raw_audio_format));
161    format.byte_order = B_MEDIA_LITTLE_ENDIAN;
162    format.frame_rate = (float) spec->freq;
163    format.channel_count = spec->channels;  /* !!! FIXME: support > 2? */
164    while ((!valid_datatype) && (test_format)) {
165        valid_datatype = 1;
166        spec->format = test_format;
167        switch (test_format) {
168            case AUDIO_S8:
169                format.format = media_raw_audio_format::B_AUDIO_CHAR;
170                break;
171
172            case AUDIO_U8:
173                format.format = media_raw_audio_format::B_AUDIO_UCHAR;
174                break;
175
176            case AUDIO_S16LSB:
177                format.format = media_raw_audio_format::B_AUDIO_SHORT;
178                break;
179
180            case AUDIO_S16MSB:
181                format.format = media_raw_audio_format::B_AUDIO_SHORT;
182                format.byte_order = B_MEDIA_BIG_ENDIAN;
183                break;
184
185            default:
186                valid_datatype = 0;
187                test_format = SDL_NextAudioFormat();
188                break;
189        }
190    }
191
192    if (!valid_datatype) { /* shouldn't happen, but just in case... */
193        SDL_SetError("Unsupported audio format");
194        return (-1);
195    }
196
197    /* Initialize the Be Application, if it's not already started */
198    if (SDL_InitBeApp() < 0) {
199        return (-1);
200    }
201
202    format.buffer_size = spec->samples;
203
204	/* Calculate the final parameters for this audio specification */
205	SDL_CalculateAudioSpec(spec);
206
207	/* Subscribe to the audio stream (creates a new thread) */
208	{ sigset_t omask;
209		SDL_MaskSignals(&omask);
210		audio_obj = new BSoundPlayer(&format, "SDL Audio", FillSound,
211		                                                 NULL, _this);
212		SDL_UnmaskSignals(&omask);
213	}
214	if ( audio_obj->Start() == B_NO_ERROR ) {
215		audio_obj->SetHasData(true);
216	} else {
217		SDL_SetError("Unable to start Be audio");
218		return(-1);
219	}
220
221	/* We're running! */
222	return(1);
223}
224
225};	/* Extern C */
226