I began working on this to address some flakyness (see e.g. https://gitlab.winehq.org/wine/wine/-/jobs/183916), and eventually I ended up rewriting `test_capture()` because the previous implementation looked somewhat incomplete.
-- v4: mmdevapi/tests: Remove a flaky test.
From: Giovanni Mascellani gmascellani@codeweavers.com
The old tests only requested a few packets and only simulated some of the possible logic paths. They were also somewhat flaky. The new tests are an attempt at improving completeness and reliability. --- dlls/mmdevapi/tests/capture.c | 422 +++++++++++++++------------------- 1 file changed, 184 insertions(+), 238 deletions(-)
diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index e4f8eea5556..23cba93a402 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -21,6 +21,7 @@ * - IAudioClient with eCapture and IAudioCaptureClient */
+#include <stdint.h> #include <math.h>
#include "wine/test.h" @@ -106,313 +107,258 @@ static void test_uninitialized(IAudioClient *ac) CloseHandle(handle); }
-static void test_capture(IAudioClient *ac, HANDLE handle, WAVEFORMATEX *wfx) +struct read_packets_data { - IAudioCaptureClient *acc; - HRESULT hr; - UINT32 frames, next, pad, sum = 0; - BYTE *data; - DWORD flags; - UINT64 pos, qpc; - REFERENCE_TIME period; - - hr = IAudioClient_GetService(ac, &IID_IAudioCaptureClient, (void**)&acc); - ok(hr == S_OK, "IAudioClient_GetService(IID_IAudioCaptureClient) returns %08lx\n", hr); - if (hr != S_OK) - return; - - ok(ResetEvent(handle), "ResetEvent\n"); - - hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); + UINT64 expected_dev_pos; + BOOL discontinuity_at_0; + BOOL discontinuity_at_later; +};
- hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - ok(next == pad, "GetNextPacketSize %u vs. GCP %u\n", next, pad); - /* later GCP will grow, while GNPS is 0 or period size */ +static void read_packets(IAudioClient *ac, IAudioCaptureClient *acc, HANDLE handle, + unsigned int packet_count, struct read_packets_data *data) +{ + unsigned int idx = 0; + HRESULT hr;
- hr = IAudioCaptureClient_GetNextPacketSize(acc, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetNextPacketSize(NULL) returns %08lx\n", hr); + data->discontinuity_at_0 = FALSE; + data->discontinuity_at_later = FALSE;
- data = (void*)0xdeadf00d; - frames = 0xdeadbeef; - flags = 0xabadcafe; - hr = IAudioCaptureClient_GetBuffer(acc, &data, NULL, NULL, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(data, NULL, NULL) returns %08lx\n", hr); + while (idx < packet_count) + { + UINT64 dev_pos, qpc_pos, dev_pos2, qpc_pos2; + UINT32 next_packet_size, padding, frames, frames2; + DWORD flags, flags2; + BYTE *ptr;
- hr = IAudioCaptureClient_GetBuffer(acc, NULL, &frames, NULL, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, &frames, NULL) returns %08lx\n", hr); + winetest_push_context("packet %u", idx);
- hr = IAudioCaptureClient_GetBuffer(acc, NULL, NULL, &flags, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, NULL, &flags) returns %08lx\n", hr); + hr = IAudioCaptureClient_GetNextPacketSize(acc, &next_packet_size); + ok(hr == S_OK, "GetNextPacketSize returns %08lx\n", hr);
- hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, NULL, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(&ata, &frames, NULL) returns %08lx\n", hr); - ok(broken((DWORD_PTR)data == 0xdeadf00d) || /* <= win8 */ - data == NULL, "data is reset to %p\n", data); - ok(frames == 0xdeadbeef, "frames is reset to %08x\n", frames); - ok(flags == 0xabadcafe, "flags is reset to %08lx\n", flags); + if (next_packet_size == 0) + { + /* There is some room for flakyness here, in theory a packet could arrive between the + * GetNextPacketSize() call and the GetBuffer() call. Hopefully this is not very probable. */ + ptr = (void*)0xdeadf00ddeadf00d; + flags2 = 0xdeadf11d; + dev_pos2 = 0xdeadf22ddeadf22d; + qpc_pos2 = 0xdeadf33ddeadf33d; + hr = IAudioCaptureClient_GetBuffer(acc, &ptr, &frames2, &flags2, &dev_pos2, &qpc_pos2); + ok(hr == AUDCLNT_S_BUFFER_EMPTY, "GetBuffer returns %08lx\n", hr); + ok(broken((uintptr_t)ptr == (uintptr_t)0xdeadf00ddeadf00d) || /* <= win8 */ + !ptr, "Unexpected data after GetBuffer: %p\n", ptr); + ok(flags2 == 0xdeadf11d, "Unexpected flags after GetBuffer: %08lx\n", flags2); + ok(dev_pos2 == 0xdeadf22ddeadf22d, "Unexpected device position after GetBuffer: %I64u\n", dev_pos2); + ok(qpc_pos2 == 0xdeadf33ddeadf33d, "Unexpected QPC position after GetBuffer: %I64u\n", qpc_pos2); + + ok(WaitForSingleObject(handle, 1000) == WAIT_OBJECT_0, "Waiting on event handle failed!\n"); + + winetest_pop_context(); + continue; + }
- hr = IAudioClient_GetDevicePeriod(ac, &period, NULL); - ok(hr == S_OK, "GetDevicePeriod failed: %08lx\n", hr); - period = MulDiv(period, wfx->nSamplesPerSec, 10000000); /* as in render.c */ + hr = IAudioCaptureClient_GetBuffer(acc, &ptr, &frames, &flags, &dev_pos, &qpc_pos); + ok(hr == S_OK, "GetBuffer returns %08lx\n", hr);
- hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr); + hr = IAudioClient_GetCurrentPadding(ac, &padding); + ok(hr == S_OK, "GetCurrentPadding returns %08lx\n", hr);
- ok(WaitForSingleObject(handle, 1000) == WAIT_OBJECT_0, "Waiting on event handle failed!\n"); - - data = (void*)0xdeadf00d; - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - ok(hr == S_OK || hr == AUDCLNT_S_BUFFER_EMPTY, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - if (hr == S_OK){ - ok(frames, "Amount of frames locked is 0!\n"); - /* broken: some w7 machines return pad == 0 and DATA_DISCONTINUITY here, - * AUDCLNT_S_BUFFER_EMPTY above, yet pos == 1-2 * period rather than 0 */ - ok(pos == sum || broken(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY), - "Position %u expected %u\n", (UINT)pos, sum); - sum = pos; - }else if (hr == AUDCLNT_S_BUFFER_EMPTY){ - ok(!frames, "Amount of frames locked with empty buffer is %u!\n", frames); - ok(broken(data == (void*)0xdeadf00d) || /* <= win8 */ - data == NULL, "No data changed to %p\n", data); - } + ok(next_packet_size == frames, "GetNextPacketSize returns %u, GetBuffer returns %u frames\n", + next_packet_size, frames); + ok(padding >= frames, "GetCurrentPadding returns %u, GetBuffer returns %u frames\n", + padding, frames);
- trace("Wait'ed position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); + if (flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) + { + if (idx == 0) + data->discontinuity_at_0 = TRUE; + else + data->discontinuity_at_later = TRUE; + }
- hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); - ok(next == frames, "GetNextPacketSize %u vs. GetBuffer %u\n", next, frames); + if (data->expected_dev_pos != UINT64_MAX) + { + /* Win <= 8 and some older Win 10 builds sometimes handle discontinuities incorrectly. */ + ok(dev_pos >= data->expected_dev_pos || broken(1), + "GetBuffer returns %I64u device position, expected at least %I64u\n", + dev_pos, data->expected_dev_pos); + if (!(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY)) + ok(dev_pos == data->expected_dev_pos || broken(1), + "GetBuffer returns %I64u device position, expected %I64u\n", + dev_pos, data->expected_dev_pos); + }
- hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); + ptr = (void*)0xdeadf00ddeadf00d; + flags2 = 0xdeadf11d; + dev_pos2 = 0xdeadf22ddeadf22d; + qpc_pos2 = 0xdeadf33ddeadf33d; + hr = IAudioCaptureClient_GetBuffer(acc, &ptr, &frames2, &flags2, &dev_pos2, &qpc_pos2); + ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Second GetBuffer returns %08lx\n", hr); + ok(broken((uintptr_t)ptr == (uintptr_t)0xdeadf00ddeadf00d) || /* <= win8 */ + !ptr, "Unexpected data after second GetBuffer: %p\n", ptr); + ok(flags2 == 0xdeadf11d, "Unexpected flags after second GetBuffer: %08lx\n", flags2); + ok(dev_pos2 == 0xdeadf22ddeadf22d, "Unexpected device position after second GetBuffer: %I64u\n", dev_pos2); + ok(qpc_pos2 == 0xdeadf33ddeadf33d, "Unexpected QPC position after second GetBuffer: %I64u\n", qpc_pos2);
- hr = IAudioCaptureClient_ReleaseBuffer(acc, 0); - ok(hr == S_OK, "Releasing 0 returns %08lx\n", hr); + hr = IAudioCaptureClient_ReleaseBuffer(acc, 0); + ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr);
- hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); + hr = IAudioCaptureClient_ReleaseBuffer(acc, 0); + ok(hr == S_OK, "Releasing buffer again returns %08lx\n", hr);
- if (frames) { hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer twice returns %08lx\n", hr); - sum += frames; - } - - Sleep(350); /* for sure there's data now */ + ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer again returns %08lx\n", hr);
- hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); + hr = IAudioCaptureClient_GetBuffer(acc, &ptr, &frames2, &flags2, &dev_pos2, &qpc_pos2); + ok(hr == S_OK, "GetBuffer returns %08lx\n", hr);
- /** GetNextPacketSize - * returns either 0 or one period worth of frames - * whereas GetCurrentPadding grows when input is not consumed. */ - hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); - flaky_wine - ok(next < pad, "GetNextPacketSize %u vs. GCP %u\n", next, pad); + ok(frames == frames2, "First GetBuffer returns %u frames, second GetBuffer returns %u\n", + frames, frames2); + ok(flags == flags2, "First GetBuffer returns %08lx flags, second GetBuffer returns %08lx\n", + flags, flags2); + ok(dev_pos == dev_pos2, "First GetBuffer returns %I64u device position, second GetBuffer returns %I64u\n", + dev_pos, dev_pos2); + /* Works with Pulse, but fails with ALSA and CoreAudio. */ + todo_wine_if(qpc_pos != qpc_pos2) + ok(qpc_pos == qpc_pos2, "First GetBuffer returns %I64u device QPC, second GetBuffer returns %I64u\n", + qpc_pos, qpc_pos2);
- hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - ok(next == frames, "GetNextPacketSize %u vs. GetBuffer %u\n", next, frames); + hr = IAudioCaptureClient_ReleaseBuffer(acc, frames - 1); + ok(hr == AUDCLNT_E_INVALID_SIZE, "Releasing buffer with the wrong frame count returns %08lx\n", hr);
- if(hr == S_OK){ - UINT32 frames2 = frames; - UINT64 pos2, qpc2; - ok(frames, "Amount of frames locked is 0!\n"); - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); + hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); + ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr);
hr = IAudioCaptureClient_ReleaseBuffer(acc, 0); - ok(hr == S_OK, "Releasing 0 returns %08lx\n", hr); - - /* GCP did not decrement, no data consumed */ - hr = IAudioClient_GetCurrentPadding(ac, &frames); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - ok(frames == pad || frames == pad + next /* concurrent feeder */, - "GCP %u past ReleaseBuffer(0) initially %u\n", frames, pad); - - /* should re-get the same data */ - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos2, &qpc2); - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - ok(frames2 == frames, "GetBuffer after ReleaseBuffer(0) %u/%u\n", frames2, frames); - ok(pos2 == pos, "Position after ReleaseBuffer(0) %u/%u\n", (UINT)pos2, (UINT)pos); - todo_wine_if(qpc2 != qpc) - /* FIXME: Some drivers fail */ - ok(qpc2 == qpc, "HPC after ReleaseBuffer(0) %u vs. %u\n", (UINT)qpc2, (UINT)qpc); - } - - /* trace after the GCP test because log output to MS-DOS console disturbs timing */ - trace("Sleep.1 position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - - if(hr == S_OK){ - UINT32 frames2 = 0xabadcafe; - BYTE *data2 = (void*)0xdeadf00d; - flags = 0xabadcafe; - - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); + ok(hr == S_OK, "Releasing buffer again returns %08lx\n", hr);
- pos = qpc = 0xdeadbeef; - hr = IAudioCaptureClient_GetBuffer(acc, &data2, &frames2, &flags, &pos, &qpc); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Out of order IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - ok(frames2 == 0xabadcafe, "Out of order frames changed to %x\n", frames2); - ok(broken(data2 == (void*)0xdeadf00d) /* <= win8 */ || - data2 == NULL, "Out of order data changed to %p\n", data2); - ok(flags == 0xabadcafe, "Out of order flags changed to %lx\n", flags); - ok(pos == 0xdeadbeef, "Out of order position changed to %x\n", (UINT)pos); - ok(qpc == 0xdeadbeef, "Out of order timer changed to %x\n", (UINT)qpc); + data->expected_dev_pos = dev_pos + frames;
- hr = IAudioCaptureClient_ReleaseBuffer(acc, frames+1); - ok(hr == AUDCLNT_E_INVALID_SIZE, "Releasing buffer+1 returns %08lx\n", hr); + ++idx;
- hr = IAudioCaptureClient_ReleaseBuffer(acc, 1); - ok(hr == AUDCLNT_E_INVALID_SIZE, "Releasing 1 returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == AUDCLNT_E_NOT_STOPPED, "Reset failed: %08lx\n", hr); + winetest_pop_context(); } +}
- hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); +static void test_capture(IAudioClient *ac, HANDLE handle, WAVEFORMATEX *wfx) +{ + struct read_packets_data data; + IAudioCaptureClient *acc; + UINT32 frames; + DWORD flags; + HRESULT hr; + BYTE *ptr;
- if (frames) { - sum += frames; - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer twice returns %08lx\n", hr); - } + hr = IAudioClient_GetService(ac, &IID_IAudioCaptureClient, (void**)&acc); + ok(hr == S_OK, "IAudioClient_GetService(IID_IAudioCaptureClient) returns %08lx\n", hr); + if (hr != S_OK) + return; + + hr = IAudioClient_Start(ac); + ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr);
- frames = period; - flaky_wine - ok(next == frames, "GetNextPacketSize %u vs. GetDevicePeriod %u\n", next, frames); + hr = IAudioCaptureClient_GetNextPacketSize(acc, NULL); + ok(hr == E_POINTER, "IAudioCaptureClient_GetNextPacketSize(NULL) returns %08lx\n", hr);
- /* GetBufferSize is not a multiple of the period size! */ - hr = IAudioClient_GetBufferSize(ac, &next); - ok(hr == S_OK, "GetBufferSize failed: %08lx\n", hr); - trace("GetBufferSize %u period size %u\n", next, frames); + ptr = (void*)0xdeadf00d; + frames = 0xdeadbeef; + flags = 0xabadcafe; + hr = IAudioCaptureClient_GetBuffer(acc, &ptr, NULL, NULL, NULL, NULL); + ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(data, NULL, NULL) returns %08lx\n", hr);
- Sleep(400); /* overrun */ + hr = IAudioCaptureClient_GetBuffer(acc, NULL, &frames, NULL, NULL, NULL); + ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, &frames, NULL) returns %08lx\n", hr);
- hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); + hr = IAudioCaptureClient_GetBuffer(acc, NULL, NULL, &flags, NULL, NULL); + ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, NULL, &flags) returns %08lx\n", hr);
- hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); + hr = IAudioCaptureClient_GetBuffer(acc, &ptr, &frames, NULL, NULL, NULL); + ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(&ata, &frames, NULL) returns %08lx\n", hr); + ok(broken((uintptr_t)ptr == 0xdeadf00d) /* <= win8 */ + || ptr == NULL, "data is reset to %p\n", ptr); + ok(frames == 0xdeadbeef, "frames is reset to %08x\n", frames); + ok(flags == 0xabadcafe, "flags is reset to %08lx\n", flags);
- trace("Overrun position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); + data.expected_dev_pos = UINT64_MAX;
- if(hr == S_OK){ - if(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY){ - /* Native's position is one period further than what we read. - * Perhaps that's precisely the meaning of DATA_DISCONTINUITY: - * signal when the position jump left a gap. */ - ok(pos >= sum + frames, "Position %u last %u frames %u\n", (UINT)pos, sum, frames); - sum = pos; - }else{ /* win10 */ - ok(pos == sum, "Position %u last %u frames %u\n", (UINT)pos, sum, frames); - } + winetest_push_context("read 10 packets");
- ok(pad == next, "GCP %u vs. BufferSize %u\n", (UINT32)pad, next); - } + read_packets(ac, acc, handle, 10, &data);
- hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - sum += frames; + todo_wine + ok(data.discontinuity_at_0, "No discontinuity at first packet\n"); + ok(!data.discontinuity_at_later, "Discontinuity at later packet\n");
- hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); + winetest_pop_context(); + winetest_push_context("sleep and read 10 packets");
- hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); + /* Wait a bit, but not enough to fill the buffer, so we shouldn't miss anything. */ + Sleep(100);
- trace("Cont'ed position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); + read_packets(ac, acc, handle, 10, &data);
- if(hr == S_OK){ - flaky_wine - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); - flaky_wine - ok(!flags, "flags %lu\n", flags); + ok(!data.discontinuity_at_0, "Discontinuity at first packet\n"); + ok(!data.discontinuity_at_later, "Discontinuity at later packet\n");
- hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - sum += frames; - } + winetest_pop_context(); + winetest_push_context("stop, start and read 10 packets");
hr = IAudioClient_Stop(ac); ok(hr == S_OK, "Stop on a started stream returns %08lx\n", hr);
+ hr = IAudioClient_Stop(ac); + ok(hr == S_FALSE, "Stop on a stopped stream returns %08lx\n", hr); + hr = IAudioClient_Start(ac); ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr);
- hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); + hr = IAudioClient_Start(ac); + ok(hr == AUDCLNT_E_NOT_STOPPED, "Start on a started stream returns %08lx\n", hr);
- hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); + read_packets(ac, acc, handle, 10, &data);
- trace("Restart position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - flaky_wine - ok(pad > sum, "restarted GCP %u\n", pad); /* GCP is still near buffer size */ + ok(!data.discontinuity_at_0, "Discontinuity at first packet\n"); + ok(!data.discontinuity_at_later, "Discontinuity at later packet\n");
- if(frames){ - flaky_wine - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); - ok(!flags, "flags %lu\n", flags); + winetest_pop_context(); + winetest_push_context("stop, reset, start and read 10 packets");
- hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - sum += frames; - } + hr = IAudioClient_Reset(ac); + ok(hr == AUDCLNT_E_NOT_STOPPED, "Reset on a started stream returns %08lx\n", hr);
hr = IAudioClient_Stop(ac); ok(hr == S_OK, "Stop on a started stream returns %08lx\n", hr);
hr = IAudioClient_Reset(ac); ok(hr == S_OK, "Reset on a stopped stream returns %08lx\n", hr); - sum += pad - frames;
- hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - ok(!pad, "reset GCP %u\n", pad); + hr = IAudioClient_Start(ac); + ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr);
- flags = 0xabadcafe; - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - ok(hr == AUDCLNT_S_BUFFER_EMPTY, - "Initial IAudioCaptureClient_GetBuffer returns %08lx\n", hr); + /* Device position is lost when resetting. */ + data.expected_dev_pos = UINT64_MAX;
- trace("Reset position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); + read_packets(ac, acc, handle, 10, &data);
- if(SUCCEEDED(hr)) - IAudioCaptureClient_ReleaseBuffer(acc, frames); + ok(!data.discontinuity_at_0, "Discontinuity at first packet\n"); + ok(!data.discontinuity_at_later, "Discontinuity at later packet\n");
- hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr); + winetest_pop_context(); + winetest_push_context("overrun buffer and read many packets");
- Sleep(180); + /* Now wait too much, to overrun the buffer. By swallowing enough packets + * we should eventually reach a discontinuity. We have a 500 ms buffer and + * normally the period is 10 ms, so 50 packets should be enough. Let's take + * a few more to stay safe. */ + Sleep(600);
- hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); + read_packets(ac, acc, handle, 75, &data);
- hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - trace("Running position %d pad %u flags %lx, amount of frames locked: %u\n", - SUCCEEDED(hr) ? (UINT)pos : -1, pad, flags, frames); + /* Works with Pulse, but fails with ALSA and CoreAudio. */ + todo_wine_if(!data.discontinuity_at_0 && !data.discontinuity_at_later) + ok(data.discontinuity_at_0 || data.discontinuity_at_later, "No discontinuity\n");
- if(SUCCEEDED(hr)){ - /* Some w7 machines signal DATA_DISCONTINUITY here following the - * previous AUDCLNT_S_BUFFER_EMPTY, others not. What logic? */ - ok(pos >= sum, "Position %u gap %d\n", (UINT)pos, (UINT)pos - sum); - IAudioCaptureClient_ReleaseBuffer(acc, frames); - } + winetest_pop_context();
IAudioCaptureClient_Release(acc); }
From: Giovanni Mascellani gmascellani@codeweavers.com
Which makes sense to me given the interface documentation and works on the TestBot and physical machines I have, but doesn't work on the GitLab CI. --- dlls/mmdevapi/tests/render.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 3febeb4c4fb..f9939fbcff6 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -1460,10 +1460,11 @@ 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: %08lx\n", avail, hr); - 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 + /* In theory 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. */ + * Afterwards, only 100ms of data should find room per iteration. + * However on some drivers a large buffer is allowed even at later + * iterations, so we don't explicitly check this. */
if(hr == S_OK) { trace("data at %p\n", data);
Ok, I ended up removing the flaky test, I don't think it's particularly important. The other failures are not related to audio and happen on all other MRs. So I think this is ready for review.
Could we try a bit harder to break this down into smaller changes?