diff --git a/dlls/qcap/audiorecord.c b/dlls/qcap/audiorecord.c index 291ca4452b3..5ece56e97ec 100644 --- a/dlls/qcap/audiorecord.c +++ b/dlls/qcap/audiorecord.c @@ -46,6 +46,7 @@ struct audio_record CRITICAL_SECTION state_cs; AM_MEDIA_TYPE format; + ALLOCATOR_PROPERTIES props; }; static struct audio_record *impl_from_strmbase_filter(struct strmbase_filter *filter) @@ -158,12 +159,18 @@ static HRESULT WINAPI audio_record_source_DecideBufferSize(struct strmbase_sourc MMRESULT ret; HRESULT hr; - props->cBuffers = 4; + props->cBuffers = (filter->props.cBuffers == -1) ? 4 : filter->props.cBuffers; /* This is the algorithm that native uses. The alignment to an even number * doesn't make much sense, and may be a bug. */ - props->cbBuffer = (format->nAvgBytesPerSec / 2) & ~1; - props->cbAlign = 1; - props->cbPrefix = 0; + if (filter->props.cbBuffer == -1) + props->cbBuffer = (format->nAvgBytesPerSec / 2) & ~1; + else + props->cbBuffer = filter->props.cbBuffer & ~1; + if (filter->props.cbAlign == -1 || filter->props.cbAlign == 0) + props->cbAlign = 1; + else + props->cbAlign = filter->props.cbAlign; + props->cbPrefix = (filter->props.cbPrefix == -1) ? 0 : filter->props.cbPrefix; if (FAILED(hr = IMemAllocator_SetProperties(allocator, props, &ret_props))) return hr; @@ -356,10 +363,17 @@ static ULONG WINAPI buffer_negotiation_Release(IAMBufferNegotiation *iface) static HRESULT WINAPI buffer_negotiation_SuggestAllocatorProperties( IAMBufferNegotiation *iface, const ALLOCATOR_PROPERTIES *props) { - FIXME("iface %p, props %p, stub!\n", iface, props); + struct audio_record *filter = impl_from_IAMBufferNegotiation(iface); + + TRACE("filter %p, props %p.\n", filter, props); TRACE("Requested %ld buffers, size %ld, alignment %ld, prefix %ld.\n", props->cBuffers, props->cbBuffer, props->cbAlign, props->cbPrefix); - return E_NOTIMPL; + + EnterCriticalSection(&filter->state_cs); + filter->props = *props; + LeaveCriticalSection(&filter->state_cs); + + return S_OK; } static HRESULT WINAPI buffer_negotiation_GetAllocatorProperties( @@ -788,6 +802,11 @@ HRESULT audio_record_create(IUnknown *outer, IUnknown **out) return hr; } + object->props.cBuffers = -1; + object->props.cbBuffer = -1; + object->props.cbAlign = -1; + object->props.cbPrefix = -1; + object->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl; strmbase_filter_init(&object->filter, outer, &CLSID_AudioRecord, &filter_ops); diff --git a/dlls/qcap/tests/audiorecord.c b/dlls/qcap/tests/audiorecord.c index a5669612351..ed6c54648d0 100644 --- a/dlls/qcap/tests/audiorecord.c +++ b/dlls/qcap/tests/audiorecord.c @@ -618,6 +618,7 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, IPin *source, struct testfilter *testsink) { ALLOCATOR_PROPERTIES props, req_props = {2, 3200, 32, 0}; + IAMBufferNegotiation *negotiation; IMemAllocator *allocator; IMediaSample *sample; WAVEFORMATEX format; @@ -692,6 +693,56 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, IFilterGraph2_Disconnect(graph, source); IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + /* Test IAMBufferNegotiation. *This* is respected. */ + + IPin_QueryInterface(source, &IID_IAMBufferNegotiation, (void **)&negotiation); + + hr = IAMBufferNegotiation_SuggestAllocatorProperties(negotiation, &req_props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&mt, &format, 1, 32000, 16); + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + todo_wine ok(testsink->sink.pAllocator && testsink->sink.pAllocator != allocator, + "Got unexpected allocator %p.\n", testsink->sink.pAllocator); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(props.cBuffers == req_props.cBuffers, "Got %ld buffers.\n", props.cBuffers); + ok(props.cbBuffer == req_props.cbBuffer, "Got size %ld.\n", props.cbBuffer); + ok(props.cbAlign == req_props.cbAlign, "Got alignment %ld.\n", props.cbAlign); + ok(props.cbPrefix == req_props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + for (req_props.cbBuffer = 32000; req_props.cbBuffer < 32050; ++req_props.cbBuffer) + { + req_props.cBuffers = -1; + req_props.cbAlign = 0; + hr = IAMBufferNegotiation_SuggestAllocatorProperties(negotiation, &req_props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&mt, &format, 1, 32000, 8); + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + todo_wine ok(testsink->sink.pAllocator && testsink->sink.pAllocator != allocator, + "Got unexpected allocator %p.\n", testsink->sink.pAllocator); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(props.cBuffers == 4, "Got %ld buffers.\n", props.cBuffers); + ok(props.cbBuffer == (req_props.cbBuffer & ~1), + "Got size %ld for %ld.\n", props.cbBuffer, req_props.cbBuffer); + ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); + ok(props.cbPrefix == req_props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + } + + IAMBufferNegotiation_Release(negotiation); } static void test_filter_state(IFilterGraph2 *graph, IMediaControl *control,