Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenwavemap.c
Go to the documentation of this file.
00001 /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 00002 /* 00003 * Wine Wave mapper driver 00004 * 00005 * Copyright 1999,2001 Eric Pouech 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 /* TODOs 00023 * + better protection against evilish dwUser parameters 00024 * + use asynchronous ACM conversion 00025 * + don't use callback functions when none is required in open 00026 * + the buffer sizes may not be accurate, so there may be some 00027 * remaining bytes in src and dst buffers after ACM conversions... 00028 * those should be taken care of... 00029 */ 00030 00031 #include <stdarg.h> 00032 #include <string.h> 00033 #include "windef.h" 00034 #include "winbase.h" 00035 #include "wingdi.h" 00036 #include "winuser.h" 00037 #include "mmddk.h" 00038 #include "mmreg.h" 00039 #include "msacm.h" 00040 #include "wine/unicode.h" 00041 #include "wine/debug.h" 00042 00043 WINE_DEFAULT_DEBUG_CHANNEL(wavemap); 00044 00045 typedef struct tagWAVEMAPDATA { 00046 struct tagWAVEMAPDATA* self; 00047 union { 00048 struct { 00049 HWAVEOUT hOuterWave; 00050 HWAVEOUT hInnerWave; 00051 } out; 00052 struct { 00053 HWAVEIN hOuterWave; 00054 HWAVEIN hInnerWave; 00055 } in; 00056 } u; 00057 HACMSTREAM hAcmStream; 00058 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */ 00059 DWORD_PTR dwCallback; 00060 DWORD_PTR dwClientInstance; 00061 DWORD dwFlags; 00062 /* ratio to compute position from a PCM playback to any format */ 00063 DWORD avgSpeedOuter; 00064 DWORD avgSpeedInner; 00065 /* channel size of inner and outer */ 00066 DWORD nSamplesPerSecOuter; 00067 DWORD nSamplesPerSecInner; 00068 } WAVEMAPDATA; 00069 00070 static BOOL WAVEMAP_IsData(const WAVEMAPDATA* wm) 00071 { 00072 return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm); 00073 } 00074 00075 /*======================================================================* 00076 * WAVE OUT part * 00077 *======================================================================*/ 00078 00079 static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwInstance, 00080 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 00081 { 00082 WAVEMAPDATA* wom = (WAVEMAPDATA*)dwInstance; 00083 00084 TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); 00085 00086 if (!WAVEMAP_IsData(wom)) { 00087 ERR("Bad data\n"); 00088 return; 00089 } 00090 00091 if (uMsg != WOM_OPEN && hWave != wom->u.out.hInnerWave) 00092 ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave); 00093 00094 switch (uMsg) { 00095 case WOM_OPEN: 00096 case WOM_CLOSE: 00097 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ 00098 break; 00099 case WOM_DONE: 00100 if (wom->hAcmStream) { 00101 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)dwParam1; 00102 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER)); 00103 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser; 00104 00105 lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE; 00106 lpWaveHdrSrc->dwFlags |= WHDR_DONE; 00107 dwParam1 = (DWORD_PTR)lpWaveHdrSrc; 00108 } 00109 break; 00110 default: 00111 ERR("Unknown msg %u\n", uMsg); 00112 } 00113 00114 DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave, 00115 uMsg, wom->dwClientInstance, dwParam1, dwParam2); 00116 } 00117 00118 /****************************************************************** 00119 * wodOpenHelper 00120 * 00121 * 00122 */ 00123 static DWORD wodOpenHelper(WAVEMAPDATA* wom, UINT idx, 00124 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 00125 DWORD dwFlags) 00126 { 00127 DWORD ret; 00128 00129 TRACE("(%p %04x %p %p %08x)\n", wom, idx, lpDesc, lpwfx, dwFlags); 00130 00131 /* destination is always PCM, so the formulas below apply */ 00132 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; 00133 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; 00134 if (dwFlags & WAVE_FORMAT_QUERY) { 00135 ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); 00136 } else { 00137 ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L); 00138 } 00139 if (ret == MMSYSERR_NOERROR) { 00140 ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, 00141 (DWORD_PTR)wodCallback, (DWORD_PTR)wom, 00142 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); 00143 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { 00144 acmStreamClose(wom->hAcmStream, 0); 00145 wom->hAcmStream = 0; 00146 } 00147 } 00148 TRACE("ret = %08x\n", ret); 00149 return ret; 00150 } 00151 00152 static DWORD wodOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) 00153 { 00154 UINT ndlo, ndhi; 00155 UINT i; 00156 WAVEMAPDATA* wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); 00157 DWORD res; 00158 00159 TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags); 00160 00161 if (!wom) { 00162 WARN("no memory\n"); 00163 return MMSYSERR_NOMEM; 00164 } 00165 00166 ndhi = waveOutGetNumDevs(); 00167 if (dwFlags & WAVE_MAPPED) { 00168 if (lpDesc->uMappedDeviceID >= ndhi) { 00169 WARN("invalid parameter: dwFlags WAVE_MAPPED\n"); 00170 HeapFree(GetProcessHeap(), 0, wom); 00171 return MMSYSERR_INVALPARAM; 00172 } 00173 ndlo = lpDesc->uMappedDeviceID; 00174 ndhi = ndlo + 1; 00175 dwFlags &= ~WAVE_MAPPED; 00176 } else { 00177 ndlo = 0; 00178 } 00179 wom->self = wom; 00180 wom->dwCallback = lpDesc->dwCallback; 00181 wom->dwFlags = dwFlags; 00182 wom->dwClientInstance = lpDesc->dwInstance; 00183 wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave; 00184 wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; 00185 wom->nSamplesPerSecOuter = wom->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec; 00186 00187 for (i = ndlo; i < ndhi; i++) { 00188 /* if no ACM stuff is involved, no need to handle callbacks at this 00189 * level, this will be done transparently 00190 */ 00191 if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, 00192 (DWORD_PTR)wodCallback, (DWORD_PTR)wom, 00193 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { 00194 wom->hAcmStream = 0; 00195 goto found; 00196 } 00197 } 00198 00199 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) { 00200 WAVEFORMATEX wfx; 00201 00202 wfx.wFormatTag = WAVE_FORMAT_PCM; 00203 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ 00204 /* try some ACM stuff */ 00205 00206 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ 00207 switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ 00208 case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \ 00209 case WAVERR_BADFORMAT: break; \ 00210 default: goto error; \ 00211 } 00212 00213 if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { 00214 /* Format changed so keep sample rate and number of channels 00215 * the same and just change the bit depth 00216 */ 00217 for (i = ndlo; i < ndhi; i++) { 00218 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 00219 wfx.nChannels = lpDesc->lpFormat->nChannels; 00220 TRY(wfx.nSamplesPerSec, 16); 00221 TRY(wfx.nSamplesPerSec, 8); 00222 } 00223 } else { 00224 /* Our resampling algorithm is quite primitive so first try 00225 * to just change the bit depth and number of channels 00226 */ 00227 for (i = ndlo; i < ndhi; i++) { 00228 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 00229 wfx.nChannels = lpDesc->lpFormat->nChannels; 00230 TRY(wfx.nSamplesPerSec, 16); 00231 TRY(wfx.nSamplesPerSec, 8); 00232 wfx.nChannels ^= 3; 00233 TRY(wfx.nSamplesPerSec, 16); 00234 TRY(wfx.nSamplesPerSec, 8); 00235 } 00236 00237 for (i = ndlo; i < ndhi; i++) { 00238 /* first try with same stereo/mono option as source */ 00239 wfx.nChannels = lpDesc->lpFormat->nChannels; 00240 TRY(96000, 16); 00241 TRY(48000, 16); 00242 TRY(44100, 16); 00243 TRY(22050, 16); 00244 TRY(11025, 16); 00245 00246 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 00247 wfx.nChannels ^= 3; 00248 TRY(96000, 16); 00249 TRY(48000, 16); 00250 TRY(44100, 16); 00251 TRY(22050, 16); 00252 TRY(11025, 16); 00253 00254 /* first try with same stereo/mono option as source */ 00255 wfx.nChannels = lpDesc->lpFormat->nChannels; 00256 TRY(96000, 8); 00257 TRY(48000, 8); 00258 TRY(44100, 8); 00259 TRY(22050, 8); 00260 TRY(11025, 8); 00261 00262 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 00263 wfx.nChannels ^= 3; 00264 TRY(96000, 8); 00265 TRY(48000, 8); 00266 TRY(44100, 8); 00267 TRY(22050, 8); 00268 TRY(11025, 8); 00269 } 00270 } 00271 #undef TRY 00272 } 00273 00274 HeapFree(GetProcessHeap(), 0, wom); 00275 WARN("ret = WAVERR_BADFORMAT\n"); 00276 return WAVERR_BADFORMAT; 00277 00278 found: 00279 if (dwFlags & WAVE_FORMAT_QUERY) { 00280 *lpdwUser = 0L; 00281 HeapFree(GetProcessHeap(), 0, wom); 00282 } else { 00283 *lpdwUser = (DWORD_PTR)wom; 00284 } 00285 return MMSYSERR_NOERROR; 00286 error: 00287 HeapFree(GetProcessHeap(), 0, wom); 00288 if (res==ACMERR_NOTPOSSIBLE) { 00289 WARN("ret = WAVERR_BADFORMAT\n"); 00290 return WAVERR_BADFORMAT; 00291 } 00292 WARN("ret = 0x%08x\n", res); 00293 return res; 00294 } 00295 00296 static DWORD wodClose(WAVEMAPDATA* wom) 00297 { 00298 DWORD ret; 00299 00300 TRACE("(%p)\n", wom); 00301 00302 ret = waveOutClose(wom->u.out.hInnerWave); 00303 if (ret == MMSYSERR_NOERROR) { 00304 if (wom->hAcmStream) { 00305 ret = acmStreamClose(wom->hAcmStream, 0); 00306 } 00307 if (ret == MMSYSERR_NOERROR) { 00308 HeapFree(GetProcessHeap(), 0, wom); 00309 } 00310 } 00311 return ret; 00312 } 00313 00314 static DWORD wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) 00315 { 00316 PACMSTREAMHEADER ash; 00317 LPWAVEHDR lpWaveHdrDst; 00318 00319 TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2); 00320 00321 if (!wom->hAcmStream) { 00322 return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); 00323 } 00324 00325 lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE; 00326 ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; 00327 /* acmStreamConvert will actually check that the new size is less than initial size */ 00328 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; 00329 if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { 00330 WARN("acmStreamConvert failed\n"); 00331 return MMSYSERR_ERROR; 00332 } 00333 00334 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 00335 if (ash->cbSrcLength > ash->cbSrcLengthUsed) 00336 FIXME("Not all src buffer has been written, expect bogus sound\n"); 00337 else if (ash->cbSrcLength < ash->cbSrcLengthUsed) 00338 ERR("CoDec has read more data than it is allowed to\n"); 00339 00340 if (ash->cbDstLengthUsed == 0) { 00341 /* something went wrong in decoding */ 00342 FIXME("Got 0 length\n"); 00343 return MMSYSERR_ERROR; 00344 } 00345 lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed; 00346 return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); 00347 } 00348 00349 static DWORD wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) 00350 { 00351 PACMSTREAMHEADER ash; 00352 DWORD size; 00353 DWORD dwRet; 00354 LPWAVEHDR lpWaveHdrDst; 00355 00356 TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2); 00357 00358 if (!wom->hAcmStream) 00359 return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); 00360 00361 if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) { 00362 WARN("acmStreamSize failed\n"); 00363 return MMSYSERR_ERROR; 00364 } 00365 00366 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); 00367 if (ash == NULL) { 00368 WARN("no memory\n"); 00369 return MMSYSERR_NOMEM; 00370 } 00371 00372 ash->cbStruct = sizeof(*ash); 00373 ash->fdwStatus = 0L; 00374 ash->dwUser = (DWORD_PTR)lpWaveHdrSrc; 00375 ash->pbSrc = (LPBYTE)lpWaveHdrSrc->lpData; 00376 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; 00377 /* ash->cbSrcLengthUsed */ 00378 ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */ 00379 ash->pbDst = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); 00380 ash->cbDstLength = size; 00381 /* ash->cbDstLengthUsed */ 00382 ash->dwDstUser = 0; /* FIXME ? */ 00383 dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L); 00384 if (dwRet != MMSYSERR_NOERROR) { 00385 WARN("acmStreamPrepareHeader failed\n"); 00386 goto errCleanUp; 00387 } 00388 00389 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 00390 lpWaveHdrDst->lpData = (LPSTR)ash->pbDst; 00391 lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */ 00392 lpWaveHdrDst->dwFlags = 0; 00393 lpWaveHdrDst->dwLoops = 0; 00394 dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); 00395 if (dwRet != MMSYSERR_NOERROR) { 00396 WARN("waveOutPrepareHeader failed\n"); 00397 goto errCleanUp; 00398 } 00399 00400 lpWaveHdrSrc->reserved = (DWORD_PTR)ash; 00401 lpWaveHdrSrc->dwFlags = WHDR_PREPARED; 00402 TRACE("=> (0)\n"); 00403 return MMSYSERR_NOERROR; 00404 errCleanUp: 00405 TRACE("=> (%d)\n", dwRet); 00406 HeapFree(GetProcessHeap(), 0, ash); 00407 return dwRet; 00408 } 00409 00410 static DWORD wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) 00411 { 00412 PACMSTREAMHEADER ash; 00413 LPWAVEHDR lpWaveHdrDst; 00414 DWORD dwRet1, dwRet2; 00415 00416 TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2); 00417 00418 if (!wom->hAcmStream) { 00419 return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); 00420 } 00421 ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; 00422 dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L); 00423 00424 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 00425 dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); 00426 00427 HeapFree(GetProcessHeap(), 0, ash); 00428 00429 lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED; 00430 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; 00431 } 00432 00433 static DWORD wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2) 00434 { 00435 DWORD val; 00436 MMTIME timepos; 00437 TRACE("(%p %p %08x)\n", wom, lpTime, dwParam2); 00438 00439 timepos = *lpTime; 00440 00441 /* For TIME_MS, we're going to recalculate using TIME_BYTES */ 00442 if (lpTime->wType == TIME_MS) 00443 timepos.wType = TIME_BYTES; 00444 00445 /* This can change timepos.wType if the requested type is not supported */ 00446 val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2); 00447 00448 if (timepos.wType == TIME_BYTES) 00449 { 00450 DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter; 00451 if (dwInnerSamplesPerOuter > 0) 00452 { 00453 DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner; 00454 DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; 00455 DWORD remainder = 0; 00456 00457 /* If we are up sampling (going from lower sample rate to higher), 00458 ** we need to make a special accommodation for times when we've 00459 ** written a partial output sample. This happens frequently 00460 ** to us because we use msacm to do our up sampling, and it 00461 ** will up sample on an unaligned basis. 00462 ** For example, if you convert a 2 byte wide 8,000 'outer' 00463 ** buffer to a 2 byte wide 48,000 inner device, you would 00464 ** expect 2 bytes of input to produce 12 bytes of output. 00465 ** Instead, msacm will produce 8 bytes of output. 00466 ** But reporting our position as 1 byte of output is 00467 ** nonsensical; the output buffer position needs to be 00468 ** aligned on outer sample size, and aggressively rounded up. 00469 */ 00470 remainder = timepos.u.cb % dwInnerBytesPerOuterSample; 00471 if (remainder > 0) 00472 { 00473 timepos.u.cb -= remainder; 00474 timepos.u.cb += dwInnerBytesPerOuterSample; 00475 } 00476 } 00477 00478 lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner); 00479 00480 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ 00481 if (lpTime->wType == TIME_MS) 00482 lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter); 00483 else 00484 lpTime->wType = TIME_BYTES; 00485 } 00486 else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) 00487 lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner); 00488 else 00489 /* other time types don't require conversion */ 00490 lpTime->u = timepos.u; 00491 00492 return val; 00493 } 00494 00495 static DWORD wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2) 00496 { 00497 static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0}; 00498 00499 TRACE("(%04x %p %p %08x)\n",wDevID, wom, lpWaveCaps, dwParam2); 00500 00501 /* if opened low driver, forward message */ 00502 if (WAVEMAP_IsData(wom)) 00503 return waveOutGetDevCapsW((UINT_PTR)wom->u.out.hInnerWave, lpWaveCaps, dwParam2); 00504 /* else if no drivers, nothing to map so return bad device */ 00505 if (waveOutGetNumDevs() == 0) { 00506 WARN("bad device id\n"); 00507 return MMSYSERR_BADDEVICEID; 00508 } 00509 /* otherwise, return caps of mapper itself */ 00510 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { 00511 WAVEOUTCAPSW woc; 00512 woc.wMid = 0x00FF; 00513 woc.wPid = 0x0001; 00514 woc.vDriverVersion = 0x0332; 00515 lstrcpyW(woc.szPname, name); 00516 woc.dwFormats = 00517 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | 00518 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | 00519 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | 00520 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | 00521 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; 00522 woc.wChannels = 2; 00523 woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME; 00524 memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc))); 00525 00526 return MMSYSERR_NOERROR; 00527 } 00528 ERR("This shouldn't happen\n"); 00529 return MMSYSERR_ERROR; 00530 } 00531 00532 static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol) 00533 { 00534 TRACE("(%04x %p %p)\n",wDevID, wom, lpVol); 00535 00536 if (WAVEMAP_IsData(wom)) 00537 return waveOutGetVolume(wom->u.out.hInnerWave, lpVol); 00538 return MMSYSERR_NOERROR; 00539 } 00540 00541 static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol) 00542 { 00543 TRACE("(%04x %p %08x)\n",wDevID, wom, vol); 00544 00545 if (WAVEMAP_IsData(wom)) 00546 return waveOutSetVolume(wom->u.out.hInnerWave, vol); 00547 return MMSYSERR_NOERROR; 00548 } 00549 00550 static DWORD wodPause(WAVEMAPDATA* wom) 00551 { 00552 TRACE("(%p)\n",wom); 00553 00554 return waveOutPause(wom->u.out.hInnerWave); 00555 } 00556 00557 static DWORD wodRestart(WAVEMAPDATA* wom) 00558 { 00559 TRACE("(%p)\n",wom); 00560 00561 return waveOutRestart(wom->u.out.hInnerWave); 00562 } 00563 00564 static DWORD wodReset(WAVEMAPDATA* wom) 00565 { 00566 TRACE("(%p)\n",wom); 00567 00568 return waveOutReset(wom->u.out.hInnerWave); 00569 } 00570 00571 static DWORD wodBreakLoop(WAVEMAPDATA* wom) 00572 { 00573 TRACE("(%p)\n",wom); 00574 00575 return waveOutBreakLoop(wom->u.out.hInnerWave); 00576 } 00577 00578 static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr) 00579 { 00580 UINT id; 00581 DWORD ret = MMSYSERR_NOTSUPPORTED; 00582 00583 TRACE("(%p %08x %p)\n",wom, flags, ptr); 00584 00585 switch (flags) { 00586 case WAVEOUT_MAPPER_STATUS_DEVICE: 00587 ret = waveOutGetID(wom->u.out.hInnerWave, &id); 00588 *(LPDWORD)ptr = id; 00589 break; 00590 case WAVEOUT_MAPPER_STATUS_MAPPED: 00591 FIXME("Unsupported flag=%d\n", flags); 00592 *(LPDWORD)ptr = 0; /* FIXME ?? */ 00593 break; 00594 case WAVEOUT_MAPPER_STATUS_FORMAT: 00595 FIXME("Unsupported flag=%d\n", flags); 00596 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ 00597 *(LPDWORD)ptr = 0; 00598 break; 00599 default: 00600 FIXME("Unsupported flag=%d\n", flags); 00601 *(LPDWORD)ptr = 0; 00602 break; 00603 } 00604 return ret; 00605 } 00606 00607 static DWORD wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2) 00608 { 00609 FIXME("(%p %08x %08x) stub!\n", wom, dwParam1, dwParam2); 00610 00611 return MMSYSERR_NOERROR; 00612 } 00613 00614 /************************************************************************** 00615 * wodMessage (MSACM.@) 00616 */ 00617 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, 00618 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 00619 { 00620 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", 00621 wDevID, wMsg, dwUser, dwParam1, dwParam2); 00622 00623 switch (wMsg) { 00624 case DRVM_INIT: 00625 case DRVM_EXIT: 00626 case DRVM_ENABLE: 00627 case DRVM_DISABLE: 00628 /* FIXME: Pretend this is supported */ 00629 return 0; 00630 case WODM_OPEN: return wodOpen ((DWORD_PTR*)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2); 00631 case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser); 00632 case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 00633 case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser); 00634 case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); 00635 case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser); 00636 case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 00637 case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 00638 case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2); 00639 case WODM_GETNUMDEVS: return 1; 00640 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; 00641 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; 00642 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; 00643 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; 00644 case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1); 00645 case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1); 00646 case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser); 00647 case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser); 00648 case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); 00649 case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); 00650 /* known but not supported */ 00651 case DRV_QUERYDEVICEINTERFACESIZE: 00652 case DRV_QUERYDEVICEINTERFACE: 00653 return MMSYSERR_NOTSUPPORTED; 00654 default: 00655 FIXME("unknown message %d!\n", wMsg); 00656 } 00657 return MMSYSERR_NOTSUPPORTED; 00658 } 00659 00660 /*======================================================================* 00661 * WAVE IN part * 00662 *======================================================================*/ 00663 00664 static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD_PTR dwInstance, 00665 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 00666 { 00667 WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance; 00668 00669 TRACE("(%p %u %lx %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); 00670 00671 if (!WAVEMAP_IsData(wim)) { 00672 ERR("Bad data\n"); 00673 return; 00674 } 00675 00676 if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN) 00677 ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave); 00678 00679 switch (uMsg) { 00680 case WIM_OPEN: 00681 case WIM_CLOSE: 00682 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ 00683 break; 00684 case WIM_DATA: 00685 if (wim->hAcmStream) { 00686 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1; 00687 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER)); 00688 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser; 00689 00690 /* convert data just gotten from waveIn into requested format */ 00691 if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { 00692 ERR("ACM conversion failed\n"); 00693 return; 00694 } else { 00695 TRACE("Converted %d bytes into %d\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed); 00696 } 00697 /* and setup the wavehdr to return accordingly */ 00698 lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE; 00699 lpWaveHdrDst->dwFlags |= WHDR_DONE; 00700 lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed; 00701 dwParam1 = (DWORD_PTR)lpWaveHdrDst; 00702 } 00703 break; 00704 default: 00705 ERR("Unknown msg %u\n", uMsg); 00706 } 00707 00708 DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave, 00709 uMsg, wim->dwClientInstance, dwParam1, dwParam2); 00710 } 00711 00712 static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx, 00713 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 00714 DWORD dwFlags) 00715 { 00716 DWORD ret; 00717 00718 TRACE("(%p %04x %p %p %08x)\n", wim, idx, lpDesc, lpwfx, dwFlags); 00719 00720 /* source is always PCM, so the formulas below apply */ 00721 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; 00722 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; 00723 if (dwFlags & WAVE_FORMAT_QUERY) { 00724 ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); 00725 } else { 00726 ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L); 00727 } 00728 if (ret == MMSYSERR_NOERROR) { 00729 ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, 00730 (DWORD_PTR)widCallback, (DWORD_PTR)wim, 00731 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); 00732 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { 00733 acmStreamClose(wim->hAcmStream, 0); 00734 wim->hAcmStream = 0; 00735 } 00736 } 00737 TRACE("ret = %08x\n", ret); 00738 return ret; 00739 } 00740 00741 static DWORD widOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) 00742 { 00743 UINT ndlo, ndhi; 00744 UINT i; 00745 WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); 00746 DWORD res; 00747 00748 TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags); 00749 00750 if (!wim) { 00751 WARN("no memory\n"); 00752 return MMSYSERR_NOMEM; 00753 } 00754 00755 wim->self = wim; 00756 wim->dwCallback = lpDesc->dwCallback; 00757 wim->dwFlags = dwFlags; 00758 wim->dwClientInstance = lpDesc->dwInstance; 00759 wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave; 00760 00761 ndhi = waveInGetNumDevs(); 00762 if (dwFlags & WAVE_MAPPED) { 00763 if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM; 00764 ndlo = lpDesc->uMappedDeviceID; 00765 ndhi = ndlo + 1; 00766 dwFlags &= ~WAVE_MAPPED; 00767 } else { 00768 ndlo = 0; 00769 } 00770 00771 wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; 00772 wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec; 00773 00774 for (i = ndlo; i < ndhi; i++) { 00775 if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, 00776 (DWORD_PTR)widCallback, (DWORD_PTR)wim, 00777 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { 00778 wim->hAcmStream = 0; 00779 goto found; 00780 } 00781 } 00782 00783 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) 00784 { 00785 WAVEFORMATEX wfx; 00786 00787 wfx.wFormatTag = WAVE_FORMAT_PCM; 00788 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ 00789 /* try some ACM stuff */ 00790 00791 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ 00792 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ 00793 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \ 00794 case WAVERR_BADFORMAT: break; \ 00795 default: goto error; \ 00796 } 00797 00798 for (i = ndlo; i < ndhi; i++) { 00799 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 00800 /* first try with same stereo/mono option as source */ 00801 wfx.nChannels = lpDesc->lpFormat->nChannels; 00802 TRY(wfx.nSamplesPerSec, 16); 00803 TRY(wfx.nSamplesPerSec, 8); 00804 wfx.nChannels ^= 3; 00805 TRY(wfx.nSamplesPerSec, 16); 00806 TRY(wfx.nSamplesPerSec, 8); 00807 } 00808 00809 for (i = ndlo; i < ndhi; i++) { 00810 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 00811 /* first try with same stereo/mono option as source */ 00812 wfx.nChannels = lpDesc->lpFormat->nChannels; 00813 TRY(96000, 16); 00814 TRY(48000, 16); 00815 TRY(44100, 16); 00816 TRY(22050, 16); 00817 TRY(11025, 16); 00818 00819 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 00820 wfx.nChannels ^= 3; 00821 TRY(96000, 16); 00822 TRY(48000, 16); 00823 TRY(44100, 16); 00824 TRY(22050, 16); 00825 TRY(11025, 16); 00826 00827 /* first try with same stereo/mono option as source */ 00828 wfx.nChannels = lpDesc->lpFormat->nChannels; 00829 TRY(96000, 8); 00830 TRY(48000, 8); 00831 TRY(44100, 8); 00832 TRY(22050, 8); 00833 TRY(11025, 8); 00834 00835 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 00836 wfx.nChannels ^= 3; 00837 TRY(96000, 8); 00838 TRY(48000, 8); 00839 TRY(44100, 8); 00840 TRY(22050, 8); 00841 TRY(11025, 8); 00842 } 00843 #undef TRY 00844 } 00845 00846 HeapFree(GetProcessHeap(), 0, wim); 00847 WARN("ret = WAVERR_BADFORMAT\n"); 00848 return WAVERR_BADFORMAT; 00849 found: 00850 if (dwFlags & WAVE_FORMAT_QUERY) { 00851 *lpdwUser = 0L; 00852 HeapFree(GetProcessHeap(), 0, wim); 00853 } else { 00854 *lpdwUser = (DWORD_PTR)wim; 00855 } 00856 TRACE("Ok (stream=%p)\n", wim->hAcmStream); 00857 return MMSYSERR_NOERROR; 00858 error: 00859 HeapFree(GetProcessHeap(), 0, wim); 00860 if (res==ACMERR_NOTPOSSIBLE) { 00861 WARN("ret = WAVERR_BADFORMAT\n"); 00862 return WAVERR_BADFORMAT; 00863 } 00864 WARN("ret = 0x%08x\n", res); 00865 return res; 00866 } 00867 00868 static DWORD widClose(WAVEMAPDATA* wim) 00869 { 00870 DWORD ret; 00871 00872 TRACE("(%p)\n", wim); 00873 00874 ret = waveInClose(wim->u.in.hInnerWave); 00875 if (ret == MMSYSERR_NOERROR) { 00876 if (wim->hAcmStream) { 00877 ret = acmStreamClose(wim->hAcmStream, 0); 00878 } 00879 if (ret == MMSYSERR_NOERROR) { 00880 HeapFree(GetProcessHeap(), 0, wim); 00881 } 00882 } 00883 return ret; 00884 } 00885 00886 static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) 00887 { 00888 PACMSTREAMHEADER ash; 00889 LPWAVEHDR lpWaveHdrSrc; 00890 00891 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2); 00892 00893 if (!wim->hAcmStream) { 00894 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); 00895 } 00896 00897 lpWaveHdrDst->dwFlags |= WHDR_INQUEUE; 00898 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; 00899 00900 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 00901 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); 00902 } 00903 00904 static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) 00905 { 00906 PACMSTREAMHEADER ash; 00907 DWORD size; 00908 DWORD dwRet; 00909 LPWAVEHDR lpWaveHdrSrc; 00910 00911 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2); 00912 00913 if (!wim->hAcmStream) { 00914 return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); 00915 } 00916 if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size, 00917 ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) { 00918 WARN("acmStreamSize failed\n"); 00919 return MMSYSERR_ERROR; 00920 } 00921 00922 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); 00923 if (ash == NULL) { 00924 WARN("no memory\n"); 00925 return MMSYSERR_NOMEM; 00926 } 00927 00928 ash->cbStruct = sizeof(*ash); 00929 ash->fdwStatus = 0L; 00930 ash->dwUser = (DWORD_PTR)lpWaveHdrDst; 00931 ash->pbSrc = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); 00932 ash->cbSrcLength = size; 00933 /* ash->cbSrcLengthUsed */ 00934 ash->dwSrcUser = 0L; /* FIXME ? */ 00935 ash->pbDst = (LPBYTE)lpWaveHdrDst->lpData; 00936 ash->cbDstLength = lpWaveHdrDst->dwBufferLength; 00937 /* ash->cbDstLengthUsed */ 00938 ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */ 00939 dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L); 00940 if (dwRet != MMSYSERR_NOERROR) { 00941 WARN("acmStreamPrepareHeader failed\n"); 00942 goto errCleanUp; 00943 } 00944 00945 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 00946 lpWaveHdrSrc->lpData = (LPSTR)ash->pbSrc; 00947 lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */ 00948 lpWaveHdrSrc->dwFlags = 0; 00949 lpWaveHdrSrc->dwLoops = 0; 00950 dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); 00951 if (dwRet != MMSYSERR_NOERROR) { 00952 WARN("waveInPrepareHeader failed\n"); 00953 goto errCleanUp; 00954 } 00955 00956 lpWaveHdrDst->reserved = (DWORD_PTR)ash; 00957 lpWaveHdrDst->dwFlags = WHDR_PREPARED; 00958 TRACE("=> (0)\n"); 00959 return MMSYSERR_NOERROR; 00960 errCleanUp: 00961 TRACE("=> (%d)\n", dwRet); 00962 HeapFree(GetProcessHeap(), 0, ash); 00963 return dwRet; 00964 } 00965 00966 static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) 00967 { 00968 PACMSTREAMHEADER ash; 00969 LPWAVEHDR lpWaveHdrSrc; 00970 DWORD dwRet1, dwRet2; 00971 00972 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2); 00973 00974 if (!wim->hAcmStream) { 00975 return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); 00976 } 00977 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; 00978 dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L); 00979 00980 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 00981 dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); 00982 00983 HeapFree(GetProcessHeap(), 0, ash); 00984 00985 lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED; 00986 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; 00987 } 00988 00989 static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2) 00990 { 00991 DWORD val; 00992 MMTIME timepos; 00993 TRACE("(%p %p %08x)\n", wim, lpTime, dwParam2); 00994 00995 timepos = *lpTime; 00996 00997 /* For TIME_MS, we're going to recalculate using TIME_BYTES */ 00998 if (lpTime->wType == TIME_MS) 00999 timepos.wType = TIME_BYTES; 01000 01001 /* This can change timepos.wType if the requested type is not supported */ 01002 val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2); 01003 01004 if (timepos.wType == TIME_BYTES) 01005 { 01006 DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter; 01007 if (dwInnerSamplesPerOuter > 0) 01008 { 01009 DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner; 01010 DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; 01011 DWORD remainder = 0; 01012 01013 /* If we are up sampling (going from lower sample rate to higher), 01014 ** we need to make a special accommodation for times when we've 01015 ** written a partial output sample. This happens frequently 01016 ** to us because we use msacm to do our up sampling, and it 01017 ** will up sample on an unaligned basis. 01018 ** For example, if you convert a 2 byte wide 8,000 'outer' 01019 ** buffer to a 2 byte wide 48,000 inner device, you would 01020 ** expect 2 bytes of input to produce 12 bytes of output. 01021 ** Instead, msacm will produce 8 bytes of output. 01022 ** But reporting our position as 1 byte of output is 01023 ** nonsensical; the output buffer position needs to be 01024 ** aligned on outer sample size, and aggressively rounded up. 01025 */ 01026 remainder = timepos.u.cb % dwInnerBytesPerOuterSample; 01027 if (remainder > 0) 01028 { 01029 timepos.u.cb -= remainder; 01030 timepos.u.cb += dwInnerBytesPerOuterSample; 01031 } 01032 } 01033 01034 lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner); 01035 01036 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ 01037 if (lpTime->wType == TIME_MS) 01038 lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter); 01039 else 01040 lpTime->wType = TIME_BYTES; 01041 } 01042 else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) 01043 lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner); 01044 else 01045 /* other time types don't require conversion */ 01046 lpTime->u = timepos.u; 01047 01048 return val; 01049 } 01050 01051 static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2) 01052 { 01053 TRACE("(%04x, %p %p %08x)\n", wDevID, wim, lpWaveCaps, dwParam2); 01054 01055 /* if opened low driver, forward message */ 01056 if (WAVEMAP_IsData(wim)) 01057 return waveInGetDevCapsW((UINT_PTR)wim->u.in.hInnerWave, lpWaveCaps, dwParam2); 01058 /* else if no drivers, nothing to map so return bad device */ 01059 if (waveInGetNumDevs() == 0) { 01060 WARN("bad device id\n"); 01061 return MMSYSERR_BADDEVICEID; 01062 } 01063 /* otherwise, return caps of mapper itself */ 01064 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { 01065 WAVEINCAPSW wic; 01066 static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0}; 01067 wic.wMid = 0x00FF; 01068 wic.wPid = 0x0001; 01069 wic.vDriverVersion = 0x0001; 01070 strcpyW(wic.szPname, init); 01071 wic.dwFormats = 01072 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | 01073 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | 01074 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | 01075 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | 01076 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; 01077 wic.wChannels = 2; 01078 memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic))); 01079 01080 return MMSYSERR_NOERROR; 01081 } 01082 ERR("This shouldn't happen\n"); 01083 return MMSYSERR_ERROR; 01084 } 01085 01086 static DWORD widStop(WAVEMAPDATA* wim) 01087 { 01088 TRACE("(%p)\n", wim); 01089 01090 return waveInStop(wim->u.in.hInnerWave); 01091 } 01092 01093 static DWORD widStart(WAVEMAPDATA* wim) 01094 { 01095 TRACE("(%p)\n", wim); 01096 01097 return waveInStart(wim->u.in.hInnerWave); 01098 } 01099 01100 static DWORD widReset(WAVEMAPDATA* wim) 01101 { 01102 TRACE("(%p)\n", wim); 01103 01104 return waveInReset(wim->u.in.hInnerWave); 01105 } 01106 01107 static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr) 01108 { 01109 UINT id; 01110 DWORD ret = MMSYSERR_NOTSUPPORTED; 01111 01112 TRACE("(%p %08x %p)\n", wim, flags, ptr); 01113 01114 switch (flags) { 01115 case WAVEIN_MAPPER_STATUS_DEVICE: 01116 ret = waveInGetID(wim->u.in.hInnerWave, &id); 01117 *(LPDWORD)ptr = id; 01118 break; 01119 case WAVEIN_MAPPER_STATUS_MAPPED: 01120 FIXME("Unsupported yet flag=%d\n", flags); 01121 *(LPDWORD)ptr = 0; /* FIXME ?? */ 01122 break; 01123 case WAVEIN_MAPPER_STATUS_FORMAT: 01124 FIXME("Unsupported flag=%d\n", flags); 01125 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ 01126 *(LPDWORD)ptr = 0; /* FIXME ?? */ 01127 break; 01128 default: 01129 FIXME("Unsupported flag=%d\n", flags); 01130 *(LPDWORD)ptr = 0; 01131 break; 01132 } 01133 return ret; 01134 } 01135 01136 static DWORD widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2) 01137 { 01138 FIXME("(%p %08x %08x) stub!\n", wim, dwParam1, dwParam2); 01139 01140 return MMSYSERR_NOERROR; 01141 } 01142 01143 /************************************************************************** 01144 * widMessage (MSACM.@) 01145 */ 01146 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD_PTR dwUser, 01147 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 01148 { 01149 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", 01150 wDevID, wMsg, dwUser, dwParam1, dwParam2); 01151 01152 switch (wMsg) { 01153 case DRVM_INIT: 01154 case DRVM_EXIT: 01155 case DRVM_ENABLE: 01156 case DRVM_DISABLE: 01157 /* FIXME: Pretend this is supported */ 01158 return 0; 01159 01160 case WIDM_OPEN: return widOpen ((DWORD_PTR*)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2); 01161 case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser); 01162 01163 case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 01164 case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 01165 case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 01166 case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2); 01167 case WIDM_GETNUMDEVS: return 1; 01168 case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); 01169 case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser); 01170 case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser); 01171 case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser); 01172 case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); 01173 case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); 01174 /* known but not supported */ 01175 case DRV_QUERYDEVICEINTERFACESIZE: 01176 case DRV_QUERYDEVICEINTERFACE: 01177 return MMSYSERR_NOTSUPPORTED; 01178 default: 01179 FIXME("unknown message %u!\n", wMsg); 01180 } 01181 return MMSYSERR_NOTSUPPORTED; 01182 } 01183 01184 /*======================================================================* 01185 * Driver part * 01186 *======================================================================*/ 01187 01188 static struct WINE_WAVEMAP* oss = NULL; 01189 01190 /************************************************************************** 01191 * WAVEMAP_drvOpen [internal] 01192 */ 01193 static LRESULT WAVEMAP_drvOpen(LPSTR str) 01194 { 01195 TRACE("(%p)\n", str); 01196 01197 if (oss) 01198 return 0; 01199 01200 /* I know, this is ugly, but who cares... */ 01201 oss = (struct WINE_WAVEMAP*)1; 01202 return 1; 01203 } 01204 01205 /************************************************************************** 01206 * WAVEMAP_drvClose [internal] 01207 */ 01208 static LRESULT WAVEMAP_drvClose(DWORD_PTR dwDevID) 01209 { 01210 TRACE("(%08lx)\n", dwDevID); 01211 01212 if (oss) { 01213 oss = NULL; 01214 return 1; 01215 } 01216 return 0; 01217 } 01218 01219 /************************************************************************** 01220 * DriverProc (MSACM.@) 01221 */ 01222 LRESULT CALLBACK WAVEMAP_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, 01223 LPARAM dwParam1, LPARAM dwParam2) 01224 { 01225 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n", 01226 dwDevID, hDriv, wMsg, dwParam1, dwParam2); 01227 01228 switch(wMsg) { 01229 case DRV_LOAD: return 1; 01230 case DRV_FREE: return 1; 01231 case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1); 01232 case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID); 01233 case DRV_ENABLE: return 1; 01234 case DRV_DISABLE: return 1; 01235 case DRV_QUERYCONFIGURE: return 1; 01236 case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1; 01237 case DRV_INSTALL: return DRVCNF_RESTART; 01238 case DRV_REMOVE: return DRVCNF_RESTART; 01239 default: 01240 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); 01241 } 01242 } Generated on Sun May 27 2012 04:24:45 for ReactOS by
1.7.6.1
|