⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buffer.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 4 页
字号:
		}
	} else {
		This->buffer->ref--;
		if (This->buffer->ref==0) {
			HeapFree(GetProcessHeap(),0,This->buffer->memory);
			HeapFree(GetProcessHeap(),0,This->buffer);
		}
	}

	HeapFree(GetProcessHeap(), 0, This->notifies);
	HeapFree(GetProcessHeap(), 0, This->pwfx);
	HeapFree(GetProcessHeap(), 0, This);

	TRACE("(%p) released\n", This);
    }
    return ref;
}

DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite)
{
	DWORD bplay = This->buf_mixpos;
	DWORD pmix = This->primary_mixpos;
	TRACE("(%p, pplay=%lu, pwrite=%lu)\n", This, pplay, pwrite);

	/* the actual primary play position (pplay) is always behind last mixed (pmix),
	 * unless the computer is too slow or something */
	/* we need to know how far away we are from there */
	if (pmix < pplay) pmix += This->dsound->device->buflen; /* wraparound */
	pmix -= pplay;
	/* detect buffer underrun */
	if (pwrite < pplay) pwrite += This->dsound->device->buflen; /* wraparound */
	pwrite -= pplay;
	if (pmix > (ds_snd_queue_max * This->dsound->device->fraglen + pwrite + This->dsound->device->writelead)) {
		WARN("detected an underrun: primary queue was %ld\n",pmix);
		pmix = 0;
	}
	/* divide the offset by its sample size */
	pmix /= This->dsound->device->pwfx->nBlockAlign;
	TRACE("primary back-samples=%ld\n",pmix);
	/* adjust for our frequency */
	pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
	/* multiply by our own sample size */
	pmix *= This->pwfx->nBlockAlign;
	TRACE("this back-offset=%ld\n", pmix);
	/* subtract from our last mixed position */
	while (bplay < pmix) bplay += This->buflen; /* wraparound */
	bplay -= pmix;
	if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
		/* seems we haven't started playing yet */
		TRACE("this still in lead-in phase\n");
		bplay = This->startpos;
	}
	/* return the result */
	return bplay;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
) {
	HRESULT	hres;
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
	TRACE("(%p,%p,%p)\n",This,playpos,writepos);
	if (This->hwbuf) {
		hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
		if (hres != DS_OK) {
		    WARN("IDsDriverBuffer_GetPosition failed\n");
		    return hres;
		}
	} else {
		if (playpos && (This->state != STATE_PLAYING)) {
			/* we haven't been merged into the primary buffer (yet) */
			*playpos = This->buf_mixpos;
		} else if (playpos) {
			DWORD pplay, pwrite;
			/* let's get this exact; first, recursively call GetPosition on the primary */
			EnterCriticalSection(&(This->dsound->device->mixlock));
			if (DSOUND_PrimaryGetPosition(This->dsound->device, &pplay, &pwrite) != DS_OK)
				WARN("DSOUND_PrimaryGetPosition failed\n");
			/* detect HEL mode underrun */
			if (!(This->dsound->device->hwbuf || This->dsound->device->pwqueue))
				TRACE("detected an underrun\n");
			if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->device->hwbuf) {
				/* calculate play position using this */
				*playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
			} else {
				/* (unless the app isn't using GETCURRENTPOSITION2) */
				/* don't know exactly how this should be handled...
				 * the docs says that play cursor is reported as directly
				 * behind write cursor, hmm... */
				/* let's just do what might work for Half-Life */
				DWORD wp;
				wp = (This->dsound->device->pwplay + ds_hel_margin) * This->dsound->device->fraglen;
				wp %= This->dsound->device->buflen;
				*playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
			}
			LeaveCriticalSection(&(This->dsound->device->mixlock));
		}
		if (writepos)
                    *writepos = This->buf_mixpos;
	}
	if (writepos) {
		if (This->state != STATE_STOPPED) {
			/* apply the documented 10ms lead to writepos */
			*writepos += This->writelead;
		}
		*writepos %= This->buflen;
	}
	if (playpos)
            This->last_playpos = *playpos;
	TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
) {
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
	TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());

	if (status == NULL) {
		WARN("invalid parameter: status = NULL\n");
		return DSERR_INVALIDPARAM;
	}

	*status = 0;
	if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
		*status |= DSBSTATUS_PLAYING;
		if (This->playflags & DSBPLAY_LOOPING)
			*status |= DSBSTATUS_LOOPING;
	}

	TRACE("status=%lx\n", *status);
	return DS_OK;
}


static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
    LPDIRECTSOUNDBUFFER8 iface,
    LPWAVEFORMATEX lpwf,
    DWORD wfsize,
    LPDWORD wfwritten)
{
    DWORD size;
    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
    TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);

    size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;

    if (lpwf) { /* NULL is valid */
        if (wfsize >= size) {
            CopyMemory(lpwf,This->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) + This->pwfx->cbSize;
        else {
            WARN("invalid parameter: wfwritten == NULL\n");
            return DSERR_INVALIDPARAM;
        }
    }

    return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
	LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
) {
	HRESULT hres = DS_OK;
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;

	TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
		This,
		writecursor,
		writebytes,
		lplpaudioptr1,
		audiobytes1,
		lplpaudioptr2,
		audiobytes2,
		flags,
		GetTickCount()
	);

	if (flags & DSBLOCK_FROMWRITECURSOR) {
		DWORD writepos;
		/* GetCurrentPosition does too much magic to duplicate here */
		hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
		if (hres != DS_OK) {
			WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
			return hres;
		}
		writecursor += writepos;
	}
	writecursor %= This->buflen;
	if (flags & DSBLOCK_ENTIREBUFFER)
		writebytes = This->buflen;
	if (writebytes > This->buflen)
		writebytes = This->buflen;

	EnterCriticalSection(&(This->lock));

	if ((writebytes == This->buflen) &&
	    ((This->state == STATE_STARTING) ||
	     (This->state == STATE_PLAYING)))
		/* some games, like Half-Life, try to be clever (not) and
		 * keep one secondary buffer, and mix sounds into it itself,
		 * locking the entire buffer every time... so we can just forget
		 * about tracking the last-written-to-position... */
		This->probably_valid_to = (DWORD)-1;
	else
		This->probably_valid_to = writecursor;

	if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
		hres = IDsDriverBuffer_Lock(This->hwbuf,
				     lplpaudioptr1, audiobytes1,
				     lplpaudioptr2, audiobytes2,
				     writecursor, writebytes,
				     0);
		if (hres != DS_OK) {
			WARN("IDsDriverBuffer_Lock failed\n");
			LeaveCriticalSection(&(This->lock));
			return hres;
		}
	} else {
		BOOL remix = FALSE;
		if (writecursor+writebytes <= This->buflen) {
			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
			*audiobytes1 = writebytes;
			if (lplpaudioptr2)
				*(LPBYTE*)lplpaudioptr2 = NULL;
			if (audiobytes2)
				*audiobytes2 = 0;
			TRACE("->%ld.0\n",writebytes);
		} else {
			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
			*audiobytes1 = This->buflen-writecursor;
			if (lplpaudioptr2)
				*(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
			if (audiobytes2)
				*audiobytes2 = writebytes-(This->buflen-writecursor);
			TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
		}
		if (This->state == STATE_PLAYING) {
			/* if the segment between playpos and buf_mixpos is touched,
			 * we need to cancel some mixing */
			/* we'll assume that the app always calls GetCurrentPosition before
			 * locking a playing buffer, so that last_playpos is up-to-date */
			if (This->buf_mixpos >= This->last_playpos) {
				if (This->buf_mixpos > writecursor &&
				    This->last_playpos < writecursor+writebytes)
					remix = TRUE;
			} else {
				if (This->buf_mixpos > writecursor ||
				    This->last_playpos < writecursor+writebytes)
					remix = TRUE;
			}
			if (remix) {
				TRACE("locking prebuffered region, ouch\n");
				DSOUND_MixCancelAt(This, writecursor);
			}
		}
	}

	LeaveCriticalSection(&(This->lock));
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
) {
	HRESULT hres = DS_OK;
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
	TRACE("(%p,%ld)\n",This,newpos);

	/* **** */
	EnterCriticalSection(&(This->lock));

	newpos %= This->buflen;
	This->buf_mixpos = newpos;
	if (This->hwbuf) {
		hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
		if (hres != DS_OK)
			WARN("IDsDriverBuffer_SetPosition failed\n");
	}

	LeaveCriticalSection(&(This->lock));
	/* **** */

	return hres;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
	LPDIRECTSOUNDBUFFER8 iface,LONG pan
) {
	HRESULT hres = DS_OK;
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;

	TRACE("(%p,%ld)\n",This,pan);

	if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
		WARN("invalid parameter: pan = %ld\n", pan);
		return DSERR_INVALIDPARAM;
	}

	/* You cannot use both pan and 3D controls */
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
	    (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
		WARN("control unavailable\n");
		return DSERR_CONTROLUNAVAIL;
	}

	/* **** */
	EnterCriticalSection(&(This->lock));

	if (This->volpan.lPan != pan) {
		This->volpan.lPan = pan;
		DSOUND_RecalcVolPan(&(This->volpan));

		if (This->hwbuf) {
			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
			if (hres != DS_OK)
				WARN("IDsDriverBuffer_SetVolumePan failed\n");
		} else
			DSOUND_ForceRemix(This);
	}

	LeaveCriticalSection(&(This->lock));
	/* **** */

	return hres;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
) {
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
	TRACE("(%p,%p)\n",This,pan);

	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
		WARN("control unavailable\n");
		return DSERR_CONTROLUNAVAIL;
	}

	if (pan == NULL) {
		WARN("invalid parameter: pan = NULL\n");
		return DSERR_INVALIDPARAM;
	}

	*pan = This->volpan.lPan;

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
	LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
) {
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
	DWORD probably_valid_to;
	HRESULT hres = DS_OK;

	TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);

	/* **** */
	EnterCriticalSection(&(This->lock));

	if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
		hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
		if (hres != DS_OK)
			WARN("IDsDriverBuffer_Unlock failed\n");
	}

        if (hres == DS_OK) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -