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
;
68 IAudioStreamSample IAudioStreamSample_iface
;
70 struct audio_stream
*parent
;
71 IAudioData
*audio_data
;
72 STREAM_TIME start_time
;
83 static void remove_queued_receive(struct queued_receive
*receive
)
85 list_remove(&receive
->entry
);
86 IMediaSample_Release(receive
->sample
);
90 static void remove_queued_update(struct audio_sample
*sample
)
94 hr
= IAudioData_SetActual(sample
->audio_data
, sample
->position
);
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
)
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
)
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
);
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
);
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
);
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
);
201 IAMMediaStream_Release(&sample
->parent
->IAMMediaStream_iface
);
202 IAudioData_Release(sample
->audio_data
);
203 CloseHandle(sample
->update_event
);
204 HeapFree(GetProcessHeap(), 0, sample
);
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
);
219 IAMMediaStream_AddRef(&sample
->parent
->IAMMediaStream_iface
);
220 *media_stream
= (IMediaStream
*)&sample
->parent
->IAMMediaStream_iface
;
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
);
233 IMediaStreamFilter_GetCurrentStreamTime(sample
->parent
->filter
, current_time
);
236 *start_time
= sample
->start_time
;
238 *end_time
= sample
->end_time
;
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
);
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
);
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
);
266 if (event
&& apc_func
)
271 FIXME("APC support is not implemented!\n");
277 FIXME("Event parameter support is not implemented!\n");
281 if (flags
& ~SSUPDATE_ASYNC
)
283 FIXME("Unsupported flags %#x.\n", flags
);
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
);
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
))
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
);
330 TRACE("sample %p, flags %#x, milliseconds %u.\n", sample
, flags
, milliseconds
);
334 FIXME("Unhandled flags %#x.\n", flags
);
338 EnterCriticalSection(&sample
->parent
->cs
);
340 hr
= sample
->update_hr
;
342 LeaveCriticalSection(&sample
->parent
->cs
);
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
);
357 IAudioData_AddRef(sample
->audio_data
);
358 *audio_data
= sample
->audio_data
;
363 static const struct IAudioStreamSampleVtbl AudioStreamSample_Vtbl
=
365 /*** IUnknown methods ***/
366 audio_sample_QueryInterface
,
368 audio_sample_Release
,
369 /*** IStreamSample methods ***/
370 audio_sample_GetMediaStream
,
371 audio_sample_GetSampleTimes
,
372 audio_sample_SetSampleTimes
,
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
));
387 return E_OUTOFMEMORY
;
389 object
->IAudioStreamSample_iface
.lpVtbl
= &AudioStreamSample_Vtbl
;
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
;
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
);
423 else if (IsEqualGUID(riid
, &IID_IAudioMediaStream
))
425 IAMMediaStream_AddRef(iface
);
426 *ret_iface
= &This
->IAudioMediaStream_iface
;
429 else if (IsEqualGUID(riid
, &IID_IPin
))
431 IAMMediaStream_AddRef(iface
);
432 *ret_iface
= &This
->IPin_iface
;
435 else if (IsEqualGUID(riid
, &IID_IMemInputPin
))
437 IAMMediaStream_AddRef(iface
);
438 *ret_iface
= &This
->IMemInputPin_iface
;
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
);
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
);
465 DeleteCriticalSection(&This
->cs
);
466 HeapFree(GetProcessHeap(), 0, This
);
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
);
484 IMultiMediaStream_AddRef(stream
->parent
);
485 *mmstream
= stream
->parent
;
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
);
497 *purpose_id
= This
->purpose_id
;
499 *type
= This
->stream_type
;
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
);
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
);
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
);
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
);
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
);
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
;
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
)
580 stream
->state
= state
;
582 LeaveCriticalSection(&stream
->cs
);
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
;
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
;
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
);
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
);
716 EnterCriticalSection(&stream
->cs
);
720 LeaveCriticalSection(&stream
->cs
);
721 return MS_E_NOSTREAM
;
724 *format
= *(WAVEFORMATEX
*)stream
->mt
.pbFormat
;
726 LeaveCriticalSection(&stream
->cs
);
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
);
740 if (format
->wFormatTag
!= WAVE_FORMAT_PCM
)
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
);
752 stream
->format
= *format
;
754 LeaveCriticalSection(&stream
->cs
);
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
);
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
;
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
);
813 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
832 heap_free(enum_media_types
);
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
,
844 .nSamplesPerSec
= 11025,
845 .nAvgBytesPerSec
= 11025 * 2,
847 .wBitsPerSample
= 16,
851 TRACE("iface %p, count %u, mts %p, ret_count %p.\n", iface
, count
, mts
, ret_count
);
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
;
872 return count
== 1 ? S_OK
: S_FALSE
;
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
;
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;
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
;
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
);
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
);
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
)
972 EnterCriticalSection(&stream
->cs
);
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
);
994 CopyMediaType(&stream
->mt
, mt
);
995 IPin_AddRef(stream
->peer
= peer
);
997 LeaveCriticalSection(&stream
->cs
);
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
);
1012 LeaveCriticalSection(&stream
->cs
);
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
);
1026 static HRESULT WINAPI
audio_sink_ConnectedTo(IPin
*iface
, IPin
**peer
)
1028 struct audio_stream
*stream
= impl_from_IPin(iface
);
1031 TRACE("stream %p, peer %p.\n", stream
, peer
);
1033 EnterCriticalSection(&stream
->cs
);
1037 IPin_AddRef(*peer
= stream
->peer
);
1043 hr
= VFW_E_NOT_CONNECTED
;
1046 LeaveCriticalSection(&stream
->cs
);
1051 static HRESULT WINAPI
audio_sink_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mt
)
1053 struct audio_stream
*stream
= impl_from_IPin(iface
);
1056 TRACE("stream %p, mt %p.\n", stream
, mt
);
1058 EnterCriticalSection(&stream
->cs
);
1062 CopyMediaType(mt
, &stream
->mt
);
1067 memset(mt
, 0, sizeof(AM_MEDIA_TYPE
));
1068 hr
= VFW_E_NOT_CONNECTED
;
1071 LeaveCriticalSection(&stream
->cs
);
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
);
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
;
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
);
1108 static HRESULT WINAPI
audio_sink_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mt
)
1110 TRACE("iface %p, mt %p.\n", iface
, mt
);
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
)
1123 if (!(object
= heap_alloc(sizeof(*object
))))
1124 return E_OUTOFMEMORY
;
1126 object
->IEnumMediaTypes_iface
.lpVtbl
= &enum_media_types_vtbl
;
1127 object
->refcount
= 1;
1130 *enum_media_types
= &object
->IEnumMediaTypes_iface
;
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
);
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
);
1156 process_updates(stream
);
1158 LeaveCriticalSection(&stream
->cs
);
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
);
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
);
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
);
1211 static const IPinVtbl audio_sink_vtbl
=
1213 audio_sink_QueryInterface
,
1217 audio_sink_ReceiveConnection
,
1218 audio_sink_Disconnect
,
1219 audio_sink_ConnectedTo
,
1220 audio_sink_ConnectionMediaType
,
1221 audio_sink_QueryPinInfo
,
1222 audio_sink_QueryDirection
,
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
);
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
);
1282 IMemAllocator_AddRef(allocator
);
1283 if (stream
->allocator
)
1284 IMemAllocator_Release(stream
->allocator
);
1285 stream
->allocator
= allocator
;
1290 static HRESULT WINAPI
audio_meminput_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
1292 TRACE("iface %p, props %p.\n", iface
, props
);
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;
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
);
1320 hr
= IMediaSample_GetPointer(sample
, &pointer
);
1323 LeaveCriticalSection(&stream
->cs
);
1327 IMediaSample_GetTime(sample
, &start_time
, &end_time
);
1329 receive
= calloc(1, sizeof(*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
);
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
);
1357 static HRESULT WINAPI
audio_meminput_ReceiveCanBlock(IMemInputPin
*iface
)
1359 TRACE("iface %p.\n", iface
);
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
;
1381 return CLASS_E_NOAGGREGATION
;
1383 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*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
;
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
;