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/list.h"
25 #include "wine/strmbase.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
29 static const WCHAR sink_id
[] = L
"I{A35FF56B-9FDA-11D0-8FDF-00C04FD9189D}";
38 STREAM_TIME start_time
;
43 IAMMediaStream IAMMediaStream_iface
;
44 IAudioMediaStream IAudioMediaStream_iface
;
45 IMemInputPin IMemInputPin_iface
;
49 IMultiMediaStream
* parent
;
51 STREAM_TYPE stream_type
;
53 IMediaStreamFilter
*filter
;
56 IMemAllocator
*allocator
;
60 REFERENCE_TIME segment_start
;
63 struct list receive_queue
;
64 struct list update_queue
;
69 IAudioStreamSample IAudioStreamSample_iface
;
71 struct audio_stream
*parent
;
72 IAudioData
*audio_data
;
73 STREAM_TIME start_time
;
84 static void remove_queued_receive(struct queued_receive
*receive
)
86 list_remove(&receive
->entry
);
87 IMediaSample_Release(receive
->sample
);
91 static void remove_queued_update(struct audio_sample
*sample
)
95 hr
= IAudioData_SetActual(sample
->audio_data
, sample
->position
);
97 sample
->update_hr
= hr
;
99 list_remove(&sample
->entry
);
100 SetEvent(sample
->update_event
);
103 static void flush_receive_queue(struct audio_stream
*stream
)
107 while ((entry
= list_head(&stream
->receive_queue
)))
108 remove_queued_receive(LIST_ENTRY(entry
, struct queued_receive
, entry
));
111 static STREAM_TIME
stream_time_from_position(struct audio_stream
*stream
, struct queued_receive
*receive
)
113 const WAVEFORMATEX
*format
= (WAVEFORMATEX
*)stream
->mt
.pbFormat
;
114 return receive
->start_time
+ (receive
->position
* 10000000 + format
->nAvgBytesPerSec
/ 2) / format
->nAvgBytesPerSec
;
117 static void process_update(struct audio_sample
*sample
, struct queued_receive
*receive
)
121 advance
= min(receive
->length
- receive
->position
, sample
->length
- sample
->position
);
122 memcpy(&sample
->pointer
[sample
->position
], &receive
->pointer
[receive
->position
], advance
);
124 if (!sample
->position
)
125 sample
->start_time
= stream_time_from_position(sample
->parent
, receive
);
127 receive
->position
+= advance
;
128 sample
->position
+= advance
;
130 sample
->end_time
= stream_time_from_position(sample
->parent
, receive
);
132 sample
->update_hr
= (sample
->position
== sample
->length
) ? S_OK
: MS_S_PENDING
;
135 static void process_updates(struct audio_stream
*stream
)
137 while (!list_empty(&stream
->update_queue
) && !list_empty(&stream
->receive_queue
))
139 struct audio_sample
*sample
= LIST_ENTRY(list_head(&stream
->update_queue
), struct audio_sample
, entry
);
140 struct queued_receive
*receive
= LIST_ENTRY(list_head(&stream
->receive_queue
), struct queued_receive
, entry
);
142 process_update(sample
, receive
);
144 if (sample
->update_hr
!= MS_S_PENDING
)
145 remove_queued_update(sample
);
146 if (receive
->position
== receive
->length
)
147 remove_queued_receive(receive
);
151 while (!list_empty(&stream
->update_queue
))
153 struct audio_sample
*sample
= LIST_ENTRY(list_head(&stream
->update_queue
), struct audio_sample
, entry
);
155 sample
->update_hr
= sample
->position
? S_OK
: MS_S_ENDOFSTREAM
;
156 remove_queued_update(sample
);
161 static inline struct audio_sample
*impl_from_IAudioStreamSample(IAudioStreamSample
*iface
)
163 return CONTAINING_RECORD(iface
, struct audio_sample
, IAudioStreamSample_iface
);
166 /*** IUnknown methods ***/
167 static HRESULT WINAPI
audio_sample_QueryInterface(IAudioStreamSample
*iface
,
168 REFIID riid
, void **ret_iface
)
170 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ret_iface
);
172 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
173 IsEqualGUID(riid
, &IID_IStreamSample
) ||
174 IsEqualGUID(riid
, &IID_IAudioStreamSample
))
176 IAudioStreamSample_AddRef(iface
);
183 ERR("(%p)->(%s,%p),not found\n", iface
, debugstr_guid(riid
), ret_iface
);
184 return E_NOINTERFACE
;
187 static ULONG WINAPI
audio_sample_AddRef(IAudioStreamSample
*iface
)
189 struct audio_sample
*sample
= impl_from_IAudioStreamSample(iface
);
190 ULONG refcount
= InterlockedIncrement(&sample
->ref
);
191 TRACE("%p increasing refcount to %lu.\n", sample
, refcount
);
195 static ULONG WINAPI
audio_sample_Release(IAudioStreamSample
*iface
)
197 struct audio_sample
*sample
= impl_from_IAudioStreamSample(iface
);
198 ULONG refcount
= InterlockedDecrement(&sample
->ref
);
199 TRACE("%p decreasing refcount to %lu.\n", sample
, refcount
);
202 IAMMediaStream_Release(&sample
->parent
->IAMMediaStream_iface
);
203 IAudioData_Release(sample
->audio_data
);
204 CloseHandle(sample
->update_event
);
210 /*** IStreamSample methods ***/
211 static HRESULT WINAPI
audio_sample_GetMediaStream(IAudioStreamSample
*iface
, IMediaStream
**media_stream
)
213 struct audio_sample
*sample
= impl_from_IAudioStreamSample(iface
);
215 TRACE("sample %p, media_stream %p.\n", iface
, media_stream
);
220 IAMMediaStream_AddRef(&sample
->parent
->IAMMediaStream_iface
);
221 *media_stream
= (IMediaStream
*)&sample
->parent
->IAMMediaStream_iface
;
226 static HRESULT WINAPI
audio_sample_GetSampleTimes(IAudioStreamSample
*iface
, STREAM_TIME
*start_time
,
227 STREAM_TIME
*end_time
, STREAM_TIME
*current_time
)
229 struct audio_sample
*sample
= impl_from_IAudioStreamSample(iface
);
231 TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample
, start_time
, end_time
, current_time
);
234 IMediaStreamFilter_GetCurrentStreamTime(sample
->parent
->filter
, current_time
);
237 *start_time
= sample
->start_time
;
239 *end_time
= sample
->end_time
;
244 static HRESULT WINAPI
audio_sample_SetSampleTimes(IAudioStreamSample
*iface
, const STREAM_TIME
*start_time
,
245 const STREAM_TIME
*end_time
)
247 FIXME("(%p)->(%p,%p): stub\n", iface
, start_time
, end_time
);
252 static HRESULT WINAPI
audio_sample_Update(IAudioStreamSample
*iface
,
253 DWORD flags
, HANDLE event
, PAPCFUNC apc_func
, DWORD apc_data
)
255 struct audio_sample
*sample
= impl_from_IAudioStreamSample(iface
);
260 TRACE("sample %p, flags %#lx, event %p, apc_func %p, apc_data %#lx.\n",
261 sample
, flags
, event
, apc_func
, apc_data
);
263 hr
= IAudioData_GetInfo(sample
->audio_data
, &length
, &pointer
, NULL
);
267 if (event
&& apc_func
)
272 FIXME("APC support is not implemented!\n");
278 FIXME("Event parameter support is not implemented!\n");
282 if (flags
& ~SSUPDATE_ASYNC
)
284 FIXME("Unsupported flags %#lx.\n", flags
);
288 EnterCriticalSection(&sample
->parent
->cs
);
290 if (sample
->parent
->state
!= State_Running
)
292 LeaveCriticalSection(&sample
->parent
->cs
);
293 return MS_E_NOTRUNNING
;
295 if (!sample
->parent
->peer
)
297 LeaveCriticalSection(&sample
->parent
->cs
);
298 return MS_S_ENDOFSTREAM
;
300 if (MS_S_PENDING
== sample
->update_hr
)
302 LeaveCriticalSection(&sample
->parent
->cs
);
306 sample
->length
= length
;
307 sample
->pointer
= pointer
;
308 sample
->position
= 0;
309 sample
->update_hr
= MS_S_PENDING
;
310 ResetEvent(sample
->update_event
);
311 list_add_tail(&sample
->parent
->update_queue
, &sample
->entry
);
313 process_updates(sample
->parent
);
314 hr
= sample
->update_hr
;
316 LeaveCriticalSection(&sample
->parent
->cs
);
318 if (hr
!= MS_S_PENDING
|| (flags
& SSUPDATE_ASYNC
))
321 WaitForSingleObject(sample
->update_event
, INFINITE
);
323 return sample
->update_hr
;
326 static HRESULT WINAPI
audio_sample_CompletionStatus(IAudioStreamSample
*iface
, DWORD flags
, DWORD milliseconds
)
328 struct audio_sample
*sample
= impl_from_IAudioStreamSample(iface
);
331 TRACE("sample %p, flags %#lx, milliseconds %lu.\n", sample
, flags
, milliseconds
);
335 FIXME("Unhandled flags %#lx.\n", flags
);
339 EnterCriticalSection(&sample
->parent
->cs
);
341 hr
= sample
->update_hr
;
343 LeaveCriticalSection(&sample
->parent
->cs
);
348 /*** IAudioStreamSample methods ***/
349 static HRESULT WINAPI
audio_sample_GetAudioData(IAudioStreamSample
*iface
, IAudioData
**audio_data
)
351 struct audio_sample
*sample
= impl_from_IAudioStreamSample(iface
);
353 TRACE("sample %p, audio_data %p.\n", sample
, audio_data
);
358 IAudioData_AddRef(sample
->audio_data
);
359 *audio_data
= sample
->audio_data
;
364 static const struct IAudioStreamSampleVtbl AudioStreamSample_Vtbl
=
366 /*** IUnknown methods ***/
367 audio_sample_QueryInterface
,
369 audio_sample_Release
,
370 /*** IStreamSample methods ***/
371 audio_sample_GetMediaStream
,
372 audio_sample_GetSampleTimes
,
373 audio_sample_SetSampleTimes
,
375 audio_sample_CompletionStatus
,
376 /*** IAudioStreamSample methods ***/
377 audio_sample_GetAudioData
380 static HRESULT
audiostreamsample_create(struct audio_stream
*parent
, IAudioData
*audio_data
, IAudioStreamSample
**audio_stream_sample
)
382 struct audio_sample
*object
;
384 TRACE("(%p)\n", audio_stream_sample
);
386 if (!(object
= calloc(1, sizeof(*object
))))
387 return E_OUTOFMEMORY
;
389 object
->IAudioStreamSample_iface
.lpVtbl
= &AudioStreamSample_Vtbl
;
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 = %lu\n", iface
, This
, ref
);
456 static ULONG WINAPI
audio_IAMMediaStream_Release(IAMMediaStream
*iface
)
458 struct audio_stream
*stream
= impl_from_IAMMediaStream(iface
);
459 ULONG ref
= InterlockedDecrement(&stream
->ref
);
461 TRACE("%p decreasing refcount to %lu.\n", stream
, ref
);
465 DeleteCriticalSection(&stream
->cs
);
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,%lx) 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)->(%lx,%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,%lx,%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)->(%lx) 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 %lx, 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,%lu,%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 %lu.\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 %lu.\n", enum_media_types
, refcount
);
832 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 %lu, 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 %lu.\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
= calloc(1, sizeof(*object
))))
907 return E_OUTOFMEMORY
;
909 object
->IEnumMediaTypes_iface
.lpVtbl
= &enum_media_types_vtbl
;
910 object
->refcount
= 1;
911 object
->index
= enum_media_types
->index
;
913 *out
= &object
->IEnumMediaTypes_iface
;
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
= calloc(1, 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
);
1160 /* Calling IMediaStreamFilter::EndOfStream() inside the critical section
1161 * would invert the locking order, so we must leave it first to avoid
1162 * the streaming thread deadlocking on the filter's critical section. */
1163 IMediaStreamFilter_EndOfStream(stream
->filter
);
1168 static HRESULT WINAPI
audio_sink_BeginFlush(IPin
*iface
)
1170 struct audio_stream
*stream
= impl_from_IPin(iface
);
1173 TRACE("stream %p.\n", stream
);
1175 EnterCriticalSection(&stream
->cs
);
1177 cancel_eos
= stream
->eos
;
1179 stream
->flushing
= TRUE
;
1180 stream
->eos
= FALSE
;
1181 flush_receive_queue(stream
);
1183 LeaveCriticalSection(&stream
->cs
);
1185 /* Calling IMediaStreamFilter::Flush() inside the critical section would
1186 * invert the locking order, so we must leave it first to avoid the
1187 * application thread deadlocking on the filter's critical section. */
1188 IMediaStreamFilter_Flush(stream
->filter
, cancel_eos
);
1193 static HRESULT WINAPI
audio_sink_EndFlush(IPin
*iface
)
1195 struct audio_stream
*stream
= impl_from_IPin(iface
);
1197 TRACE("stream %p.\n", stream
);
1199 EnterCriticalSection(&stream
->cs
);
1201 stream
->flushing
= FALSE
;
1203 LeaveCriticalSection(&stream
->cs
);
1208 static HRESULT WINAPI
audio_sink_NewSegment(IPin
*iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
1210 struct audio_stream
*stream
= impl_from_IPin(iface
);
1212 TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1213 stream
, wine_dbgstr_longlong(start
), wine_dbgstr_longlong(stop
), rate
);
1215 EnterCriticalSection(&stream
->cs
);
1217 stream
->segment_start
= start
;
1219 LeaveCriticalSection(&stream
->cs
);
1224 static const IPinVtbl audio_sink_vtbl
=
1226 audio_sink_QueryInterface
,
1230 audio_sink_ReceiveConnection
,
1231 audio_sink_Disconnect
,
1232 audio_sink_ConnectedTo
,
1233 audio_sink_ConnectionMediaType
,
1234 audio_sink_QueryPinInfo
,
1235 audio_sink_QueryDirection
,
1237 audio_sink_QueryAccept
,
1238 audio_sink_EnumMediaTypes
,
1239 audio_sink_QueryInternalConnections
,
1240 audio_sink_EndOfStream
,
1241 audio_sink_BeginFlush
,
1242 audio_sink_EndFlush
,
1243 audio_sink_NewSegment
,
1246 static inline struct audio_stream
*impl_from_IMemInputPin(IMemInputPin
*iface
)
1248 return CONTAINING_RECORD(iface
, struct audio_stream
, IMemInputPin_iface
);
1251 static HRESULT WINAPI
audio_meminput_QueryInterface(IMemInputPin
*iface
, REFIID iid
, void **out
)
1253 struct audio_stream
*stream
= impl_from_IMemInputPin(iface
);
1254 return IAMMediaStream_QueryInterface(&stream
->IAMMediaStream_iface
, iid
, out
);
1257 static ULONG WINAPI
audio_meminput_AddRef(IMemInputPin
*iface
)
1259 struct audio_stream
*stream
= impl_from_IMemInputPin(iface
);
1260 return IAMMediaStream_AddRef(&stream
->IAMMediaStream_iface
);
1263 static ULONG WINAPI
audio_meminput_Release(IMemInputPin
*iface
)
1265 struct audio_stream
*stream
= impl_from_IMemInputPin(iface
);
1266 return IAMMediaStream_Release(&stream
->IAMMediaStream_iface
);
1269 static HRESULT WINAPI
audio_meminput_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**allocator
)
1271 struct audio_stream
*stream
= impl_from_IMemInputPin(iface
);
1273 TRACE("stream %p, allocator %p.\n", stream
, allocator
);
1275 if (stream
->allocator
)
1277 IMemAllocator_AddRef(*allocator
= stream
->allocator
);
1282 return VFW_E_NO_ALLOCATOR
;
1285 static HRESULT WINAPI
audio_meminput_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*allocator
, BOOL readonly
)
1287 struct audio_stream
*stream
= impl_from_IMemInputPin(iface
);
1289 TRACE("stream %p, allocator %p, readonly %d.\n", stream
, allocator
, readonly
);
1295 IMemAllocator_AddRef(allocator
);
1296 if (stream
->allocator
)
1297 IMemAllocator_Release(stream
->allocator
);
1298 stream
->allocator
= allocator
;
1303 static HRESULT WINAPI
audio_meminput_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
1305 TRACE("iface %p, props %p.\n", iface
, props
);
1309 static HRESULT WINAPI
audio_meminput_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
1311 struct audio_stream
*stream
= impl_from_IMemInputPin(iface
);
1312 struct queued_receive
*receive
;
1313 REFERENCE_TIME start_time
= 0;
1314 REFERENCE_TIME end_time
= 0;
1318 TRACE("stream %p, sample %p.\n", stream
, sample
);
1320 EnterCriticalSection(&stream
->cs
);
1322 if (stream
->state
== State_Stopped
)
1324 LeaveCriticalSection(&stream
->cs
);
1325 return VFW_E_WRONG_STATE
;
1327 if (stream
->flushing
)
1329 LeaveCriticalSection(&stream
->cs
);
1333 hr
= IMediaSample_GetPointer(sample
, &pointer
);
1336 LeaveCriticalSection(&stream
->cs
);
1340 IMediaSample_GetTime(sample
, &start_time
, &end_time
);
1342 receive
= calloc(1, sizeof(*receive
));
1345 LeaveCriticalSection(&stream
->cs
);
1346 return E_OUTOFMEMORY
;
1349 receive
->length
= IMediaSample_GetActualDataLength(sample
);
1350 receive
->pointer
= pointer
;
1351 receive
->sample
= sample
;
1352 receive
->start_time
= start_time
+ stream
->segment_start
;
1353 IMediaSample_AddRef(receive
->sample
);
1354 list_add_tail(&stream
->receive_queue
, &receive
->entry
);
1356 process_updates(stream
);
1358 LeaveCriticalSection(&stream
->cs
);
1363 static HRESULT WINAPI
audio_meminput_ReceiveMultiple(IMemInputPin
*iface
,
1364 IMediaSample
**samples
, LONG count
, LONG
*processed
)
1366 FIXME("iface %p, samples %p, count %lu, processed %p, stub!\n", iface
, samples
, count
, processed
);
1370 static HRESULT WINAPI
audio_meminput_ReceiveCanBlock(IMemInputPin
*iface
)
1372 TRACE("iface %p.\n", iface
);
1376 static const IMemInputPinVtbl audio_meminput_vtbl
=
1378 audio_meminput_QueryInterface
,
1379 audio_meminput_AddRef
,
1380 audio_meminput_Release
,
1381 audio_meminput_GetAllocator
,
1382 audio_meminput_NotifyAllocator
,
1383 audio_meminput_GetAllocatorRequirements
,
1384 audio_meminput_Receive
,
1385 audio_meminput_ReceiveMultiple
,
1386 audio_meminput_ReceiveCanBlock
,
1389 HRESULT
audio_stream_create(IUnknown
*outer
, void **out
)
1391 struct audio_stream
*object
;
1394 return CLASS_E_NOAGGREGATION
;
1396 if (!(object
= calloc(1, sizeof(*object
))))
1397 return E_OUTOFMEMORY
;
1399 object
->IAMMediaStream_iface
.lpVtbl
= &audio_IAMMediaStream_vtbl
;
1400 object
->IAudioMediaStream_iface
.lpVtbl
= &audio_IAudioMediaStream_vtbl
;
1401 object
->IMemInputPin_iface
.lpVtbl
= &audio_meminput_vtbl
;
1402 object
->IPin_iface
.lpVtbl
= &audio_sink_vtbl
;
1405 InitializeCriticalSection(&object
->cs
);
1406 list_init(&object
->receive_queue
);
1407 list_init(&object
->update_queue
);
1409 TRACE("Created audio stream %p.\n", object
);
1411 *out
= &object
->IAMMediaStream_iface
;