Mercurial > sdl-ios-xcode
annotate src/audio/nas/SDL_nasaudio.c @ 4001:6831b8723a85 SDL-1.2
Don't initialize the audio buffer passed to the application's audio callback,
since they are expected to entirely fill it with data or silence.
For legacy apps that might expect the buffer to already have silence and thus
may not fill the buffer in the callback, there's an environment variable to
expose the old behaviour.
Fixes Bugzilla #416.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Thu, 05 Jul 2007 02:24:36 +0000 |
parents | d910939febfa |
children | 782fd950bd46 c121d94672cb a1b03ba2fcd0 |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
3 Copyright (C) 1997-2006 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
6 modify it under the terms of the GNU Lesser General Public |
0 | 7 License as published by the Free Software Foundation; either |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
8 version 2.1 of the License, or (at your option) any later version. |
0 | 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 | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
13 Lesser General Public License for more details. |
0 | 14 |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
16 License along with this library; if not, write to the Free Software |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 |
22 This driver was written by: | |
23 Erik Inge Bolsų | |
24 knan@mo.himolde.no | |
25 */ | |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
26 #include "SDL_config.h" |
0 | 27 |
28 /* Allow access to a raw mixing buffer */ | |
29 | |
30 #include <signal.h> | |
31 #include <unistd.h> | |
32 | |
1358
c71e05b4dc2e
More header massaging... works great on Windows. ;-)
Sam Lantinga <slouken@libsdl.org>
parents:
1338
diff
changeset
|
33 #include "SDL_timer.h" |
0 | 34 #include "SDL_audio.h" |
1361
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
35 #include "../SDL_audiomem.h" |
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
36 #include "../SDL_audio_c.h" |
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
37 #include "../SDL_audiodev_c.h" |
0 | 38 #include "SDL_nasaudio.h" |
39 | |
40 /* The tag name used by artsc audio */ | |
41 #define NAS_DRIVER_NAME "nas" | |
42 | |
43 static struct SDL_PrivateAudioData *this2 = NULL; | |
44 | |
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); | |
51 | |
52 /* Audio driver bootstrap functions */ | |
53 | |
54 static int Audio_Available(void) | |
55 { | |
56 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); | |
57 if (!aud) return 0; | |
58 | |
59 AuCloseServer(aud); | |
60 return 1; | |
61 } | |
62 | |
63 static void Audio_DeleteDevice(SDL_AudioDevice *device) | |
64 { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
65 SDL_free(device->hidden); |
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
66 SDL_free(device); |
0 | 67 } |
68 | |
69 static SDL_AudioDevice *Audio_CreateDevice(int devindex) | |
70 { | |
71 SDL_AudioDevice *this; | |
72 | |
73 /* Initialize all variables that we clean on shutdown */ | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
74 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); |
0 | 75 if ( this ) { |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
76 SDL_memset(this, 0, (sizeof *this)); |
0 | 77 this->hidden = (struct SDL_PrivateAudioData *) |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
78 SDL_malloc((sizeof *this->hidden)); |
0 | 79 } |
80 if ( (this == NULL) || (this->hidden == NULL) ) { | |
81 SDL_OutOfMemory(); | |
82 if ( this ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
83 SDL_free(this); |
0 | 84 } |
85 return(0); | |
86 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
87 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); |
0 | 88 |
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; | |
95 | |
96 this->free = Audio_DeleteDevice; | |
97 | |
98 return this; | |
99 } | |
100 | |
101 AudioBootStrap NAS_bootstrap = { | |
102 NAS_DRIVER_NAME, "Network Audio System", | |
103 Audio_Available, Audio_CreateDevice | |
104 }; | |
105 | |
106 /* This function waits until it is possible to write a full sound buffer */ | |
107 static void NAS_WaitAudio(_THIS) | |
108 { | |
109 while ( this->hidden->buf_free < this->hidden->mixlen ) { | |
110 AuEvent ev; | |
111 AuNextEvent(this->hidden->aud, AuTrue, &ev); | |
112 AuDispatchEvent(this->hidden->aud, &ev); | |
113 } | |
114 } | |
115 | |
116 static void NAS_PlayAudio(_THIS) | |
117 { | |
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. */ | |
121 AuEvent ev; | |
122 AuNextEvent(this->hidden->aud, AuTrue, &ev); | |
123 AuDispatchEvent(this->hidden->aud, &ev); | |
124 } | |
125 this->hidden->buf_free -= this->hidden->mixlen; | |
126 | |
127 /* Write the audio data */ | |
128 AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL); | |
129 | |
130 this->hidden->written += this->hidden->mixlen; | |
131 | |
132 #ifdef DEBUG_AUDIO | |
133 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); | |
134 #endif | |
135 } | |
136 | |
137 static Uint8 *NAS_GetAudioBuf(_THIS) | |
138 { | |
139 return(this->hidden->mixbuf); | |
140 } | |
141 | |
142 static void NAS_CloseAudio(_THIS) | |
143 { | |
144 if ( this->hidden->mixbuf != NULL ) { | |
145 SDL_FreeAudioMem(this->hidden->mixbuf); | |
146 this->hidden->mixbuf = NULL; | |
147 } | |
148 if ( this->hidden->aud ) { | |
149 AuCloseServer(this->hidden->aud); | |
150 this->hidden->aud = 0; | |
151 } | |
152 } | |
153 | |
154 static unsigned char sdlformat_to_auformat(unsigned int fmt) | |
155 { | |
156 switch (fmt) | |
157 { | |
158 case AUDIO_U8: | |
159 return AuFormatLinearUnsigned8; | |
160 case AUDIO_S8: | |
161 return AuFormatLinearSigned8; | |
162 case AUDIO_U16LSB: | |
163 return AuFormatLinearUnsigned16LSB; | |
164 case AUDIO_U16MSB: | |
165 return AuFormatLinearUnsigned16MSB; | |
166 case AUDIO_S16LSB: | |
167 return AuFormatLinearSigned16LSB; | |
168 case AUDIO_S16MSB: | |
169 return AuFormatLinearSigned16MSB; | |
170 } | |
171 return AuNone; | |
172 } | |
173 | |
174 static AuBool | |
175 event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd) | |
176 { | |
177 switch (ev->type) { | |
178 case AuEventTypeElementNotify: { | |
179 AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev; | |
180 | |
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; | |
187 } else { | |
188 this2->buf_free = event->num_bytes; | |
189 } | |
190 break; | |
191 case AuElementNotifyKindState: | |
192 switch (event->cur_state) { | |
193 case AuStatePause: | |
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; | |
199 } else { | |
200 this2->buf_free = event->num_bytes; | |
201 } | |
202 } | |
203 break; | |
204 } | |
205 } | |
206 } | |
207 } | |
208 return AuTrue; | |
209 } | |
210 | |
211 static AuDeviceID | |
212 find_device(_THIS, int nch) | |
213 { | |
214 int i; | |
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)); | |
220 } | |
221 } | |
222 return AuNone; | |
223 } | |
224 | |
225 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec) | |
226 { | |
227 AuElement elms[3]; | |
228 int buffer_size; | |
229 Uint16 test_format, format; | |
230 | |
231 this->hidden->mixbuf = NULL; | |
232 | |
233 /* Try for a closest match on audio format */ | |
234 format = 0; | |
235 for ( test_format = SDL_FirstAudioFormat(spec->format); | |
236 ! format && test_format; ) { | |
237 format = sdlformat_to_auformat(test_format); | |
238 | |
239 if (format == AuNone) { | |
240 test_format = SDL_NextAudioFormat(); | |
241 } | |
242 } | |
243 if ( format == 0 ) { | |
244 SDL_SetError("Couldn't find any hardware audio formats"); | |
245 return(-1); | |
246 } | |
247 spec->format = test_format; | |
248 | |
249 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); | |
250 if (this->hidden->aud == 0) | |
251 { | |
252 SDL_SetError("Couldn't open connection to NAS server"); | |
253 return (-1); | |
254 } | |
255 | |
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"); | |
261 return (-1); | |
262 } | |
263 | |
264 buffer_size = spec->freq; | |
265 if (buffer_size < 4096) | |
266 buffer_size = 4096; | |
267 | |
268 if (buffer_size > 32768) | |
269 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */ | |
270 | |
271 /* Calculate the final parameters for this audio specification */ | |
272 SDL_CalculateAudioSpec(spec); | |
273 | |
274 this2 = this->hidden; | |
275 | |
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); | |
283 | |
284 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); | |
285 | |
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 ) { | |
290 return(-1); | |
291 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
292 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size); |
0 | 293 |
294 /* Get the parent process id (we're the parent of the audio thread) */ | |
295 this->hidden->parent = getpid(); | |
296 | |
297 /* We're ready to rock and roll. :-) */ | |
298 return(0); | |
299 } |