Use consistent identifiers for the various platforms we support.
Make sure every source file includes SDL_config.h, so the proper system
headers are chosen.
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
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.
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.
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
22 This driver was written by:
26 #include "SDL_config.h"
28 /* Allow access to a raw mixing buffer */
33 #include "SDL_timer.h"
34 #include "SDL_audio.h"
35 #include "../SDL_audiomem.h"
36 #include "../SDL_audio_c.h"
37 #include "../SDL_audiodev_c.h"
38 #include "SDL_nasaudio.h"
40 /* The tag name used by artsc audio */
41 #define NAS_DRIVER_NAME "nas"
43 static struct SDL_PrivateAudioData *this2 = NULL;
45 /* Audio driver functions */
46 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec);
47 static void NAS_WaitAudio(_THIS);
48 static void NAS_PlayAudio(_THIS);
49 static Uint8 *NAS_GetAudioBuf(_THIS);
50 static void NAS_CloseAudio(_THIS);
52 /* Audio driver bootstrap functions */
54 static int Audio_Available(void)
56 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
63 static void Audio_DeleteDevice(SDL_AudioDevice *device)
65 SDL_free(device->hidden);
69 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
71 SDL_AudioDevice *this;
73 /* Initialize all variables that we clean on shutdown */
74 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
76 SDL_memset(this, 0, (sizeof *this));
77 this->hidden = (struct SDL_PrivateAudioData *)
78 SDL_malloc((sizeof *this->hidden));
80 if ( (this == NULL) || (this->hidden == NULL) ) {
87 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
89 /* Set the function pointers */
90 this->OpenAudio = NAS_OpenAudio;
91 this->WaitAudio = NAS_WaitAudio;
92 this->PlayAudio = NAS_PlayAudio;
93 this->GetAudioBuf = NAS_GetAudioBuf;
94 this->CloseAudio = NAS_CloseAudio;
96 this->free = Audio_DeleteDevice;
101 AudioBootStrap NAS_bootstrap = {
102 NAS_DRIVER_NAME, "Network Audio System",
103 Audio_Available, Audio_CreateDevice
106 /* This function waits until it is possible to write a full sound buffer */
107 static void NAS_WaitAudio(_THIS)
109 while ( this->hidden->buf_free < this->hidden->mixlen ) {
111 AuNextEvent(this->hidden->aud, AuTrue, &ev);
112 AuDispatchEvent(this->hidden->aud, &ev);
116 static void NAS_PlayAudio(_THIS)
118 while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
119 in the hope that some of them is LowWater events telling us more
120 of the buffer is free now than what we think. */
122 AuNextEvent(this->hidden->aud, AuTrue, &ev);
123 AuDispatchEvent(this->hidden->aud, &ev);
125 this->hidden->buf_free -= this->hidden->mixlen;
127 /* Write the audio data */
128 AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
130 this->hidden->written += this->hidden->mixlen;
133 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
137 static Uint8 *NAS_GetAudioBuf(_THIS)
139 return(this->hidden->mixbuf);
142 static void NAS_CloseAudio(_THIS)
144 if ( this->hidden->mixbuf != NULL ) {
145 SDL_FreeAudioMem(this->hidden->mixbuf);
146 this->hidden->mixbuf = NULL;
148 if ( this->hidden->aud ) {
149 AuCloseServer(this->hidden->aud);
150 this->hidden->aud = 0;
154 static unsigned char sdlformat_to_auformat(unsigned int fmt)
159 return AuFormatLinearUnsigned8;
161 return AuFormatLinearSigned8;
163 return AuFormatLinearUnsigned16LSB;
165 return AuFormatLinearUnsigned16MSB;
167 return AuFormatLinearSigned16LSB;
169 return AuFormatLinearSigned16MSB;
175 event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd)
178 case AuEventTypeElementNotify: {
179 AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev;
181 switch (event->kind) {
182 case AuElementNotifyKindLowWater:
183 if (this2->buf_free >= 0) {
184 this2->really += event->num_bytes;
185 gettimeofday(&this2->last_tv, 0);
186 this2->buf_free += event->num_bytes;
188 this2->buf_free = event->num_bytes;
191 case AuElementNotifyKindState:
192 switch (event->cur_state) {
194 if (event->reason != AuReasonUser) {
195 if (this2->buf_free >= 0) {
196 this2->really += event->num_bytes;
197 gettimeofday(&this2->last_tv, 0);
198 this2->buf_free += event->num_bytes;
200 this2->buf_free = event->num_bytes;
212 find_device(_THIS, int nch)
215 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
216 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
217 AuComponentKindPhysicalOutput) &&
218 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
219 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
225 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec)
229 Uint16 test_format, format;
231 this->hidden->mixbuf = NULL;
233 /* Try for a closest match on audio format */
235 for ( test_format = SDL_FirstAudioFormat(spec->format);
236 ! format && test_format; ) {
237 format = sdlformat_to_auformat(test_format);
239 if (format == AuNone) {
240 test_format = SDL_NextAudioFormat();
244 SDL_SetError("Couldn't find any hardware audio formats");
247 spec->format = test_format;
249 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
250 if (this->hidden->aud == 0)
252 SDL_SetError("Couldn't open connection to NAS server");
256 this->hidden->dev = find_device(this, spec->channels);
257 if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
258 AuCloseServer(this->hidden->aud);
259 this->hidden->aud = 0;
260 SDL_SetError("Couldn't find a fitting playback device on NAS server");
264 buffer_size = spec->freq;
265 if (buffer_size < 4096)
268 if (buffer_size > 32768)
269 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
271 /* Calculate the final parameters for this audio specification */
272 SDL_CalculateAudioSpec(spec);
274 this2 = this->hidden;
276 AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
277 buffer_size, buffer_size / 4, 0, NULL);
278 AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
279 AuUnlimitedSamples, 0, NULL);
280 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
281 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
282 event_handler, (AuPointer) NULL);
284 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
286 /* Allocate mixing buffer */
287 this->hidden->mixlen = spec->size;
288 this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen);
289 if ( this->hidden->mixbuf == NULL ) {
292 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
294 /* Get the parent process id (we're the parent of the audio thread) */
295 this->hidden->parent = getpid();
297 /* We're ready to rock and roll. :-) */