📄 audio_05.c
字号:
case WODM_UNPREPARE: return wodUnprepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (LPWAVEOUTCAPSA)dwParam1, dwParam2); case WODM_GETNUMDEVS: return wodGetNumDevs (); case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; case WODM_GETVOLUME: return wodGetVolume (wDevID, (LPDWORD)dwParam1); case WODM_SETVOLUME: return wodSetVolume (wDevID, dwParam1); case WODM_RESTART: return wodRestart (wDevID); case WODM_RESET: return wodReset (wDevID); case DRV_QUERYDSOUNDIFACE: return wodDsCreate(wDevID, (PIDSDRIVER*)dwParam1); default: FIXME("unknown message %d!\n", wMsg); } return MMSYSERR_NOTSUPPORTED;}/*======================================================================* * Low level DSOUND implementation * *======================================================================*/typedef struct IDsDriverImpl IDsDriverImpl;typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;struct IDsDriverImpl{ /* IUnknown fields */ ICOM_VFIELD(IDsDriver); DWORD ref; /* IDsDriverImpl fields */ UINT wDevID; IDsDriverBufferImpl*primary;};struct IDsDriverBufferImpl{ /* IUnknown fields */ ICOM_VFIELD(IDsDriverBuffer); DWORD ref; /* IDsDriverBufferImpl fields */ IDsDriverImpl* drv; DWORD buflen;};static HRESULT DSDB_UnmapPrimary(IDsDriverBufferImpl *dsdb){ WINE_WAVEOUT *wwo = &(WOutDev[dsdb->drv->wDevID]); if (wwo->mmap_buffer) { if (snd_pcm_munmap(wwo->handle, SND_PCM_CHANNEL_PLAYBACK) < 0) { ERR("(%p): Could not unmap sound device (errno=%d)\n", dsdb, errno); return DSERR_GENERIC; } wwo->mmap_buffer = wwo->mmap_control = NULL; TRACE("(%p): sound device unmapped\n", dsdb); } return DS_OK;}static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj){ /* ICOM_THIS(IDsDriverBufferImpl,iface); */ FIXME("(): stub!\n"); return DSERR_UNSUPPORTED;}static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface){ ICOM_THIS(IDsDriverBufferImpl,iface); This->ref++; return This->ref;}static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface){ ICOM_THIS(IDsDriverBufferImpl,iface); if (--This->ref) return This->ref; if (This == This->drv->primary) This->drv->primary = NULL; DSDB_UnmapPrimary(This); HeapFree(GetProcessHeap(),0,This); return 0;}static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface, LPVOID*ppvAudio1,LPDWORD pdwLen1, LPVOID*ppvAudio2,LPDWORD pdwLen2, DWORD dwWritePosition,DWORD dwWriteLen, DWORD dwFlags){ /* ICOM_THIS(IDsDriverBufferImpl,iface); */ /* FIXME: we need to implement it */ TRACE("(%p)\n",iface); return DSERR_UNSUPPORTED;}static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface, LPVOID pvAudio1,DWORD dwLen1, LPVOID pvAudio2,DWORD dwLen2){ /* ICOM_THIS(IDsDriverBufferImpl,iface); */ TRACE("(%p)\n",iface); return DSERR_UNSUPPORTED;}static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface, LPWAVEFORMATEX pwfx){ /* ICOM_THIS(IDsDriverBufferImpl,iface); */ TRACE("(%p,%p)\n",iface,pwfx); /* On our request (GetDriverDesc flags), DirectSound has by now used * waveOutClose/waveOutOpen to set the format... * unfortunately, this means our mmap() is now gone... * so we need to somehow signal to our DirectSound implementation * that it should completely recreate this HW buffer... * this unexpected error code should do the trick... */ return DSERR_BUFFERLOST;}static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq){ /* ICOM_THIS(IDsDriverBufferImpl,iface); */ TRACE("(%p,%ld): stub\n",iface,dwFreq); return DSERR_UNSUPPORTED;}static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan){ /* ICOM_THIS(IDsDriverBufferImpl,iface); */ FIXME("(%p,%p): stub!\n",iface,pVolPan); return DSERR_UNSUPPORTED;}static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos){ /* ICOM_THIS(IDsDriverImpl,iface); */ TRACE("(%p,%ld): stub\n",iface,dwNewPos); return DSERR_UNSUPPORTED;}static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface, LPDWORD lpdwPlay, LPDWORD lpdwWrite){#if 0 ICOM_THIS(IDsDriverBufferImpl,iface); TODO; count_info info; DWORD ptr; TRACE("(%p)\n",iface); if (WOutDev[This->drv->wDevID].handle == NULL) { ERR("device not open, but accessing?\n"); return DSERR_UNINITIALIZED; } if (ioctl(WOutDev[This->drv->wDevID].unixdev, SNDCTL_DSP_GETOPTR, &info) < 0) { ERR("ioctl failed (%d)\n", errno); return DSERR_GENERIC; } ptr = info.ptr & ~3; /* align the pointer, just in case */ if (lpdwPlay) *lpdwPlay = ptr; if (lpdwWrite) { /* add some safety margin (not strictly necessary, but...) */ if (WOutDev[This->drv->wDevID].caps.dwSupport & WAVECAPS_SAMPLEACCURATE) *lpdwWrite = ptr + 32; else *lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize; while (*lpdwWrite > This->buflen) *lpdwWrite -= This->buflen; }#endif TRACE("playpos=%ld, writepos=%ld\n", lpdwPlay?*lpdwPlay:0, lpdwWrite?*lpdwWrite:0); return DS_OK;}static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags){ ICOM_THIS(IDsDriverBufferImpl,iface); TRACE("(%p,%lx,%lx,%lx)\n",iface,dwRes1,dwRes2,dwFlags); /* FIXME: error handling */ snd_pcm_playback_go(WOutDev[This->drv->wDevID].handle); return DS_OK;}static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface){ ICOM_THIS(IDsDriverBufferImpl,iface); TRACE("(%p)\n",iface); /* no more playing */ /* FIXME: error handling */ snd_pcm_playback_drain(WOutDev[This->drv->wDevID].handle); /* Most ALSA drivers just can't stop the playback without closing the device... * so we need to somehow signal to our DirectSound implementation * that it should completely recreate this HW buffer... * this unexpected error code should do the trick... */ return DSERR_BUFFERLOST;}static ICOM_VTABLE(IDsDriverBuffer) dsdbvt ={ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE IDsDriverBufferImpl_QueryInterface, IDsDriverBufferImpl_AddRef, IDsDriverBufferImpl_Release, IDsDriverBufferImpl_Lock, IDsDriverBufferImpl_Unlock, IDsDriverBufferImpl_SetFormat, IDsDriverBufferImpl_SetFrequency, IDsDriverBufferImpl_SetVolumePan, IDsDriverBufferImpl_SetPosition, IDsDriverBufferImpl_GetPosition, IDsDriverBufferImpl_Play, IDsDriverBufferImpl_Stop};static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj){ /* ICOM_THIS(IDsDriverImpl,iface); */ FIXME("(%p): stub!\n",iface); return DSERR_UNSUPPORTED;}static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface){ ICOM_THIS(IDsDriverImpl,iface); This->ref++; return This->ref;}static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface){ ICOM_THIS(IDsDriverImpl,iface); if (--This->ref) return This->ref; HeapFree(GetProcessHeap(),0,This); return 0;}static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface, PDSDRIVERDESC pDesc){ ICOM_THIS(IDsDriverImpl,iface); TRACE("(%p,%p)\n",iface,pDesc); pDesc->dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT | DSDDESC_USESYSTEMMEMORY; strcpy(pDesc->szDesc,"WineALSA DirectSound Driver"); strcpy(pDesc->szDrvName,"winealsa.drv"); pDesc->dnDevNode = WOutDev[This->wDevID].waveDesc.dnDevNode; pDesc->wVxdId = 0; pDesc->wReserved = 0; pDesc->ulDeviceNum = This->wDevID; pDesc->dwHeapType = DSDHEAP_NOHEAP; pDesc->pvDirectDrawHeap = NULL; pDesc->dwMemStartAddress = 0; pDesc->dwMemEndAddress = 0; pDesc->dwMemAllocExtra = 0; pDesc->pvReserved1 = NULL; pDesc->pvReserved2 = NULL; return DS_OK;}static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface){ ICOM_THIS(IDsDriverImpl,iface); TRACE("(%p)\n",iface); /* FIXME: error handling */ snd_pcm_channel_prepare(WOutDev[This->wDevID].handle, SND_PCM_CHANNEL_PLAYBACK); return DS_OK;}static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface){ ICOM_THIS(IDsDriverImpl,iface); TRACE("(%p)\n",iface); if (This->primary) { ERR("problem with DirectSound: primary not released\n"); return DSERR_GENERIC; } return DS_OK;}static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps){ /* ICOM_THIS(IDsDriverImpl,iface); */ TRACE("(%p,%p)\n",iface,pCaps); memset(pCaps, 0, sizeof(*pCaps)); /* FIXME: need to check actual capabilities */ pCaps->dwFlags = DSCAPS_PRIMARYMONO | DSCAPS_PRIMARYSTEREO | DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARY16BIT; pCaps->dwPrimaryBuffers = 1; /* the other fields only apply to secondary buffers, which we don't support * (unless we want to mess with wavetable synthesizers and MIDI) */ return DS_OK;}static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface, LPWAVEFORMATEX pwfx, DWORD dwFlags, DWORD dwCardAddress, LPDWORD pdwcbBufferSize, LPBYTE *ppbBuffer, LPVOID *ppvObj){ ICOM_THIS(IDsDriverImpl,iface); IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj; WINE_WAVEOUT *wwo = &(WOutDev[This->wDevID]); struct snd_pcm_channel_setup setup; TRACE("(%p,%p,%lx,%lx)\n",iface,pwfx,dwFlags,dwCardAddress); /* we only support primary buffers */ if (!(dwFlags & DSBCAPS_PRIMARYBUFFER)) return DSERR_UNSUPPORTED; if (This->primary) return DSERR_ALLOCATED; if (dwFlags & (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN)) return DSERR_CONTROLUNAVAIL; *ippdsdb = (IDsDriverBufferImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDsDriverBufferImpl)); if (*ippdsdb == NULL) return DSERR_OUTOFMEMORY; (*ippdsdb)->lpVtbl = &dsdbvt; (*ippdsdb)->ref = 1; (*ippdsdb)->drv = This; if (!wwo->mmap_buffer) { if (snd_pcm_mmap(wwo->handle, SND_PCM_CHANNEL_PLAYBACK, &wwo->mmap_control, &wwo->mmap_buffer)) { ERR("(%p): Could not map sound device for direct access (%s)\n", *ippdsdb, snd_strerror(errno)); return DSERR_GENERIC; } setup.mode = SND_PCM_MODE_BLOCK; setup.channel = SND_PCM_CHANNEL_PLAYBACK; if (snd_pcm_channel_setup(wwo->handle, &setup) < 0) { ERR("Unable to obtain setup\n"); /* FIXME: resource cleanup */ return DSERR_GENERIC; } wwo->mmap_block_size = setup.buf.block.frag_size; wwo->mmap_block_number = setup.buf.block.frags; TRACE("(%p): sound device has been mapped for direct access at %p, size=%d\n", *ippdsdb, wwo->mmap_buffer, setup.buf.block.frags * setup.buf.block.frag_size);#if 0 /* for some reason, es1371 and sblive! sometimes have junk in here. * clear it, or we get junk noise */ /* some libc implementations are buggy: their memset reads from the buffer... * to work around it, we have to zero the block by hand. We don't do the expected: * memset(wwo->mapping, 0, wwo->maplen); */ { char* p1 = wwo->mapping; unsigned len = wwo->maplen; if (len >= 16) /* so we can have at least a 4 long area to store... */ { /* the mmap:ed value is (at least) dword aligned * so, start filling the complete unsigned long:s */ int b = len >> 2; unsigned long* p4 = (unsigned long*)p1; while (b--) *p4++ = 0; /* prepare for filling the rest */ len &= 3; p1 = (unsigned char*)p4; } /* in all cases, fill the remaining bytes */ while (len-- != 0) *p1++ = 0; }#endif } /* primary buffer is ready to go */ *pdwcbBufferSize = wwo->mmap_block_size * wwo->mmap_block_number; *ppbBuffer = wwo->mmap_buffer; This->primary = *ippdsdb; return DS_OK;}static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface, PIDSDRIVERBUFFER pBuffer, LPVOID *ppvObj){ /* ICOM_THIS(IDsDriverImpl,iface); */ TRACE("(%p,%p): stub\n",iface,pBuffer); return DSERR_INVALIDCALL;}static ICOM_VTABLE(IDsDriver) dsdvt ={ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE IDsDriverImpl_QueryInterface, IDsDriverImpl_AddRef, IDsDriverImpl_Release, IDsDriverImpl_GetDriverDesc, IDsDriverImpl_Open, IDsDriverImpl_Close, IDsDriverImpl_GetCaps, IDsDriverImpl_CreateSoundBuffer, IDsDriverImpl_DuplicateSoundBuffer};static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv){ IDsDriverImpl** idrv = (IDsDriverImpl**)drv; /* the HAL isn't much better than the HEL if we can't do mmap() */ if (!(WOutDev[wDevID].caps.dwSupport & WAVECAPS_DIRECTSOUND)) { ERR("DirectSound flag not set\n"); MESSAGE("This sound card's driver does not support direct access\n"); MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n"); return MMSYSERR_NOTSUPPORTED; } *idrv = (IDsDriverImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDsDriverImpl)); if (!*idrv) return MMSYSERR_NOMEM; (*idrv)->lpVtbl = &dsdvt; (*idrv)->ref = 1; (*idrv)->wDevID = wDevID; (*idrv)->primary = NULL; return MMSYSERR_NOERROR;}/* we don't need a default wodMessage for audio when we don't have ALSA, the * audio.c file will provide it for us */#endif /* HAVE_ALSA && interface == 0.5 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -