dmime/tests: Check more notification / dirty messages fields.
[wine.git] / dlls / amstream / audiostream.c
blobd76156cb68243ae7944343dd2852e459b99125ab
1 /*
2 * Primary audio stream
4 * Copyright 2012 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
22 #include "amstream_private.h"
23 #include "wine/debug.h"
24 #include "wine/list.h"
25 #include "wine/strmbase.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
29 static const WCHAR sink_id[] = L"I{A35FF56B-9FDA-11D0-8FDF-00C04FD9189D}";
31 struct queued_receive
33 struct list entry;
34 IMediaSample *sample;
35 DWORD length;
36 BYTE *pointer;
37 DWORD position;
38 STREAM_TIME start_time;
41 struct audio_stream
43 IAMMediaStream IAMMediaStream_iface;
44 IAudioMediaStream IAudioMediaStream_iface;
45 IMemInputPin IMemInputPin_iface;
46 IPin IPin_iface;
47 LONG ref;
49 IMultiMediaStream* parent;
50 MSPID purpose_id;
51 STREAM_TYPE stream_type;
52 CRITICAL_SECTION cs;
53 IMediaStreamFilter *filter;
55 IPin *peer;
56 IMemAllocator *allocator;
57 AM_MEDIA_TYPE mt;
58 WAVEFORMATEX format;
59 FILTER_STATE state;
60 REFERENCE_TIME segment_start;
61 BOOL eos;
62 BOOL flushing;
63 struct list receive_queue;
64 struct list update_queue;
67 struct audio_sample
69 IAudioStreamSample IAudioStreamSample_iface;
70 LONG ref;
71 struct audio_stream *parent;
72 IAudioData *audio_data;
73 STREAM_TIME start_time;
74 STREAM_TIME end_time;
75 HANDLE update_event;
77 struct list entry;
78 DWORD length;
79 BYTE *pointer;
80 DWORD position;
81 HRESULT update_hr;
84 static void remove_queued_receive(struct queued_receive *receive)
86 list_remove(&receive->entry);
87 IMediaSample_Release(receive->sample);
88 free(receive);
91 static void remove_queued_update(struct audio_sample *sample)
93 HRESULT hr;
95 hr = IAudioData_SetActual(sample->audio_data, sample->position);
96 if (FAILED(hr))
97 sample->update_hr = hr;
99 list_remove(&sample->entry);
100 SetEvent(sample->update_event);
103 static void flush_receive_queue(struct audio_stream *stream)
105 struct list *entry;
107 while ((entry = list_head(&stream->receive_queue)))
108 remove_queued_receive(LIST_ENTRY(entry, struct queued_receive, entry));
111 static STREAM_TIME stream_time_from_position(struct audio_stream *stream, struct queued_receive *receive)
113 const WAVEFORMATEX *format = (WAVEFORMATEX *)stream->mt.pbFormat;
114 return receive->start_time + (receive->position * 10000000 + format->nAvgBytesPerSec / 2) / format->nAvgBytesPerSec;
117 static void process_update(struct audio_sample *sample, struct queued_receive *receive)
119 DWORD advance;
121 advance = min(receive->length - receive->position, sample->length - sample->position);
122 memcpy(&sample->pointer[sample->position], &receive->pointer[receive->position], advance);
124 if (!sample->position)
125 sample->start_time = stream_time_from_position(sample->parent, receive);
127 receive->position += advance;
128 sample->position += advance;
130 sample->end_time = stream_time_from_position(sample->parent, receive);
132 sample->update_hr = (sample->position == sample->length) ? S_OK : MS_S_PENDING;
135 static void process_updates(struct audio_stream *stream)
137 while (!list_empty(&stream->update_queue) && !list_empty(&stream->receive_queue))
139 struct audio_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct audio_sample, entry);
140 struct queued_receive *receive = LIST_ENTRY(list_head(&stream->receive_queue), struct queued_receive, entry);
142 process_update(sample, receive);
144 if (sample->update_hr != MS_S_PENDING)
145 remove_queued_update(sample);
146 if (receive->position == receive->length)
147 remove_queued_receive(receive);
149 if (stream->eos)
151 while (!list_empty(&stream->update_queue))
153 struct audio_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct audio_sample, entry);
155 sample->update_hr = sample->position ? S_OK : MS_S_ENDOFSTREAM;
156 remove_queued_update(sample);
161 static inline struct audio_sample *impl_from_IAudioStreamSample(IAudioStreamSample *iface)
163 return CONTAINING_RECORD(iface, struct audio_sample, IAudioStreamSample_iface);
166 /*** IUnknown methods ***/
167 static HRESULT WINAPI audio_sample_QueryInterface(IAudioStreamSample *iface,
168 REFIID riid, void **ret_iface)
170 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
172 if (IsEqualGUID(riid, &IID_IUnknown) ||
173 IsEqualGUID(riid, &IID_IStreamSample) ||
174 IsEqualGUID(riid, &IID_IAudioStreamSample))
176 IAudioStreamSample_AddRef(iface);
177 *ret_iface = iface;
178 return S_OK;
181 *ret_iface = NULL;
183 ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
184 return E_NOINTERFACE;
187 static ULONG WINAPI audio_sample_AddRef(IAudioStreamSample *iface)
189 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
190 ULONG refcount = InterlockedIncrement(&sample->ref);
191 TRACE("%p increasing refcount to %lu.\n", sample, refcount);
192 return refcount;
195 static ULONG WINAPI audio_sample_Release(IAudioStreamSample *iface)
197 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
198 ULONG refcount = InterlockedDecrement(&sample->ref);
199 TRACE("%p decreasing refcount to %lu.\n", sample, refcount);
200 if (!refcount)
202 IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
203 IAudioData_Release(sample->audio_data);
204 CloseHandle(sample->update_event);
205 free(sample);
207 return refcount;
210 /*** IStreamSample methods ***/
211 static HRESULT WINAPI audio_sample_GetMediaStream(IAudioStreamSample *iface, IMediaStream **media_stream)
213 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
215 TRACE("sample %p, media_stream %p.\n", iface, media_stream);
217 if (!media_stream)
218 return E_POINTER;
220 IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
221 *media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
223 return S_OK;
226 static HRESULT WINAPI audio_sample_GetSampleTimes(IAudioStreamSample *iface, STREAM_TIME *start_time,
227 STREAM_TIME *end_time, STREAM_TIME *current_time)
229 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
231 TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
233 if (current_time)
234 IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
236 if (start_time)
237 *start_time = sample->start_time;
238 if (end_time)
239 *end_time = sample->end_time;
241 return S_OK;
244 static HRESULT WINAPI audio_sample_SetSampleTimes(IAudioStreamSample *iface, const STREAM_TIME *start_time,
245 const STREAM_TIME *end_time)
247 FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
249 return E_NOTIMPL;
252 static HRESULT WINAPI audio_sample_Update(IAudioStreamSample *iface,
253 DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
255 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
256 BYTE *pointer;
257 DWORD length;
258 HRESULT hr;
260 TRACE("sample %p, flags %#lx, event %p, apc_func %p, apc_data %#lx.\n",
261 sample, flags, event, apc_func, apc_data);
263 hr = IAudioData_GetInfo(sample->audio_data, &length, &pointer, NULL);
264 if (FAILED(hr))
265 return hr;
267 if (event && apc_func)
268 return E_INVALIDARG;
270 if (apc_func)
272 FIXME("APC support is not implemented!\n");
273 return E_NOTIMPL;
276 if (event)
278 FIXME("Event parameter support is not implemented!\n");
279 return E_NOTIMPL;
282 if (flags & ~SSUPDATE_ASYNC)
284 FIXME("Unsupported flags %#lx.\n", flags);
285 return E_NOTIMPL;
288 EnterCriticalSection(&sample->parent->cs);
290 if (sample->parent->state != State_Running)
292 LeaveCriticalSection(&sample->parent->cs);
293 return MS_E_NOTRUNNING;
295 if (!sample->parent->peer)
297 LeaveCriticalSection(&sample->parent->cs);
298 return MS_S_ENDOFSTREAM;
300 if (MS_S_PENDING == sample->update_hr)
302 LeaveCriticalSection(&sample->parent->cs);
303 return MS_E_BUSY;
306 sample->length = length;
307 sample->pointer = pointer;
308 sample->position = 0;
309 sample->update_hr = MS_S_PENDING;
310 ResetEvent(sample->update_event);
311 list_add_tail(&sample->parent->update_queue, &sample->entry);
313 process_updates(sample->parent);
314 hr = sample->update_hr;
316 LeaveCriticalSection(&sample->parent->cs);
318 if (hr != MS_S_PENDING || (flags & SSUPDATE_ASYNC))
319 return hr;
321 WaitForSingleObject(sample->update_event, INFINITE);
323 return sample->update_hr;
326 static HRESULT WINAPI audio_sample_CompletionStatus(IAudioStreamSample *iface, DWORD flags, DWORD milliseconds)
328 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
329 HRESULT hr;
331 TRACE("sample %p, flags %#lx, milliseconds %lu.\n", sample, flags, milliseconds);
333 if (flags)
335 FIXME("Unhandled flags %#lx.\n", flags);
336 return E_NOTIMPL;
339 EnterCriticalSection(&sample->parent->cs);
341 hr = sample->update_hr;
343 LeaveCriticalSection(&sample->parent->cs);
345 return hr;
348 /*** IAudioStreamSample methods ***/
349 static HRESULT WINAPI audio_sample_GetAudioData(IAudioStreamSample *iface, IAudioData **audio_data)
351 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
353 TRACE("sample %p, audio_data %p.\n", sample, audio_data);
355 if (!audio_data)
356 return E_POINTER;
358 IAudioData_AddRef(sample->audio_data);
359 *audio_data = sample->audio_data;
361 return S_OK;
364 static const struct IAudioStreamSampleVtbl AudioStreamSample_Vtbl =
366 /*** IUnknown methods ***/
367 audio_sample_QueryInterface,
368 audio_sample_AddRef,
369 audio_sample_Release,
370 /*** IStreamSample methods ***/
371 audio_sample_GetMediaStream,
372 audio_sample_GetSampleTimes,
373 audio_sample_SetSampleTimes,
374 audio_sample_Update,
375 audio_sample_CompletionStatus,
376 /*** IAudioStreamSample methods ***/
377 audio_sample_GetAudioData
380 static HRESULT audiostreamsample_create(struct audio_stream *parent, IAudioData *audio_data, IAudioStreamSample **audio_stream_sample)
382 struct audio_sample *object;
384 TRACE("(%p)\n", audio_stream_sample);
386 if (!(object = calloc(1, sizeof(*object))))
387 return E_OUTOFMEMORY;
389 object->IAudioStreamSample_iface.lpVtbl = &AudioStreamSample_Vtbl;
390 object->ref = 1;
391 object->parent = parent;
392 IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
393 object->audio_data = audio_data;
394 IAudioData_AddRef(audio_data);
395 object->update_event = CreateEventW(NULL, FALSE, FALSE, NULL);
397 *audio_stream_sample = &object->IAudioStreamSample_iface;
399 return S_OK;
402 static inline struct audio_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
404 return CONTAINING_RECORD(iface, struct audio_stream, IAMMediaStream_iface);
407 /*** IUnknown methods ***/
408 static HRESULT WINAPI audio_IAMMediaStream_QueryInterface(IAMMediaStream *iface,
409 REFIID riid, void **ret_iface)
411 struct audio_stream *This = impl_from_IAMMediaStream(iface);
413 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
415 if (IsEqualGUID(riid, &IID_IUnknown) ||
416 IsEqualGUID(riid, &IID_IMediaStream) ||
417 IsEqualGUID(riid, &IID_IAMMediaStream))
419 IAMMediaStream_AddRef(iface);
420 *ret_iface = iface;
421 return S_OK;
423 else if (IsEqualGUID(riid, &IID_IAudioMediaStream))
425 IAMMediaStream_AddRef(iface);
426 *ret_iface = &This->IAudioMediaStream_iface;
427 return S_OK;
429 else if (IsEqualGUID(riid, &IID_IPin))
431 IAMMediaStream_AddRef(iface);
432 *ret_iface = &This->IPin_iface;
433 return S_OK;
435 else if (IsEqualGUID(riid, &IID_IMemInputPin))
437 IAMMediaStream_AddRef(iface);
438 *ret_iface = &This->IMemInputPin_iface;
439 return S_OK;
442 ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface);
443 return E_NOINTERFACE;
446 static ULONG WINAPI audio_IAMMediaStream_AddRef(IAMMediaStream *iface)
448 struct audio_stream *This = impl_from_IAMMediaStream(iface);
449 ULONG ref = InterlockedIncrement(&This->ref);
451 TRACE("(%p/%p)->(): new ref = %lu\n", iface, This, ref);
453 return ref;
456 static ULONG WINAPI audio_IAMMediaStream_Release(IAMMediaStream *iface)
458 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
459 ULONG ref = InterlockedDecrement(&stream->ref);
461 TRACE("%p decreasing refcount to %lu.\n", stream, ref);
463 if (!ref)
465 DeleteCriticalSection(&stream->cs);
466 free(stream);
469 return ref;
472 /*** IMediaStream methods ***/
473 static HRESULT WINAPI audio_IAMMediaStream_GetMultiMediaStream(IAMMediaStream *iface,
474 IMultiMediaStream **mmstream)
476 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
478 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
480 if (!mmstream)
481 return E_POINTER;
483 if (stream->parent)
484 IMultiMediaStream_AddRef(stream->parent);
485 *mmstream = stream->parent;
486 return S_OK;
489 static HRESULT WINAPI audio_IAMMediaStream_GetInformation(IAMMediaStream *iface,
490 MSPID *purpose_id, STREAM_TYPE *type)
492 struct audio_stream *This = impl_from_IAMMediaStream(iface);
494 TRACE("(%p/%p)->(%p,%p)\n", This, iface, purpose_id, type);
496 if (purpose_id)
497 *purpose_id = This->purpose_id;
498 if (type)
499 *type = This->stream_type;
501 return S_OK;
504 static HRESULT WINAPI audio_IAMMediaStream_SetSameFormat(IAMMediaStream *iface,
505 IMediaStream *pStreamThatHasDesiredFormat, DWORD flags)
507 struct audio_stream *This = impl_from_IAMMediaStream(iface);
509 FIXME("(%p/%p)->(%p,%lx) stub!\n", This, iface, pStreamThatHasDesiredFormat, flags);
511 return S_FALSE;
514 static HRESULT WINAPI audio_IAMMediaStream_AllocateSample(IAMMediaStream *iface,
515 DWORD flags, IStreamSample **sample)
517 struct audio_stream *This = impl_from_IAMMediaStream(iface);
519 FIXME("(%p/%p)->(%lx,%p) stub!\n", This, iface, flags, sample);
521 return S_FALSE;
524 static HRESULT WINAPI audio_IAMMediaStream_CreateSharedSample(IAMMediaStream *iface,
525 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
527 struct audio_stream *This = impl_from_IAMMediaStream(iface);
529 FIXME("(%p/%p)->(%p,%lx,%p) stub!\n", This, iface, existing_sample, flags, sample);
531 return S_FALSE;
534 static HRESULT WINAPI audio_IAMMediaStream_SendEndOfStream(IAMMediaStream *iface, DWORD flags)
536 struct audio_stream *This = impl_from_IAMMediaStream(iface);
538 FIXME("(%p/%p)->(%lx) stub!\n", This, iface, flags);
540 return S_FALSE;
543 /*** IAMMediaStream methods ***/
544 static HRESULT WINAPI audio_IAMMediaStream_Initialize(IAMMediaStream *iface, IUnknown *source_object, DWORD flags,
545 REFMSPID purpose_id, const STREAM_TYPE stream_type)
547 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
549 TRACE("stream %p, source_object %p, flags %lx, purpose_id %s, stream_type %u.\n", stream, source_object, flags,
550 debugstr_guid(purpose_id), stream_type);
552 if (!purpose_id)
553 return E_POINTER;
555 if (source_object)
556 FIXME("Specifying a stream object is not yet supported.\n");
558 if (flags & AMMSF_CREATEPEER)
559 FIXME("AMMSF_CREATEPEER is not yet supported.\n");
561 stream->purpose_id = *purpose_id;
562 stream->stream_type = stream_type;
564 return S_OK;
567 static HRESULT WINAPI audio_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state)
569 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
571 TRACE("stream %p, state %u.\n", stream, state);
573 EnterCriticalSection(&stream->cs);
575 if (state == State_Stopped)
576 flush_receive_queue(stream);
577 if (stream->state == State_Stopped)
578 stream->eos = FALSE;
580 stream->state = state;
582 LeaveCriticalSection(&stream->cs);
584 return S_OK;
587 static HRESULT WINAPI audio_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface,
588 IAMMultiMediaStream *mmstream)
590 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
592 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
594 stream->parent = (IMultiMediaStream *)mmstream;
596 return S_OK;
599 static HRESULT WINAPI audio_IAMMediaStream_JoinFilter(IAMMediaStream *iface, IMediaStreamFilter *filter)
601 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
603 TRACE("stream %p, filter %p.\n", stream, filter);
605 stream->filter = filter;
607 return S_OK;
610 static HRESULT WINAPI audio_IAMMediaStream_JoinFilterGraph(IAMMediaStream *iface, IFilterGraph *filtergraph)
612 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
614 TRACE("stream %p, filtergraph %p.\n", stream, filtergraph);
616 return S_OK;
619 static const struct IAMMediaStreamVtbl audio_IAMMediaStream_vtbl =
621 audio_IAMMediaStream_QueryInterface,
622 audio_IAMMediaStream_AddRef,
623 audio_IAMMediaStream_Release,
624 audio_IAMMediaStream_GetMultiMediaStream,
625 audio_IAMMediaStream_GetInformation,
626 audio_IAMMediaStream_SetSameFormat,
627 audio_IAMMediaStream_AllocateSample,
628 audio_IAMMediaStream_CreateSharedSample,
629 audio_IAMMediaStream_SendEndOfStream,
630 audio_IAMMediaStream_Initialize,
631 audio_IAMMediaStream_SetState,
632 audio_IAMMediaStream_JoinAMMultiMediaStream,
633 audio_IAMMediaStream_JoinFilter,
634 audio_IAMMediaStream_JoinFilterGraph,
637 static inline struct audio_stream *impl_from_IAudioMediaStream(IAudioMediaStream *iface)
639 return CONTAINING_RECORD(iface, struct audio_stream, IAudioMediaStream_iface);
642 /*** IUnknown methods ***/
643 static HRESULT WINAPI audio_IAudioMediaStream_QueryInterface(IAudioMediaStream *iface,
644 REFIID riid, void **ret_iface)
646 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
647 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
648 return IAMMediaStream_QueryInterface(&This->IAMMediaStream_iface, riid, ret_iface);
651 static ULONG WINAPI audio_IAudioMediaStream_AddRef(IAudioMediaStream *iface)
653 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
654 TRACE("(%p/%p)\n", iface, This);
655 return IAMMediaStream_AddRef(&This->IAMMediaStream_iface);
658 static ULONG WINAPI audio_IAudioMediaStream_Release(IAudioMediaStream *iface)
660 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
661 TRACE("(%p/%p)\n", iface, This);
662 return IAMMediaStream_Release(&This->IAMMediaStream_iface);
665 static HRESULT WINAPI audio_IAudioMediaStream_GetMultiMediaStream(IAudioMediaStream *iface,
666 IMultiMediaStream **mmstream)
668 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
669 return IAMMediaStream_GetMultiMediaStream(&stream->IAMMediaStream_iface, mmstream);
672 static HRESULT WINAPI audio_IAudioMediaStream_GetInformation(IAudioMediaStream *iface,
673 MSPID *purpose_id, STREAM_TYPE *type)
675 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
676 return IAMMediaStream_GetInformation(&stream->IAMMediaStream_iface, purpose_id, type);
679 static HRESULT WINAPI audio_IAudioMediaStream_SetSameFormat(IAudioMediaStream *iface,
680 IMediaStream *other, DWORD flags)
682 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
683 return IAMMediaStream_SetSameFormat(&stream->IAMMediaStream_iface, other, flags);
686 static HRESULT WINAPI audio_IAudioMediaStream_AllocateSample(IAudioMediaStream *iface,
687 DWORD flags, IStreamSample **sample)
689 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
690 return IAMMediaStream_AllocateSample(&stream->IAMMediaStream_iface, flags, sample);
693 static HRESULT WINAPI audio_IAudioMediaStream_CreateSharedSample(IAudioMediaStream *iface,
694 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
696 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
697 return IAMMediaStream_CreateSharedSample(&stream->IAMMediaStream_iface, existing_sample, flags, sample);
700 static HRESULT WINAPI audio_IAudioMediaStream_SendEndOfStream(IAudioMediaStream *iface, DWORD flags)
702 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
703 return IAMMediaStream_SendEndOfStream(&stream->IAMMediaStream_iface, flags);
706 /*** IAudioMediaStream methods ***/
707 static HRESULT WINAPI audio_IAudioMediaStream_GetFormat(IAudioMediaStream *iface, WAVEFORMATEX *format)
709 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
711 TRACE("stream %p, format %p.\n", stream, format);
713 if (!format)
714 return E_POINTER;
716 EnterCriticalSection(&stream->cs);
718 if (!stream->peer)
720 LeaveCriticalSection(&stream->cs);
721 return MS_E_NOSTREAM;
724 *format = *(WAVEFORMATEX *)stream->mt.pbFormat;
726 LeaveCriticalSection(&stream->cs);
728 return S_OK;
731 static HRESULT WINAPI audio_IAudioMediaStream_SetFormat(IAudioMediaStream *iface, const WAVEFORMATEX *format)
733 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
735 TRACE("stream %p, format %p.\n", stream, format);
737 if (!format)
738 return E_POINTER;
740 if (format->wFormatTag != WAVE_FORMAT_PCM)
741 return E_INVALIDARG;
743 EnterCriticalSection(&stream->cs);
745 if ((stream->peer && memcmp(format, stream->mt.pbFormat, sizeof(WAVEFORMATEX)))
746 || (stream->format.wFormatTag && memcmp(format, &stream->format, sizeof(WAVEFORMATEX))))
748 LeaveCriticalSection(&stream->cs);
749 return E_INVALIDARG;
752 stream->format = *format;
754 LeaveCriticalSection(&stream->cs);
756 return S_OK;
759 static HRESULT WINAPI audio_IAudioMediaStream_CreateSample(IAudioMediaStream *iface, IAudioData *audio_data,
760 DWORD flags, IAudioStreamSample **sample)
762 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
764 TRACE("(%p/%p)->(%p,%lu,%p)\n", iface, This, audio_data, flags, sample);
766 if (!audio_data)
767 return E_POINTER;
769 return audiostreamsample_create(This, audio_data, sample);
772 static const struct IAudioMediaStreamVtbl audio_IAudioMediaStream_vtbl =
774 audio_IAudioMediaStream_QueryInterface,
775 audio_IAudioMediaStream_AddRef,
776 audio_IAudioMediaStream_Release,
777 audio_IAudioMediaStream_GetMultiMediaStream,
778 audio_IAudioMediaStream_GetInformation,
779 audio_IAudioMediaStream_SetSameFormat,
780 audio_IAudioMediaStream_AllocateSample,
781 audio_IAudioMediaStream_CreateSharedSample,
782 audio_IAudioMediaStream_SendEndOfStream,
783 audio_IAudioMediaStream_GetFormat,
784 audio_IAudioMediaStream_SetFormat,
785 audio_IAudioMediaStream_CreateSample,
788 struct enum_media_types
790 IEnumMediaTypes IEnumMediaTypes_iface;
791 LONG refcount;
792 unsigned int index;
795 static const IEnumMediaTypesVtbl enum_media_types_vtbl;
797 static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
799 return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
802 static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
804 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
806 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
808 IEnumMediaTypes_AddRef(iface);
809 *out = iface;
810 return S_OK;
813 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
814 *out = NULL;
815 return E_NOINTERFACE;
818 static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
820 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
821 ULONG refcount = InterlockedIncrement(&enum_media_types->refcount);
822 TRACE("%p increasing refcount to %lu.\n", enum_media_types, refcount);
823 return refcount;
826 static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
828 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
829 ULONG refcount = InterlockedDecrement(&enum_media_types->refcount);
830 TRACE("%p decreasing refcount to %lu.\n", enum_media_types, refcount);
831 if (!refcount)
832 free(enum_media_types);
833 return refcount;
836 static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **mts, ULONG *ret_count)
838 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
840 static const WAVEFORMATEX wfx =
842 .wFormatTag = WAVE_FORMAT_PCM,
843 .nChannels = 1,
844 .nSamplesPerSec = 11025,
845 .nAvgBytesPerSec = 11025 * 2,
846 .nBlockAlign = 2,
847 .wBitsPerSample = 16,
848 .cbSize = 0,
851 TRACE("iface %p, count %lu, mts %p, ret_count %p.\n", iface, count, mts, ret_count);
853 if (!ret_count)
854 return E_POINTER;
856 if (count && !enum_media_types->index)
858 mts[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
859 memset(mts[0], 0, sizeof(AM_MEDIA_TYPE));
860 mts[0]->majortype = MEDIATYPE_Audio;
861 mts[0]->subtype = GUID_NULL;
862 mts[0]->bFixedSizeSamples = TRUE;
863 mts[0]->bTemporalCompression = FALSE;
864 mts[0]->lSampleSize = 2;
865 mts[0]->formattype = FORMAT_WaveFormatEx;
866 mts[0]->cbFormat = sizeof(WAVEFORMATEX);
867 mts[0]->pbFormat = CoTaskMemAlloc(sizeof(WAVEFORMATEX));
868 memcpy(mts[0]->pbFormat, &wfx, sizeof(WAVEFORMATEX));
870 ++enum_media_types->index;
871 *ret_count = 1;
872 return count == 1 ? S_OK : S_FALSE;
875 *ret_count = 0;
876 return count ? S_FALSE : S_OK;
879 static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
881 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
883 TRACE("iface %p, count %lu.\n", iface, count);
885 enum_media_types->index += count;
886 return S_OK;
889 static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
891 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
893 TRACE("iface %p.\n", iface);
895 enum_media_types->index = 0;
896 return S_OK;
899 static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
901 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
902 struct enum_media_types *object;
904 TRACE("iface %p, out %p.\n", iface, out);
906 if (!(object = calloc(1, sizeof(*object))))
907 return E_OUTOFMEMORY;
909 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
910 object->refcount = 1;
911 object->index = enum_media_types->index;
913 *out = &object->IEnumMediaTypes_iface;
914 return S_OK;
917 static const IEnumMediaTypesVtbl enum_media_types_vtbl =
919 enum_media_types_QueryInterface,
920 enum_media_types_AddRef,
921 enum_media_types_Release,
922 enum_media_types_Next,
923 enum_media_types_Skip,
924 enum_media_types_Reset,
925 enum_media_types_Clone,
928 static inline struct audio_stream *impl_from_IPin(IPin *iface)
930 return CONTAINING_RECORD(iface, struct audio_stream, IPin_iface);
933 static HRESULT WINAPI audio_sink_QueryInterface(IPin *iface, REFIID iid, void **out)
935 struct audio_stream *stream = impl_from_IPin(iface);
936 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
939 static ULONG WINAPI audio_sink_AddRef(IPin *iface)
941 struct audio_stream *stream = impl_from_IPin(iface);
942 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
945 static ULONG WINAPI audio_sink_Release(IPin *iface)
947 struct audio_stream *stream = impl_from_IPin(iface);
948 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
951 static HRESULT WINAPI audio_sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
953 WARN("iface %p, peer %p, mt %p, unexpected call!\n", iface, peer, mt);
954 return E_UNEXPECTED;
957 static HRESULT WINAPI audio_sink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
959 struct audio_stream *stream = impl_from_IPin(iface);
960 PIN_DIRECTION dir;
962 TRACE("stream %p, peer %p, mt %p.\n", stream, peer, mt);
964 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)
965 || !IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)
966 || mt->cbFormat < sizeof(WAVEFORMATEX))
967 return VFW_E_TYPE_NOT_ACCEPTED;
969 if (((const WAVEFORMATEX *)mt->pbFormat)->wFormatTag != WAVE_FORMAT_PCM)
970 return E_INVALIDARG;
972 EnterCriticalSection(&stream->cs);
974 if (stream->peer)
976 LeaveCriticalSection(&stream->cs);
977 return VFW_E_ALREADY_CONNECTED;
980 IPin_QueryDirection(peer, &dir);
981 if (dir != PINDIR_OUTPUT)
983 WARN("Rejecting connection from input pin.\n");
984 LeaveCriticalSection(&stream->cs);
985 return VFW_E_INVALID_DIRECTION;
988 if (stream->format.wFormatTag && memcmp(mt->pbFormat, &stream->format, sizeof(WAVEFORMATEX)))
990 LeaveCriticalSection(&stream->cs);
991 return E_INVALIDARG;
994 CopyMediaType(&stream->mt, mt);
995 IPin_AddRef(stream->peer = peer);
997 LeaveCriticalSection(&stream->cs);
999 return S_OK;
1002 static HRESULT WINAPI audio_sink_Disconnect(IPin *iface)
1004 struct audio_stream *stream = impl_from_IPin(iface);
1006 TRACE("stream %p.\n", stream);
1008 EnterCriticalSection(&stream->cs);
1010 if (!stream->peer)
1012 LeaveCriticalSection(&stream->cs);
1013 return S_FALSE;
1016 IPin_Release(stream->peer);
1017 stream->peer = NULL;
1018 FreeMediaType(&stream->mt);
1019 memset(&stream->mt, 0, sizeof(AM_MEDIA_TYPE));
1021 LeaveCriticalSection(&stream->cs);
1023 return S_OK;
1026 static HRESULT WINAPI audio_sink_ConnectedTo(IPin *iface, IPin **peer)
1028 struct audio_stream *stream = impl_from_IPin(iface);
1029 HRESULT hr;
1031 TRACE("stream %p, peer %p.\n", stream, peer);
1033 EnterCriticalSection(&stream->cs);
1035 if (stream->peer)
1037 IPin_AddRef(*peer = stream->peer);
1038 hr = S_OK;
1040 else
1042 *peer = NULL;
1043 hr = VFW_E_NOT_CONNECTED;
1046 LeaveCriticalSection(&stream->cs);
1048 return hr;
1051 static HRESULT WINAPI audio_sink_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
1053 struct audio_stream *stream = impl_from_IPin(iface);
1054 HRESULT hr;
1056 TRACE("stream %p, mt %p.\n", stream, mt);
1058 EnterCriticalSection(&stream->cs);
1060 if (stream->peer)
1062 CopyMediaType(mt, &stream->mt);
1063 hr = S_OK;
1065 else
1067 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1068 hr = VFW_E_NOT_CONNECTED;
1071 LeaveCriticalSection(&stream->cs);
1073 return hr;
1076 static HRESULT WINAPI audio_sink_QueryPinInfo(IPin *iface, PIN_INFO *info)
1078 struct audio_stream *stream = impl_from_IPin(iface);
1080 TRACE("stream %p, info %p.\n", stream, info);
1082 IBaseFilter_AddRef(info->pFilter = (IBaseFilter *)stream->filter);
1083 info->dir = PINDIR_INPUT;
1084 wcscpy(info->achName, sink_id);
1086 return S_OK;
1089 static HRESULT WINAPI audio_sink_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1091 TRACE("iface %p, dir %p.\n", iface, dir);
1092 *dir = PINDIR_INPUT;
1093 return S_OK;
1096 static HRESULT WINAPI audio_sink_QueryId(IPin *iface, WCHAR **id)
1098 TRACE("iface %p, id %p.\n", iface, id);
1100 if (!(*id = CoTaskMemAlloc(sizeof(sink_id))))
1101 return E_OUTOFMEMORY;
1103 wcscpy(*id, sink_id);
1105 return S_OK;
1108 static HRESULT WINAPI audio_sink_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
1110 TRACE("iface %p, mt %p.\n", iface, mt);
1111 return E_NOTIMPL;
1114 static HRESULT WINAPI audio_sink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
1116 struct enum_media_types *object;
1118 TRACE("iface %p, enum_media_types %p.\n", iface, enum_media_types);
1120 if (!enum_media_types)
1121 return E_POINTER;
1123 if (!(object = calloc(1, sizeof(*object))))
1124 return E_OUTOFMEMORY;
1126 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1127 object->refcount = 1;
1128 object->index = 0;
1130 *enum_media_types = &object->IEnumMediaTypes_iface;
1131 return S_OK;
1134 static HRESULT WINAPI audio_sink_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
1136 TRACE("iface %p, pins %p, count %p.\n", iface, pins, count);
1137 return E_NOTIMPL;
1140 static HRESULT WINAPI audio_sink_EndOfStream(IPin *iface)
1142 struct audio_stream *stream = impl_from_IPin(iface);
1144 TRACE("stream %p.\n", stream);
1146 EnterCriticalSection(&stream->cs);
1148 if (stream->eos || stream->flushing)
1150 LeaveCriticalSection(&stream->cs);
1151 return E_FAIL;
1154 stream->eos = TRUE;
1156 process_updates(stream);
1158 LeaveCriticalSection(&stream->cs);
1160 /* Calling IMediaStreamFilter::EndOfStream() inside the critical section
1161 * would invert the locking order, so we must leave it first to avoid
1162 * the streaming thread deadlocking on the filter's critical section. */
1163 IMediaStreamFilter_EndOfStream(stream->filter);
1165 return S_OK;
1168 static HRESULT WINAPI audio_sink_BeginFlush(IPin *iface)
1170 struct audio_stream *stream = impl_from_IPin(iface);
1171 BOOL cancel_eos;
1173 TRACE("stream %p.\n", stream);
1175 EnterCriticalSection(&stream->cs);
1177 cancel_eos = stream->eos;
1179 stream->flushing = TRUE;
1180 stream->eos = FALSE;
1181 flush_receive_queue(stream);
1183 LeaveCriticalSection(&stream->cs);
1185 /* Calling IMediaStreamFilter::Flush() inside the critical section would
1186 * invert the locking order, so we must leave it first to avoid the
1187 * application thread deadlocking on the filter's critical section. */
1188 IMediaStreamFilter_Flush(stream->filter, cancel_eos);
1190 return S_OK;
1193 static HRESULT WINAPI audio_sink_EndFlush(IPin *iface)
1195 struct audio_stream *stream = impl_from_IPin(iface);
1197 TRACE("stream %p.\n", stream);
1199 EnterCriticalSection(&stream->cs);
1201 stream->flushing = FALSE;
1203 LeaveCriticalSection(&stream->cs);
1205 return S_OK;
1208 static HRESULT WINAPI audio_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1210 struct audio_stream *stream = impl_from_IPin(iface);
1212 TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1213 stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1215 EnterCriticalSection(&stream->cs);
1217 stream->segment_start = start;
1219 LeaveCriticalSection(&stream->cs);
1221 return S_OK;
1224 static const IPinVtbl audio_sink_vtbl =
1226 audio_sink_QueryInterface,
1227 audio_sink_AddRef,
1228 audio_sink_Release,
1229 audio_sink_Connect,
1230 audio_sink_ReceiveConnection,
1231 audio_sink_Disconnect,
1232 audio_sink_ConnectedTo,
1233 audio_sink_ConnectionMediaType,
1234 audio_sink_QueryPinInfo,
1235 audio_sink_QueryDirection,
1236 audio_sink_QueryId,
1237 audio_sink_QueryAccept,
1238 audio_sink_EnumMediaTypes,
1239 audio_sink_QueryInternalConnections,
1240 audio_sink_EndOfStream,
1241 audio_sink_BeginFlush,
1242 audio_sink_EndFlush,
1243 audio_sink_NewSegment,
1246 static inline struct audio_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1248 return CONTAINING_RECORD(iface, struct audio_stream, IMemInputPin_iface);
1251 static HRESULT WINAPI audio_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1253 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1254 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1257 static ULONG WINAPI audio_meminput_AddRef(IMemInputPin *iface)
1259 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1260 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1263 static ULONG WINAPI audio_meminput_Release(IMemInputPin *iface)
1265 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1266 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1269 static HRESULT WINAPI audio_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1271 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1273 TRACE("stream %p, allocator %p.\n", stream, allocator);
1275 if (stream->allocator)
1277 IMemAllocator_AddRef(*allocator = stream->allocator);
1278 return S_OK;
1281 *allocator = NULL;
1282 return VFW_E_NO_ALLOCATOR;
1285 static HRESULT WINAPI audio_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1287 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1289 TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1291 if (!allocator)
1292 return E_POINTER;
1294 if (allocator)
1295 IMemAllocator_AddRef(allocator);
1296 if (stream->allocator)
1297 IMemAllocator_Release(stream->allocator);
1298 stream->allocator = allocator;
1300 return S_OK;
1303 static HRESULT WINAPI audio_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1305 TRACE("iface %p, props %p.\n", iface, props);
1306 return E_NOTIMPL;
1309 static HRESULT WINAPI audio_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
1311 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1312 struct queued_receive *receive;
1313 REFERENCE_TIME start_time = 0;
1314 REFERENCE_TIME end_time = 0;
1315 BYTE *pointer;
1316 HRESULT hr;
1318 TRACE("stream %p, sample %p.\n", stream, sample);
1320 EnterCriticalSection(&stream->cs);
1322 if (stream->state == State_Stopped)
1324 LeaveCriticalSection(&stream->cs);
1325 return VFW_E_WRONG_STATE;
1327 if (stream->flushing)
1329 LeaveCriticalSection(&stream->cs);
1330 return S_FALSE;
1333 hr = IMediaSample_GetPointer(sample, &pointer);
1334 if (FAILED(hr))
1336 LeaveCriticalSection(&stream->cs);
1337 return hr;
1340 IMediaSample_GetTime(sample, &start_time, &end_time);
1342 receive = calloc(1, sizeof(*receive));
1343 if (!receive)
1345 LeaveCriticalSection(&stream->cs);
1346 return E_OUTOFMEMORY;
1349 receive->length = IMediaSample_GetActualDataLength(sample);
1350 receive->pointer = pointer;
1351 receive->sample = sample;
1352 receive->start_time = start_time + stream->segment_start;
1353 IMediaSample_AddRef(receive->sample);
1354 list_add_tail(&stream->receive_queue, &receive->entry);
1356 process_updates(stream);
1358 LeaveCriticalSection(&stream->cs);
1360 return S_OK;
1363 static HRESULT WINAPI audio_meminput_ReceiveMultiple(IMemInputPin *iface,
1364 IMediaSample **samples, LONG count, LONG *processed)
1366 FIXME("iface %p, samples %p, count %lu, processed %p, stub!\n", iface, samples, count, processed);
1367 return E_NOTIMPL;
1370 static HRESULT WINAPI audio_meminput_ReceiveCanBlock(IMemInputPin *iface)
1372 TRACE("iface %p.\n", iface);
1373 return S_OK;
1376 static const IMemInputPinVtbl audio_meminput_vtbl =
1378 audio_meminput_QueryInterface,
1379 audio_meminput_AddRef,
1380 audio_meminput_Release,
1381 audio_meminput_GetAllocator,
1382 audio_meminput_NotifyAllocator,
1383 audio_meminput_GetAllocatorRequirements,
1384 audio_meminput_Receive,
1385 audio_meminput_ReceiveMultiple,
1386 audio_meminput_ReceiveCanBlock,
1389 HRESULT audio_stream_create(IUnknown *outer, void **out)
1391 struct audio_stream *object;
1393 if (outer)
1394 return CLASS_E_NOAGGREGATION;
1396 if (!(object = calloc(1, sizeof(*object))))
1397 return E_OUTOFMEMORY;
1399 object->IAMMediaStream_iface.lpVtbl = &audio_IAMMediaStream_vtbl;
1400 object->IAudioMediaStream_iface.lpVtbl = &audio_IAudioMediaStream_vtbl;
1401 object->IMemInputPin_iface.lpVtbl = &audio_meminput_vtbl;
1402 object->IPin_iface.lpVtbl = &audio_sink_vtbl;
1403 object->ref = 1;
1405 InitializeCriticalSection(&object->cs);
1406 list_init(&object->receive_queue);
1407 list_init(&object->update_queue);
1409 TRACE("Created audio stream %p.\n", object);
1411 *out = &object->IAMMediaStream_iface;
1413 return S_OK;