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

📄 mixer.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
			still_behind = FALSE;

		dsb->primary_mixpos += slen; len -= slen;
		dsb->primary_mixpos %= dsb->dsound->device->buflen;

		if ((dsb->state == STATE_STOPPED) || !slen) break;
	}
	TRACE("new primary_mixpos=%ld, primary_advbase=%ld\n", dsb->primary_mixpos, dsb->dsound->device->mixpos);
	TRACE("mixed data len=%ld, still_behind=%d\n", mixlen-len, still_behind);

post_mix:
	/* check if buffer should be considered complete */
	if (buf_left < dsb->writelead &&
	    !(dsb->playflags & DSBPLAY_LOOPING)) {
		dsb->state = STATE_STOPPED;
		dsb->playpos = 0;
		dsb->last_playpos = 0;
		dsb->buf_mixpos = 0;
		dsb->leadin = FALSE;
		dsb->need_remix = FALSE;
		DSOUND_CheckEvent(dsb, buf_left);
	}

	/* return how far we think the primary buffer can
	 * advance its underrun detector...*/
	if (still_behind) return 0;
	if ((mixlen - len) < primary_done) return 0;
	slen = ((dsb->primary_mixpos < dsb->dsound->device->mixpos) ?
		dsb->dsound->device->buflen : 0) + dsb->primary_mixpos -
		dsb->dsound->device->mixpos;
	if (slen > mixlen) {
		/* the primary_done and still_behind checks above should have worked */
		FIXME("problem with advancement calculation (advlen=%ld > mixlen=%ld)\n", slen, mixlen);
		slen = 0;
	}
	return slen;
}

static DWORD DSOUND_MixToPrimary(DirectSoundDevice *device, DWORD playpos, DWORD writepos, DWORD mixlen, BOOL recover)
{
	INT			i, len, maxlen = 0;
	IDirectSoundBufferImpl	*dsb;

	TRACE("(%ld,%ld,%ld,%d)\n", playpos, writepos, mixlen, recover);
	for (i = 0; i < device->nrofbuffers; i++) {
		dsb = device->buffers[i];

		if (dsb->buflen && dsb->state && !dsb->hwbuf) {
			TRACE("Checking %p, mixlen=%ld\n", dsb, mixlen);
			EnterCriticalSection(&(dsb->lock));
			if (dsb->state == STATE_STOPPING) {
				DSOUND_MixCancel(dsb, writepos, TRUE);
				dsb->state = STATE_STOPPED;
				DSOUND_CheckEvent(dsb, 0);
			} else {
				if ((dsb->state == STATE_STARTING) || recover) {
					dsb->primary_mixpos = writepos;
					dsb->cvolpan = dsb->volpan;
					dsb->need_remix = FALSE;
				}
				else if (dsb->need_remix) {
					DSOUND_MixCancel(dsb, writepos, TRUE);
					dsb->cvolpan = dsb->volpan;
					dsb->need_remix = FALSE;
				}
				len = DSOUND_MixOne(dsb, playpos, writepos, mixlen);
				if (dsb->state == STATE_STARTING)
					dsb->state = STATE_PLAYING;
				maxlen = (len > maxlen) ? len : maxlen;
			}
			LeaveCriticalSection(&(dsb->lock));
		}
	}

	return maxlen;
}

static void DSOUND_MixReset(DirectSoundDevice *device, DWORD writepos)
{
	INT			i;
	IDirectSoundBufferImpl	*dsb;
	int nfiller;

	TRACE("(%p,%ld)\n", device, writepos);

	/* the sound of silence */
	nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;

	/* reset all buffer mix positions */
	for (i = 0; i < device->nrofbuffers; i++) {
		dsb = device->buffers[i];

		if (dsb->buflen && dsb->state && !dsb->hwbuf) {
			TRACE("Resetting %p\n", dsb);
			EnterCriticalSection(&(dsb->lock));
			if (dsb->state == STATE_STOPPING) {
				dsb->state = STATE_STOPPED;
			}
			else if (dsb->state == STATE_STARTING) {
				/* nothing */
			} else {
				DSOUND_MixCancel(dsb, writepos, FALSE);
				dsb->cvolpan = dsb->volpan;
				dsb->need_remix = FALSE;
			}
			LeaveCriticalSection(&(dsb->lock));
		}
	}

	/* wipe out premixed data */
	if (device->mixpos < writepos) {
		FillMemory(device->buffer + writepos, device->buflen - writepos, nfiller);
		FillMemory(device->buffer, device->mixpos, nfiller);
	} else {
		FillMemory(device->buffer + writepos, device->mixpos - writepos, nfiller);
	}

	/* reset primary mix position */
	device->mixpos = writepos;
}

static void DSOUND_CheckReset(DirectSoundDevice *device, DWORD writepos)
{
	TRACE("(%p,%ld)\n",device,writepos);
	if (device->need_remix) {
		DSOUND_MixReset(device, writepos);
		device->need_remix = FALSE;
		/* maximize Half-Life performance */
		device->prebuf = ds_snd_queue_min;
		device->precount = 0;
	} else {
		device->precount++;
		if (device->precount >= 4) {
			if (device->prebuf < ds_snd_queue_max)
				device->prebuf++;
			device->precount = 0;
		}
	}
	TRACE("premix adjust: %d\n", device->prebuf);
}

void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq)
{
	TRACE("(%p,%ld)\n", device, mixq);
	if (mixq + device->pwqueue > ds_hel_queue) mixq = ds_hel_queue - device->pwqueue;
	TRACE("queueing %ld buffers, starting at %d\n", mixq, device->pwwrite);
	for (; mixq; mixq--) {
		waveOutWrite(device->hwo, device->pwave[device->pwwrite], sizeof(WAVEHDR));
		device->pwwrite++;
		if (device->pwwrite >= DS_HEL_FRAGS) device->pwwrite = 0;
		device->pwqueue++;
	}
}

/* #define SYNC_CALLBACK */

void DSOUND_PerformMix(DirectSoundDevice *device)
{
	int nfiller;
	BOOL forced;
	HRESULT hres;

	TRACE("(%p)\n", device);

	/* the sound of silence */
	nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;

	/* whether the primary is forced to play even without secondary buffers */
	forced = ((device->state == STATE_PLAYING) || (device->state == STATE_STARTING));

	if (device->priolevel != DSSCL_WRITEPRIMARY) {
		BOOL paused = ((device->state == STATE_STOPPED) || (device->state == STATE_STARTING));
		/* FIXME: document variables */
 		DWORD playpos, writepos, inq, maxq, frag;
 		if (device->hwbuf) {
			hres = IDsDriverBuffer_GetPosition(device->hwbuf, &playpos, &writepos);
			if (hres) {
			    WARN("IDsDriverBuffer_GetPosition failed\n");
			    return;
			}
			/* Well, we *could* do Just-In-Time mixing using the writepos,
			 * but that's a little bit ambitious and unnecessary... */
			/* rather add our safety margin to the writepos, if we're playing */
			if (!paused) {
				writepos += device->writelead;
				writepos %= device->buflen;
			} else writepos = playpos;
		} else {
 			playpos = device->pwplay * device->fraglen;
 			writepos = playpos;
 			if (!paused) {
	 			writepos += ds_hel_margin * device->fraglen;
 				writepos %= device->buflen;
	 		}
		}
		TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld, buflen=%ld\n",
		      playpos,writepos,device->playpos,device->mixpos,device->buflen);
		assert(device->playpos < device->buflen);
		/* wipe out just-played sound data */
		if (playpos < device->playpos) {
			FillMemory(device->buffer + device->playpos, device->buflen - device->playpos, nfiller);
			FillMemory(device->buffer, playpos, nfiller);
		} else {
			FillMemory(device->buffer + device->playpos, playpos - device->playpos, nfiller);
		}
		device->playpos = playpos;

		EnterCriticalSection(&(device->mixlock));

		/* reset mixing if necessary */
		DSOUND_CheckReset(device, writepos);

		/* check how much prebuffering is left */
		inq = device->mixpos;
		if (inq < writepos)
			inq += device->buflen;
		inq -= writepos;

		/* find the maximum we can prebuffer */
		if (!paused) {
			maxq = playpos;
			if (maxq < writepos)
				maxq += device->buflen;
			maxq -= writepos;
		} else maxq = device->buflen;

		/* clip maxq to device->prebuf */
		frag = device->prebuf * device->fraglen;
		if (maxq > frag) maxq = frag;

		/* check for consistency */
		if (inq > maxq) {
			/* the playback position must have passed our last
			 * mixed position, i.e. it's an underrun, or we have
			 * nothing more to play */
			TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq, maxq);
			inq = 0;
			/* stop the playback now, to allow buffers to refill */
			if (device->state == STATE_PLAYING) {
				device->state = STATE_STARTING;
			}
			else if (device->state == STATE_STOPPING) {
				device->state = STATE_STOPPED;
			}
			else {
				/* how can we have an underrun if we aren't playing? */
				WARN("unexpected primary state (%ld)\n", device->state);
			}
#ifdef SYNC_CALLBACK
			/* DSOUND_callback may need this lock */
			LeaveCriticalSection(&(device->mixlock));
#endif
			if (DSOUND_PrimaryStop(device) != DS_OK)
				WARN("DSOUND_PrimaryStop failed\n");
#ifdef SYNC_CALLBACK
			EnterCriticalSection(&(device->mixlock));
#endif
			if (device->hwbuf) {
				/* the Stop is supposed to reset play position to beginning of buffer */
				/* unfortunately, OSS is not able to do so, so get current pointer */
				hres = IDsDriverBuffer_GetPosition(device->hwbuf, &playpos, NULL);
				if (hres) {
					LeaveCriticalSection(&(device->mixlock));
					WARN("IDsDriverBuffer_GetPosition failed\n");
					return;
				}
			} else {
	 			playpos = device->pwplay * device->fraglen;
			}
			writepos = playpos;
			device->playpos = playpos;
			device->mixpos = writepos;
			inq = 0;
			maxq = device->buflen;
			if (maxq > frag) maxq = frag;
			FillMemory(device->buffer, device->buflen, nfiller);
			paused = TRUE;
		}

		/* do the mixing */
		frag = DSOUND_MixToPrimary(device, playpos, writepos, maxq, paused);
		if (forced) frag = maxq - inq;
		device->mixpos += frag;
		device->mixpos %= device->buflen;

		if (frag) {
			/* buffers have been filled, restart playback */
			if (device->state == STATE_STARTING) {
				device->state = STATE_PLAYING;
			}
			else if (device->state == STATE_STOPPED) {
				/* the dsound is supposed to play if there's something to play
				 * even if it is reported as stopped, so don't let this confuse you */
				device->state = STATE_STOPPING;
			}
			LeaveCriticalSection(&(device->mixlock));
			if (paused) {
				if (DSOUND_PrimaryPlay(device) != DS_OK)
					WARN("DSOUND_PrimaryPlay failed\n");
				else
					TRACE("starting playback\n");
			}
		}
		else
			LeaveCriticalSection(&(device->mixlock));
	} else {
		/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
		if (device->state == STATE_STARTING) {
			if (DSOUND_PrimaryPlay(device) != DS_OK)
				WARN("DSOUND_PrimaryPlay failed\n");
			else
				device->state = STATE_PLAYING;
		}
		else if (device->state == STATE_STOPPING) {
			if (DSOUND_PrimaryStop(device) != DS_OK)
				WARN("DSOUND_PrimaryStop failed\n");
			else
				device->state = STATE_STOPPED;
		}
	}
}

void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
        DirectSoundDevice * device = (DirectSoundDevice*)dwUser;
	DWORD start_time =  GetTickCount();
        DWORD end_time;
	TRACE("(%d,%d,0x%lx,0x%lx,0x%lx)\n",timerID,msg,dwUser,dw1,dw2);
        TRACE("entering at %ld\n", start_time);

	if (DSOUND_renderer[device->drvdesc.dnDevNode] != device) {
		ERR("dsound died without killing us?\n");
		timeKillEvent(timerID);
		timeEndPeriod(DS_TIME_RES);
		return;
	}

	RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);

	if (device->ref)
		DSOUND_PerformMix(device);

	RtlReleaseResource(&(device->buffer_list_lock));

	end_time = GetTickCount();
	TRACE("completed processing at %ld, duration = %ld\n", end_time, end_time - start_time);
}

void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
        DirectSoundDevice * device = (DirectSoundDevice*)dwUser;
	TRACE("(%p,%x,%lx,%lx,%lx)\n",hwo,msg,dwUser,dw1,dw2);
	TRACE("entering at %ld, msg=%08x(%s)\n", GetTickCount(), msg, 
		msg==MM_WOM_DONE ? "MM_WOM_DONE" : msg==MM_WOM_CLOSE ? "MM_WOM_CLOSE" : 
		msg==MM_WOM_OPEN ? "MM_WOM_OPEN" : "UNKNOWN");
	if (msg == MM_WOM_DONE) {
		DWORD inq, mixq, fraglen, buflen, pwplay, playpos, mixpos;
		if (device->pwqueue == (DWORD)-1) {
			TRACE("completed due to reset\n");
			return;
		}
/* it could be a bad idea to enter critical section here... if there's lock contention,
 * the resulting scheduling delays might obstruct the winmm player thread */
#ifdef SYNC_CALLBACK
		EnterCriticalSection(&(device->mixlock));
#endif
		/* retrieve current values */
		fraglen = device->fraglen;
		buflen = device->buflen;
		pwplay = device->pwplay;
		playpos = pwplay * fraglen;
		mixpos = device->mixpos;
		/* check remaining mixed data */
		inq = ((mixpos < playpos) ? buflen : 0) + mixpos - playpos;
		mixq = inq / fraglen;
		if ((inq - (mixq * fraglen)) > 0) mixq++;
		/* complete the playing buffer */
		TRACE("done playing primary pos=%ld\n", playpos);
		pwplay++;
		if (pwplay >= DS_HEL_FRAGS) pwplay = 0;
		/* write new values */
		device->pwplay = pwplay;
		device->pwqueue--;
		/* queue new buffer if we have data for it */
		if (inq>1) DSOUND_WaveQueue(device, inq-1);
#ifdef SYNC_CALLBACK
		LeaveCriticalSection(&(device->mixlock));
#endif
	}
	TRACE("completed\n");
}

⌨️ 快捷键说明

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