widl: Strip last separator in append_namespaces if suffix is NULL.
[wine.git] / dlls / amstream / audiostream.c
blobdc6c810d19adeb7019513ea7608245502460ac06
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 struct audio_sample
68 IAudioStreamSample IAudioStreamSample_iface;
69 LONG ref;
70 struct audio_stream *parent;
71 IAudioData *audio_data;
72 STREAM_TIME start_time;
73 STREAM_TIME end_time;
74 HANDLE update_event;
76 struct list entry;
77 DWORD length;
78 BYTE *pointer;
79 DWORD position;
80 HRESULT update_hr;
83 static void remove_queued_receive(struct queued_receive *receive)
85 list_remove(&receive->entry);
86 IMediaSample_Release(receive->sample);
87 free(receive);
90 static void remove_queued_update(struct audio_sample *sample)
92 HRESULT hr;
94 hr = IAudioData_SetActual(sample->audio_data, sample->position);
95 if (FAILED(hr))
96 sample->update_hr = hr;
98 list_remove(&sample->entry);
99 SetEvent(sample->update_event);
102 static void flush_receive_queue(struct audio_stream *stream)
104 struct list *entry;
106 while ((entry = list_head(&stream->receive_queue)))
107 remove_queued_receive(LIST_ENTRY(entry, struct queued_receive, entry));
110 static STREAM_TIME stream_time_from_position(struct audio_stream *stream, struct queued_receive *receive)
112 const WAVEFORMATEX *format = (WAVEFORMATEX *)stream->mt.pbFormat;
113 return receive->start_time + (receive->position * 10000000 + format->nAvgBytesPerSec / 2) / format->nAvgBytesPerSec;
116 static void process_update(struct audio_sample *sample, struct queued_receive *receive)
118 DWORD advance;
120 advance = min(receive->length - receive->position, sample->length - sample->position);
121 memcpy(&sample->pointer[sample->position], &receive->pointer[receive->position], advance);
123 if (!sample->position)
124 sample->start_time = stream_time_from_position(sample->parent, receive);
126 receive->position += advance;
127 sample->position += advance;
129 sample->end_time = stream_time_from_position(sample->parent, receive);
131 sample->update_hr = (sample->position == sample->length) ? S_OK : MS_S_PENDING;
134 static void process_updates(struct audio_stream *stream)
136 while (!list_empty(&stream->update_queue) && !list_empty(&stream->receive_queue))
138 struct audio_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct audio_sample, entry);
139 struct queued_receive *receive = LIST_ENTRY(list_head(&stream->receive_queue), struct queued_receive, entry);
141 process_update(sample, receive);
143 if (sample->update_hr != MS_S_PENDING)
144 remove_queued_update(sample);
145 if (receive->position == receive->length)
146 remove_queued_receive(receive);
148 if (stream->eos)
150 while (!list_empty(&stream->update_queue))
152 struct audio_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct audio_sample, entry);
154 sample->update_hr = sample->position ? S_OK : MS_S_ENDOFSTREAM;
155 remove_queued_update(sample);
160 static inline struct audio_sample *impl_from_IAudioStreamSample(IAudioStreamSample *iface)
162 return CONTAINING_RECORD(iface, struct audio_sample, IAudioStreamSample_iface);
165 /*** IUnknown methods ***/
166 static HRESULT WINAPI audio_sample_QueryInterface(IAudioStreamSample *iface,
167 REFIID riid, void **ret_iface)
169 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
171 if (IsEqualGUID(riid, &IID_IUnknown) ||
172 IsEqualGUID(riid, &IID_IStreamSample) ||
173 IsEqualGUID(riid, &IID_IAudioStreamSample))
175 IAudioStreamSample_AddRef(iface);
176 *ret_iface = iface;
177 return S_OK;
180 *ret_iface = NULL;
182 ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
183 return E_NOINTERFACE;
186 static ULONG WINAPI audio_sample_AddRef(IAudioStreamSample *iface)
188 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
189 ULONG refcount = InterlockedIncrement(&sample->ref);
190 TRACE("%p increasing refcount to %u.\n", sample, refcount);
191 return refcount;
194 static ULONG WINAPI audio_sample_Release(IAudioStreamSample *iface)
196 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
197 ULONG refcount = InterlockedDecrement(&sample->ref);
198 TRACE("%p decreasing refcount to %u.\n", sample, refcount);
199 if (!refcount)
201 IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
202 IAudioData_Release(sample->audio_data);
203 CloseHandle(sample->update_event);
204 HeapFree(GetProcessHeap(), 0, sample);
206 return refcount;
209 /*** IStreamSample methods ***/
210 static HRESULT WINAPI audio_sample_GetMediaStream(IAudioStreamSample *iface, IMediaStream **media_stream)
212 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
214 TRACE("sample %p, media_stream %p.\n", iface, media_stream);
216 if (!media_stream)
217 return E_POINTER;
219 IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
220 *media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
222 return S_OK;
225 static HRESULT WINAPI audio_sample_GetSampleTimes(IAudioStreamSample *iface, STREAM_TIME *start_time,
226 STREAM_TIME *end_time, STREAM_TIME *current_time)
228 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
230 TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
232 if (current_time)
233 IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
235 if (start_time)
236 *start_time = sample->start_time;
237 if (end_time)
238 *end_time = sample->end_time;
240 return S_OK;
243 static HRESULT WINAPI audio_sample_SetSampleTimes(IAudioStreamSample *iface, const STREAM_TIME *start_time,
244 const STREAM_TIME *end_time)
246 FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
248 return E_NOTIMPL;
251 static HRESULT WINAPI audio_sample_Update(IAudioStreamSample *iface,
252 DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
254 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
255 BYTE *pointer;
256 DWORD length;
257 HRESULT hr;
259 TRACE("sample %p, flags %#x, event %p, apc_func %p, apc_data %#x.\n",
260 sample, flags, event, apc_func, apc_data);
262 hr = IAudioData_GetInfo(sample->audio_data, &length, &pointer, NULL);
263 if (FAILED(hr))
264 return hr;
266 if (event && apc_func)
267 return E_INVALIDARG;
269 if (apc_func)
271 FIXME("APC support is not implemented!\n");
272 return E_NOTIMPL;
275 if (event)
277 FIXME("Event parameter support is not implemented!\n");
278 return E_NOTIMPL;
281 if (flags & ~SSUPDATE_ASYNC)
283 FIXME("Unsupported flags %#x.\n", flags);
284 return E_NOTIMPL;
287 EnterCriticalSection(&sample->parent->cs);
289 if (sample->parent->state != State_Running)
291 LeaveCriticalSection(&sample->parent->cs);
292 return MS_E_NOTRUNNING;
294 if (!sample->parent->peer)
296 LeaveCriticalSection(&sample->parent->cs);
297 return MS_S_ENDOFSTREAM;
299 if (MS_S_PENDING == sample->update_hr)
301 LeaveCriticalSection(&sample->parent->cs);
302 return MS_E_BUSY;
305 sample->length = length;
306 sample->pointer = pointer;
307 sample->position = 0;
308 sample->update_hr = MS_S_PENDING;
309 ResetEvent(sample->update_event);
310 list_add_tail(&sample->parent->update_queue, &sample->entry);
312 process_updates(sample->parent);
313 hr = sample->update_hr;
315 LeaveCriticalSection(&sample->parent->cs);
317 if (hr != MS_S_PENDING || (flags & SSUPDATE_ASYNC))
318 return hr;
320 WaitForSingleObject(sample->update_event, INFINITE);
322 return sample->update_hr;
325 static HRESULT WINAPI audio_sample_CompletionStatus(IAudioStreamSample *iface, DWORD flags, DWORD milliseconds)
327 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
328 HRESULT hr;
330 TRACE("sample %p, flags %#x, milliseconds %u.\n", sample, flags, milliseconds);
332 if (flags)
334 FIXME("Unhandled flags %#x.\n", flags);
335 return E_NOTIMPL;
338 EnterCriticalSection(&sample->parent->cs);
340 hr = sample->update_hr;
342 LeaveCriticalSection(&sample->parent->cs);
344 return hr;
347 /*** IAudioStreamSample methods ***/
348 static HRESULT WINAPI audio_sample_GetAudioData(IAudioStreamSample *iface, IAudioData **audio_data)
350 struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
352 TRACE("sample %p, audio_data %p.\n", sample, audio_data);
354 if (!audio_data)
355 return E_POINTER;
357 IAudioData_AddRef(sample->audio_data);
358 *audio_data = sample->audio_data;
360 return S_OK;
363 static const struct IAudioStreamSampleVtbl AudioStreamSample_Vtbl =
365 /*** IUnknown methods ***/
366 audio_sample_QueryInterface,
367 audio_sample_AddRef,
368 audio_sample_Release,
369 /*** IStreamSample methods ***/
370 audio_sample_GetMediaStream,
371 audio_sample_GetSampleTimes,
372 audio_sample_SetSampleTimes,
373 audio_sample_Update,
374 audio_sample_CompletionStatus,
375 /*** IAudioStreamSample methods ***/
376 audio_sample_GetAudioData
379 static HRESULT audiostreamsample_create(struct audio_stream *parent, IAudioData *audio_data, IAudioStreamSample **audio_stream_sample)
381 struct audio_sample *object;
383 TRACE("(%p)\n", audio_stream_sample);
385 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
386 if (!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 = %u\n", iface, This, ref);
453 return ref;
456 static ULONG WINAPI audio_IAMMediaStream_Release(IAMMediaStream *iface)
458 struct audio_stream *This = impl_from_IAMMediaStream(iface);
459 ULONG ref = InterlockedDecrement(&This->ref);
461 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
463 if (!ref)
465 DeleteCriticalSection(&This->cs);
466 HeapFree(GetProcessHeap(), 0, This);
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,%x) 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)->(%x,%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,%x,%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)->(%x) 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 %x, 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,%u,%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 %u.\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 %u.\n", enum_media_types, refcount);
831 if (!refcount)
832 heap_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 %u, 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 %u.\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 = heap_alloc(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 = heap_alloc(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 return S_OK;
1163 static HRESULT WINAPI audio_sink_BeginFlush(IPin *iface)
1165 struct audio_stream *stream = impl_from_IPin(iface);
1167 TRACE("stream %p.\n", stream);
1169 EnterCriticalSection(&stream->cs);
1171 stream->flushing = TRUE;
1172 stream->eos = FALSE;
1173 flush_receive_queue(stream);
1175 LeaveCriticalSection(&stream->cs);
1177 return S_OK;
1180 static HRESULT WINAPI audio_sink_EndFlush(IPin *iface)
1182 struct audio_stream *stream = impl_from_IPin(iface);
1184 TRACE("stream %p.\n", stream);
1186 EnterCriticalSection(&stream->cs);
1188 stream->flushing = FALSE;
1190 LeaveCriticalSection(&stream->cs);
1192 return S_OK;
1195 static HRESULT WINAPI audio_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1197 struct audio_stream *stream = impl_from_IPin(iface);
1199 TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1200 stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1202 EnterCriticalSection(&stream->cs);
1204 stream->segment_start = start;
1206 LeaveCriticalSection(&stream->cs);
1208 return S_OK;
1211 static const IPinVtbl audio_sink_vtbl =
1213 audio_sink_QueryInterface,
1214 audio_sink_AddRef,
1215 audio_sink_Release,
1216 audio_sink_Connect,
1217 audio_sink_ReceiveConnection,
1218 audio_sink_Disconnect,
1219 audio_sink_ConnectedTo,
1220 audio_sink_ConnectionMediaType,
1221 audio_sink_QueryPinInfo,
1222 audio_sink_QueryDirection,
1223 audio_sink_QueryId,
1224 audio_sink_QueryAccept,
1225 audio_sink_EnumMediaTypes,
1226 audio_sink_QueryInternalConnections,
1227 audio_sink_EndOfStream,
1228 audio_sink_BeginFlush,
1229 audio_sink_EndFlush,
1230 audio_sink_NewSegment,
1233 static inline struct audio_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1235 return CONTAINING_RECORD(iface, struct audio_stream, IMemInputPin_iface);
1238 static HRESULT WINAPI audio_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1240 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1241 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1244 static ULONG WINAPI audio_meminput_AddRef(IMemInputPin *iface)
1246 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1247 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1250 static ULONG WINAPI audio_meminput_Release(IMemInputPin *iface)
1252 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1253 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1256 static HRESULT WINAPI audio_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1258 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1260 TRACE("stream %p, allocator %p.\n", stream, allocator);
1262 if (stream->allocator)
1264 IMemAllocator_AddRef(*allocator = stream->allocator);
1265 return S_OK;
1268 *allocator = NULL;
1269 return VFW_E_NO_ALLOCATOR;
1272 static HRESULT WINAPI audio_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1274 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1276 TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1278 if (!allocator)
1279 return E_POINTER;
1281 if (allocator)
1282 IMemAllocator_AddRef(allocator);
1283 if (stream->allocator)
1284 IMemAllocator_Release(stream->allocator);
1285 stream->allocator = allocator;
1287 return S_OK;
1290 static HRESULT WINAPI audio_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1292 TRACE("iface %p, props %p.\n", iface, props);
1293 return E_NOTIMPL;
1296 static HRESULT WINAPI audio_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
1298 struct audio_stream *stream = impl_from_IMemInputPin(iface);
1299 struct queued_receive *receive;
1300 REFERENCE_TIME start_time = 0;
1301 REFERENCE_TIME end_time = 0;
1302 BYTE *pointer;
1303 HRESULT hr;
1305 TRACE("stream %p, sample %p.\n", stream, sample);
1307 EnterCriticalSection(&stream->cs);
1309 if (stream->state == State_Stopped)
1311 LeaveCriticalSection(&stream->cs);
1312 return VFW_E_WRONG_STATE;
1314 if (stream->flushing)
1316 LeaveCriticalSection(&stream->cs);
1317 return S_FALSE;
1320 hr = IMediaSample_GetPointer(sample, &pointer);
1321 if (FAILED(hr))
1323 LeaveCriticalSection(&stream->cs);
1324 return hr;
1327 IMediaSample_GetTime(sample, &start_time, &end_time);
1329 receive = calloc(1, sizeof(*receive));
1330 if (!receive)
1332 LeaveCriticalSection(&stream->cs);
1333 return E_OUTOFMEMORY;
1336 receive->length = IMediaSample_GetActualDataLength(sample);
1337 receive->pointer = pointer;
1338 receive->sample = sample;
1339 receive->start_time = start_time + stream->segment_start;
1340 IMediaSample_AddRef(receive->sample);
1341 list_add_tail(&stream->receive_queue, &receive->entry);
1343 process_updates(stream);
1345 LeaveCriticalSection(&stream->cs);
1347 return S_OK;
1350 static HRESULT WINAPI audio_meminput_ReceiveMultiple(IMemInputPin *iface,
1351 IMediaSample **samples, LONG count, LONG *processed)
1353 FIXME("iface %p, samples %p, count %u, processed %p, stub!\n", iface, samples, count, processed);
1354 return E_NOTIMPL;
1357 static HRESULT WINAPI audio_meminput_ReceiveCanBlock(IMemInputPin *iface)
1359 TRACE("iface %p.\n", iface);
1360 return S_OK;
1363 static const IMemInputPinVtbl audio_meminput_vtbl =
1365 audio_meminput_QueryInterface,
1366 audio_meminput_AddRef,
1367 audio_meminput_Release,
1368 audio_meminput_GetAllocator,
1369 audio_meminput_NotifyAllocator,
1370 audio_meminput_GetAllocatorRequirements,
1371 audio_meminput_Receive,
1372 audio_meminput_ReceiveMultiple,
1373 audio_meminput_ReceiveCanBlock,
1376 HRESULT audio_stream_create(IUnknown *outer, void **out)
1378 struct audio_stream *object;
1380 if (outer)
1381 return CLASS_E_NOAGGREGATION;
1383 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1384 if (!object)
1385 return E_OUTOFMEMORY;
1387 object->IAMMediaStream_iface.lpVtbl = &audio_IAMMediaStream_vtbl;
1388 object->IAudioMediaStream_iface.lpVtbl = &audio_IAudioMediaStream_vtbl;
1389 object->IMemInputPin_iface.lpVtbl = &audio_meminput_vtbl;
1390 object->IPin_iface.lpVtbl = &audio_sink_vtbl;
1391 object->ref = 1;
1393 InitializeCriticalSection(&object->cs);
1394 list_init(&object->receive_queue);
1395 list_init(&object->update_queue);
1397 TRACE("Created audio stream %p.\n", object);
1399 *out = &object->IAMMediaStream_iface;
1401 return S_OK;