Updated copyright information and removed rcs id lines (problematic in branch merges)
I batch edited these files, so please let me know if I've accidentally removed anybody's
credit here.
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 */
36 #include "SDL_audio.h"
37 #include "SDL_error.h"
38 #include "SDL_audiomem.h"
39 #include "SDL_audio_c.h"
40 #include "SDL_timer.h"
41 #include "SDL_audiodev_c.h"
42 #include "SDL_nasaudio.h"
44 /* The tag name used by artsc audio */
45 #define NAS_DRIVER_NAME "nas"
47 static struct SDL_PrivateAudioData *this2 = NULL;
49 /* Audio driver functions */
50 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec);
51 static void NAS_WaitAudio(_THIS);
52 static void NAS_PlayAudio(_THIS);
53 static Uint8 *NAS_GetAudioBuf(_THIS);
54 static void NAS_CloseAudio(_THIS);
56 /* Audio driver bootstrap functions */
58 static int Audio_Available(void)
60 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
67 static void Audio_DeleteDevice(SDL_AudioDevice *device)
73 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
75 SDL_AudioDevice *this;
77 /* Initialize all variables that we clean on shutdown */
78 this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
80 memset(this, 0, (sizeof *this));
81 this->hidden = (struct SDL_PrivateAudioData *)
82 malloc((sizeof *this->hidden));
84 if ( (this == NULL) || (this->hidden == NULL) ) {
91 memset(this->hidden, 0, (sizeof *this->hidden));
93 /* Set the function pointers */
94 this->OpenAudio = NAS_OpenAudio;
95 this->WaitAudio = NAS_WaitAudio;
96 this->PlayAudio = NAS_PlayAudio;
97 this->GetAudioBuf = NAS_GetAudioBuf;
98 this->CloseAudio = NAS_CloseAudio;
100 this->free = Audio_DeleteDevice;
105 AudioBootStrap NAS_bootstrap = {
106 NAS_DRIVER_NAME, "Network Audio System",
107 Audio_Available, Audio_CreateDevice
110 /* This function waits until it is possible to write a full sound buffer */
111 static void NAS_WaitAudio(_THIS)
113 while ( this->hidden->buf_free < this->hidden->mixlen ) {
115 AuNextEvent(this->hidden->aud, AuTrue, &ev);
116 AuDispatchEvent(this->hidden->aud, &ev);
120 static void NAS_PlayAudio(_THIS)
122 while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
123 in the hope that some of them is LowWater events telling us more
124 of the buffer is free now than what we think. */
126 AuNextEvent(this->hidden->aud, AuTrue, &ev);
127 AuDispatchEvent(this->hidden->aud, &ev);
129 this->hidden->buf_free -= this->hidden->mixlen;
131 /* Write the audio data */
132 AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
134 this->hidden->written += this->hidden->mixlen;
137 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
141 static Uint8 *NAS_GetAudioBuf(_THIS)
143 return(this->hidden->mixbuf);
146 static void NAS_CloseAudio(_THIS)
148 if ( this->hidden->mixbuf != NULL ) {
149 SDL_FreeAudioMem(this->hidden->mixbuf);
150 this->hidden->mixbuf = NULL;
152 if ( this->hidden->aud ) {
153 AuCloseServer(this->hidden->aud);
154 this->hidden->aud = 0;
158 static unsigned char sdlformat_to_auformat(unsigned int fmt)
163 return AuFormatLinearUnsigned8;
165 return AuFormatLinearSigned8;
167 return AuFormatLinearUnsigned16LSB;
169 return AuFormatLinearUnsigned16MSB;
171 return AuFormatLinearSigned16LSB;
173 return AuFormatLinearSigned16MSB;
179 event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd)
182 case AuEventTypeElementNotify: {
183 AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev;
185 switch (event->kind) {
186 case AuElementNotifyKindLowWater:
187 if (this2->buf_free >= 0) {
188 this2->really += event->num_bytes;
189 gettimeofday(&this2->last_tv, 0);
190 this2->buf_free += event->num_bytes;
192 this2->buf_free = event->num_bytes;
195 case AuElementNotifyKindState:
196 switch (event->cur_state) {
198 if (event->reason != AuReasonUser) {
199 if (this2->buf_free >= 0) {
200 this2->really += event->num_bytes;
201 gettimeofday(&this2->last_tv, 0);
202 this2->buf_free += event->num_bytes;
204 this2->buf_free = event->num_bytes;
216 find_device(_THIS, int nch)
219 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
220 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
221 AuComponentKindPhysicalOutput) &&
222 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
223 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
229 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec)
233 Uint16 test_format, format;
235 this->hidden->mixbuf = NULL;
237 /* Try for a closest match on audio format */
239 for ( test_format = SDL_FirstAudioFormat(spec->format);
240 ! format && test_format; ) {
241 format = sdlformat_to_auformat(test_format);
243 if (format == AuNone) {
244 test_format = SDL_NextAudioFormat();
248 SDL_SetError("Couldn't find any hardware audio formats");
251 spec->format = test_format;
253 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
254 if (this->hidden->aud == 0)
256 SDL_SetError("Couldn't open connection to NAS server");
260 this->hidden->dev = find_device(this, spec->channels);
261 if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
262 AuCloseServer(this->hidden->aud);
263 this->hidden->aud = 0;
264 SDL_SetError("Couldn't find a fitting playback device on NAS server");
268 buffer_size = spec->freq;
269 if (buffer_size < 4096)
272 if (buffer_size > 32768)
273 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
275 /* Calculate the final parameters for this audio specification */
276 SDL_CalculateAudioSpec(spec);
278 this2 = this->hidden;
280 AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
281 buffer_size, buffer_size / 4, 0, NULL);
282 AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
283 AuUnlimitedSamples, 0, NULL);
284 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
285 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
286 event_handler, (AuPointer) NULL);
288 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
290 /* Allocate mixing buffer */
291 this->hidden->mixlen = spec->size;
292 this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen);
293 if ( this->hidden->mixbuf == NULL ) {
296 memset(this->hidden->mixbuf, spec->silence, spec->size);
298 /* Get the parent process id (we're the parent of the audio thread) */
299 this->hidden->parent = getpid();
301 /* We're ready to rock and roll. :-) */