source: trunk/src/winmm/playsound.cpp@ 8470

Last change on this file since 8470 was 8470, checked in by sandervl, 23 years ago

added debug wrappers (.def)

File size: 13.6 KB
Line 
1/* $Id: playsound.cpp,v 1.8 2002-05-22 15:50:25 sandervl Exp $ */
2
3/*
4 * Playsound implementation
5 *
6 * Wine port (winmm\mmsystem.c)
7 *
8 * Copyright 1993 Martin Ayotte
9 * Eric POUECH
10 *
11 * Project Odin Software License can be found in LICENSE.TXT
12 *
13 */
14
15
16/****************************************************************************
17 * Includes *
18 ****************************************************************************/
19
20#include <os2win.h>
21#include <odinwrap.h>
22#include <mmsystem.h>
23#include <heapstring.h>
24#include <misc.h>
25#include <string.h>
26#include <win\debugtools.h>
27
28#define DBG_LOCALLOG DBG_playsound
29#include "dbglocal.h"
30
31
32static HANDLE PlaySound_hThread = 0;
33static HANDLE PlaySound_hPlayEvent = 0;
34static HANDLE PlaySound_hReadyEvent = 0;
35static HANDLE PlaySound_hMiddleEvent = 0;
36static BOOL PlaySound_Result = FALSE;
37static int PlaySound_Stop = FALSE;
38static int PlaySound_Playing = FALSE;
39
40static LPCSTR PlaySound_pszSound = NULL;
41static HMODULE PlaySound_hmod = 0;
42static DWORD PlaySound_fdwSound = 0;
43static int PlaySound_Loop = FALSE;
44static int PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
45 2 - PlaySound order */
46
47static HMMIO get_mmioFromFile(LPCSTR lpszName)
48{
49 return mmioOpenA((LPSTR)lpszName, NULL,
50 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
51}
52
53static HMMIO get_mmioFromProfile(UINT uFlags, LPCSTR lpszName)
54{
55 char str[128];
56 LPSTR ptr;
57 HMMIO hmmio;
58
59 TRACE("searching in SystemSound List !\n");
60 GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
61 if (strlen(str) == 0) {
62 if (uFlags & SND_NODEFAULT) return 0;
63 GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
64 if (strlen(str) == 0) return 0;
65 }
66 if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
67 hmmio = get_mmioFromFile(str);
68 if (hmmio == 0) {
69 WARN("can't find SystemSound='%s' !\n", str);
70 return 0;
71 }
72 return hmmio;
73}
74
75struct playsound_data {
76 HANDLE hEvent;
77 DWORD dwEventCount;
78};
79
80static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg,
81 DWORD dwInstance,
82 DWORD dwParam1, DWORD dwParam2)
83{
84 struct playsound_data* s = (struct playsound_data*)dwInstance;
85
86 switch (uMsg) {
87 case WOM_OPEN:
88 case WOM_CLOSE:
89 break;
90 case WOM_DONE:
91 InterlockedIncrement((LPLONG)&s->dwEventCount);
92 TRACE("Returning waveHdr=%lx\n", dwParam1);
93 SetEvent(s->hEvent);
94 break;
95 default:
96 ERR("Unknown uMsg=%d\n", uMsg);
97 }
98}
99
100static void PlaySound_WaitDone(struct playsound_data* s)
101{
102 for (;;) {
103 ResetEvent(s->hEvent);
104 if (InterlockedDecrement((LPLONG)&s->dwEventCount) >= 0) {
105 break;
106 }
107 InterlockedIncrement((LPLONG)&s->dwEventCount);
108
109 WaitForSingleObject(s->hEvent, INFINITE);
110 }
111}
112
113static BOOL WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
114{
115 BOOL bRet = FALSE;
116 HMMIO hmmio = 0;
117 MMCKINFO ckMainRIFF;
118 MMCKINFO mmckInfo;
119 LPWAVEFORMATEX lpWaveFormat = NULL;
120 HWAVE hWave = 0;
121 LPWAVEHDR waveHdr = NULL;
122 INT count, bufsize, left, index;
123 struct playsound_data s;
124
125 s.hEvent = 0;
126
127 TRACE("SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
128 if (lpszSoundName == NULL) {
129 TRACE("Stop !\n");
130 return FALSE;
131 }
132 if (uFlags & SND_MEMORY) {
133 MMIOINFO mminfo;
134 memset(&mminfo, 0, sizeof(mminfo));
135 mminfo.fccIOProc = FOURCC_MEM;
136 mminfo.pchBuffer = (LPSTR)lpszSoundName;
137 mminfo.cchBuffer = -1;
138 TRACE("Memory sound %p\n", lpszSoundName);
139 hmmio = mmioOpenA(NULL, &mminfo, MMIO_READ);
140 } else {
141 hmmio = 0;
142 if (uFlags & SND_ALIAS)
143 if ((hmmio = get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
144 return FALSE;
145
146 if (uFlags & SND_FILENAME)
147 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
148
149 if (PlaySound_SearchMode == 1) {
150 PlaySound_SearchMode = 0;
151 if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
152 hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
153 }
154
155 if (PlaySound_SearchMode == 2) {
156 PlaySound_SearchMode = 0;
157 if ((hmmio = get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0)
158 if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
159 hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
160 }
161 }
162 if (hmmio == 0) return FALSE;
163
164 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0))
165 goto errCleanUp;
166
167 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
168 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
169
170 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
171 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
172 goto errCleanUp;
173
174 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
175 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
176 goto errCleanUp;
177
178 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
179 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
180
181 lpWaveFormat = (WAVEFORMATEX*)HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
182 if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT))
183 goto errCleanUp;
184
185 TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag);
186 TRACE("nChannels=%d \n", lpWaveFormat->nChannels);
187 TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec);
188 TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec);
189 TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign);
190 TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample);
191
192 /* move to end of 'fmt ' chunk */
193 mmioAscend(hmmio, &mmckInfo, 0);
194
195 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
196 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
197 goto errCleanUp;
198
199 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
200 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
201
202 s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
203
204 if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback,
205 (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
206 goto errCleanUp;
207
208 /* make it so that 3 buffers per second are needed */
209 bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) *
210 lpWaveFormat->nBlockAlign;
211 waveHdr = (LPWAVEHDR)HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
212 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
213 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
214 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
215 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
216 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
217 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
218 if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
219 waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) {
220 goto errCleanUp;
221 }
222
223 do {
224 index = 0;
225 left = mmckInfo.cksize;
226 s.dwEventCount = 1L; /* for first buffer */
227
228 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
229 while (left) {
230 if (PlaySound_Stop) {
231 PlaySound_Stop = PlaySound_Loop = FALSE;
232 break;
233 }
234 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
235 if (count < 1) break;
236 left -= count;
237 waveHdr[index].dwBufferLength = count;
238 waveHdr[index].dwFlags &= ~WHDR_DONE;
239 waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR));
240 index ^= 1;
241 PlaySound_WaitDone(&s);
242 }
243 bRet = TRUE;
244 } while (PlaySound_Loop);
245
246 PlaySound_WaitDone(&s);
247 waveOutReset(hWave);
248
249 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
250 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
251
252errCleanUp:
253 CloseHandle(s.hEvent);
254 HeapFree(GetProcessHeap(), 0, waveHdr);
255 HeapFree(GetProcessHeap(), 0, lpWaveFormat);
256 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
257 if (hmmio) mmioClose(hmmio, 0);
258
259 return bRet;
260}
261
262static DWORD WINAPI PlaySound_Thread(LPVOID arg)
263{
264 DWORD res;
265
266 for (;;) {
267 PlaySound_Playing = FALSE;
268 SetEvent(PlaySound_hReadyEvent);
269 res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
270 ResetEvent(PlaySound_hReadyEvent);
271 SetEvent(PlaySound_hMiddleEvent);
272 if (res == WAIT_FAILED) ExitThread(2);
273 if (res != WAIT_OBJECT_0) continue;
274 PlaySound_Playing = TRUE;
275
276 if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
277 HRSRC hRES;
278 HGLOBAL hGLOB;
279 void* ptr;
280
281 if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
282 PlaySound_Result = FALSE;
283 continue;
284 }
285 if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
286 PlaySound_Result = FALSE;
287 continue;
288 }
289 if ((ptr = LockResource(hGLOB)) == NULL) {
290 FreeResource(hGLOB);
291 PlaySound_Result = FALSE;
292 continue;
293 }
294 PlaySound_Result = proc_PlaySound((LPCSTR)ptr,
295 ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
296 FreeResource(hGLOB);
297 continue;
298 }
299 PlaySound_Result = proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
300 }
301}
302
303
304/*****************************************************************************
305 * Plays a sound specified by the given filename, resource, or
306 * system event.
307 * Parameters: LPCSTR pszSound
308 * HMODULE hMod
309 * DWORD fdwSound
310 * Variables :
311 * Result :
312 * Remark :
313 * Status :
314 *
315 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
316 *****************************************************************************/
317
318BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
319{
320 static LPSTR StrDup = NULL;
321
322 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
323 pszSound, hmod, fdwSound);
324
325 if (PlaySound_hThread == 0) { /* This is the first time they called us */
326 DWORD id;
327 if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
328 return FALSE;
329 if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
330 return FALSE;
331 if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
332 return FALSE;
333 if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0)
334 return FALSE;
335 }
336
337 /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */
338 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing)
339 return FALSE;
340
341 /* Trying to stop if playing */
342 if (PlaySound_Playing) PlaySound_Stop = TRUE;
343
344 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
345 if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
346 return FALSE;
347
348 if (!pszSound || (fdwSound & SND_PURGE))
349 return FALSE; /* We stoped playing so leaving */
350
351 if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
352 if (!(fdwSound & SND_ASYNC)) {
353 if (fdwSound & SND_LOOP)
354 return FALSE;
355 PlaySound_pszSound = pszSound;
356 PlaySound_hmod = hmod;
357 PlaySound_fdwSound = fdwSound;
358 PlaySound_Result = FALSE;
359 SetEvent(PlaySound_hPlayEvent);
360 if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0)
361 return FALSE;
362 if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0)
363 return FALSE;
364 return PlaySound_Result;
365 } else {
366 PlaySound_hmod = hmod;
367 PlaySound_fdwSound = fdwSound;
368 PlaySound_Result = FALSE;
369 if (StrDup) {
370 HeapFree(GetProcessHeap(), 0, StrDup);
371 StrDup = NULL;
372 }
373 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
374 !((DWORD)pszSound >> 16)) || !pszSound)) {
375 StrDup = HEAP_strdupA(GetProcessHeap(), 0,pszSound);
376 PlaySound_pszSound = StrDup;
377 } else PlaySound_pszSound = pszSound;
378 PlaySound_Loop = fdwSound & SND_LOOP;
379 SetEvent(PlaySound_hPlayEvent);
380 ResetEvent(PlaySound_hMiddleEvent);
381 return TRUE;
382 }
383 return FALSE;
384}
385
386
387/*****************************************************************************
388 * Plays a sound specified by the given filename, resource, or
389 * system event.
390 * Parameters: LPCSTR pszSound
391 * HMODULE hMod
392 * DWORD fdwSound
393 * Variables :
394 * Result :
395 * Remark :
396 * Status :
397 *
398 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
399 *****************************************************************************/
400
401BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
402{
403 LPSTR pszSoundA;
404 BOOL bSound;
405
406 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
407 !((DWORD)pszSound >> 16)) || !pszSound)) {
408 pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
409 bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
410 HeapFree(GetProcessHeap(), 0, pszSoundA);
411 } else
412 bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
413
414 return bSound;
415}
416
417
418/*****************************************************************************
419 * Plays a sound specified by the given filename
420 * Parameters: LPCSTR pszSound
421 * UINT fuSound
422 * Variables :
423 * Result :
424 * Remark :
425 * Status :
426 *
427 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
428 *****************************************************************************/
429
430BOOL WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT uFlags)
431{
432 PlaySound_SearchMode = 1;
433 return PlaySoundA(lpszSoundName, 0, uFlags);
434}
435
436
437/*****************************************************************************
438 * Plays a sound specified by the given filename
439 * Parameters: LPCWSTR pszSound
440 * HMODULE hMod
441 * DWORD fdwSound
442 * Variables :
443 * Result :
444 * Remark :
445 * Status :
446 *
447 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
448 *****************************************************************************/
449
450BOOL WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT uFlags)
451{
452 PlaySound_SearchMode = 1;
453 return PlaySoundW(lpszSoundName, 0, uFlags);
454}
455
Note: See TracBrowser for help on using the repository browser.