amstream: Implement AMAudioStream::NewSegment.
[wine/zf.git] / dlls / amstream / audiostream.c
bloba19cb4ea96f662ab4dd1ca9a5844f4d8e11d4ea2
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/strmbase.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(amstream);
28 static const WCHAR sink_id[] = L"I{A35FF56B-9FDA-11D0-8FDF-00C04FD9189D}";
30 struct queued_receive
32 struct list entry;
33 IMediaSample *sample;
34 DWORD length;
35 BYTE *pointer;
36 DWORD position;
37 STREAM_TIME start_time;
40 struct audio_stream
42 IAMMediaStream IAMMediaStream_iface;
43 IAudioMediaStream IAudioMediaStream_iface;
44 IMemInputPin IMemInputPin_iface;
45 IPin IPin_iface;
46 LONG ref;
48 IMultiMediaStream* parent;
49 MSPID purpose_id;
50 STREAM_TYPE stream_type;
51 CRITICAL_SECTION cs;
52 IMediaStreamFilter *filter;
54 IPin *peer;
55 IMemAllocator *allocator;
56 AM_MEDIA_TYPE mt;
57 WAVEFORMATEX format;
58 FILTER_STATE state;
59 REFERENCE_TIME segment_start;
60 BOOL eos;
61 BOOL flushing;
62 struct list receive_queue;
63 struct list update_queue;
66 typedef struct {
67 IAudioStreamSample IAudioStreamSample_iface;
68 LONG ref;
69 struct audio_stream *parent;
70 IAudioData *audio_data;
71 STREAM_TIME start_time;
72 STREAM_TIME end_time;
73 HANDLE update_event;
75 struct list entry;
76 DWORD length;
77 BYTE *pointer;
78 DWORD position;
79 HRESULT update_hr;
80 } IAudioStreamSampleImpl;
82 static void remove_queued_receive(struct queued_receive *receive)
84 list_remove(&receive->entry);
85 IMediaSample_Release(receive->sample);
86 free(receive);
89 static void remove_queued_update(IAudioStreamSampleImpl *sample)
91 HRESULT hr;
93 hr = IAudioData_SetActual(sample->audio_data, sample->position);
94 if (FAILED(hr))
95 sample->update_hr = hr;
97 list_remove(&sample->entry);
98 SetEvent(sample->update_event);
101 static void flush_receive_queue(struct audio_stream *stream)
103 struct list *entry;
105 while ((entry = list_head(&stream->receive_queue)))
106 remove_queued_receive(LIST_ENTRY(entry, struct queued_receive, entry));
109 static STREAM_TIME stream_time_from_position(struct audio_stream *stream, struct queued_receive *receive)
111 const WAVEFORMATEX *format = (WAVEFORMATEX *)stream->mt.pbFormat;
112 return receive->start_time + (receive->position * 10000000 + format->nAvgBytesPerSec / 2) / format->nAvgBytesPerSec;
115 static void process_update(IAudioStreamSampleImpl *sample, struct queued_receive *receive)
117 DWORD advance;
119 advance = min(receive->length - receive->position, sample->length - sample->position);
120 memcpy(&sample->pointer[sample->position], &receive->pointer[receive->position], advance);
122 if (!sample->position)
123 sample->start_time = stream_time_from_position(sample->parent, receive);
125 receive->position += advance;
126 sample->position += advance;
128 sample->end_time = stream_time_from_position(sample->parent, receive);
130 sample->update_hr = (sample->position == sample->length) ? S_OK : MS_S_PENDING;
133 static void process_updates(struct audio_stream *stream)
135 while (!list_empty(&stream->update_queue) && !list_empty(&stream->receive_queue))
137 IAudioStreamSampleImpl *sample = LIST_ENTRY(list_head(&stream->update_queue), IAudioStreamSampleImpl, entry);
138 struct queued_receive *receive = LIST_ENTRY(list_head(&stream->receive_queue), struct queued_receive, entry);
140 process_update(sample, receive);
142 if (sample->update_hr != MS_S_PENDING)
143 remove_queued_update(sample);
144 if (receive->position == receive->length)
145 remove_queued_receive(receive);
147 if (stream->eos)
149 while (!list_empty(&stream->update_queue))
151 IAudioStreamSampleImpl *sample = LIST_ENTRY(list_head(&stream->update_queue), IAudioStreamSampleImpl, entry);
153 sample->update_hr = sample->position ? S_OK : MS_S_ENDOFSTREAM;
154 remove_queued_update(sample);
159 static inline IAudioStreamSampleImpl *impl_from_IAudioStreamSample(IAudioStreamSample *iface)
161 return CONTAINING_RECORD(iface, IAudioStreamSampleImpl, IAudioStreamSample_iface);
164 /*** IUnknown methods ***/
165 static HRESULT WINAPI IAudioStreamSampleImpl_QueryInterface(IAudioStreamSample *iface,
166 REFIID riid, void **ret_iface)
168 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
170 if (IsEqualGUID(riid, &IID_IUnknown) ||
171 IsEqualGUID(riid, &IID_IStreamSample) ||
172 IsEqualGUID(riid, &IID_IAudioStreamSample))
174 IAudioStreamSample_AddRef(iface);
175 *ret_iface = iface;
176 return S_OK;
179 *ret_iface = NULL;
181 ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
182 return E_NOINTERFACE;
185 static ULONG WINAPI IAudioStreamSampleImpl_AddRef(IAudioStreamSample *iface)
187 IAudioStreamSampleImpl *This = impl_from_IAudioStreamSample(iface);
188 ULONG ref = InterlockedIncrement(&This->ref);
190 TRACE("(%p)->(): new ref = %u\n", iface, ref);
192 return ref;
195 static ULONG WINAPI IAudioStreamSampleImpl_Release(IAudioStreamSample *iface)
197 IAudioStreamSampleImpl *This = impl_from_IAudioStreamSample(iface);
198 ULONG ref = InterlockedDecrement(&This->ref);
200 TRACE("(%p)->(): new ref = %u\n", iface, ref);
202 if (!ref)
204 CloseHandle(This->update_event);
205 HeapFree(GetProcessHeap(), 0, This);
208 return ref;
211 /*** IStreamSample methods ***/
212 static HRESULT WINAPI IAudioStreamSampleImpl_GetMediaStream(IAudioStreamSample *iface, IMediaStream **media_stream)
214 FIXME("(%p)->(%p): stub\n", iface, media_stream);
216 return E_NOTIMPL;
219 static HRESULT WINAPI IAudioStreamSampleImpl_GetSampleTimes(IAudioStreamSample *iface, STREAM_TIME *start_time,
220 STREAM_TIME *end_time, STREAM_TIME *current_time)
222 IAudioStreamSampleImpl *sample = impl_from_IAudioStreamSample(iface);
224 TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
226 if (current_time)
227 IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
229 if (start_time)
230 *start_time = sample->start_time;
231 if (end_time)
232 *end_time = sample->end_time;
234 return S_OK;
237 static HRESULT WINAPI IAudioStreamSampleImpl_SetSampleTimes(IAudioStreamSample *iface, const STREAM_TIME *start_time,
238 const STREAM_TIME *end_time)
240 FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
242 return E_NOTIMPL;
245 static HRESULT WINAPI IAudioStreamSampleImpl_Update(IAudioStreamSample *iface,
246 DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
248 IAudioStreamSampleImpl *sample = impl_from_IAudioStreamSample(iface);
249 BYTE *pointer;
250 DWORD length;
251 HRESULT hr;
253 TRACE("sample %p, flags %#x, event %p, apc_func %p, apc_data %#x.\n",
254 sample, flags, event, apc_func, apc_data);
256 hr = IAudioData_GetInfo(sample->audio_data, &length, &pointer, NULL);
257 if (FAILED(hr))
258 return hr;
260 if (event && apc_func)
261 return E_INVALIDARG;
263 if (apc_func)
265 FIXME("APC support is not implemented!\n");
266 return E_NOTIMPL;
269 if (event)
271 FIXME("Event parameter support is not implemented!\n");
272 return E_NOTIMPL;
275 if (flags & ~SSUPDATE_ASYNC)
277 FIXME("Unsupported flags %#x.\n", flags);
278 return E_NOTIMPL;
281 EnterCriticalSection(&sample->parent->cs);
283 if (sample->parent->state != State_Running)
285 LeaveCriticalSection(&sample->parent->cs);
286 return MS_E_NOTRUNNING;
288 if (!sample->parent->peer)
290 LeaveCriticalSection(&sample->parent->cs);
291 return MS_S_ENDOFSTREAM;
293 if (MS_S_PENDING == sample->update_hr)
295 LeaveCriticalSection(&sample->parent->cs);
296 return MS_E_BUSY;
299 sample->length = length;
300 sample->pointer = pointer;
301 sample->position = 0;
302 sample->update_hr = MS_S_PENDING;
303 ResetEvent(sample->update_event);
304 list_add_tail(&sample->parent->update_queue, &sample->entry);
306 process_updates(sample->parent);
307 hr = sample->update_hr;
309 LeaveCriticalSection(&sample->parent->cs);
311 if (hr != MS_S_PENDING || (flags & SSUPDATE_ASYNC))
312 return hr;
314 WaitForSingleObject(sample->update_event, INFINITE);
316 return sample->update_hr;
319 static HRESULT WINAPI IAudioStreamSampleImpl_CompletionStatus(IAudioStreamSample *iface, DWORD flags, DWORD milliseconds)
321 IAudioStreamSampleImpl *sample = impl_from_IAudioStreamSample(iface);
322 HRESULT hr;
324 TRACE("sample %p, flags %#x, milliseconds %u.\n", sample, flags, milliseconds);
326 if (flags)
328 FIXME("Unhandled flags %#x.\n", flags);
329 return E_NOTIMPL;
332 EnterCriticalSection(&sample->parent->cs);
334 hr = sample->update_hr;
336 LeaveCriticalSection(&sample->parent->cs);
338 return hr;
341 /*** IAudioStreamSample methods ***/
342 static HRESULT WINAPI IAudioStreamSampleImpl_GetAudioData(IAudioStreamSample *iface, IAudioData **audio_data)
344 FIXME("(%p)->(%p): stub\n", iface, audio_data);
346 return E_NOTIMPL;
349 static const struct IAudioStreamSampleVtbl AudioStreamSample_Vtbl =
351 /*** IUnknown methods ***/
352 IAudioStreamSampleImpl_QueryInterface,
353 IAudioStreamSampleImpl_AddRef,
354 IAudioStreamSampleImpl_Release,
355 /*** IStreamSample methods ***/
356 IAudioStreamSampleImpl_GetMediaStream,
357 IAudioStreamSampleImpl_GetSampleTimes,
358 IAudioStreamSampleImpl_SetSampleTimes,
359 IAudioStreamSampleImpl_Update,
360 IAudioStreamSampleImpl_CompletionStatus,
361 /*** IAudioStreamSample methods ***/
362 IAudioStreamSampleImpl_GetAudioData
365 static HRESULT audiostreamsample_create(struct audio_stream *parent, IAudioData *audio_data, IAudioStreamSample **audio_stream_sample)
367 IAudioStreamSampleImpl *object;
369 TRACE("(%p)\n", audio_stream_sample);
371 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAudioStreamSampleImpl));
372 if (!object)
373 return E_OUTOFMEMORY;
375 object->IAudioStreamSample_iface.lpVtbl = &AudioStreamSample_Vtbl;
376 object->ref = 1;
377 object->parent = parent;
378 object->audio_data = audio_data;
379 object->update_event = CreateEventW(NULL, FALSE, FALSE, NULL);
381 *audio_stream_sample = &object->IAudioStreamSample_iface;
383 return S_OK;
386 static inline struct audio_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
388 return CONTAINING_RECORD(iface, struct audio_stream, IAMMediaStream_iface);
391 /*** IUnknown methods ***/
392 static HRESULT WINAPI audio_IAMMediaStream_QueryInterface(IAMMediaStream *iface,
393 REFIID riid, void **ret_iface)
395 struct audio_stream *This = impl_from_IAMMediaStream(iface);
397 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
399 if (IsEqualGUID(riid, &IID_IUnknown) ||
400 IsEqualGUID(riid, &IID_IMediaStream) ||
401 IsEqualGUID(riid, &IID_IAMMediaStream))
403 IAMMediaStream_AddRef(iface);
404 *ret_iface = iface;
405 return S_OK;
407 else if (IsEqualGUID(riid, &IID_IAudioMediaStream))
409 IAMMediaStream_AddRef(iface);
410 *ret_iface = &This->IAudioMediaStream_iface;
411 return S_OK;
413 else if (IsEqualGUID(riid, &IID_IPin))
415 IAMMediaStream_AddRef(iface);
416 *ret_iface = &This->IPin_iface;
417 return S_OK;
419 else if (IsEqualGUID(riid, &IID_IMemInputPin))
421 IAMMediaStream_AddRef(iface);
422 *ret_iface = &This->IMemInputPin_iface;
423 return S_OK;
426 ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface);
427 return E_NOINTERFACE;
430 static ULONG WINAPI audio_IAMMediaStream_AddRef(IAMMediaStream *iface)
432 struct audio_stream *This = impl_from_IAMMediaStream(iface);
433 ULONG ref = InterlockedIncrement(&This->ref);
435 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
437 return ref;
440 static ULONG WINAPI audio_IAMMediaStream_Release(IAMMediaStream *iface)
442 struct audio_stream *This = impl_from_IAMMediaStream(iface);
443 ULONG ref = InterlockedDecrement(&This->ref);
445 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
447 if (!ref)
449 DeleteCriticalSection(&This->cs);
450 HeapFree(GetProcessHeap(), 0, This);
453 return ref;
456 /*** IMediaStream methods ***/
457 static HRESULT WINAPI audio_IAMMediaStream_GetMultiMediaStream(IAMMediaStream *iface,
458 IMultiMediaStream **mmstream)
460 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
462 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
464 if (!mmstream)
465 return E_POINTER;
467 if (stream->parent)
468 IMultiMediaStream_AddRef(stream->parent);
469 *mmstream = stream->parent;
470 return S_OK;
473 static HRESULT WINAPI audio_IAMMediaStream_GetInformation(IAMMediaStream *iface,
474 MSPID *purpose_id, STREAM_TYPE *type)
476 struct audio_stream *This = impl_from_IAMMediaStream(iface);
478 TRACE("(%p/%p)->(%p,%p)\n", This, iface, purpose_id, type);
480 if (purpose_id)
481 *purpose_id = This->purpose_id;
482 if (type)
483 *type = This->stream_type;
485 return S_OK;
488 static HRESULT WINAPI audio_IAMMediaStream_SetSameFormat(IAMMediaStream *iface,
489 IMediaStream *pStreamThatHasDesiredFormat, DWORD flags)
491 struct audio_stream *This = impl_from_IAMMediaStream(iface);
493 FIXME("(%p/%p)->(%p,%x) stub!\n", This, iface, pStreamThatHasDesiredFormat, flags);
495 return S_FALSE;
498 static HRESULT WINAPI audio_IAMMediaStream_AllocateSample(IAMMediaStream *iface,
499 DWORD flags, IStreamSample **sample)
501 struct audio_stream *This = impl_from_IAMMediaStream(iface);
503 FIXME("(%p/%p)->(%x,%p) stub!\n", This, iface, flags, sample);
505 return S_FALSE;
508 static HRESULT WINAPI audio_IAMMediaStream_CreateSharedSample(IAMMediaStream *iface,
509 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
511 struct audio_stream *This = impl_from_IAMMediaStream(iface);
513 FIXME("(%p/%p)->(%p,%x,%p) stub!\n", This, iface, existing_sample, flags, sample);
515 return S_FALSE;
518 static HRESULT WINAPI audio_IAMMediaStream_SendEndOfStream(IAMMediaStream *iface, DWORD flags)
520 struct audio_stream *This = impl_from_IAMMediaStream(iface);
522 FIXME("(%p/%p)->(%x) stub!\n", This, iface, flags);
524 return S_FALSE;
527 /*** IAMMediaStream methods ***/
528 static HRESULT WINAPI audio_IAMMediaStream_Initialize(IAMMediaStream *iface, IUnknown *source_object, DWORD flags,
529 REFMSPID purpose_id, const STREAM_TYPE stream_type)
531 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
533 TRACE("stream %p, source_object %p, flags %x, purpose_id %s, stream_type %u.\n", stream, source_object, flags,
534 debugstr_guid(purpose_id), stream_type);
536 if (!purpose_id)
537 return E_POINTER;
539 if (source_object)
540 FIXME("Specifying a stream object is not yet supported.\n");
542 if (flags & AMMSF_CREATEPEER)
543 FIXME("AMMSF_CREATEPEER is not yet supported.\n");
545 stream->purpose_id = *purpose_id;
546 stream->stream_type = stream_type;
548 return S_OK;
551 static HRESULT WINAPI audio_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state)
553 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
555 TRACE("stream %p, state %u.\n", stream, state);
557 EnterCriticalSection(&stream->cs);
559 if (state == State_Stopped)
560 flush_receive_queue(stream);
561 if (stream->state == State_Stopped)
562 stream->eos = FALSE;
564 stream->state = state;
566 LeaveCriticalSection(&stream->cs);
568 return S_OK;
571 static HRESULT WINAPI audio_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface,
572 IAMMultiMediaStream *mmstream)
574 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
576 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
578 stream->parent = (IMultiMediaStream *)mmstream;
580 return S_OK;
583 static HRESULT WINAPI audio_IAMMediaStream_JoinFilter(IAMMediaStream *iface, IMediaStreamFilter *filter)
585 struct audio_stream *stream = impl_from_IAMMediaStream(iface);
587 TRACE("stream %p, filter %p.\n", stream, filter);
589 stream->filter = filter;
591 return S_OK;
594 static HRESULT WINAPI audio_IAMMediaStream_JoinFilterGraph(IAMMediaStream *iface, IFilterGraph *filtergraph)
596 struct audio_stream *This = impl_from_IAMMediaStream(iface);
598 FIXME("(%p/%p)->(%p) stub!\n", This, iface, filtergraph);
600 return S_FALSE;
603 static const struct IAMMediaStreamVtbl audio_IAMMediaStream_vtbl =
605 audio_IAMMediaStream_QueryInterface,
606 audio_IAMMediaStream_AddRef,
607 audio_IAMMediaStream_Release,
608 audio_IAMMediaStream_GetMultiMediaStream,
609 audio_IAMMediaStream_GetInformation,
610 audio_IAMMediaStream_SetSameFormat,
611 audio_IAMMediaStream_AllocateSample,
612 audio_IAMMediaStream_CreateSharedSample,
613 audio_IAMMediaStream_SendEndOfStream,
614 audio_IAMMediaStream_Initialize,
615 audio_IAMMediaStream_SetState,
616 audio_IAMMediaStream_JoinAMMultiMediaStream,
617 audio_IAMMediaStream_JoinFilter,
618 audio_IAMMediaStream_JoinFilterGraph,
621 static inline struct audio_stream *impl_from_IAudioMediaStream(IAudioMediaStream *iface)
623 return CONTAINING_RECORD(iface, struct audio_stream, IAudioMediaStream_iface);
626 /*** IUnknown methods ***/
627 static HRESULT WINAPI audio_IAudioMediaStream_QueryInterface(IAudioMediaStream *iface,
628 REFIID riid, void **ret_iface)
630 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
631 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
632 return IAMMediaStream_QueryInterface(&This->IAMMediaStream_iface, riid, ret_iface);
635 static ULONG WINAPI audio_IAudioMediaStream_AddRef(IAudioMediaStream *iface)
637 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
638 TRACE("(%p/%p)\n", iface, This);
639 return IAMMediaStream_AddRef(&This->IAMMediaStream_iface);
642 static ULONG WINAPI audio_IAudioMediaStream_Release(IAudioMediaStream *iface)
644 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
645 TRACE("(%p/%p)\n", iface, This);
646 return IAMMediaStream_Release(&This->IAMMediaStream_iface);
649 static HRESULT WINAPI audio_IAudioMediaStream_GetMultiMediaStream(IAudioMediaStream *iface,
650 IMultiMediaStream **mmstream)
652 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
653 return IAMMediaStream_GetMultiMediaStream(&stream->IAMMediaStream_iface, mmstream);
656 static HRESULT WINAPI audio_IAudioMediaStream_GetInformation(IAudioMediaStream *iface,
657 MSPID *purpose_id, STREAM_TYPE *type)
659 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
660 return IAMMediaStream_GetInformation(&stream->IAMMediaStream_iface, purpose_id, type);
663 static HRESULT WINAPI audio_IAudioMediaStream_SetSameFormat(IAudioMediaStream *iface,
664 IMediaStream *other, DWORD flags)
666 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
667 return IAMMediaStream_SetSameFormat(&stream->IAMMediaStream_iface, other, flags);
670 static HRESULT WINAPI audio_IAudioMediaStream_AllocateSample(IAudioMediaStream *iface,
671 DWORD flags, IStreamSample **sample)
673 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
674 return IAMMediaStream_AllocateSample(&stream->IAMMediaStream_iface, flags, sample);
677 static HRESULT WINAPI audio_IAudioMediaStream_CreateSharedSample(IAudioMediaStream *iface,
678 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
680 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
681 return IAMMediaStream_CreateSharedSample(&stream->IAMMediaStream_iface, existing_sample, flags, sample);
684 static HRESULT WINAPI audio_IAudioMediaStream_SendEndOfStream(IAudioMediaStream *iface, DWORD flags)
686 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
687 return IAMMediaStream_SendEndOfStream(&stream->IAMMediaStream_iface, flags);
690 /*** IAudioMediaStream methods ***/
691 static HRESULT WINAPI audio_IAudioMediaStream_GetFormat(IAudioMediaStream *iface, WAVEFORMATEX *format)
693 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
695 TRACE("stream %p, format %p.\n", stream, format);
697 if (!format)
698 return E_POINTER;
700 EnterCriticalSection(&stream->cs);
702 if (!stream->peer)
704 LeaveCriticalSection(&stream->cs);
705 return MS_E_NOSTREAM;
708 *format = *(WAVEFORMATEX *)stream->mt.pbFormat;
710 LeaveCriticalSection(&stream->cs);
712 return S_OK;
715 static HRESULT WINAPI audio_IAudioMediaStream_SetFormat(IAudioMediaStream *iface, const WAVEFORMATEX *format)
717 struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
719 TRACE("stream %p, format %p.\n", stream, format);
721 if (!format)
722 return E_POINTER;
724 if (format->wFormatTag != WAVE_FORMAT_PCM)
725 return E_INVALIDARG;
727 EnterCriticalSection(&stream->cs);
729 if ((stream->peer && memcmp(format, stream->mt.pbFormat, sizeof(WAVEFORMATEX)))
730 || (stream->format.wFormatTag && memcmp(format, &stream->format, sizeof(WAVEFORMATEX))))
732 LeaveCriticalSection(&stream->cs);
733 return E_INVALIDARG;
736 stream->format = *format;
738 LeaveCriticalSection(&stream->cs);
740 return S_OK;
743 static HRESULT WINAPI audio_IAudioMediaStream_CreateSample(IAudioMediaStream *iface, IAudioData *audio_data,
744 DWORD flags, IAudioStreamSample **sample)
746 struct audio_stream *This = impl_from_IAudioMediaStream(iface);
748 TRACE("(%p/%p)->(%p,%u,%p)\n", iface, This, audio_data, flags, sample);
750 if (!audio_data)
751 return E_POINTER;
753 return audiostreamsample_create(This, audio_data, sample);
756 static const struct IAudioMediaStreamVtbl audio_IAudioMediaStream_vtbl =
758 audio_IAudioMediaStream_QueryInterface,
759 audio_IAudioMediaStream_AddRef,
760 audio_IAudioMediaStream_Release,
761 audio_IAudioMediaStream_GetMultiMediaStream,
762 audio_IAudioMediaStream_GetInformation,
763 audio_IAudioMediaStream_SetSameFormat,
764 audio_IAudioMediaStream_AllocateSample,
765 audio_IAudioMediaStream_CreateSharedSample,
766 audio_IAudioMediaStream_SendEndOfStream,
767 audio_IAudioMediaStream_GetFormat,
768 audio_IAudioMediaStream_SetFormat,
769 audio_IAudioMediaStream_CreateSample,
772 struct enum_media_types
774 IEnumMediaTypes IEnumMediaTypes_iface;
775 LONG refcount;
776 unsigned int index;
779 static const IEnumMediaTypesVtbl enum_media_types_vtbl;
781 static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
783 return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
786 static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
788 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
790 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
792 IEnumMediaTypes_AddRef(iface);
793 *out = iface;
794 return S_OK;
797 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
798 *out = NULL;
799 return E_NOINTERFACE;
802 static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
804 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
805 ULONG refcount = InterlockedIncrement(&enum_media_types->refcount);
806 TRACE("%p increasing refcount to %u.\n", enum_media_types, refcount);
807 return refcount;
810 static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
812 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
813 ULONG refcount = InterlockedDecrement(&enum_media_types->refcount);
814 TRACE("%p decreasing refcount to %u.\n", enum_media_types, refcount);
815 if (!refcount)
816 heap_free(enum_media_types);
817 return refcount;
820 static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **mts, ULONG *ret_count)
822 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
824 TRACE("iface %p, count %u, mts %p, ret_count %p.\n", iface, count, mts, ret_count);
826 if (!ret_count)
827 return E_POINTER;
829 if (count && !enum_media_types->index)
831 mts[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
832 memset(mts[0], 0, sizeof(AM_MEDIA_TYPE));
833 mts[0]->majortype = MEDIATYPE_Audio;
834 mts[0]->subtype = MEDIASUBTYPE_PCM;
835 ++enum_media_types->index;
836 *ret_count = 1;
837 return count == 1 ? S_OK : S_FALSE;
840 *ret_count = 0;
841 return count ? S_FALSE : S_OK;
844 static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
846 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
848 TRACE("iface %p, count %u.\n", iface, count);
850 enum_media_types->index += count;
851 return S_OK;
854 static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
856 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
858 TRACE("iface %p.\n", iface);
860 enum_media_types->index = 0;
861 return S_OK;
864 static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
866 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
867 struct enum_media_types *object;
869 TRACE("iface %p, out %p.\n", iface, out);
871 if (!(object = heap_alloc(sizeof(*object))))
872 return E_OUTOFMEMORY;
874 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
875 object->refcount = 1;
876 object->index = enum_media_types->index;
878 *out = &object->IEnumMediaTypes_iface;
879 return S_OK;
882 static const IEnumMediaTypesVtbl enum_media_types_vtbl =
884 enum_media_types_QueryInterface,
885 enum_media_types_AddRef,
886 enum_media_types_Release,
887 enum_media_types_Next,
888 enum_media_types_Skip,
889 enum_media_types_Reset,
890 enum_media_types_Clone,
893 static inline struct audio_stream *impl_from_IPin(IPin *iface)
895 return CONTAINING_RECORD(iface, struct audio_stream, IPin_iface);
898 static HRESULT WINAPI audio_sink_QueryInterface(IPin *iface, REFIID iid, void **out)
900 struct audio_stream *stream = impl_from_IPin(iface);
901 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
904 static ULONG WINAPI audio_sink_AddRef(IPin *iface)
906 struct audio_stream *stream = impl_from_IPin(iface);
907 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
910 static ULONG WINAPI audio_sink_Release(IPin *iface)
912 struct audio_stream *stream = impl_from_IPin(iface);
913 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
916 static HRESULT WINAPI audio_sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
918 WARN("iface %p, peer %p, mt %p, unexpected call!\n", iface, peer, mt);
919 return E_UNEXPECTED;
922 static HRESULT WINAPI audio_sink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
924 struct audio_stream *stream = impl_from_IPin(iface);
925 PIN_DIRECTION dir;
927 TRACE("stream %p, peer %p, mt %p.\n", stream, peer, mt);
929 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)
930 || !IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)
931 || mt->cbFormat < sizeof(WAVEFORMATEX))
932 return VFW_E_TYPE_NOT_ACCEPTED;
934 if (((const WAVEFORMATEX *)mt->pbFormat)->wFormatTag != WAVE_FORMAT_PCM)
935 return E_INVALIDARG;
937 EnterCriticalSection(&stream->cs);
939 if (stream->peer)
941 LeaveCriticalSection(&stream->cs);
942 return VFW_E_ALREADY_CONNECTED;
945 IPin_QueryDirection(peer, &dir);
946 if (dir != PINDIR_OUTPUT)
948 WARN("Rejecting connection from input pin.\n");
949 LeaveCriticalSection(&stream->cs);
950 return VFW_E_INVALID_DIRECTION;
953 if (stream->format.wFormatTag && memcmp(mt->pbFormat, &stream->format, sizeof(WAVEFORMATEX)))
955 LeaveCriticalSection(&stream->cs);
956 return E_INVALIDARG;
959 CopyMediaType(&stream->mt, mt);
960 IPin_AddRef(stream->peer = peer);
962 LeaveCriticalSection(&stream->cs);
964 return S_OK;
967 static HRESULT WINAPI audio_sink_Disconnect(IPin *iface)
969 struct audio_stream *stream = impl_from_IPin(iface);
971 TRACE("stream %p.\n", stream);
973 EnterCriticalSection(&stream->cs);
975 if (!stream->peer)
977 LeaveCriticalSection(&stream->cs);
978 return S_FALSE;
981 IPin_Release(stream->peer);
982 stream->peer = NULL;
983 FreeMediaType(&stream->mt);
984 memset(&stream->mt, 0, sizeof(AM_MEDIA_TYPE));
986 LeaveCriticalSection(&stream->cs);
988 return S_OK;
991 static HRESULT WINAPI audio_sink_ConnectedTo(IPin *iface, IPin **peer)
993 struct audio_stream *stream = impl_from_IPin(iface);
994 HRESULT hr;
996 TRACE("stream %p, peer %p.\n", stream, peer);
998 EnterCriticalSection(&stream->cs);
1000 if (stream->peer)
1002 IPin_AddRef(*peer = stream->peer);
1003 hr = S_OK;
1005 else
1007 *peer = NULL;
1008 hr = VFW_E_NOT_CONNECTED;
1011 LeaveCriticalSection(&stream->cs);
1013 return hr;
1016 static HRESULT WINAPI audio_sink_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
1018 struct audio_stream *stream = impl_from_IPin(iface);
1019 HRESULT hr;
1021 TRACE("stream %p, mt %p.\n", stream, mt);
1023 EnterCriticalSection(&stream->cs);
1025 if (stream->peer)
1027 CopyMediaType(mt, &stream->mt);
1028 hr = S_OK;
1030 else
1032 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1033 hr = VFW_E_NOT_CONNECTED;
1036 LeaveCriticalSection(&stream->cs);
1038 return hr;
1041 static HRESULT WINAPI audio_sink_QueryPinInfo(IPin *iface, PIN_INFO *info)
1043 struct audio_stream *stream = impl_from_IPin(iface);
1045 TRACE("stream %p, info %p.\n", stream, info);
1047 IBaseFilter_AddRef(info->pFilter = (IBaseFilter *)stream->filter);
1048 info->dir = PINDIR_INPUT;
1049 wcscpy(info->achName, sink_id);
1051 return S_OK;
1054 static HRESULT WINAPI audio_sink_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1056 TRACE("iface %p, dir %p.\n", iface, dir);
1057 *dir = PINDIR_INPUT;
1058 return S_OK;
1061 static HRESULT WINAPI audio_sink_QueryId(IPin *iface, WCHAR **id)
1063 TRACE("iface %p, id %p.\n", iface, id);
1065 if (!(*id = CoTaskMemAlloc(sizeof(sink_id))))
1066 return E_OUTOFMEMORY;
1068 wcscpy(*id, sink_id);
1070 return S_OK;
1073 static HRESULT WINAPI audio_sink_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
1075 TRACE("iface %p, mt %p.\n", iface, mt);
1076 return S_OK;
1079 static HRESULT WINAPI audio_sink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
1081 struct enum_media_types *object;
1083 TRACE("iface %p, enum_media_types %p.\n", iface, enum_media_types);
1085 if (!enum_media_types)
1086 return E_POINTER;
1088 if (!(object = heap_alloc(sizeof(*object))))
1089 return E_OUTOFMEMORY;
1091 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1092 object->refcount = 1;
1093 object->index = 0;
1095 *enum_media_types = &object->IEnumMediaTypes_iface;
1096 return S_OK;
1099 static HRESULT WINAPI audio_sink_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
1101 TRACE("iface %p, pins %p, count %p.\n", iface, pins, count);
1102 return E_NOTIMPL;
1105 static HRESULT WINAPI audio_sink_EndOfStream(IPin *iface)
1107 struct audio_stream *stream = impl_from_IPin(iface);
1109 TRACE("stream %p.\n", stream);
1111 EnterCriticalSection(&stream->cs);
1113 if (stream->eos || stream->flushing)
1115 LeaveCriticalSection(&stream->cs);
1116 return E_FAIL;
1119 stream->eos = TRUE;
1121 process_updates(stream);
1123 LeaveCriticalSection(&stream->cs);
1125 return S_OK;
1128 static HRESULT WINAPI audio_sink_BeginFlush(IPin *iface)
1130 struct audio_stream *stream = impl_from_IPin(iface);
1132 TRACE("stream %p.\n", stream);
1134 EnterCriticalSection(&stream->cs);
1136 stream->flushing = TRUE;
1137 stream->eos = FALSE;
1138 flush_receive_queue(stream);
1140 LeaveCriticalSection(&stream->cs);
1142 return S_OK;
1145 static HRESULT WINAPI audio_sink_EndFlush(IPin *iface)
1147 struct audio_stream *stream = impl_from_IPin(iface);
1149 TRACE("stream %p.\n", stream);
1151 EnterCriticalSection(&stream->cs);
1153 stream->flushing = FALSE;
1155 LeaveCriticalSection(&stream->cs);
1157 return S_OK;
1160 static HRESULT WINAPI audio_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1162 struct audio_stream *stream = impl_from_IPin(iface);
1164 TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1165 stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1167 EnterCriticalSection(&stream->cs);
1169 stream->segment_start = start;
1171 LeaveCriticalSection(&stream->cs);
1173 return S_OK;
1176 static const IPinVtbl audio_sink_vtbl =
1178 audio_sink_QueryInterface,
1179 audio_sink_AddRef,
1180 audio_sink_Release,
1181 audio_sink_Connect,
1182 audio_sink_ReceiveConnection,
1183 audio_sink_Disconnect,
1184 audio_sink_ConnectedTo,
1185 audio_sink_ConnectionMediaType,
1186 audio_sink_QueryPinInfo,
1187 audio_sink_QueryDirection,
1188 audio_sink_QueryId,
1189 audio_sink_QueryAccept,
1190 audio_sink_EnumMediaTypes,
1191 audio_sink_QueryInternalConnections,
1192 audio_sink_EndOfStream,
1193 audio_sink_BeginFlush,
1194 audio_sink_EndFlush,
1195 audio_sink_NewSegment,
1198 static inline struct audio_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1200 return CONTAINING_RECORD(iface, struct audio_stream, IMemInputPin_iface);
1203 static HRESULT WINAPI audio_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1205 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1206 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1209 static ULONG WINAPI audio_meminput_AddRef(IMemInputPin *iface)
1211 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1212 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1215 static ULONG WINAPI audio_meminput_Release(IMemInputPin *iface)
1217 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1218 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1221 static HRESULT WINAPI audio_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1223 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1225 TRACE("stream %p, allocator %p.\n", stream, allocator);
1227 if (stream->allocator)
1229 IMemAllocator_AddRef(*allocator = stream->allocator);
1230 return S_OK;
1233 *allocator = NULL;
1234 return VFW_E_NO_ALLOCATOR;
1237 static HRESULT WINAPI audio_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1239 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1241 TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1243 if (!allocator)
1244 return E_POINTER;
1246 if (allocator)
1247 IMemAllocator_AddRef(allocator);
1248 if (stream->allocator)
1249 IMemAllocator_Release(stream->allocator);
1250 stream->allocator = allocator;
1252 return S_OK;
1255 static HRESULT WINAPI audio_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1257 TRACE("iface %p, props %p.\n", iface, props);
1258 return E_NOTIMPL;
1261 static HRESULT WINAPI audio_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
1263 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1264 struct queued_receive *receive;
1265 REFERENCE_TIME start_time = 0;
1266 REFERENCE_TIME end_time = 0;
1267 BYTE *pointer;
1268 HRESULT hr;
1270 TRACE("stream %p, sample %p.\n", stream, sample);
1272 EnterCriticalSection(&stream->cs);
1274 if (stream->state == State_Stopped)
1276 LeaveCriticalSection(&stream->cs);
1277 return VFW_E_WRONG_STATE;
1279 if (stream->flushing)
1281 LeaveCriticalSection(&stream->cs);
1282 return S_FALSE;
1285 hr = IMediaSample_GetPointer(sample, &pointer);
1286 if (FAILED(hr))
1288 LeaveCriticalSection(&stream->cs);
1289 return hr;
1292 IMediaSample_GetTime(sample, &start_time, &end_time);
1294 receive = calloc(1, sizeof(*receive));
1295 if (!receive)
1297 LeaveCriticalSection(&stream->cs);
1298 return E_OUTOFMEMORY;
1301 receive->length = IMediaSample_GetActualDataLength(sample);
1302 receive->pointer = pointer;
1303 receive->sample = sample;
1304 receive->start_time = start_time + stream->segment_start;
1305 IMediaSample_AddRef(receive->sample);
1306 list_add_tail(&stream->receive_queue, &receive->entry);
1308 process_updates(stream);
1310 LeaveCriticalSection(&stream->cs);
1312 return S_OK;
1315 static HRESULT WINAPI audio_meminput_ReceiveMultiple(IMemInputPin *iface,
1316 IMediaSample **samples, LONG count, LONG *processed)
1318 FIXME("iface %p, samples %p, count %u, processed %p, stub!\n", iface, samples, count, processed);
1319 return E_NOTIMPL;
1322 static HRESULT WINAPI audio_meminput_ReceiveCanBlock(IMemInputPin *iface)
1324 TRACE("iface %p.\n", iface);
1325 return S_OK;
1328 static const IMemInputPinVtbl audio_meminput_vtbl =
1330 audio_meminput_QueryInterface,
1331 audio_meminput_AddRef,
1332 audio_meminput_Release,
1333 audio_meminput_GetAllocator,
1334 audio_meminput_NotifyAllocator,
1335 audio_meminput_GetAllocatorRequirements,
1336 audio_meminput_Receive,
1337 audio_meminput_ReceiveMultiple,
1338 audio_meminput_ReceiveCanBlock,
1341 HRESULT audio_stream_create(IUnknown *outer, void **out)
1343 struct audio_stream *object;
1345 if (outer)
1346 return CLASS_E_NOAGGREGATION;
1348 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1349 if (!object)
1350 return E_OUTOFMEMORY;
1352 object->IAMMediaStream_iface.lpVtbl = &audio_IAMMediaStream_vtbl;
1353 object->IAudioMediaStream_iface.lpVtbl = &audio_IAudioMediaStream_vtbl;
1354 object->IMemInputPin_iface.lpVtbl = &audio_meminput_vtbl;
1355 object->IPin_iface.lpVtbl = &audio_sink_vtbl;
1356 object->ref = 1;
1358 InitializeCriticalSection(&object->cs);
1359 list_init(&object->receive_queue);
1360 list_init(&object->update_queue);
1362 TRACE("Created audio stream %p.\n", object);
1364 *out = &object->IAMMediaStream_iface;
1366 return S_OK;