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: */