📄 primary.c
字号:
device->pwfx = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,device->pwfx,alloc_size);
nSamplesPerSec = device->pwfx->nSamplesPerSec;
CopyMemory(device->pwfx, wfex, cp_size);
if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) {
DWORD flags = CALLBACK_FUNCTION;
if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
flags |= WAVE_DIRECTSOUND;
/* FIXME: check for errors */
DSOUND_PrimaryClose(device);
waveOutClose(device->hwo);
device->hwo = 0;
err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode,
device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device,
flags));
if (err == DS_OK) {
err = DSOUND_PrimaryOpen(device);
if (err != DS_OK) {
WARN("DSOUND_PrimaryOpen failed\n");
goto done;
}
} else {
WARN("waveOutOpen failed\n");
goto done;
}
} else if (device->hwbuf) {
err = IDsDriverBuffer_SetFormat(device->hwbuf, device->pwfx);
if (err == DSERR_BUFFERLOST) {
/* Wine-only: the driver wants us to recreate the HW buffer */
IDsDriverBuffer_Release(device->hwbuf);
err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx,
DSBCAPS_PRIMARYBUFFER,0,
&(device->buflen),&(device->buffer),
(LPVOID)&(device->hwbuf));
if (err != DS_OK) {
WARN("IDsDriver_CreateSoundBuffer failed\n");
goto done;
}
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
} else {
WARN("IDsDriverBuffer_SetFormat failed\n");
goto done;
}
/* FIXME: should we set err back to DS_OK in all cases ? */
}
DSOUND_RecalcPrimary(device);
if (nSamplesPerSec != device->pwfx->nSamplesPerSec) {
IDirectSoundBufferImpl** dsb = device->buffers;
for (i = 0; i < device->nrofbuffers; i++, dsb++) {
/* **** */
EnterCriticalSection(&((*dsb)->lock));
(*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
wfex->nSamplesPerSec;
LeaveCriticalSection(&((*dsb)->lock));
/* **** */
}
}
done:
LeaveCriticalSection(&(device->mixlock));
RtlReleaseResource(&(device->buffer_list_lock));
/* **** */
return err;
}
static HRESULT WINAPI PrimaryBufferImpl_SetVolume(
LPDIRECTSOUNDBUFFER8 iface,LONG vol
) {
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
DWORD ampfactors;
DSVOLUMEPAN volpan;
HRESULT hres = DS_OK;
TRACE("(%p,%ld)\n", iface, vol);
if (!(device->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
WARN("control unavailable\n");
return DSERR_CONTROLUNAVAIL;
}
if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
WARN("invalid parameter: vol = %ld\n", vol);
return DSERR_INVALIDPARAM;
}
/* **** */
EnterCriticalSection(&(device->mixlock));
waveOutGetVolume(device->hwo, &factors);
volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
volpan.dwTotalRightAmpFactor=ampfactors >> 16;
DSOUND_AmpFactorToVolPan(&volpan);
if (vol != volpan.lVolume) {
volpan.lVolume=vol;
DSOUND_RecalcVolPan(&volpan);
if (device->hwbuf) {
hres = IDsDriverBuffer_SetVolumePan(device->hwbuf, &volpan);
if (hres != DS_OK)
WARN("IDsDriverBuffer_SetVolumePan failed\n");
} else {
ampfactors = (volpan.dwTotalLeftAmpFactor & 0xffff) | (volpan.dwTotalRightAmpFactor << 16);
waveOutSetVolume(device->hwo, ampfactors);
}
}
LeaveCriticalSection(&(device->mixlock));
/* **** */
return hres;
}
static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
) {
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
DWORD ampfactors;
DSVOLUMEPAN volpan;
TRACE("(%p,%p)\n", iface, vol);
if (!(device->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
WARN("control unavailable\n");
return DSERR_CONTROLUNAVAIL;
}
if (vol == NULL) {
WARN("invalid parameter: vol = NULL\n");
return DSERR_INVALIDPARAM;
}
waveOutGetVolume(device->hwo, &factors);
volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
volpan.dwTotalRightAmpFactor=ampfactors >> 16;
DSOUND_AmpFactorToVolPan(&volpan);
*vol = volpan.lVolume;
return DS_OK;
}
static HRESULT WINAPI PrimaryBufferImpl_SetFrequency(
LPDIRECTSOUNDBUFFER8 iface,DWORD freq
) {
PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface;
TRACE("(%p,%ld)\n",This,freq);
/* You cannot set the frequency of the primary buffer */
WARN("control unavailable\n");
return DSERR_CONTROLUNAVAIL;
}
static HRESULT WINAPI PrimaryBufferImpl_Play(
LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
) {
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
TRACE("(%p,%08lx,%08lx,%08lx)\n", iface, reserved1, reserved2, flags);
if (!(flags & DSBPLAY_LOOPING)) {
WARN("invalid parameter: flags = %08lx\n", flags);
return DSERR_INVALIDPARAM;
}
/* **** */
EnterCriticalSection(&(device->mixlock));
if (device->state == STATE_STOPPED)
device->state = STATE_STARTING;
else if (device->state == STATE_STOPPING)
device->state = STATE_PLAYING;
LeaveCriticalSection(&(device->mixlock));
/* **** */
return DS_OK;
}
static HRESULT WINAPI PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
{
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
TRACE("(%p)\n", iface);
/* **** */
EnterCriticalSection(&(device->mixlock));
if (device->state == STATE_PLAYING)
device->state = STATE_STOPPING;
else if (device->state == STATE_STARTING)
device->state = STATE_STOPPED;
LeaveCriticalSection(&(device->mixlock));
/* **** */
return DS_OK;
}
static ULONG WINAPI PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
{
PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface;
ULONG ref = InterlockedIncrement(&(This->ref));
TRACE("(%p) ref was %ld\n", This, ref - 1);
return ref;
}
static ULONG WINAPI PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
{
PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface;
DWORD ref = InterlockedDecrement(&(This->ref));
TRACE("(%p) ref was %ld\n", This, ref + 1);
if (!ref) {
This->dsound->device->primary = NULL;
HeapFree(GetProcessHeap(), 0, This);
TRACE("(%p) released\n", This);
}
return ref;
}
static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
) {
HRESULT hres;
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
TRACE("(%p,%p,%p)\n", iface, playpos, writepos);
hres = DSOUND_PrimaryGetPosition(device, playpos, writepos);
if (hres != DS_OK) {
WARN("DSOUND_PrimaryGetPosition failed\n");
return hres;
}
if (writepos) {
if (device->state != STATE_STOPPED)
/* apply the documented 10ms lead to writepos */
*writepos += device->writelead;
while (*writepos >= device->buflen) *writepos -= device->buflen;
}
TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount());
return DS_OK;
}
static HRESULT WINAPI PrimaryBufferImpl_GetStatus(
LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
) {
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
TRACE("(%p,%p)\n", iface, status);
if (status == NULL) {
WARN("invalid parameter: status == NULL\n");
return DSERR_INVALIDPARAM;
}
*status = 0;
if ((device->state == STATE_STARTING) ||
(device->state == STATE_PLAYING))
*status |= DSBSTATUS_PLAYING | DSBSTATUS_LOOPING;
TRACE("status=%lx\n", *status);
return DS_OK;
}
static HRESULT WINAPI PrimaryBufferImpl_GetFormat(
LPDIRECTSOUNDBUFFER8 iface,
LPWAVEFORMATEX lpwf,
DWORD wfsize,
LPDWORD wfwritten)
{
DWORD size;
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
TRACE("(%p,%p,%ld,%p)\n", iface, lpwf, wfsize, wfwritten);
size = sizeof(WAVEFORMATEX) + device->pwfx->cbSize;
if (lpwf) { /* NULL is valid */
if (wfsize >= size) {
CopyMemory(lpwf,device->pwfx,size);
if (wfwritten)
*wfwritten = size;
} else {
WARN("invalid parameter: wfsize too small\n");
if (wfwritten)
*wfwritten = 0;
return DSERR_INVALIDPARAM;
}
} else {
if (wfwritten)
*wfwritten = sizeof(WAVEFORMATEX) + device->pwfx->cbSize;
else {
WARN("invalid parameter: wfwritten == NULL\n");
return DSERR_INVALIDPARAM;
}
}
return DS_OK;
}
static HRESULT WINAPI PrimaryBufferImpl_Lock(
LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
) {
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device;
TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
iface,
writecursor,
writebytes,
lplpaudioptr1,
audiobytes1,
lplpaudioptr2,
audiobytes2,
flags,
GetTickCount()
);
if (device->priolevel != DSSCL_WRITEPRIMARY) {
WARN("failed priority check!\n");
return DSERR_PRIOLEVELNEEDED;
}
if (flags & DSBLOCK_FROMWRITECURSOR) {
DWORD writepos;
HRESULT hres;
/* GetCurrentPosition does too much magic to duplicate here */
hres = IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writepos);
if (hres != DS_OK) {
WARN("IDirectSoundBuffer_GetCurrentPosition failed\n");
return hres;
}
writecursor += writepos;
}
while (writecursor >= device->buflen)
writecursor -= device->buflen;
if (flags & DSBLOCK_ENTIREBUFFER)
writebytes = device->buflen;
if (writebytes > device->buflen)
writebytes = device->buflen;
if (!(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && device->hwbuf) {
HRESULT hres;
hres = IDsDriverBuffer_Lock(device->hwbuf,
lplpaudioptr1, audiobytes1,
lplpaudioptr2, audiobytes2,
writecursor, writebytes,
0);
if (hres != DS_OK) {
WARN("IDsDriverBuffer_Lock failed\n");
return hres;
}
} else {
if (writecursor+writebytes <= device->buflen) {
*(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor;
*audiobytes1 = writebytes;
if (lplpaudioptr2)
*(LPBYTE*)lplpaudioptr2 = NULL;
if (audiobytes2)
*audiobytes2 = 0;
TRACE("->%ld.0\n",writebytes);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -