static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user, DWORD_PTR dw1, DWORD_PTR dw2) { DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user; UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0; DWORD flags; BYTE *buf; HRESULT hr; if(!device->ref) return; EnterCriticalSection(&device->lock); if(!device->capture_buffer || device->state == STATE_STOPPED){ LeaveCriticalSection(&device->lock); return; } if(device->state == STATE_STOPPING){ device->state = STATE_STOPPED; LeaveCriticalSection(&device->lock); return; } if(device->state == STATE_STARTING) device->state = STATE_CAPTURING; hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames, &flags, NULL, NULL); if(FAILED(hr)){ LeaveCriticalSection(&device->lock); WARN("GetBuffer failed: %08x\n", hr); return; } packet_bytes = packet_frames * device->pwfx->nBlockAlign; if(packet_bytes > device->buflen){ TRACE("audio glitch: dsound buffer too small for data\n"); skip_bytes = packet_bytes - device->buflen; packet_bytes = device->buflen; } avail_bytes = device->buflen - device->write_pos_bytes; if(avail_bytes > packet_bytes) avail_bytes = packet_bytes; memcpy(device->buffer + device->write_pos_bytes, buf + skip_bytes, avail_bytes); capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes); packet_bytes -= avail_bytes; if(packet_bytes > 0){ if(device->capture_buffer->flags & DSCBSTART_LOOPING){ memcpy(device->buffer, buf + skip_bytes + avail_bytes, packet_bytes); capture_CheckNotify(device->capture_buffer, 0, packet_bytes); }else{ device->state = STATE_STOPPED; capture_CheckNotify(device->capture_buffer, 0, 0); } } device->write_pos_bytes += avail_bytes + packet_bytes; device->write_pos_bytes %= device->buflen; hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames); if(FAILED(hr)){ LeaveCriticalSection(&device->lock); WARN("ReleaseBuffer failed: %08x\n", hr); return; } LeaveCriticalSection(&device->lock); }
static void test_capture(IAudioClient *ac, HANDLE handle, WAVEFORMATEX *wfx) { IAudioCaptureClient *acc; HRESULT hr; UINT32 frames = 0; BYTE *data = NULL; DWORD flags; UINT64 devpos, qpcpos; hr = IAudioClient_GetService(ac, &IID_IAudioCaptureClient, (void**)&acc); ok(hr == S_OK, "IAudioClient_GetService(IID_IAudioCaptureClient) returns %08x\n", hr); if (hr != S_OK) return; hr = IAudioCaptureClient_GetNextPacketSize(acc, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetNextPacketSize(NULL) returns %08x\n", hr); ok(WaitForSingleObject(handle, 2000) == WAIT_OBJECT_0, "Waiting on event handle failed!\n"); /* frames can be 0 if no data is available yet.. */ hr = IAudioCaptureClient_GetNextPacketSize(acc, &frames); ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08x\n", hr); data = (BYTE*)(DWORD_PTR)0xdeadbeef; hr = IAudioCaptureClient_GetBuffer(acc, &data, NULL, NULL, NULL, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(data, NULL, NULL) returns %08x\n", hr); ok((DWORD_PTR)data == 0xdeadbeef, "data is reset to %p\n", data); frames = 0xdeadbeef; hr = IAudioCaptureClient_GetBuffer(acc, NULL, &frames, NULL, NULL, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, &frames, NULL) returns %08x\n", hr); ok(frames == 0xdeadbeef, "frames is reset to %08x\n", frames); flags = 0xdeadbeef; hr = IAudioCaptureClient_GetBuffer(acc, NULL, NULL, &flags, NULL, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, NULL, &flags) returns %08x\n", hr); ok(flags == 0xdeadbeef, "flags is reset to %08x\n", flags); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, NULL, NULL, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(&ata, &frames, NULL) returns %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &devpos, &qpcpos); ok(hr == S_OK || hr == AUDCLNT_S_BUFFER_EMPTY, "Valid IAudioCaptureClient_GetBuffer returns %08x\n", hr); if (hr == S_OK) ok(frames, "Amount of frames locked is 0!\n"); else if (hr == AUDCLNT_S_BUFFER_EMPTY) ok(!frames, "Amount of frames locked with empty buffer is %u!\n", frames); else ok(0, "GetBuffer returned %08x\n", hr); trace("Device position is at %u, amount of frames locked: %u\n", (DWORD)devpos, frames); if (frames) { hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &devpos, &qpcpos); ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Out of order IAudioCaptureClient_GetBuffer returns %08x\n", hr); } hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); if (frames) { hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer twice returns %08x\n", hr); } IUnknown_Release(acc); }
static GstFlowReturn gst_wasapi_src_create (GstPushSrc * src, GstBuffer ** buf) { GstWasapiSrc *self = GST_WASAPI_SRC (src); GstFlowReturn ret = GST_FLOW_OK; GstClock *clock; GstClockTime timestamp, duration = self->period_time; HRESULT hr; gint16 *samples = NULL; guint32 nsamples_read = 0, nsamples; DWORD flags = 0; guint64 devpos; GST_OBJECT_LOCK (self); clock = GST_ELEMENT_CLOCK (self); if (clock != NULL) gst_object_ref (clock); GST_OBJECT_UNLOCK (self); if (clock != NULL && GST_CLOCK_TIME_IS_VALID (self->next_time)) { GstClockID id; id = gst_clock_new_single_shot_id (clock, self->next_time); gst_clock_id_wait (id, NULL); gst_clock_id_unref (id); } do { hr = IAudioCaptureClient_GetBuffer (self->capture_client, (BYTE **) & samples, &nsamples_read, &flags, &devpos, NULL); } while (hr == AUDCLNT_S_BUFFER_EMPTY); if (hr != S_OK) { GST_ERROR_OBJECT (self, "IAudioCaptureClient::GetBuffer () failed: %s", gst_wasapi_util_hresult_to_string (hr)); ret = GST_FLOW_ERROR; goto beach; } if (flags != 0) { GST_WARNING_OBJECT (self, "devpos %" G_GUINT64_FORMAT ": flags=0x%08x", devpos, flags); } /* FIXME: Why do we get 1024 sometimes and not a multiple of * samples_per_buffer? Shouldn't WASAPI provide a DISCONT * flag if we read too slow? */ nsamples = nsamples_read; g_assert (nsamples >= self->samples_per_buffer); if (nsamples > self->samples_per_buffer) { GST_WARNING_OBJECT (self, "devpos %" G_GUINT64_FORMAT ": got %d samples, expected %d, clipping!", devpos, nsamples, self->samples_per_buffer); nsamples = self->samples_per_buffer; } if (clock == NULL || clock == self->clock) { timestamp = gst_util_uint64_scale (devpos, GST_SECOND, self->client_clock_freq); } else { GstClockTime base_time; timestamp = gst_clock_get_time (clock); base_time = GST_ELEMENT_CAST (self)->base_time; if (timestamp > base_time) timestamp -= base_time; else timestamp = 0; if (timestamp > duration) timestamp -= duration; else timestamp = 0; } ret = gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (self), devpos, nsamples * sizeof (gint16), GST_PAD_CAPS (GST_BASE_SRC_PAD (self)), buf); if (ret == GST_FLOW_OK) { guint i; gint16 *dst; GST_BUFFER_OFFSET_END (*buf) = devpos + self->samples_per_buffer; GST_BUFFER_TIMESTAMP (*buf) = timestamp; GST_BUFFER_DURATION (*buf) = duration; dst = (gint16 *) GST_BUFFER_DATA (*buf); for (i = 0; i < nsamples; i++) { *dst = *samples; samples += 2; dst++; } } hr = IAudioCaptureClient_ReleaseBuffer (self->capture_client, nsamples_read); if (hr != S_OK) { GST_ERROR_OBJECT (self, "IAudioCaptureClient::ReleaseBuffer () failed: %s", gst_wasapi_util_hresult_to_string (hr)); ret = GST_FLOW_ERROR; goto beach; } beach: if (clock != NULL) gst_object_unref (clock); return ret; }
static HRESULT DSOUND_capture_data(DirectSoundCaptureDevice *device) { HRESULT hr; UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0; DWORD flags; BYTE *buf; if(!device->capture_buffer || device->state == STATE_STOPPED) return S_FALSE; if(device->state == STATE_STOPPING){ device->state = STATE_STOPPED; return S_FALSE; } if(device->state == STATE_STARTING) device->state = STATE_CAPTURING; hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames, &flags, NULL, NULL); if(FAILED(hr)){ WARN("GetBuffer failed: %08x\n", hr); return hr; } packet_bytes = packet_frames * device->pwfx->nBlockAlign; if(packet_bytes > device->buflen){ TRACE("audio glitch: dsound buffer too small for data\n"); skip_bytes = packet_bytes - device->buflen; packet_bytes = device->buflen; } avail_bytes = device->buflen - device->write_pos_bytes; if(avail_bytes > packet_bytes) avail_bytes = packet_bytes; memcpy(device->buffer + device->write_pos_bytes, buf + skip_bytes, avail_bytes); capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes); packet_bytes -= avail_bytes; if(packet_bytes > 0){ if(device->capture_buffer->flags & DSCBSTART_LOOPING){ memcpy(device->buffer, buf + skip_bytes + avail_bytes, packet_bytes); capture_CheckNotify(device->capture_buffer, 0, packet_bytes); }else{ device->state = STATE_STOPPED; capture_CheckNotify(device->capture_buffer, 0, 0); } } device->write_pos_bytes += avail_bytes + packet_bytes; device->write_pos_bytes %= device->buflen; hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames); if(FAILED(hr)){ WARN("ReleaseBuffer failed: %08x\n", hr); return hr; } return S_OK; }
JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_wasapi_WASAPI_IAudioCaptureClient_1Read (JNIEnv *env, jclass clazz, jlong thiz, jbyteArray data, jint offset, jint length, jint srcSampleSize, jint srcChannels, jint dstSampleSize, jint dstChannels) { HRESULT hr; IAudioCaptureClient *iAudioCaptureClient = (IAudioCaptureClient *) (intptr_t) thiz; BYTE *pData; UINT32 numFramesToRead; DWORD dwFlags; jint read; hr = IAudioCaptureClient_GetBuffer( iAudioCaptureClient, &pData, &numFramesToRead, &dwFlags, NULL, NULL); if (SUCCEEDED(hr)) { UINT32 numFramesRead; jint dstFrameSize = dstSampleSize * dstChannels; if ((numFramesToRead == 0) || (hr == AUDCLNT_S_BUFFER_EMPTY)) numFramesRead = 0; else { if (length < numFramesToRead * dstFrameSize) { numFramesRead = 0; WASAPI_throwNewHResultException( env, E_INVALIDARG, __func__, __LINE__); } else { jbyte *data_ = (*env)->GetPrimitiveArrayCritical(env, data, NULL); if (data_) { numFramesRead = WASAPI_audiocopy( pData, srcSampleSize, srcChannels, data_ + offset, dstSampleSize, dstChannels, numFramesToRead); (*env)->ReleasePrimitiveArrayCritical(env, data, data_, 0); } else numFramesRead = 0; /* An OutOfMemoryError has been thrown. */ } } hr = IAudioCaptureClient_ReleaseBuffer( iAudioCaptureClient, numFramesRead); read = numFramesRead * dstFrameSize; if (FAILED(hr)) WASAPI_throwNewHResultException(env, hr, __func__, __LINE__); } else { read = 0; WASAPI_throwNewHResultException(env, hr, __func__, __LINE__); } return read; }
static void test_capture(IAudioClient *ac, HANDLE handle, WAVEFORMATEX *wfx) { 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 %08x\n", hr); if (hr != S_OK) return; frames = 0xabadcafe; data = (void*)0xdeadf00d; flags = 0xabadcafe; pos = qpc = 0xdeadbeef; hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == AUDCLNT_S_BUFFER_EMPTY, "Initial IAudioCaptureClient_GetBuffer returns %08x\n", hr); /* should be empty right after start. Otherwise consume one packet */ if(hr == S_OK){ hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); sum += frames; frames = 0xabadcafe; data = (void*)0xdeadf00d; flags = 0xabadcafe; pos = qpc = 0xdeadbeef; hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == AUDCLNT_S_BUFFER_EMPTY, "Initial IAudioCaptureClient_GetBuffer returns %08x\n", hr); } if(hr == AUDCLNT_S_BUFFER_EMPTY){ ok(!frames, "frames changed to %u\n", frames); ok(data == (void*)0xdeadf00d, "data changed to %p\n", data); ok(flags == 0xabadcafe, "flags changed to %x\n", flags); ok(pos == 0xdeadbeef, "position changed to %u\n", (UINT)pos); ok(qpc == 0xdeadbeef, "timer changed to %u\n", (UINT)qpc); /* GetNextPacketSize yields 0 if no data is yet available * it is not constantly period_size * SamplesPerSec */ hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08x\n", hr); ok(!next, "GetNextPacketSize %u\n", next); } hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); sum += frames; ok(ResetEvent(handle), "ResetEvent\n"); hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08x\n", hr); hr = IAudioClient_GetCurrentPadding(ac, &pad); ok(hr == S_OK, "GetCurrentPadding call returns %08x\n", hr); ok(next == pad, "GetNextPacketSize %u vs. GCP %u\n", next, pad); /* later GCP will grow, while GNPS is 0 or period size */ hr = IAudioCaptureClient_GetNextPacketSize(acc, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetNextPacketSize(NULL) returns %08x\n", hr); 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 %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, NULL, &frames, NULL, NULL, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, &frames, NULL) returns %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, NULL, NULL, &flags, NULL, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, NULL, &flags) returns %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, NULL, NULL, NULL); ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(&ata, &frames, NULL) returns %08x\n", hr); ok((DWORD_PTR)data == 0xdeadf00d, "data is reset to %p\n", data); ok(frames == 0xdeadbeef, "frames is reset to %08x\n", frames); ok(flags == 0xabadcafe, "flags is reset to %08x\n", flags); hr = IAudioClient_GetDevicePeriod(ac, &period, NULL); ok(hr == S_OK, "GetDevicePeriod failed: %08x\n", hr); period = MulDiv(period, wfx->nSamplesPerSec, 10000000); /* as in render.c */ 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 %08x\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(pos == period || pos == 2*period), "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(data == (void*)0xdeadf00d, "No data changed to %p\n", data); } trace("Wait'ed position %d pad %u flags %x, amount of frames locked: %u\n", hr==S_OK ? (UINT)pos : -1, pad, flags, frames); hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08x\n", hr); ok(next == frames, "GetNextPacketSize %u vs. GetBuffer %u\n", next, frames); hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); hr = IAudioCaptureClient_ReleaseBuffer(acc, 0); ok(hr == S_OK, "Releasing 0 returns %08x\n", hr); hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08x\n", hr); if (frames) { hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer twice returns %08x\n", hr); sum += frames; } Sleep(350); /* for sure there's data now */ hr = IAudioClient_GetCurrentPadding(ac, &pad); ok(hr == S_OK, "GetCurrentPadding call returns %08x\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 %08x\n", hr); ok(next < pad, "GetNextPacketSize %u vs. GCP %u\n", next, pad); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08x\n", hr); ok(next == frames, "GetNextPacketSize %u vs. GetBuffer %u\n", next, frames); 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, 0); ok(hr == S_OK, "Releasing 0 returns %08x\n", hr); /* GCP did not decrement, no data consumed */ hr = IAudioClient_GetCurrentPadding(ac, &frames); ok(hr == S_OK, "GetCurrentPadding call returns %08x\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 %08x\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 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 %x, 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); 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 %08x\n", hr); ok(frames2 == 0xabadcafe, "Out of order frames changed to %x\n", frames2); ok(data2 == (void*)0xdeadf00d, "Out of order data changed to %p\n", data2); ok(flags == 0xabadcafe, "Out of order flags changed to %x\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); hr = IAudioCaptureClient_ReleaseBuffer(acc, frames+1); ok(hr == AUDCLNT_E_INVALID_SIZE, "Releasing buffer+1 returns %08x\n", hr); hr = IAudioCaptureClient_ReleaseBuffer(acc, 1); ok(hr == AUDCLNT_E_INVALID_SIZE, "Releasing 1 returns %08x\n", hr); hr = IAudioClient_Reset(ac); ok(hr == AUDCLNT_E_NOT_STOPPED, "Reset failed: %08x\n", hr); } hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); if (frames) { sum += frames; hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer twice returns %08x\n", hr); } frames = period; ok(next == frames, "GetNextPacketSize %u vs. GetDevicePeriod %u\n", next, frames); /* GetBufferSize is not a multiple of the period size! */ hr = IAudioClient_GetBufferSize(ac, &next); ok(hr == S_OK, "GetBufferSize failed: %08x\n", hr); trace("GetBufferSize %u period size %u\n", next, frames); Sleep(400); /* overrun */ hr = IAudioClient_GetCurrentPadding(ac, &pad); ok(hr == S_OK, "GetCurrentPadding call returns %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08x\n", hr); trace("Overrun position %d pad %u flags %x, amount of frames locked: %u\n", hr==S_OK ? (UINT)pos : -1, pad, flags, frames); if(hr == S_OK){ /* The discontinuity is reported here, but is this an old or new packet? */ todo_wine ok(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY, "expect DISCONTINUITY %x\n", flags); ok(pad == next, "GCP %u vs. BufferSize %u\n", (UINT32)pad, next); /* 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. */ todo_wine ok(pos == sum + frames, "Position %u gap %d\n", (UINT)pos, (UINT)pos - sum); if(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) sum = pos; } hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); sum += frames; hr = IAudioClient_GetCurrentPadding(ac, &pad); ok(hr == S_OK, "GetCurrentPadding call returns %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08x\n", hr); trace("Cont'ed position %d pad %u flags %x, amount of frames locked: %u\n", hr==S_OK ? (UINT)pos : -1, pad, flags, frames); if(hr == S_OK){ ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); ok(!flags, "flags %u\n", flags); hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); sum += frames; } hr = IAudioClient_Stop(ac); ok(hr == S_OK, "Stop on a started stream returns %08x\n", hr); hr = IAudioClient_Start(ac); ok(hr == S_OK, "Start on a stopped stream returns %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08x\n", hr); hr = IAudioClient_GetCurrentPadding(ac, &pad); ok(hr == S_OK, "GetCurrentPadding call returns %08x\n", hr); trace("Restart position %d pad %u flags %x, amount of frames locked: %u\n", hr==S_OK ? (UINT)pos : -1, pad, flags, frames); ok(pad > sum, "restarted GCP %u\n", pad); /* GCP is still near buffer size */ if(frames){ ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); ok(!flags, "flags %u\n", flags); hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); sum += frames; } hr = IAudioClient_Stop(ac); ok(hr == S_OK, "Stop on a started stream returns %08x\n", hr); hr = IAudioClient_Reset(ac); ok(hr == S_OK, "Reset on a stopped stream returns %08x\n", hr); sum += pad - frames; hr = IAudioClient_Start(ac); ok(hr == S_OK, "Start on a stopped stream returns %08x\n", hr); hr = IAudioClient_GetCurrentPadding(ac, &pad); ok(hr == S_OK, "GetCurrentPadding call returns %08x\n", hr); flags = 0xabadcafe; hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == AUDCLNT_S_BUFFER_EMPTY || /*PulseAudio*/hr == S_OK, "Initial IAudioCaptureClient_GetBuffer returns %08x\n", hr); trace("Reset position %d pad %u flags %x, amount of frames locked: %u\n", hr==S_OK ? (UINT)pos : -1, pad, flags, frames); if(hr == S_OK){ /* Only PulseAudio goes here; despite snd_pcm_drop it manages * to fill GetBufferSize with a single snd_pcm_read */ trace("Test marked todo: only PulseAudio gets here\n"); todo_wine ok(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY, "expect DISCONTINUITY %x\n", flags); /* Reset zeroes padding, not the position */ ok(pos >= sum, "Position %u last %u\n", (UINT)pos, sum); /*sum = pos; check after next GetBuffer */ hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); ok(hr == S_OK, "Releasing buffer returns %08x\n", hr); sum += frames; } else if(hr == AUDCLNT_S_BUFFER_EMPTY){ ok(!pad, "resetted GCP %u\n", pad); Sleep(180); } hr = IAudioClient_GetCurrentPadding(ac, &pad); ok(hr == S_OK, "GetCurrentPadding call returns %08x\n", hr); hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08x\n", hr); trace("Running position %d pad %u flags %x, amount of frames locked: %u\n", hr==S_OK ? (UINT)pos : -1, pad, flags, frames); if(hr == S_OK){ /* 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); } IAudioCaptureClient_Release(acc); }