comparison src/audio/windib/SDL_dibaudio.c @ 2049:5f6550e5184f

Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 17 Oct 2006 09:15:21 +0000
parents a5d0758f88d8
children bbc89e09503f
comparison
equal deleted inserted replaced
2048:6067c7f9a672 2049:5f6550e5184f
33 #include "SDL_dibaudio.h" 33 #include "SDL_dibaudio.h"
34 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 34 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
35 #include "win_ce_semaphore.h" 35 #include "win_ce_semaphore.h"
36 #endif 36 #endif
37 37
38 38 #if defined(_WIN32_WCE)
39 /* Audio driver functions */ 39 #define WINDOWS_OS_NAME "Windows CE/PocketPC"
40 static int DIB_OpenAudio(_THIS, SDL_AudioSpec * spec); 40 #elif defined(WIN64)
41 static void DIB_ThreadInit(_THIS); 41 #define WINDOWS_OS_NAME "Win64"
42 static void DIB_WaitAudio(_THIS); 42 #else
43 static Uint8 *DIB_GetAudioBuf(_THIS); 43 #define WINDOWS_OS_NAME "Win32"
44 static void DIB_PlayAudio(_THIS); 44 #endif
45 static void DIB_WaitDone(_THIS);
46 static void DIB_CloseAudio(_THIS);
47
48 /* Audio driver bootstrap functions */
49
50 static int
51 Audio_Available(void)
52 {
53 return (1);
54 }
55
56 static void
57 Audio_DeleteDevice(SDL_AudioDevice * device)
58 {
59 SDL_free(device->hidden);
60 SDL_free(device);
61 }
62
63 static SDL_AudioDevice *
64 Audio_CreateDevice(int devindex)
65 {
66 SDL_AudioDevice *this;
67
68 /* Initialize all variables that we clean on shutdown */
69 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
70 if (this) {
71 SDL_memset(this, 0, (sizeof *this));
72 this->hidden = (struct SDL_PrivateAudioData *)
73 SDL_malloc((sizeof *this->hidden));
74 }
75 if ((this == NULL) || (this->hidden == NULL)) {
76 SDL_OutOfMemory();
77 if (this) {
78 SDL_free(this);
79 }
80 return (0);
81 }
82 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
83
84 /* Set the function pointers */
85 this->OpenAudio = DIB_OpenAudio;
86 this->ThreadInit = DIB_ThreadInit;
87 this->WaitAudio = DIB_WaitAudio;
88 this->PlayAudio = DIB_PlayAudio;
89 this->GetAudioBuf = DIB_GetAudioBuf;
90 this->WaitDone = DIB_WaitDone;
91 this->CloseAudio = DIB_CloseAudio;
92
93 this->free = Audio_DeleteDevice;
94
95 return this;
96 }
97
98 AudioBootStrap WAVEOUT_bootstrap = {
99 "waveout", "Win95/98/NT/2000 WaveOut",
100 Audio_Available, Audio_CreateDevice
101 };
102
103 45
104 /* The Win32 callback for filling the WAVE device */ 46 /* The Win32 callback for filling the WAVE device */
105 static void CALLBACK 47 static void CALLBACK
106 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, 48 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
107 DWORD dwParam1, DWORD dwParam2) 49 DWORD dwParam1, DWORD dwParam2)
112 if (uMsg != WOM_DONE) 54 if (uMsg != WOM_DONE)
113 return; 55 return;
114 56
115 /* Signal that we are done playing a buffer */ 57 /* Signal that we are done playing a buffer */
116 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 58 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
117 ReleaseSemaphoreCE(audio_sem, 1, NULL); 59 ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
118 #else 60 #else
119 ReleaseSemaphore(audio_sem, 1, NULL); 61 ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
120 #endif 62 #endif
121 } 63 }
122 64
123 static void 65 static void
124 SetMMerror(char *function, MMRESULT code) 66 SetMMerror(char *function, MMRESULT code)
144 SDL_SetError("%s", errbuf); 86 SDL_SetError("%s", errbuf);
145 } 87 }
146 88
147 /* Set high priority for the audio thread */ 89 /* Set high priority for the audio thread */
148 static void 90 static void
149 DIB_ThreadInit(_THIS) 91 WINWAVEOUT_ThreadInit(_THIS)
150 { 92 {
151 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 93 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
152 } 94 }
153 95
154 void 96 void
155 DIB_WaitAudio(_THIS) 97 WINWAVEOUT_WaitDevice(_THIS)
156 { 98 {
157 /* Wait for an audio chunk to finish */ 99 /* Wait for an audio chunk to finish */
158 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 100 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
159 WaitForSemaphoreCE(audio_sem, INFINITE); 101 WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
160 #else 102 #else
161 WaitForSingleObject(audio_sem, INFINITE); 103 WaitForSingleObject(this->hidden->audio_sem, INFINITE);
162 #endif 104 #endif
163 } 105 }
164 106
165 Uint8 * 107 Uint8 *
166 DIB_GetAudioBuf(_THIS) 108 WINWAVEOUT_GetDeviceBuf(_THIS)
167 { 109 {
168 Uint8 *retval; 110 return (Uint8 *) (this->hidden->wavebuf[this->hidden->next_buffer].lpData);
169
170 retval = (Uint8 *) (wavebuf[next_buffer].lpData);
171 return retval;
172 } 111 }
173 112
174 void 113 void
175 DIB_PlayAudio(_THIS) 114 WINWAVEOUT_PlayDevice(_THIS)
176 { 115 {
177 /* Queue it up */ 116 /* Queue it up */
178 waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0])); 117 waveOutWrite(this->hidden->sound,
179 next_buffer = (next_buffer + 1) % NUM_BUFFERS; 118 &this->hidden->wavebuf[this->hidden->next_buffer],
119 sizeof (this->hidden->wavebuf[0]));
120 this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
180 } 121 }
181 122
182 void 123 void
183 DIB_WaitDone(_THIS) 124 WINWAVEOUT_WaitDone(_THIS)
184 { 125 {
185 int i, left; 126 int i, left;
186 127
187 do { 128 do {
188 left = NUM_BUFFERS; 129 left = NUM_BUFFERS;
189 for (i = 0; i < NUM_BUFFERS; ++i) { 130 for (i = 0; i < NUM_BUFFERS; ++i) {
190 if (wavebuf[i].dwFlags & WHDR_DONE) { 131 if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
191 --left; 132 --left;
192 } 133 }
193 } 134 }
194 if (left > 0) { 135 if (left > 0) {
195 SDL_Delay(100); 136 SDL_Delay(100);
197 } 138 }
198 while (left > 0); 139 while (left > 0);
199 } 140 }
200 141
201 void 142 void
202 DIB_CloseAudio(_THIS) 143 WINWAVEOUT_CloseDevice(_THIS)
203 { 144 {
145 /* Close up audio */
146 if (this->hidden != NULL) {
147 int i;
148
149 if (this->hidden->audio_sem) {
150 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
151 CloseSynchHandle(this->hidden->audio_sem);
152 #else
153 CloseHandle(this->hidden->audio_sem);
154 #endif
155 this->hidden->audio_sem = 0;
156 }
157
158 if (this->hidden->sound) {
159 waveOutClose(this->hidden->sound);
160 this->hidden->sound = 0;
161 }
162
163 /* Clean up mixing buffers */
164 for (i = 0; i < NUM_BUFFERS; ++i) {
165 if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
166 waveOutUnprepareHeader(this->hidden->sound,
167 &this->hidden->wavebuf[i],
168 sizeof (this->hidden->wavebuf[i]));
169 this->hidden->wavebuf[i].dwUser = 0xFFFF;
170 }
171 }
172
173 if (this->hidden->mixbuf != NULL) {
174 /* Free raw mixing buffer */
175 SDL_free(this->hidden->mixbuf);
176 this->hidden->mixbuf = NULL;
177 }
178
179 SDL_free(this->hidden);
180 this->hidden = NULL;
181 }
182 }
183
184 int
185 WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture)
186 {
187 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
188 int valid_datatype = 0;
189 MMRESULT result;
190 WAVEFORMATEX waveformat;
204 int i; 191 int i;
205 192
206 /* Close up audio */ 193 /* Initialize all variables that we clean on shutdown */
207 if (audio_sem) { 194 this->hidden = (struct SDL_PrivateAudioData *)
208 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 195 SDL_malloc((sizeof *this->hidden));
209 CloseSynchHandle(audio_sem); 196 if (this->hidden == NULL) {
210 #else 197 SDL_OutOfMemory();
211 CloseHandle(audio_sem); 198 return 0;
212 #endif 199 }
213 } 200 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
214 if (sound) {
215 waveOutClose(sound);
216 }
217
218 /* Clean up mixing buffers */
219 for (i = 0; i < NUM_BUFFERS; ++i) {
220 if (wavebuf[i].dwUser != 0xFFFF) {
221 waveOutUnprepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
222 wavebuf[i].dwUser = 0xFFFF;
223 }
224 }
225 /* Free raw mixing buffer */
226 if (mixbuf != NULL) {
227 SDL_free(mixbuf);
228 mixbuf = NULL;
229 }
230 }
231
232 int
233 DIB_OpenAudio(_THIS, SDL_AudioSpec * spec)
234 {
235 MMRESULT result;
236 int i;
237 WAVEFORMATEX waveformat;
238 201
239 /* Initialize the wavebuf structures for closing */ 202 /* Initialize the wavebuf structures for closing */
240 sound = NULL;
241 audio_sem = NULL;
242 for (i = 0; i < NUM_BUFFERS; ++i) 203 for (i = 0; i < NUM_BUFFERS; ++i)
243 wavebuf[i].dwUser = 0xFFFF; 204 this->hidden->wavebuf[i].dwUser = 0xFFFF;
244 mixbuf = NULL; 205
206 while ((!valid_datatype) && (test_format)) {
207 valid_datatype = 1;
208 _this->spec.format = test_format;
209 switch (test_format) {
210 case AUDIO_U8:
211 case AUDIO_S16:
212 case AUDIO_S32:
213 break; /* valid. */
214
215 default:
216 valid_datatype = 0;
217 test_format = SDL_NextAudioFormat();
218 break;
219 }
220 }
221
222 if (!valid_datatype) {
223 WINWAVEOUT_CloseDevice(this);
224 SDL_SetError("Unsupported audio format");
225 return 0;
226 }
245 227
246 /* Set basic WAVE format parameters */ 228 /* Set basic WAVE format parameters */
247 SDL_memset(&waveformat, 0, sizeof(waveformat)); 229 SDL_memset(&waveformat, '\0', sizeof (waveformat));
248 waveformat.wFormatTag = WAVE_FORMAT_PCM; 230 waveformat.wFormatTag = WAVE_FORMAT_PCM;
249 231 waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
250 /* Determine the audio parameters from the AudioSpec */ 232
251 switch (SDL_AUDIO_BITSIZE(spec->format)) { 233 if (this->spec.channels > 2)
252 case 8: 234 this->spec.channels = 2; /* !!! FIXME: is this right? */
253 /* Unsigned 8 bit audio data */ 235
254 spec->format = AUDIO_U8; 236 waveformat.nChannels = this->spec.channels;
255 waveformat.wBitsPerSample = 8; 237 waveformat.nSamplesPerSec = this->spec.freq;
256 break;
257 case 16:
258 /* Signed 16 bit audio data */
259 spec->format = AUDIO_S16;
260 waveformat.wBitsPerSample = 16;
261 break;
262 case 32:
263 /* Signed 32 bit audio data */
264 spec->format = AUDIO_S32;
265 waveformat.wBitsPerSample = 32;
266 break;
267 default:
268 SDL_SetError("Unsupported audio format");
269 return (-1);
270 }
271 waveformat.nChannels = spec->channels;
272 waveformat.nSamplesPerSec = spec->freq;
273 waveformat.nBlockAlign = 238 waveformat.nBlockAlign =
274 waveformat.nChannels * (waveformat.wBitsPerSample / 8); 239 waveformat.nChannels * (waveformat.wBitsPerSample / 8);
275 waveformat.nAvgBytesPerSec = 240 waveformat.nAvgBytesPerSec =
276 waveformat.nSamplesPerSec * waveformat.nBlockAlign; 241 waveformat.nSamplesPerSec * waveformat.nBlockAlign;
277 242
278 /* Check the buffer size -- minimum of 1/4 second (word aligned) */ 243 /* Check the buffer size -- minimum of 1/4 second (word aligned) */
279 if (spec->samples < (spec->freq / 4)) 244 if (this->spec.samples < (this->spec.freq / 4))
280 spec->samples = ((spec->freq / 4) + 3) & ~3; 245 this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
281 246
282 /* Update the fragment size as size in bytes */ 247 /* Update the fragment size as size in bytes */
283 SDL_CalculateAudioSpec(spec); 248 SDL_CalculateAudioSpec(&this->spec);
284 249
285 /* Open the audio device */ 250 /* Open the audio device */
286 result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat, 251 result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat,
287 (DWORD_PTR) FillSound, (DWORD_PTR) this, 252 (DWORD_PTR) FillSound, (DWORD_PTR) this,
288 CALLBACK_FUNCTION); 253 CALLBACK_FUNCTION);
289 if (result != MMSYSERR_NOERROR) { 254 if (result != MMSYSERR_NOERROR) {
255 WINWAVEOUT_CloseDevice(this);
290 SetMMerror("waveOutOpen()", result); 256 SetMMerror("waveOutOpen()", result);
291 return (-1); 257 return 0;
292 } 258 }
293 #ifdef SOUND_DEBUG 259 #ifdef SOUND_DEBUG
294 /* Check the sound device we retrieved */ 260 /* Check the sound device we retrieved */
295 { 261 {
296 WAVEOUTCAPS caps; 262 WAVEOUTCAPS caps;
297 263
298 result = waveOutGetDevCaps((UINT) sound, &caps, sizeof(caps)); 264 result = waveOutGetDevCaps((UINT) this->hidden->sound,
265 &caps, sizeof(caps));
299 if (result != MMSYSERR_NOERROR) { 266 if (result != MMSYSERR_NOERROR) {
267 WINWAVEOUT_CloseDevice(this);
300 SetMMerror("waveOutGetDevCaps()", result); 268 SetMMerror("waveOutGetDevCaps()", result);
301 return (-1); 269 return 0;
302 } 270 }
303 printf("Audio device: %s\n", caps.szPname); 271 printf("Audio device: %s\n", caps.szPname);
304 } 272 }
305 #endif 273 #endif
306 274
307 /* Create the audio buffer semaphore */ 275 /* Create the audio buffer semaphore */
308 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 276 this->hidden->audio_sem =
309 audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); 277 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
310 #else 278 CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
311 audio_sem = CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); 279 #else
312 #endif 280 CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
313 if (audio_sem == NULL) { 281 #endif
282 if (this->hidden->audio_sem == NULL) {
283 WINWAVEOUT_CloseDevice(this);
314 SDL_SetError("Couldn't create semaphore"); 284 SDL_SetError("Couldn't create semaphore");
315 return (-1); 285 return 0;
316 } 286 }
317 287
318 /* Create the sound buffers */ 288 /* Create the sound buffers */
319 mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * spec->size); 289 this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
320 if (mixbuf == NULL) { 290 if (mixbuf == NULL) {
321 SDL_SetError("Out of memory"); 291 WINWAVEOUT_CloseDevice(this);
322 return (-1); 292 SDL_OutOfMemory();
293 return 0;
323 } 294 }
324 for (i = 0; i < NUM_BUFFERS; ++i) { 295 for (i = 0; i < NUM_BUFFERS; ++i) {
325 SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i])); 296 SDL_memset(&this->hidden->wavebuf[i], '\0',
326 wavebuf[i].lpData = (LPSTR) & mixbuf[i * spec->size]; 297 sizeof (this->hidden->wavebuf[i]));
327 wavebuf[i].dwBufferLength = spec->size; 298 this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
328 wavebuf[i].dwFlags = WHDR_DONE; 299 this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
329 result = waveOutPrepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i])); 300 this->hidden->wavebuf[i].lpData =
301 (LPSTR) &this->hidden->mixbuf[i * this->spec.size];
302 result = waveOutPrepareHeader(this->hidden->sound,
303 &this->hidden->wavebuf[i],
304 sizeof (this->hidden->wavebuf[i]));
330 if (result != MMSYSERR_NOERROR) { 305 if (result != MMSYSERR_NOERROR) {
306 WINWAVEOUT_CloseDevice(this);
331 SetMMerror("waveOutPrepareHeader()", result); 307 SetMMerror("waveOutPrepareHeader()", result);
332 return (-1); 308 return 0;
333 } 309 }
334 } 310 }
335 311
336 /* Ready to go! */ 312 return 1; /* Ready to go! */
337 next_buffer = 0; 313 }
338 return (0); 314
339 } 315
316 static int
317 WINWAVEOUT_Init(SDL_AudioDriverImpl *impl)
318 {
319 /* Set the function pointers */
320 impl->OpenDevice = WINWAVEOUT_OpenDevice;
321 impl->ThreadInit = WINWAVEOUT_ThreadInit;
322 impl->PlayDevice = WINWAVEOUT_PlayDevice;
323 impl->WaitDevice = WINWAVEOUT_WaitDevice;
324 impl->WaitDone = WINWAVEOUT_WaitDone;
325 impl->GetDeviceBuf = WINWAVEOUT_GetDeviceBuf;
326 impl->CloseDevice = WINWAVEOUT_CloseDevice;
327 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Is this true? */
328
329 return 1;
330 }
331
332 AudioBootStrap WINWAVEOUT_bootstrap = {
333 "waveout", WINDOWS_OS_NAME " WaveOut", WINWAVEOUT_Init, 0
334 };
340 335
341 /* vi: set ts=4 sw=4 expandtab: */ 336 /* vi: set ts=4 sw=4 expandtab: */