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
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}";
37 STREAM_TIME start_time
;
42 IAMMediaStream IAMMediaStream_iface
;
43 IAudioMediaStream IAudioMediaStream_iface
;
44 IMemInputPin IMemInputPin_iface
;
48 IMultiMediaStream
* parent
;
50 STREAM_TYPE stream_type
;
52 IMediaStreamFilter
*filter
;
55 IMemAllocator
*allocator
;
59 REFERENCE_TIME segment_start
;
62 struct list receive_queue
;
63 struct list update_queue
;
67 IAudioStreamSample IAudioStreamSample_iface
;
69 struct audio_stream
*parent
;
70 IAudioData
*audio_data
;
71 STREAM_TIME start_time
;
80 } IAudioStreamSampleImpl
;
82 static void remove_queued_receive(struct queued_receive
*receive
)
84 list_remove(&receive
->entry
);
85 IMediaSample_Release(receive
->sample
);
89 static void remove_queued_update(IAudioStreamSampleImpl
*sample
)
93 hr
= IAudioData_SetActual(sample
->audio_data
, sample
->position
);
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
)
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
)
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
);
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
);
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
);
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
);
204 CloseHandle(This
->update_event
);
205 HeapFree(GetProcessHeap(), 0, This
);
211 /*** IStreamSample methods ***/
212 static HRESULT WINAPI
IAudioStreamSampleImpl_GetMediaStream(IAudioStreamSample
*iface
, IMediaStream
**media_stream
)
214 FIXME("(%p)->(%p): stub\n", iface
, media_stream
);
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
);
227 IMediaStreamFilter_GetCurrentStreamTime(sample
->parent
->filter
, current_time
);
230 *start_time
= sample
->start_time
;
232 *end_time
= sample
->end_time
;
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
);
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
);
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
);
260 if (event
&& apc_func
)
265 FIXME("APC support is not implemented!\n");
271 FIXME("Event parameter support is not implemented!\n");
275 if (flags
& ~SSUPDATE_ASYNC
)
277 FIXME("Unsupported flags %#x.\n", flags
);
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
);
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
))
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
);
324 TRACE("sample %p, flags %#x, milliseconds %u.\n", sample
, flags
, milliseconds
);
328 FIXME("Unhandled flags %#x.\n", flags
);
332 EnterCriticalSection(&sample
->parent
->cs
);
334 hr
= sample
->update_hr
;
336 LeaveCriticalSection(&sample
->parent
->cs
);
341 /*** IAudioStreamSample methods ***/
342 static HRESULT WINAPI
IAudioStreamSampleImpl_GetAudioData(IAudioStreamSample
*iface
, IAudioData
**audio_data
)
344 FIXME("(%p)->(%p): stub\n", iface
, audio_data
);
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
));
373 return E_OUTOFMEMORY
;
375 object
->IAudioStreamSample_iface
.lpVtbl
= &AudioStreamSample_Vtbl
;
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
;
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
);
407 else if (IsEqualGUID(riid
, &IID_IAudioMediaStream
))
409 IAMMediaStream_AddRef(iface
);
410 *ret_iface
= &This
->IAudioMediaStream_iface
;
413 else if (IsEqualGUID(riid
, &IID_IPin
))
415 IAMMediaStream_AddRef(iface
);
416 *ret_iface
= &This
->IPin_iface
;
419 else if (IsEqualGUID(riid
, &IID_IMemInputPin
))
421 IAMMediaStream_AddRef(iface
);
422 *ret_iface
= &This
->IMemInputPin_iface
;
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
);
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
);
449 DeleteCriticalSection(&This
->cs
);
450 HeapFree(GetProcessHeap(), 0, This
);
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
);
468 IMultiMediaStream_AddRef(stream
->parent
);
469 *mmstream
= stream
->parent
;
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
);
481 *purpose_id
= This
->purpose_id
;
483 *type
= This
->stream_type
;
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
);
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
);
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
);
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
);
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
);
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
;
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
)
564 stream
->state
= state
;
566 LeaveCriticalSection(&stream
->cs
);
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
;
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
;
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
);
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
);
700 EnterCriticalSection(&stream
->cs
);
704 LeaveCriticalSection(&stream
->cs
);
705 return MS_E_NOSTREAM
;
708 *format
= *(WAVEFORMATEX
*)stream
->mt
.pbFormat
;
710 LeaveCriticalSection(&stream
->cs
);
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
);
724 if (format
->wFormatTag
!= WAVE_FORMAT_PCM
)
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
);
736 stream
->format
= *format
;
738 LeaveCriticalSection(&stream
->cs
);
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
);
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
;
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
);
797 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
816 heap_free(enum_media_types
);
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
);
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
;
837 return count
== 1 ? S_OK
: S_FALSE
;
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
;
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;
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
;
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
);
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
);
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
)
937 EnterCriticalSection(&stream
->cs
);
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
);
959 CopyMediaType(&stream
->mt
, mt
);
960 IPin_AddRef(stream
->peer
= peer
);
962 LeaveCriticalSection(&stream
->cs
);
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
);
977 LeaveCriticalSection(&stream
->cs
);
981 IPin_Release(stream
->peer
);
983 FreeMediaType(&stream
->mt
);
984 memset(&stream
->mt
, 0, sizeof(AM_MEDIA_TYPE
));
986 LeaveCriticalSection(&stream
->cs
);
991 static HRESULT WINAPI
audio_sink_ConnectedTo(IPin
*iface
, IPin
**peer
)
993 struct audio_stream
*stream
= impl_from_IPin(iface
);
996 TRACE("stream %p, peer %p.\n", stream
, peer
);
998 EnterCriticalSection(&stream
->cs
);
1002 IPin_AddRef(*peer
= stream
->peer
);
1008 hr
= VFW_E_NOT_CONNECTED
;
1011 LeaveCriticalSection(&stream
->cs
);
1016 static HRESULT WINAPI
audio_sink_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mt
)
1018 struct audio_stream
*stream
= impl_from_IPin(iface
);
1021 TRACE("stream %p, mt %p.\n", stream
, mt
);
1023 EnterCriticalSection(&stream
->cs
);
1027 CopyMediaType(mt
, &stream
->mt
);
1032 memset(mt
, 0, sizeof(AM_MEDIA_TYPE
));
1033 hr
= VFW_E_NOT_CONNECTED
;
1036 LeaveCriticalSection(&stream
->cs
);
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
);
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
;
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
);
1073 static HRESULT WINAPI
audio_sink_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mt
)
1075 TRACE("iface %p, mt %p.\n", iface
, mt
);
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
)
1088 if (!(object
= heap_alloc(sizeof(*object
))))
1089 return E_OUTOFMEMORY
;
1091 object
->IEnumMediaTypes_iface
.lpVtbl
= &enum_media_types_vtbl
;
1092 object
->refcount
= 1;
1095 *enum_media_types
= &object
->IEnumMediaTypes_iface
;
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
);
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
);
1121 process_updates(stream
);
1123 LeaveCriticalSection(&stream
->cs
);
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
);
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
);
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
);
1176 static const IPinVtbl audio_sink_vtbl
=
1178 audio_sink_QueryInterface
,
1182 audio_sink_ReceiveConnection
,
1183 audio_sink_Disconnect
,
1184 audio_sink_ConnectedTo
,
1185 audio_sink_ConnectionMediaType
,
1186 audio_sink_QueryPinInfo
,
1187 audio_sink_QueryDirection
,
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
);
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
);
1247 IMemAllocator_AddRef(allocator
);
1248 if (stream
->allocator
)
1249 IMemAllocator_Release(stream
->allocator
);
1250 stream
->allocator
= allocator
;
1255 static HRESULT WINAPI
audio_meminput_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
1257 TRACE("iface %p, props %p.\n", iface
, props
);
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;
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
);
1285 hr
= IMediaSample_GetPointer(sample
, &pointer
);
1288 LeaveCriticalSection(&stream
->cs
);
1292 IMediaSample_GetTime(sample
, &start_time
, &end_time
);
1294 receive
= calloc(1, sizeof(*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
);
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
);
1322 static HRESULT WINAPI
audio_meminput_ReceiveCanBlock(IMemInputPin
*iface
)
1324 TRACE("iface %p.\n", iface
);
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
;
1346 return CLASS_E_NOAGGREGATION
;
1348 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*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
;
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
;