Moved NAS audio driver to 1.3 API.
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_nasaudio.h"
39 /* The tag name used by nas audio */
40 #define NAS_DRIVER_NAME "nas"
42 static struct SDL_PrivateAudioData *this2 = NULL;
44 /* !!! FIXME: dynamic loading? */
49 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
57 /* This function waits until it is possible to write a full sound buffer */
61 while (this->hidden->buf_free < this->hidden->mixlen) {
63 AuNextEvent(this->hidden->aud, AuTrue, &ev);
64 AuDispatchEvent(this->hidden->aud, &ev);
71 while (this->hidden->mixlen > this->hidden->buf_free) {
73 * We think the buffer is full? Yikes! Ask the server for events,
74 * in the hope that some of them is LowWater events telling us more
75 * of the buffer is free now than what we think.
78 AuNextEvent(this->hidden->aud, AuTrue, &ev);
79 AuDispatchEvent(this->hidden->aud, &ev);
81 this->hidden->buf_free -= this->hidden->mixlen;
83 /* Write the audio data */
84 AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
85 this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
87 this->hidden->written += this->hidden->mixlen;
90 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
95 NAS_GetDeviceBuf(_THIS)
97 return (this->hidden->mixbuf);
101 NAS_CloseDevice(_THIS)
103 if (this->hidden != NULL) {
104 if (this->hidden->mixbuf != NULL) {
105 SDL_FreeAudioMem(this->hidden->mixbuf);
106 this->hidden->mixbuf = NULL;
108 if (this->hidden->aud) {
109 AuCloseServer(this->hidden->aud);
110 this->hidden->aud = 0;
112 SDL_free(this->hidden);
118 sdlformat_to_auformat(unsigned int fmt)
122 return AuFormatLinearUnsigned8;
124 return AuFormatLinearSigned8;
126 return AuFormatLinearUnsigned16LSB;
128 return AuFormatLinearUnsigned16MSB;
130 return AuFormatLinearSigned16LSB;
132 return AuFormatLinearSigned16MSB;
138 event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
141 case AuEventTypeElementNotify:
143 AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
145 switch (event->kind) {
146 case AuElementNotifyKindLowWater:
147 if (this2->buf_free >= 0) {
148 this2->really += event->num_bytes;
149 gettimeofday(&this2->last_tv, 0);
150 this2->buf_free += event->num_bytes;
152 this2->buf_free = event->num_bytes;
155 case AuElementNotifyKindState:
156 switch (event->cur_state) {
158 if (event->reason != AuReasonUser) {
159 if (this2->buf_free >= 0) {
160 this2->really += event->num_bytes;
161 gettimeofday(&this2->last_tv, 0);
162 this2->buf_free += event->num_bytes;
164 this2->buf_free = event->num_bytes;
176 find_device(_THIS, int nch)
179 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
180 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
181 AuComponentKindPhysicalOutput) &&
182 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
183 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
190 NAS_OpenDevice(_THIS, const char *devname, int iscapture)
194 SDL_AudioFormat test_format, format;
196 /* Initialize all variables that we clean on shutdown */
197 this->hidden = (struct SDL_PrivateAudioData *)
198 SDL_malloc((sizeof *this->hidden));
199 if (this->hidden == NULL) {
203 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
205 /* Try for a closest match on audio format */
207 for (test_format = SDL_FirstAudioFormat(this->spec.format);
208 !format && test_format;) {
209 format = sdlformat_to_auformat(test_format);
210 if (format == AuNone) {
211 test_format = SDL_NextAudioFormat();
215 NAS_CloseDevice(this);
216 SDL_SetError("NAS: Couldn't find any hardware audio formats");
219 this->spec.format = test_format;
221 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
222 if (this->hidden->aud == 0) {
223 NAS_CloseDevice(this);
224 SDL_SetError("NAS: Couldn't open connection to NAS server");
228 this->hidden->dev = find_device(this, this->spec.channels);
229 if ((this->hidden->dev == AuNone)
230 || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
231 NAS_CloseDevice(this);
232 SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
236 buffer_size = this->spec.freq;
237 if (buffer_size < 4096)
240 if (buffer_size > 32768)
241 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
243 /* Calculate the final parameters for this audio specification */
244 SDL_CalculateAudioSpec(&this->spec);
246 this2 = this->hidden;
248 AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels,
249 AuTrue, buffer_size, buffer_size / 4, 0, NULL);
250 AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
251 AuUnlimitedSamples, 0, NULL);
252 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
253 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
254 this->hidden->flow, event_handler,
257 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
259 /* Allocate mixing buffer */
260 this->hidden->mixlen = this->spec.size;
261 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
262 if (this->hidden->mixbuf == NULL) {
263 NAS_CloseDevice(this);
267 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
269 /* We're ready to rock and roll. :-) */
274 NAS_Init(SDL_AudioDriverImpl *impl)
276 /* Set the function pointers */
277 impl->OpenDevice = NAS_OpenDevice;
278 impl->PlayDevice = NAS_PlayDevice;
279 impl->WaitDevice = NAS_WaitDevice;
280 impl->GetDeviceBuf = NAS_GetDeviceBuf;
281 impl->CloseDevice = NAS_CloseDevice;
282 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
287 AudioBootStrap NAS_bootstrap = {
288 NAS_DRIVER_NAME, "Network Audio System",
289 NAS_Available, NAS_Init, 0
292 /* vi: set ts=4 sw=4 expandtab: */