Commit d301254e authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard

mmdevapi: More accurately track device position.

parent b8da8fa4
......@@ -1020,7 +1020,7 @@ static void test_clock(int share)
ok(hr == S_OK, "GetPosition failed: %08x\n", hr);
ok(pos >= last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last);
last = pos;
if(/*share &&*/ winetest_debug>1) todo_wine
if(/*share &&*/ winetest_debug>1)
ok(pos*1000/freq <= slept*1.1, "Position %u too far after stop %ums\n", (UINT)pos, slept);
hr = IAudioClient_Start(ac); /* #2 */
......@@ -1054,7 +1054,7 @@ static void test_clock(int share)
ok(pos * pwfx->nSamplesPerSec <= sum * freq, "Position %u > written %u\n", (UINT)pos, sum);
/* Prove that Stop must not drop frames (in shared mode). */
ok(pad ? pos > last : pos >= last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last);
if (share && pad > 0 && winetest_debug>1) todo_wine
if (share && pad > 0 && winetest_debug>1)
ok(pos*1000/freq <= slept*1.1, "Position %u too far after playing %ums\n", (UINT)pos, slept);
/* in exclusive mode, testbot's w7 machines yield pos > sum-pad */
if(/*share &&*/ winetest_debug>1)
......@@ -1133,7 +1133,7 @@ static void test_clock(int share)
ok(pos >= last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last);
ok(pcpos > pcpos0, "pcpos should increase\n");
ok(pos * pwfx->nSamplesPerSec <= sum * freq, "Position %u > written %u\n", (UINT)pos, sum);
if (pad > 0 && winetest_debug>1) todo_wine
if (pad > 0 && winetest_debug>1)
ok(pos*1000/freq <= slept*1.1, "Position %u too far after stop %ums\n", (UINT)pos, slept);
if(winetest_debug>1)
ok(pos * pwfx->nSamplesPerSec == (sum-pad) * freq,
......@@ -1223,7 +1223,7 @@ static void test_clock(int share)
ok(pos*1000/freq <= slept*1.1, "Position %u too far after %ums\n", (UINT)pos, slept);
if (pad) /* not in case of underrun */
ok((pos-last)*1000/freq >= 90 && 110 >= (pos-last)*1000/freq,
"Position delta %ld not regular\n", (long)(pos-last));
"Position delta %ld not regular: %ld ms\n", (long)(pos-last), (long)((pos-last)*1000/freq));
}
last = pos;
......@@ -1237,7 +1237,7 @@ static void test_clock(int share)
/* ok(hr == AUDCLNT_E_BUFFER_TOO_LARGE || (hr == S_OK && i==0) without todo_wine */
ok(hr == S_OK || hr == AUDCLNT_E_BUFFER_TOO_LARGE,
"GetBuffer large (%u) failed: %08x\n", avail, hr);
if(hr == S_OK && i) todo_wine ok(FALSE, "GetBuffer large (%u) at iteration %d\n", avail, i);
if(hr == S_OK && i) ok(FALSE, "GetBuffer large (%u) at iteration %d\n", avail, i);
/* Only the first iteration should allow that large a buffer
* as prefill was drained during the first 350+100ms sleep.
* Afterwards, only 100ms of data should find room per iteration. */
......
......@@ -117,7 +117,7 @@ struct ACImpl {
BOOL initted, playing;
UINT64 written_frames, last_pos_frames;
UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames;
UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, in_oss_frames;
UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
BYTE *local_buffer, *tmp_buffer;
......@@ -1393,19 +1393,10 @@ static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
static void oss_write_data(ACImpl *This)
{
ssize_t written_bytes;
UINT32 written_frames, in_oss_frames, write_limit, max_period;
size_t to_write_frames, to_write_bytes;
UINT32 written_frames, in_oss_frames, write_limit, max_period, write_offs_frames, new_frames;
size_t to_write_frames, to_write_bytes, advanced;
audio_buf_info bi;
BYTE *buf =
This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
if(This->held_frames == 0)
return;
if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
to_write_frames = This->bufsize_frames - This->lcl_offs_frames;
else
to_write_frames = This->held_frames;
BYTE *buf;
if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
......@@ -1430,9 +1421,38 @@ static void oss_write_data(ACImpl *This)
if(write_limit == 0)
return;
/* vvvvvv - in_oss_frames
* [--xxxxxxxxxx]
* [xxxxxxxxxx--]
* ^^^^^^^^^^ - held_frames
* ^ - lcl_offs_frames
*/
advanced = This->in_oss_frames - in_oss_frames;
if(advanced > This->held_frames)
advanced = This->held_frames;
This->lcl_offs_frames += advanced;
This->lcl_offs_frames %= This->bufsize_frames;
This->held_frames -= advanced;
This->in_oss_frames = in_oss_frames;
if(This->held_frames == This->in_oss_frames)
return;
write_offs_frames = (This->lcl_offs_frames + This->in_oss_frames) % This->bufsize_frames;
new_frames = This->held_frames - This->in_oss_frames;
if(write_offs_frames + new_frames > This->bufsize_frames)
to_write_frames = This->bufsize_frames - write_offs_frames;
else
to_write_frames = new_frames;
to_write_frames = min(to_write_frames, write_limit);
to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
buf = This->local_buffer + write_offs_frames * This->fmt->nBlockAlign;
if(This->session->mute)
silence_buffer(This, buf, to_write_frames);
......@@ -1444,19 +1464,17 @@ static void oss_write_data(ACImpl *This)
}
written_frames = written_bytes / This->fmt->nBlockAlign;
This->lcl_offs_frames += written_frames;
This->lcl_offs_frames %= This->bufsize_frames;
This->held_frames -= written_frames;
This->in_oss_frames += written_frames;
if(written_frames < to_write_frames){
/* OSS buffer probably full */
return;
}
if(This->held_frames && written_frames < write_limit){
if(new_frames > written_frames && written_frames < write_limit){
/* wrapped and have some data back at the start to write */
to_write_frames = min(write_limit - written_frames, This->held_frames);
to_write_frames = min(write_limit - written_frames, new_frames - written_frames);
to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
if(This->session->mute)
......@@ -1468,10 +1486,7 @@ static void oss_write_data(ACImpl *This)
return;
}
written_frames = written_bytes / This->fmt->nBlockAlign;
This->lcl_offs_frames += written_frames;
This->lcl_offs_frames %= This->bufsize_frames;
This->held_frames -= written_frames;
This->in_oss_frames += written_frames;
}
}
......@@ -1584,6 +1599,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
}
This->playing = FALSE;
This->in_oss_frames = 0;
LeaveCriticalSection(&This->lock);
......@@ -1621,6 +1637,7 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
}
This->held_frames = 0;
This->lcl_offs_frames = 0;
This->in_oss_frames = 0;
LeaveCriticalSection(&This->lock);
......@@ -2156,7 +2173,6 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
UINT64 *qpctime)
{
ACImpl *This = impl_from_IAudioClock(iface);
int delay;
TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
......@@ -2166,18 +2182,9 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
EnterCriticalSection(&This->lock);
if(This->dataflow == eRender){
if(!This->playing || !This->held_frames ||
ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay) < 0)
delay = 0;
else
delay /= This->fmt->nBlockAlign;
if(This->held_frames + delay >= This->written_frames)
*pos = This->written_frames - This->held_frames;
if(*pos < This->last_pos_frames)
*pos = This->last_pos_frames;
else{
*pos = This->written_frames - This->held_frames - delay;
if(*pos < This->last_pos_frames)
*pos = This->last_pos_frames;
}
}else if(This->dataflow == eCapture){
audio_buf_info bi;
UINT32 held;
......@@ -2197,6 +2204,7 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
This->last_pos_frames = *pos;
TRACE("returning: %s\n", wine_dbgstr_longlong(*pos));
if(This->share == AUDCLNT_SHAREMODE_SHARED)
*pos *= This->fmt->nBlockAlign;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment