source: trunk/src/winmm/playsound.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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