Mercurial > sdl-ios-xcode
comparison src/audio/nas/SDL_nasaudio.c @ 1895:c121d94672cb
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 10 Jul 2006 21:04:37 +0000 |
parents | d910939febfa |
children | 3b4ce57c6215 |
comparison
equal
deleted
inserted
replaced
1894:c69cee13dd76 | 1895:c121d94672cb |
---|---|
41 #define NAS_DRIVER_NAME "nas" | 41 #define NAS_DRIVER_NAME "nas" |
42 | 42 |
43 static struct SDL_PrivateAudioData *this2 = NULL; | 43 static struct SDL_PrivateAudioData *this2 = NULL; |
44 | 44 |
45 /* Audio driver functions */ | 45 /* Audio driver functions */ |
46 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec); | 46 static int NAS_OpenAudio(_THIS, SDL_AudioSpec * spec); |
47 static void NAS_WaitAudio(_THIS); | 47 static void NAS_WaitAudio(_THIS); |
48 static void NAS_PlayAudio(_THIS); | 48 static void NAS_PlayAudio(_THIS); |
49 static Uint8 *NAS_GetAudioBuf(_THIS); | 49 static Uint8 *NAS_GetAudioBuf(_THIS); |
50 static void NAS_CloseAudio(_THIS); | 50 static void NAS_CloseAudio(_THIS); |
51 | 51 |
52 /* Audio driver bootstrap functions */ | 52 /* Audio driver bootstrap functions */ |
53 | 53 |
54 static int Audio_Available(void) | 54 static int |
55 { | 55 Audio_Available(void) |
56 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); | 56 { |
57 if (!aud) return 0; | 57 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); |
58 | 58 if (!aud) |
59 AuCloseServer(aud); | 59 return 0; |
60 return 1; | 60 |
61 } | 61 AuCloseServer(aud); |
62 | 62 return 1; |
63 static void Audio_DeleteDevice(SDL_AudioDevice *device) | 63 } |
64 { | 64 |
65 SDL_free(device->hidden); | 65 static void |
66 SDL_free(device); | 66 Audio_DeleteDevice(SDL_AudioDevice * device) |
67 } | 67 { |
68 | 68 SDL_free(device->hidden); |
69 static SDL_AudioDevice *Audio_CreateDevice(int devindex) | 69 SDL_free(device); |
70 { | 70 } |
71 SDL_AudioDevice *this; | 71 |
72 | 72 static SDL_AudioDevice * |
73 /* Initialize all variables that we clean on shutdown */ | 73 Audio_CreateDevice(int devindex) |
74 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); | 74 { |
75 if ( this ) { | 75 SDL_AudioDevice *this; |
76 SDL_memset(this, 0, (sizeof *this)); | 76 |
77 this->hidden = (struct SDL_PrivateAudioData *) | 77 /* Initialize all variables that we clean on shutdown */ |
78 SDL_malloc((sizeof *this->hidden)); | 78 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); |
79 } | 79 if (this) { |
80 if ( (this == NULL) || (this->hidden == NULL) ) { | 80 SDL_memset(this, 0, (sizeof *this)); |
81 SDL_OutOfMemory(); | 81 this->hidden = (struct SDL_PrivateAudioData *) |
82 if ( this ) { | 82 SDL_malloc((sizeof *this->hidden)); |
83 SDL_free(this); | 83 } |
84 } | 84 if ((this == NULL) || (this->hidden == NULL)) { |
85 return(0); | 85 SDL_OutOfMemory(); |
86 } | 86 if (this) { |
87 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | 87 SDL_free(this); |
88 | 88 } |
89 /* Set the function pointers */ | 89 return (0); |
90 this->OpenAudio = NAS_OpenAudio; | 90 } |
91 this->WaitAudio = NAS_WaitAudio; | 91 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); |
92 this->PlayAudio = NAS_PlayAudio; | 92 |
93 this->GetAudioBuf = NAS_GetAudioBuf; | 93 /* Set the function pointers */ |
94 this->CloseAudio = NAS_CloseAudio; | 94 this->OpenAudio = NAS_OpenAudio; |
95 | 95 this->WaitAudio = NAS_WaitAudio; |
96 this->free = Audio_DeleteDevice; | 96 this->PlayAudio = NAS_PlayAudio; |
97 | 97 this->GetAudioBuf = NAS_GetAudioBuf; |
98 return this; | 98 this->CloseAudio = NAS_CloseAudio; |
99 | |
100 this->free = Audio_DeleteDevice; | |
101 | |
102 return this; | |
99 } | 103 } |
100 | 104 |
101 AudioBootStrap NAS_bootstrap = { | 105 AudioBootStrap NAS_bootstrap = { |
102 NAS_DRIVER_NAME, "Network Audio System", | 106 NAS_DRIVER_NAME, "Network Audio System", |
103 Audio_Available, Audio_CreateDevice | 107 Audio_Available, Audio_CreateDevice |
104 }; | 108 }; |
105 | 109 |
106 /* This function waits until it is possible to write a full sound buffer */ | 110 /* This function waits until it is possible to write a full sound buffer */ |
107 static void NAS_WaitAudio(_THIS) | 111 static void |
108 { | 112 NAS_WaitAudio(_THIS) |
109 while ( this->hidden->buf_free < this->hidden->mixlen ) { | 113 { |
110 AuEvent ev; | 114 while (this->hidden->buf_free < this->hidden->mixlen) { |
111 AuNextEvent(this->hidden->aud, AuTrue, &ev); | 115 AuEvent ev; |
112 AuDispatchEvent(this->hidden->aud, &ev); | 116 AuNextEvent(this->hidden->aud, AuTrue, &ev); |
113 } | 117 AuDispatchEvent(this->hidden->aud, &ev); |
114 } | 118 } |
115 | 119 } |
116 static void NAS_PlayAudio(_THIS) | 120 |
117 { | 121 static void |
118 while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events, | 122 NAS_PlayAudio(_THIS) |
119 in the hope that some of them is LowWater events telling us more | 123 { |
120 of the buffer is free now than what we think. */ | 124 while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events, |
121 AuEvent ev; | 125 in the hope that some of them is LowWater events telling us more |
122 AuNextEvent(this->hidden->aud, AuTrue, &ev); | 126 of the buffer is free now than what we think. */ |
123 AuDispatchEvent(this->hidden->aud, &ev); | 127 AuEvent ev; |
124 } | 128 AuNextEvent(this->hidden->aud, AuTrue, &ev); |
125 this->hidden->buf_free -= this->hidden->mixlen; | 129 AuDispatchEvent(this->hidden->aud, &ev); |
126 | 130 } |
127 /* Write the audio data */ | 131 this->hidden->buf_free -= this->hidden->mixlen; |
128 AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL); | 132 |
129 | 133 /* Write the audio data */ |
130 this->hidden->written += this->hidden->mixlen; | 134 AuWriteElement(this->hidden->aud, this->hidden->flow, 0, |
131 | 135 this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL); |
136 | |
137 this->hidden->written += this->hidden->mixlen; | |
138 | |
132 #ifdef DEBUG_AUDIO | 139 #ifdef DEBUG_AUDIO |
133 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); | 140 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); |
134 #endif | 141 #endif |
135 } | 142 } |
136 | 143 |
137 static Uint8 *NAS_GetAudioBuf(_THIS) | 144 static Uint8 * |
138 { | 145 NAS_GetAudioBuf(_THIS) |
139 return(this->hidden->mixbuf); | 146 { |
140 } | 147 return (this->hidden->mixbuf); |
141 | 148 } |
142 static void NAS_CloseAudio(_THIS) | 149 |
143 { | 150 static void |
144 if ( this->hidden->mixbuf != NULL ) { | 151 NAS_CloseAudio(_THIS) |
145 SDL_FreeAudioMem(this->hidden->mixbuf); | 152 { |
146 this->hidden->mixbuf = NULL; | 153 if (this->hidden->mixbuf != NULL) { |
147 } | 154 SDL_FreeAudioMem(this->hidden->mixbuf); |
148 if ( this->hidden->aud ) { | 155 this->hidden->mixbuf = NULL; |
149 AuCloseServer(this->hidden->aud); | 156 } |
150 this->hidden->aud = 0; | 157 if (this->hidden->aud) { |
151 } | 158 AuCloseServer(this->hidden->aud); |
152 } | 159 this->hidden->aud = 0; |
153 | 160 } |
154 static unsigned char sdlformat_to_auformat(unsigned int fmt) | 161 } |
155 { | 162 |
156 switch (fmt) | 163 static unsigned char |
157 { | 164 sdlformat_to_auformat(unsigned int fmt) |
165 { | |
166 switch (fmt) { | |
158 case AUDIO_U8: | 167 case AUDIO_U8: |
159 return AuFormatLinearUnsigned8; | 168 return AuFormatLinearUnsigned8; |
160 case AUDIO_S8: | 169 case AUDIO_S8: |
161 return AuFormatLinearSigned8; | 170 return AuFormatLinearSigned8; |
162 case AUDIO_U16LSB: | 171 case AUDIO_U16LSB: |
163 return AuFormatLinearUnsigned16LSB; | 172 return AuFormatLinearUnsigned16LSB; |
164 case AUDIO_U16MSB: | 173 case AUDIO_U16MSB: |
165 return AuFormatLinearUnsigned16MSB; | 174 return AuFormatLinearUnsigned16MSB; |
166 case AUDIO_S16LSB: | 175 case AUDIO_S16LSB: |
167 return AuFormatLinearSigned16LSB; | 176 return AuFormatLinearSigned16LSB; |
168 case AUDIO_S16MSB: | 177 case AUDIO_S16MSB: |
169 return AuFormatLinearSigned16MSB; | 178 return AuFormatLinearSigned16MSB; |
170 } | 179 } |
171 return AuNone; | 180 return AuNone; |
172 } | 181 } |
173 | 182 |
174 static AuBool | 183 static AuBool |
175 event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd) | 184 event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) |
176 { | 185 { |
177 switch (ev->type) { | 186 switch (ev->type) { |
178 case AuEventTypeElementNotify: { | 187 case AuEventTypeElementNotify: |
179 AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev; | 188 { |
180 | 189 AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev; |
181 switch (event->kind) { | 190 |
182 case AuElementNotifyKindLowWater: | 191 switch (event->kind) { |
183 if (this2->buf_free >= 0) { | 192 case AuElementNotifyKindLowWater: |
184 this2->really += event->num_bytes; | 193 if (this2->buf_free >= 0) { |
185 gettimeofday(&this2->last_tv, 0); | 194 this2->really += event->num_bytes; |
186 this2->buf_free += event->num_bytes; | 195 gettimeofday(&this2->last_tv, 0); |
187 } else { | 196 this2->buf_free += event->num_bytes; |
188 this2->buf_free = event->num_bytes; | 197 } else { |
189 } | 198 this2->buf_free = event->num_bytes; |
190 break; | 199 } |
191 case AuElementNotifyKindState: | 200 break; |
192 switch (event->cur_state) { | 201 case AuElementNotifyKindState: |
193 case AuStatePause: | 202 switch (event->cur_state) { |
194 if (event->reason != AuReasonUser) { | 203 case AuStatePause: |
195 if (this2->buf_free >= 0) { | 204 if (event->reason != AuReasonUser) { |
196 this2->really += event->num_bytes; | 205 if (this2->buf_free >= 0) { |
197 gettimeofday(&this2->last_tv, 0); | 206 this2->really += event->num_bytes; |
198 this2->buf_free += event->num_bytes; | 207 gettimeofday(&this2->last_tv, 0); |
199 } else { | 208 this2->buf_free += event->num_bytes; |
200 this2->buf_free = event->num_bytes; | 209 } else { |
201 } | 210 this2->buf_free = event->num_bytes; |
202 } | 211 } |
203 break; | 212 } |
204 } | 213 break; |
205 } | 214 } |
206 } | 215 } |
207 } | 216 } |
208 return AuTrue; | 217 } |
218 return AuTrue; | |
209 } | 219 } |
210 | 220 |
211 static AuDeviceID | 221 static AuDeviceID |
212 find_device(_THIS, int nch) | 222 find_device(_THIS, int nch) |
213 { | 223 { |
214 int i; | 224 int i; |
215 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) { | 225 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) { |
216 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) == | 226 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) == |
217 AuComponentKindPhysicalOutput) && | 227 AuComponentKindPhysicalOutput) && |
218 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) { | 228 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) { |
219 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i)); | 229 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i)); |
220 } | 230 } |
221 } | 231 } |
222 return AuNone; | 232 return AuNone; |
223 } | 233 } |
224 | 234 |
225 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec) | 235 static int |
226 { | 236 NAS_OpenAudio(_THIS, SDL_AudioSpec * spec) |
227 AuElement elms[3]; | 237 { |
228 int buffer_size; | 238 AuElement elms[3]; |
229 Uint16 test_format, format; | 239 int buffer_size; |
230 | 240 Uint16 test_format, format; |
231 this->hidden->mixbuf = NULL; | 241 |
232 | 242 this->hidden->mixbuf = NULL; |
233 /* Try for a closest match on audio format */ | 243 |
234 format = 0; | 244 /* Try for a closest match on audio format */ |
235 for ( test_format = SDL_FirstAudioFormat(spec->format); | 245 format = 0; |
236 ! format && test_format; ) { | 246 for (test_format = SDL_FirstAudioFormat(spec->format); |
237 format = sdlformat_to_auformat(test_format); | 247 !format && test_format;) { |
238 | 248 format = sdlformat_to_auformat(test_format); |
239 if (format == AuNone) { | 249 |
240 test_format = SDL_NextAudioFormat(); | 250 if (format == AuNone) { |
241 } | 251 test_format = SDL_NextAudioFormat(); |
242 } | 252 } |
243 if ( format == 0 ) { | 253 } |
244 SDL_SetError("Couldn't find any hardware audio formats"); | 254 if (format == 0) { |
245 return(-1); | 255 SDL_SetError("Couldn't find any hardware audio formats"); |
246 } | 256 return (-1); |
247 spec->format = test_format; | 257 } |
248 | 258 spec->format = test_format; |
249 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); | 259 |
250 if (this->hidden->aud == 0) | 260 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); |
251 { | 261 if (this->hidden->aud == 0) { |
252 SDL_SetError("Couldn't open connection to NAS server"); | 262 SDL_SetError("Couldn't open connection to NAS server"); |
253 return (-1); | 263 return (-1); |
254 } | 264 } |
255 | 265 |
256 this->hidden->dev = find_device(this, spec->channels); | 266 this->hidden->dev = find_device(this, spec->channels); |
257 if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) { | 267 if ((this->hidden->dev == AuNone) |
258 AuCloseServer(this->hidden->aud); | 268 || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) { |
259 this->hidden->aud = 0; | 269 AuCloseServer(this->hidden->aud); |
260 SDL_SetError("Couldn't find a fitting playback device on NAS server"); | 270 this->hidden->aud = 0; |
261 return (-1); | 271 SDL_SetError("Couldn't find a fitting playback device on NAS server"); |
262 } | 272 return (-1); |
263 | 273 } |
264 buffer_size = spec->freq; | 274 |
265 if (buffer_size < 4096) | 275 buffer_size = spec->freq; |
266 buffer_size = 4096; | 276 if (buffer_size < 4096) |
267 | 277 buffer_size = 4096; |
268 if (buffer_size > 32768) | 278 |
269 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */ | 279 if (buffer_size > 32768) |
270 | 280 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */ |
271 /* Calculate the final parameters for this audio specification */ | 281 |
272 SDL_CalculateAudioSpec(spec); | 282 /* Calculate the final parameters for this audio specification */ |
273 | 283 SDL_CalculateAudioSpec(spec); |
274 this2 = this->hidden; | 284 |
275 | 285 this2 = this->hidden; |
276 AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue, | 286 |
277 buffer_size, buffer_size / 4, 0, NULL); | 287 AuMakeElementImportClient(elms, spec->freq, format, spec->channels, |
278 AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq, | 288 AuTrue, buffer_size, buffer_size / 4, 0, NULL); |
279 AuUnlimitedSamples, 0, NULL); | 289 AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, spec->freq, |
280 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL); | 290 AuUnlimitedSamples, 0, NULL); |
281 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow, | 291 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, |
282 event_handler, (AuPointer) NULL); | 292 NULL); |
283 | 293 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, |
284 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); | 294 this->hidden->flow, event_handler, |
285 | 295 (AuPointer) NULL); |
286 /* Allocate mixing buffer */ | 296 |
287 this->hidden->mixlen = spec->size; | 297 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); |
288 this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen); | 298 |
289 if ( this->hidden->mixbuf == NULL ) { | 299 /* Allocate mixing buffer */ |
290 return(-1); | 300 this->hidden->mixlen = spec->size; |
291 } | 301 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); |
292 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size); | 302 if (this->hidden->mixbuf == NULL) { |
293 | 303 return (-1); |
294 /* Get the parent process id (we're the parent of the audio thread) */ | 304 } |
295 this->hidden->parent = getpid(); | 305 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size); |
296 | 306 |
297 /* We're ready to rock and roll. :-) */ | 307 /* Get the parent process id (we're the parent of the audio thread) */ |
298 return(0); | 308 this->hidden->parent = getpid(); |
299 } | 309 |
310 /* We're ready to rock and roll. :-) */ | |
311 return (0); | |
312 } | |
313 | |
314 /* vi: set ts=4 sw=4 expandtab: */ |