More header massaging... works great on Windows. ;-)
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:
27 /* Allow access to a raw mixing buffer */
32 #include "SDL_timer.h"
33 #include "SDL_audio.h"
34 #include "SDL_audiomem.h"
35 #include "SDL_audio_c.h"
36 #include "SDL_audiodev_c.h"
37 #include "SDL_nasaudio.h"
39 /* The tag name used by artsc audio */
40 #define NAS_DRIVER_NAME "nas"
42 static struct SDL_PrivateAudioData *this2 = NULL;
44 /* Audio driver functions */
45 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec);
46 static void NAS_WaitAudio(_THIS);
47 static void NAS_PlayAudio(_THIS);
48 static Uint8 *NAS_GetAudioBuf(_THIS);
49 static void NAS_CloseAudio(_THIS);
51 /* Audio driver bootstrap functions */
53 static int Audio_Available(void)
55 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
62 static void Audio_DeleteDevice(SDL_AudioDevice *device)
64 SDL_free(device->hidden);
68 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
70 SDL_AudioDevice *this;
72 /* Initialize all variables that we clean on shutdown */
73 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
75 SDL_memset(this, 0, (sizeof *this));
76 this->hidden = (struct SDL_PrivateAudioData *)
77 SDL_malloc((sizeof *this->hidden));
79 if ( (this == NULL) || (this->hidden == NULL) ) {
86 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
88 /* Set the function pointers */
89 this->OpenAudio = NAS_OpenAudio;
90 this->WaitAudio = NAS_WaitAudio;
91 this->PlayAudio = NAS_PlayAudio;
92 this->GetAudioBuf = NAS_GetAudioBuf;
93 this->CloseAudio = NAS_CloseAudio;
95 this->free = Audio_DeleteDevice;
100 AudioBootStrap NAS_bootstrap = {
101 NAS_DRIVER_NAME, "Network Audio System",
102 Audio_Available, Audio_CreateDevice
105 /* This function waits until it is possible to write a full sound buffer */
106 static void NAS_WaitAudio(_THIS)
108 while ( this->hidden->buf_free < this->hidden->mixlen ) {
110 AuNextEvent(this->hidden->aud, AuTrue, &ev);
111 AuDispatchEvent(this->hidden->aud, &ev);
115 static void NAS_PlayAudio(_THIS)
117 while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
118 in the hope that some of them is LowWater events telling us more
119 of the buffer is free now than what we think. */
121 AuNextEvent(this->hidden->aud, AuTrue, &ev);
122 AuDispatchEvent(this->hidden->aud, &ev);
124 this->hidden->buf_free -= this->hidden->mixlen;
126 /* Write the audio data */
127 AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
129 this->hidden->written += this->hidden->mixlen;
132 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
136 static Uint8 *NAS_GetAudioBuf(_THIS)
138 return(this->hidden->mixbuf);
141 static void NAS_CloseAudio(_THIS)
143 if ( this->hidden->mixbuf != NULL ) {
144 SDL_FreeAudioMem(this->hidden->mixbuf);
145 this->hidden->mixbuf = NULL;
147 if ( this->hidden->aud ) {
148 AuCloseServer(this->hidden->aud);
149 this->hidden->aud = 0;
153 static unsigned char sdlformat_to_auformat(unsigned int fmt)
158 return AuFormatLinearUnsigned8;
160 return AuFormatLinearSigned8;
162 return AuFormatLinearUnsigned16LSB;
164 return AuFormatLinearUnsigned16MSB;
166 return AuFormatLinearSigned16LSB;
168 return AuFormatLinearSigned16MSB;
174 event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd)
177 case AuEventTypeElementNotify: {
178 AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev;
180 switch (event->kind) {
181 case AuElementNotifyKindLowWater:
182 if (this2->buf_free >= 0) {
183 this2->really += event->num_bytes;
184 gettimeofday(&this2->last_tv, 0);
185 this2->buf_free += event->num_bytes;
187 this2->buf_free = event->num_bytes;
190 case AuElementNotifyKindState:
191 switch (event->cur_state) {
193 if (event->reason != AuReasonUser) {
194 if (this2->buf_free >= 0) {
195 this2->really += event->num_bytes;
196 gettimeofday(&this2->last_tv, 0);
197 this2->buf_free += event->num_bytes;
199 this2->buf_free = event->num_bytes;
211 find_device(_THIS, int nch)
214 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
215 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
216 AuComponentKindPhysicalOutput) &&
217 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
218 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
224 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec)
228 Uint16 test_format, format;
230 this->hidden->mixbuf = NULL;
232 /* Try for a closest match on audio format */
234 for ( test_format = SDL_FirstAudioFormat(spec->format);
235 ! format && test_format; ) {
236 format = sdlformat_to_auformat(test_format);
238 if (format == AuNone) {
239 test_format = SDL_NextAudioFormat();
243 SDL_SetError("Couldn't find any hardware audio formats");
246 spec->format = test_format;
248 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
249 if (this->hidden->aud == 0)
251 SDL_SetError("Couldn't open connection to NAS server");
255 this->hidden->dev = find_device(this, spec->channels);
256 if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
257 AuCloseServer(this->hidden->aud);
258 this->hidden->aud = 0;
259 SDL_SetError("Couldn't find a fitting playback device on NAS server");
263 buffer_size = spec->freq;
264 if (buffer_size < 4096)
267 if (buffer_size > 32768)
268 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
270 /* Calculate the final parameters for this audio specification */
271 SDL_CalculateAudioSpec(spec);
273 this2 = this->hidden;
275 AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
276 buffer_size, buffer_size / 4, 0, NULL);
277 AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
278 AuUnlimitedSamples, 0, NULL);
279 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
280 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
281 event_handler, (AuPointer) NULL);
283 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
285 /* Allocate mixing buffer */
286 this->hidden->mixlen = spec->size;
287 this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen);
288 if ( this->hidden->mixbuf == NULL ) {
291 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
293 /* Get the parent process id (we're the parent of the audio thread) */
294 this->hidden->parent = getpid();
296 /* We're ready to rock and roll. :-) */