Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/amstream/audiostream.c
4388 views
1
/*
2
* Primary audio stream
3
*
4
* Copyright 2012 Christian Costa
5
*
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.
10
*
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.
15
*
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
19
*/
20
21
#define COBJMACROS
22
#include "amstream_private.h"
23
#include "wine/debug.h"
24
#include "wine/list.h"
25
#include "wine/strmbase.h"
26
27
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
28
29
static const WCHAR sink_id[] = L"I{A35FF56B-9FDA-11D0-8FDF-00C04FD9189D}";
30
31
struct queued_receive
32
{
33
struct list entry;
34
IMediaSample *sample;
35
DWORD length;
36
BYTE *pointer;
37
DWORD position;
38
STREAM_TIME start_time;
39
};
40
41
struct audio_stream
42
{
43
IAMMediaStream IAMMediaStream_iface;
44
IAudioMediaStream IAudioMediaStream_iface;
45
IMemInputPin IMemInputPin_iface;
46
IPin IPin_iface;
47
LONG ref;
48
49
IMultiMediaStream* parent;
50
MSPID purpose_id;
51
STREAM_TYPE stream_type;
52
CRITICAL_SECTION cs;
53
IMediaStreamFilter *filter;
54
55
IPin *peer;
56
IMemAllocator *allocator;
57
AM_MEDIA_TYPE mt;
58
WAVEFORMATEX format;
59
FILTER_STATE state;
60
REFERENCE_TIME segment_start;
61
BOOL eos;
62
BOOL flushing;
63
struct list receive_queue;
64
struct list update_queue;
65
};
66
67
struct audio_sample
68
{
69
IAudioStreamSample IAudioStreamSample_iface;
70
LONG ref;
71
struct audio_stream *parent;
72
IAudioData *audio_data;
73
STREAM_TIME start_time;
74
STREAM_TIME end_time;
75
HANDLE update_event;
76
77
struct list entry;
78
DWORD length;
79
BYTE *pointer;
80
DWORD position;
81
HRESULT update_hr;
82
};
83
84
static void remove_queued_receive(struct queued_receive *receive)
85
{
86
list_remove(&receive->entry);
87
IMediaSample_Release(receive->sample);
88
free(receive);
89
}
90
91
static void remove_queued_update(struct audio_sample *sample)
92
{
93
HRESULT hr;
94
95
hr = IAudioData_SetActual(sample->audio_data, sample->position);
96
if (FAILED(hr))
97
sample->update_hr = hr;
98
99
list_remove(&sample->entry);
100
SetEvent(sample->update_event);
101
}
102
103
static void flush_receive_queue(struct audio_stream *stream)
104
{
105
struct list *entry;
106
107
while ((entry = list_head(&stream->receive_queue)))
108
remove_queued_receive(LIST_ENTRY(entry, struct queued_receive, entry));
109
}
110
111
static STREAM_TIME stream_time_from_position(struct audio_stream *stream, struct queued_receive *receive)
112
{
113
const WAVEFORMATEX *format = (WAVEFORMATEX *)stream->mt.pbFormat;
114
return receive->start_time + (receive->position * 10000000 + format->nAvgBytesPerSec / 2) / format->nAvgBytesPerSec;
115
}
116
117
static void process_update(struct audio_sample *sample, struct queued_receive *receive)
118
{
119
DWORD advance;
120
121
advance = min(receive->length - receive->position, sample->length - sample->position);
122
memcpy(&sample->pointer[sample->position], &receive->pointer[receive->position], advance);
123
124
if (!sample->position)
125
sample->start_time = stream_time_from_position(sample->parent, receive);
126
127
receive->position += advance;
128
sample->position += advance;
129
130
sample->end_time = stream_time_from_position(sample->parent, receive);
131
132
sample->update_hr = (sample->position == sample->length) ? S_OK : MS_S_PENDING;
133
}
134
135
static void process_updates(struct audio_stream *stream)
136
{
137
while (!list_empty(&stream->update_queue) && !list_empty(&stream->receive_queue))
138
{
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);
141
142
process_update(sample, receive);
143
144
if (sample->update_hr != MS_S_PENDING)
145
remove_queued_update(sample);
146
if (receive->position == receive->length)
147
remove_queued_receive(receive);
148
}
149
if (stream->eos)
150
{
151
while (!list_empty(&stream->update_queue))
152
{
153
struct audio_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct audio_sample, entry);
154
155
sample->update_hr = sample->position ? S_OK : MS_S_ENDOFSTREAM;
156
remove_queued_update(sample);
157
}
158
}
159
}
160
161
static inline struct audio_sample *impl_from_IAudioStreamSample(IAudioStreamSample *iface)
162
{
163
return CONTAINING_RECORD(iface, struct audio_sample, IAudioStreamSample_iface);
164
}
165
166
/*** IUnknown methods ***/
167
static HRESULT WINAPI audio_sample_QueryInterface(IAudioStreamSample *iface,
168
REFIID riid, void **ret_iface)
169
{
170
TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
171
172
if (IsEqualGUID(riid, &IID_IUnknown) ||
173
IsEqualGUID(riid, &IID_IStreamSample) ||
174
IsEqualGUID(riid, &IID_IAudioStreamSample))
175
{
176
IAudioStreamSample_AddRef(iface);
177
*ret_iface = iface;
178
return S_OK;
179
}
180
181
*ret_iface = NULL;
182
183
ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
184
return E_NOINTERFACE;
185
}
186
187
static ULONG WINAPI audio_sample_AddRef(IAudioStreamSample *iface)
188
{
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);
192
return refcount;
193
}
194
195
static ULONG WINAPI audio_sample_Release(IAudioStreamSample *iface)
196
{
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);
200
if (!refcount)
201
{
202
IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
203
IAudioData_Release(sample->audio_data);
204
CloseHandle(sample->update_event);
205
free(sample);
206
}
207
return refcount;
208
}
209
210
/*** IStreamSample methods ***/
211
static HRESULT WINAPI audio_sample_GetMediaStream(IAudioStreamSample *iface, IMediaStream **media_stream)
212
{
213
struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
214
215
TRACE("sample %p, media_stream %p.\n", iface, media_stream);
216
217
if (!media_stream)
218
return E_POINTER;
219
220
IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
221
*media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
222
223
return S_OK;
224
}
225
226
static HRESULT WINAPI audio_sample_GetSampleTimes(IAudioStreamSample *iface, STREAM_TIME *start_time,
227
STREAM_TIME *end_time, STREAM_TIME *current_time)
228
{
229
struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
230
231
TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
232
233
if (current_time)
234
IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
235
236
if (start_time)
237
*start_time = sample->start_time;
238
if (end_time)
239
*end_time = sample->end_time;
240
241
return S_OK;
242
}
243
244
static HRESULT WINAPI audio_sample_SetSampleTimes(IAudioStreamSample *iface, const STREAM_TIME *start_time,
245
const STREAM_TIME *end_time)
246
{
247
FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
248
249
return E_NOTIMPL;
250
}
251
252
static HRESULT WINAPI audio_sample_Update(IAudioStreamSample *iface,
253
DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
254
{
255
struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
256
BYTE *pointer;
257
DWORD length;
258
HRESULT hr;
259
260
TRACE("sample %p, flags %#lx, event %p, apc_func %p, apc_data %#lx.\n",
261
sample, flags, event, apc_func, apc_data);
262
263
hr = IAudioData_GetInfo(sample->audio_data, &length, &pointer, NULL);
264
if (FAILED(hr))
265
return hr;
266
267
if (event && apc_func)
268
return E_INVALIDARG;
269
270
if (apc_func)
271
{
272
FIXME("APC support is not implemented!\n");
273
return E_NOTIMPL;
274
}
275
276
if (event)
277
{
278
FIXME("Event parameter support is not implemented!\n");
279
return E_NOTIMPL;
280
}
281
282
if (flags & ~SSUPDATE_ASYNC)
283
{
284
FIXME("Unsupported flags %#lx.\n", flags);
285
return E_NOTIMPL;
286
}
287
288
EnterCriticalSection(&sample->parent->cs);
289
290
if (sample->parent->state != State_Running)
291
{
292
LeaveCriticalSection(&sample->parent->cs);
293
return MS_E_NOTRUNNING;
294
}
295
if (!sample->parent->peer)
296
{
297
LeaveCriticalSection(&sample->parent->cs);
298
return MS_S_ENDOFSTREAM;
299
}
300
if (MS_S_PENDING == sample->update_hr)
301
{
302
LeaveCriticalSection(&sample->parent->cs);
303
return MS_E_BUSY;
304
}
305
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);
312
313
process_updates(sample->parent);
314
hr = sample->update_hr;
315
316
LeaveCriticalSection(&sample->parent->cs);
317
318
if (hr != MS_S_PENDING || (flags & SSUPDATE_ASYNC))
319
return hr;
320
321
WaitForSingleObject(sample->update_event, INFINITE);
322
323
return sample->update_hr;
324
}
325
326
static HRESULT WINAPI audio_sample_CompletionStatus(IAudioStreamSample *iface, DWORD flags, DWORD milliseconds)
327
{
328
struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
329
HRESULT hr;
330
331
TRACE("sample %p, flags %#lx, milliseconds %lu.\n", sample, flags, milliseconds);
332
333
if (flags)
334
{
335
FIXME("Unhandled flags %#lx.\n", flags);
336
return E_NOTIMPL;
337
}
338
339
EnterCriticalSection(&sample->parent->cs);
340
341
hr = sample->update_hr;
342
343
LeaveCriticalSection(&sample->parent->cs);
344
345
return hr;
346
}
347
348
/*** IAudioStreamSample methods ***/
349
static HRESULT WINAPI audio_sample_GetAudioData(IAudioStreamSample *iface, IAudioData **audio_data)
350
{
351
struct audio_sample *sample = impl_from_IAudioStreamSample(iface);
352
353
TRACE("sample %p, audio_data %p.\n", sample, audio_data);
354
355
if (!audio_data)
356
return E_POINTER;
357
358
IAudioData_AddRef(sample->audio_data);
359
*audio_data = sample->audio_data;
360
361
return S_OK;
362
}
363
364
static const struct IAudioStreamSampleVtbl AudioStreamSample_Vtbl =
365
{
366
/*** IUnknown methods ***/
367
audio_sample_QueryInterface,
368
audio_sample_AddRef,
369
audio_sample_Release,
370
/*** IStreamSample methods ***/
371
audio_sample_GetMediaStream,
372
audio_sample_GetSampleTimes,
373
audio_sample_SetSampleTimes,
374
audio_sample_Update,
375
audio_sample_CompletionStatus,
376
/*** IAudioStreamSample methods ***/
377
audio_sample_GetAudioData
378
};
379
380
static HRESULT audiostreamsample_create(struct audio_stream *parent, IAudioData *audio_data, IAudioStreamSample **audio_stream_sample)
381
{
382
struct audio_sample *object;
383
384
TRACE("(%p)\n", audio_stream_sample);
385
386
if (!(object = calloc(1, sizeof(*object))))
387
return E_OUTOFMEMORY;
388
389
object->IAudioStreamSample_iface.lpVtbl = &AudioStreamSample_Vtbl;
390
object->ref = 1;
391
object->parent = parent;
392
IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
393
object->audio_data = audio_data;
394
IAudioData_AddRef(audio_data);
395
object->update_event = CreateEventW(NULL, FALSE, FALSE, NULL);
396
397
*audio_stream_sample = &object->IAudioStreamSample_iface;
398
399
return S_OK;
400
}
401
402
static inline struct audio_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
403
{
404
return CONTAINING_RECORD(iface, struct audio_stream, IAMMediaStream_iface);
405
}
406
407
/*** IUnknown methods ***/
408
static HRESULT WINAPI audio_IAMMediaStream_QueryInterface(IAMMediaStream *iface,
409
REFIID riid, void **ret_iface)
410
{
411
struct audio_stream *This = impl_from_IAMMediaStream(iface);
412
413
TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
414
415
if (IsEqualGUID(riid, &IID_IUnknown) ||
416
IsEqualGUID(riid, &IID_IMediaStream) ||
417
IsEqualGUID(riid, &IID_IAMMediaStream))
418
{
419
IAMMediaStream_AddRef(iface);
420
*ret_iface = iface;
421
return S_OK;
422
}
423
else if (IsEqualGUID(riid, &IID_IAudioMediaStream))
424
{
425
IAMMediaStream_AddRef(iface);
426
*ret_iface = &This->IAudioMediaStream_iface;
427
return S_OK;
428
}
429
else if (IsEqualGUID(riid, &IID_IPin))
430
{
431
IAMMediaStream_AddRef(iface);
432
*ret_iface = &This->IPin_iface;
433
return S_OK;
434
}
435
else if (IsEqualGUID(riid, &IID_IMemInputPin))
436
{
437
IAMMediaStream_AddRef(iface);
438
*ret_iface = &This->IMemInputPin_iface;
439
return S_OK;
440
}
441
442
ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface);
443
return E_NOINTERFACE;
444
}
445
446
static ULONG WINAPI audio_IAMMediaStream_AddRef(IAMMediaStream *iface)
447
{
448
struct audio_stream *This = impl_from_IAMMediaStream(iface);
449
ULONG ref = InterlockedIncrement(&This->ref);
450
451
TRACE("(%p/%p)->(): new ref = %lu\n", iface, This, ref);
452
453
return ref;
454
}
455
456
static ULONG WINAPI audio_IAMMediaStream_Release(IAMMediaStream *iface)
457
{
458
struct audio_stream *stream = impl_from_IAMMediaStream(iface);
459
ULONG ref = InterlockedDecrement(&stream->ref);
460
461
TRACE("%p decreasing refcount to %lu.\n", stream, ref);
462
463
if (!ref)
464
{
465
DeleteCriticalSection(&stream->cs);
466
free(stream);
467
}
468
469
return ref;
470
}
471
472
/*** IMediaStream methods ***/
473
static HRESULT WINAPI audio_IAMMediaStream_GetMultiMediaStream(IAMMediaStream *iface,
474
IMultiMediaStream **mmstream)
475
{
476
struct audio_stream *stream = impl_from_IAMMediaStream(iface);
477
478
TRACE("stream %p, mmstream %p.\n", stream, mmstream);
479
480
if (!mmstream)
481
return E_POINTER;
482
483
if (stream->parent)
484
IMultiMediaStream_AddRef(stream->parent);
485
*mmstream = stream->parent;
486
return S_OK;
487
}
488
489
static HRESULT WINAPI audio_IAMMediaStream_GetInformation(IAMMediaStream *iface,
490
MSPID *purpose_id, STREAM_TYPE *type)
491
{
492
struct audio_stream *This = impl_from_IAMMediaStream(iface);
493
494
TRACE("(%p/%p)->(%p,%p)\n", This, iface, purpose_id, type);
495
496
if (purpose_id)
497
*purpose_id = This->purpose_id;
498
if (type)
499
*type = This->stream_type;
500
501
return S_OK;
502
}
503
504
static HRESULT WINAPI audio_IAMMediaStream_SetSameFormat(IAMMediaStream *iface,
505
IMediaStream *pStreamThatHasDesiredFormat, DWORD flags)
506
{
507
struct audio_stream *This = impl_from_IAMMediaStream(iface);
508
509
FIXME("(%p/%p)->(%p,%lx) stub!\n", This, iface, pStreamThatHasDesiredFormat, flags);
510
511
return S_FALSE;
512
}
513
514
static HRESULT WINAPI audio_IAMMediaStream_AllocateSample(IAMMediaStream *iface,
515
DWORD flags, IStreamSample **sample)
516
{
517
struct audio_stream *This = impl_from_IAMMediaStream(iface);
518
519
FIXME("(%p/%p)->(%lx,%p) stub!\n", This, iface, flags, sample);
520
521
return S_FALSE;
522
}
523
524
static HRESULT WINAPI audio_IAMMediaStream_CreateSharedSample(IAMMediaStream *iface,
525
IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
526
{
527
struct audio_stream *This = impl_from_IAMMediaStream(iface);
528
529
FIXME("(%p/%p)->(%p,%lx,%p) stub!\n", This, iface, existing_sample, flags, sample);
530
531
return S_FALSE;
532
}
533
534
static HRESULT WINAPI audio_IAMMediaStream_SendEndOfStream(IAMMediaStream *iface, DWORD flags)
535
{
536
struct audio_stream *This = impl_from_IAMMediaStream(iface);
537
538
FIXME("(%p/%p)->(%lx) stub!\n", This, iface, flags);
539
540
return S_FALSE;
541
}
542
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)
546
{
547
struct audio_stream *stream = impl_from_IAMMediaStream(iface);
548
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);
551
552
if (!purpose_id)
553
return E_POINTER;
554
555
if (source_object)
556
FIXME("Specifying a stream object is not yet supported.\n");
557
558
if (flags & AMMSF_CREATEPEER)
559
FIXME("AMMSF_CREATEPEER is not yet supported.\n");
560
561
stream->purpose_id = *purpose_id;
562
stream->stream_type = stream_type;
563
564
return S_OK;
565
}
566
567
static HRESULT WINAPI audio_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state)
568
{
569
struct audio_stream *stream = impl_from_IAMMediaStream(iface);
570
571
TRACE("stream %p, state %u.\n", stream, state);
572
573
EnterCriticalSection(&stream->cs);
574
575
if (state == State_Stopped)
576
flush_receive_queue(stream);
577
if (stream->state == State_Stopped)
578
stream->eos = FALSE;
579
580
stream->state = state;
581
582
LeaveCriticalSection(&stream->cs);
583
584
return S_OK;
585
}
586
587
static HRESULT WINAPI audio_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface,
588
IAMMultiMediaStream *mmstream)
589
{
590
struct audio_stream *stream = impl_from_IAMMediaStream(iface);
591
592
TRACE("stream %p, mmstream %p.\n", stream, mmstream);
593
594
stream->parent = (IMultiMediaStream *)mmstream;
595
596
return S_OK;
597
}
598
599
static HRESULT WINAPI audio_IAMMediaStream_JoinFilter(IAMMediaStream *iface, IMediaStreamFilter *filter)
600
{
601
struct audio_stream *stream = impl_from_IAMMediaStream(iface);
602
603
TRACE("stream %p, filter %p.\n", stream, filter);
604
605
stream->filter = filter;
606
607
return S_OK;
608
}
609
610
static HRESULT WINAPI audio_IAMMediaStream_JoinFilterGraph(IAMMediaStream *iface, IFilterGraph *filtergraph)
611
{
612
struct audio_stream *stream = impl_from_IAMMediaStream(iface);
613
614
TRACE("stream %p, filtergraph %p.\n", stream, filtergraph);
615
616
return S_OK;
617
}
618
619
static const struct IAMMediaStreamVtbl audio_IAMMediaStream_vtbl =
620
{
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,
635
};
636
637
static inline struct audio_stream *impl_from_IAudioMediaStream(IAudioMediaStream *iface)
638
{
639
return CONTAINING_RECORD(iface, struct audio_stream, IAudioMediaStream_iface);
640
}
641
642
/*** IUnknown methods ***/
643
static HRESULT WINAPI audio_IAudioMediaStream_QueryInterface(IAudioMediaStream *iface,
644
REFIID riid, void **ret_iface)
645
{
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);
649
}
650
651
static ULONG WINAPI audio_IAudioMediaStream_AddRef(IAudioMediaStream *iface)
652
{
653
struct audio_stream *This = impl_from_IAudioMediaStream(iface);
654
TRACE("(%p/%p)\n", iface, This);
655
return IAMMediaStream_AddRef(&This->IAMMediaStream_iface);
656
}
657
658
static ULONG WINAPI audio_IAudioMediaStream_Release(IAudioMediaStream *iface)
659
{
660
struct audio_stream *This = impl_from_IAudioMediaStream(iface);
661
TRACE("(%p/%p)\n", iface, This);
662
return IAMMediaStream_Release(&This->IAMMediaStream_iface);
663
}
664
665
static HRESULT WINAPI audio_IAudioMediaStream_GetMultiMediaStream(IAudioMediaStream *iface,
666
IMultiMediaStream **mmstream)
667
{
668
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
669
return IAMMediaStream_GetMultiMediaStream(&stream->IAMMediaStream_iface, mmstream);
670
}
671
672
static HRESULT WINAPI audio_IAudioMediaStream_GetInformation(IAudioMediaStream *iface,
673
MSPID *purpose_id, STREAM_TYPE *type)
674
{
675
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
676
return IAMMediaStream_GetInformation(&stream->IAMMediaStream_iface, purpose_id, type);
677
}
678
679
static HRESULT WINAPI audio_IAudioMediaStream_SetSameFormat(IAudioMediaStream *iface,
680
IMediaStream *other, DWORD flags)
681
{
682
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
683
return IAMMediaStream_SetSameFormat(&stream->IAMMediaStream_iface, other, flags);
684
}
685
686
static HRESULT WINAPI audio_IAudioMediaStream_AllocateSample(IAudioMediaStream *iface,
687
DWORD flags, IStreamSample **sample)
688
{
689
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
690
return IAMMediaStream_AllocateSample(&stream->IAMMediaStream_iface, flags, sample);
691
}
692
693
static HRESULT WINAPI audio_IAudioMediaStream_CreateSharedSample(IAudioMediaStream *iface,
694
IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
695
{
696
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
697
return IAMMediaStream_CreateSharedSample(&stream->IAMMediaStream_iface, existing_sample, flags, sample);
698
}
699
700
static HRESULT WINAPI audio_IAudioMediaStream_SendEndOfStream(IAudioMediaStream *iface, DWORD flags)
701
{
702
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
703
return IAMMediaStream_SendEndOfStream(&stream->IAMMediaStream_iface, flags);
704
}
705
706
/*** IAudioMediaStream methods ***/
707
static HRESULT WINAPI audio_IAudioMediaStream_GetFormat(IAudioMediaStream *iface, WAVEFORMATEX *format)
708
{
709
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
710
711
TRACE("stream %p, format %p.\n", stream, format);
712
713
if (!format)
714
return E_POINTER;
715
716
EnterCriticalSection(&stream->cs);
717
718
if (!stream->peer)
719
{
720
LeaveCriticalSection(&stream->cs);
721
return MS_E_NOSTREAM;
722
}
723
724
*format = *(WAVEFORMATEX *)stream->mt.pbFormat;
725
726
LeaveCriticalSection(&stream->cs);
727
728
return S_OK;
729
}
730
731
static HRESULT WINAPI audio_IAudioMediaStream_SetFormat(IAudioMediaStream *iface, const WAVEFORMATEX *format)
732
{
733
struct audio_stream *stream = impl_from_IAudioMediaStream(iface);
734
735
TRACE("stream %p, format %p.\n", stream, format);
736
737
if (!format)
738
return E_POINTER;
739
740
if (format->wFormatTag != WAVE_FORMAT_PCM)
741
return E_INVALIDARG;
742
743
EnterCriticalSection(&stream->cs);
744
745
if ((stream->peer && memcmp(format, stream->mt.pbFormat, sizeof(WAVEFORMATEX)))
746
|| (stream->format.wFormatTag && memcmp(format, &stream->format, sizeof(WAVEFORMATEX))))
747
{
748
LeaveCriticalSection(&stream->cs);
749
return E_INVALIDARG;
750
}
751
752
stream->format = *format;
753
754
LeaveCriticalSection(&stream->cs);
755
756
return S_OK;
757
}
758
759
static HRESULT WINAPI audio_IAudioMediaStream_CreateSample(IAudioMediaStream *iface, IAudioData *audio_data,
760
DWORD flags, IAudioStreamSample **sample)
761
{
762
struct audio_stream *This = impl_from_IAudioMediaStream(iface);
763
764
TRACE("(%p/%p)->(%p,%lu,%p)\n", iface, This, audio_data, flags, sample);
765
766
if (!audio_data)
767
return E_POINTER;
768
769
return audiostreamsample_create(This, audio_data, sample);
770
}
771
772
static const struct IAudioMediaStreamVtbl audio_IAudioMediaStream_vtbl =
773
{
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,
786
};
787
788
struct enum_media_types
789
{
790
IEnumMediaTypes IEnumMediaTypes_iface;
791
LONG refcount;
792
unsigned int index;
793
};
794
795
static const IEnumMediaTypesVtbl enum_media_types_vtbl;
796
797
static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
798
{
799
return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
800
}
801
802
static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
803
{
804
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
805
806
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
807
{
808
IEnumMediaTypes_AddRef(iface);
809
*out = iface;
810
return S_OK;
811
}
812
813
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
814
*out = NULL;
815
return E_NOINTERFACE;
816
}
817
818
static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
819
{
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);
823
return refcount;
824
}
825
826
static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
827
{
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);
831
if (!refcount)
832
free(enum_media_types);
833
return refcount;
834
}
835
836
static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **mts, ULONG *ret_count)
837
{
838
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
839
840
static const WAVEFORMATEX wfx =
841
{
842
.wFormatTag = WAVE_FORMAT_PCM,
843
.nChannels = 1,
844
.nSamplesPerSec = 11025,
845
.nAvgBytesPerSec = 11025 * 2,
846
.nBlockAlign = 2,
847
.wBitsPerSample = 16,
848
.cbSize = 0,
849
};
850
851
TRACE("iface %p, count %lu, mts %p, ret_count %p.\n", iface, count, mts, ret_count);
852
853
if (!ret_count)
854
return E_POINTER;
855
856
if (count && !enum_media_types->index)
857
{
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));
869
870
++enum_media_types->index;
871
*ret_count = 1;
872
return count == 1 ? S_OK : S_FALSE;
873
}
874
875
*ret_count = 0;
876
return count ? S_FALSE : S_OK;
877
}
878
879
static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
880
{
881
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
882
883
TRACE("iface %p, count %lu.\n", iface, count);
884
885
enum_media_types->index += count;
886
return S_OK;
887
}
888
889
static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
890
{
891
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
892
893
TRACE("iface %p.\n", iface);
894
895
enum_media_types->index = 0;
896
return S_OK;
897
}
898
899
static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
900
{
901
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
902
struct enum_media_types *object;
903
904
TRACE("iface %p, out %p.\n", iface, out);
905
906
if (!(object = calloc(1, sizeof(*object))))
907
return E_OUTOFMEMORY;
908
909
object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
910
object->refcount = 1;
911
object->index = enum_media_types->index;
912
913
*out = &object->IEnumMediaTypes_iface;
914
return S_OK;
915
}
916
917
static const IEnumMediaTypesVtbl enum_media_types_vtbl =
918
{
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,
926
};
927
928
static inline struct audio_stream *impl_from_IPin(IPin *iface)
929
{
930
return CONTAINING_RECORD(iface, struct audio_stream, IPin_iface);
931
}
932
933
static HRESULT WINAPI audio_sink_QueryInterface(IPin *iface, REFIID iid, void **out)
934
{
935
struct audio_stream *stream = impl_from_IPin(iface);
936
return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
937
}
938
939
static ULONG WINAPI audio_sink_AddRef(IPin *iface)
940
{
941
struct audio_stream *stream = impl_from_IPin(iface);
942
return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
943
}
944
945
static ULONG WINAPI audio_sink_Release(IPin *iface)
946
{
947
struct audio_stream *stream = impl_from_IPin(iface);
948
return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
949
}
950
951
static HRESULT WINAPI audio_sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
952
{
953
WARN("iface %p, peer %p, mt %p, unexpected call!\n", iface, peer, mt);
954
return E_UNEXPECTED;
955
}
956
957
static HRESULT WINAPI audio_sink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
958
{
959
struct audio_stream *stream = impl_from_IPin(iface);
960
PIN_DIRECTION dir;
961
962
TRACE("stream %p, peer %p, mt %p.\n", stream, peer, mt);
963
strmbase_dump_media_type(mt);
964
965
if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)
966
|| !IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)
967
|| mt->cbFormat < sizeof(WAVEFORMATEX))
968
return VFW_E_TYPE_NOT_ACCEPTED;
969
970
if (((const WAVEFORMATEX *)mt->pbFormat)->wFormatTag != WAVE_FORMAT_PCM)
971
return E_INVALIDARG;
972
973
EnterCriticalSection(&stream->cs);
974
975
if (stream->peer)
976
{
977
LeaveCriticalSection(&stream->cs);
978
return VFW_E_ALREADY_CONNECTED;
979
}
980
981
IPin_QueryDirection(peer, &dir);
982
if (dir != PINDIR_OUTPUT)
983
{
984
WARN("Rejecting connection from input pin.\n");
985
LeaveCriticalSection(&stream->cs);
986
return VFW_E_INVALID_DIRECTION;
987
}
988
989
if (stream->format.wFormatTag && memcmp(mt->pbFormat, &stream->format, sizeof(WAVEFORMATEX)))
990
{
991
LeaveCriticalSection(&stream->cs);
992
return E_INVALIDARG;
993
}
994
995
CopyMediaType(&stream->mt, mt);
996
IPin_AddRef(stream->peer = peer);
997
998
LeaveCriticalSection(&stream->cs);
999
1000
return S_OK;
1001
}
1002
1003
static HRESULT WINAPI audio_sink_Disconnect(IPin *iface)
1004
{
1005
struct audio_stream *stream = impl_from_IPin(iface);
1006
1007
TRACE("stream %p.\n", stream);
1008
1009
EnterCriticalSection(&stream->cs);
1010
1011
if (!stream->peer)
1012
{
1013
LeaveCriticalSection(&stream->cs);
1014
return S_FALSE;
1015
}
1016
1017
IPin_Release(stream->peer);
1018
stream->peer = NULL;
1019
FreeMediaType(&stream->mt);
1020
memset(&stream->mt, 0, sizeof(AM_MEDIA_TYPE));
1021
1022
LeaveCriticalSection(&stream->cs);
1023
1024
return S_OK;
1025
}
1026
1027
static HRESULT WINAPI audio_sink_ConnectedTo(IPin *iface, IPin **peer)
1028
{
1029
struct audio_stream *stream = impl_from_IPin(iface);
1030
HRESULT hr;
1031
1032
TRACE("stream %p, peer %p.\n", stream, peer);
1033
1034
EnterCriticalSection(&stream->cs);
1035
1036
if (stream->peer)
1037
{
1038
IPin_AddRef(*peer = stream->peer);
1039
hr = S_OK;
1040
}
1041
else
1042
{
1043
*peer = NULL;
1044
hr = VFW_E_NOT_CONNECTED;
1045
}
1046
1047
LeaveCriticalSection(&stream->cs);
1048
1049
return hr;
1050
}
1051
1052
static HRESULT WINAPI audio_sink_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
1053
{
1054
struct audio_stream *stream = impl_from_IPin(iface);
1055
HRESULT hr;
1056
1057
TRACE("stream %p, mt %p.\n", stream, mt);
1058
1059
EnterCriticalSection(&stream->cs);
1060
1061
if (stream->peer)
1062
{
1063
CopyMediaType(mt, &stream->mt);
1064
hr = S_OK;
1065
}
1066
else
1067
{
1068
memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1069
hr = VFW_E_NOT_CONNECTED;
1070
}
1071
1072
LeaveCriticalSection(&stream->cs);
1073
1074
return hr;
1075
}
1076
1077
static HRESULT WINAPI audio_sink_QueryPinInfo(IPin *iface, PIN_INFO *info)
1078
{
1079
struct audio_stream *stream = impl_from_IPin(iface);
1080
1081
TRACE("stream %p, info %p.\n", stream, info);
1082
1083
IBaseFilter_AddRef(info->pFilter = (IBaseFilter *)stream->filter);
1084
info->dir = PINDIR_INPUT;
1085
wcscpy(info->achName, sink_id);
1086
1087
return S_OK;
1088
}
1089
1090
static HRESULT WINAPI audio_sink_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1091
{
1092
TRACE("iface %p, dir %p.\n", iface, dir);
1093
*dir = PINDIR_INPUT;
1094
return S_OK;
1095
}
1096
1097
static HRESULT WINAPI audio_sink_QueryId(IPin *iface, WCHAR **id)
1098
{
1099
TRACE("iface %p, id %p.\n", iface, id);
1100
1101
if (!(*id = CoTaskMemAlloc(sizeof(sink_id))))
1102
return E_OUTOFMEMORY;
1103
1104
wcscpy(*id, sink_id);
1105
1106
return S_OK;
1107
}
1108
1109
static HRESULT WINAPI audio_sink_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
1110
{
1111
TRACE("iface %p, mt %p.\n", iface, mt);
1112
return E_NOTIMPL;
1113
}
1114
1115
static HRESULT WINAPI audio_sink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
1116
{
1117
struct enum_media_types *object;
1118
1119
TRACE("iface %p, enum_media_types %p.\n", iface, enum_media_types);
1120
1121
if (!enum_media_types)
1122
return E_POINTER;
1123
1124
if (!(object = calloc(1, sizeof(*object))))
1125
return E_OUTOFMEMORY;
1126
1127
object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1128
object->refcount = 1;
1129
object->index = 0;
1130
1131
*enum_media_types = &object->IEnumMediaTypes_iface;
1132
return S_OK;
1133
}
1134
1135
static HRESULT WINAPI audio_sink_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
1136
{
1137
TRACE("iface %p, pins %p, count %p.\n", iface, pins, count);
1138
return E_NOTIMPL;
1139
}
1140
1141
static HRESULT WINAPI audio_sink_EndOfStream(IPin *iface)
1142
{
1143
struct audio_stream *stream = impl_from_IPin(iface);
1144
1145
TRACE("stream %p.\n", stream);
1146
1147
EnterCriticalSection(&stream->cs);
1148
1149
if (stream->eos || stream->flushing)
1150
{
1151
LeaveCriticalSection(&stream->cs);
1152
return E_FAIL;
1153
}
1154
1155
stream->eos = TRUE;
1156
1157
process_updates(stream);
1158
1159
LeaveCriticalSection(&stream->cs);
1160
1161
/* Calling IMediaStreamFilter::EndOfStream() inside the critical section
1162
* would invert the locking order, so we must leave it first to avoid
1163
* the streaming thread deadlocking on the filter's critical section. */
1164
IMediaStreamFilter_EndOfStream(stream->filter);
1165
1166
return S_OK;
1167
}
1168
1169
static HRESULT WINAPI audio_sink_BeginFlush(IPin *iface)
1170
{
1171
struct audio_stream *stream = impl_from_IPin(iface);
1172
BOOL cancel_eos;
1173
1174
TRACE("stream %p.\n", stream);
1175
1176
EnterCriticalSection(&stream->cs);
1177
1178
cancel_eos = stream->eos;
1179
1180
stream->flushing = TRUE;
1181
stream->eos = FALSE;
1182
flush_receive_queue(stream);
1183
1184
LeaveCriticalSection(&stream->cs);
1185
1186
/* Calling IMediaStreamFilter::Flush() inside the critical section would
1187
* invert the locking order, so we must leave it first to avoid the
1188
* application thread deadlocking on the filter's critical section. */
1189
IMediaStreamFilter_Flush(stream->filter, cancel_eos);
1190
1191
return S_OK;
1192
}
1193
1194
static HRESULT WINAPI audio_sink_EndFlush(IPin *iface)
1195
{
1196
struct audio_stream *stream = impl_from_IPin(iface);
1197
1198
TRACE("stream %p.\n", stream);
1199
1200
EnterCriticalSection(&stream->cs);
1201
1202
stream->flushing = FALSE;
1203
1204
LeaveCriticalSection(&stream->cs);
1205
1206
return S_OK;
1207
}
1208
1209
static HRESULT WINAPI audio_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1210
{
1211
struct audio_stream *stream = impl_from_IPin(iface);
1212
1213
TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1214
stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1215
1216
EnterCriticalSection(&stream->cs);
1217
1218
stream->segment_start = start;
1219
1220
LeaveCriticalSection(&stream->cs);
1221
1222
return S_OK;
1223
}
1224
1225
static const IPinVtbl audio_sink_vtbl =
1226
{
1227
audio_sink_QueryInterface,
1228
audio_sink_AddRef,
1229
audio_sink_Release,
1230
audio_sink_Connect,
1231
audio_sink_ReceiveConnection,
1232
audio_sink_Disconnect,
1233
audio_sink_ConnectedTo,
1234
audio_sink_ConnectionMediaType,
1235
audio_sink_QueryPinInfo,
1236
audio_sink_QueryDirection,
1237
audio_sink_QueryId,
1238
audio_sink_QueryAccept,
1239
audio_sink_EnumMediaTypes,
1240
audio_sink_QueryInternalConnections,
1241
audio_sink_EndOfStream,
1242
audio_sink_BeginFlush,
1243
audio_sink_EndFlush,
1244
audio_sink_NewSegment,
1245
};
1246
1247
static inline struct audio_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1248
{
1249
return CONTAINING_RECORD(iface, struct audio_stream, IMemInputPin_iface);
1250
}
1251
1252
static HRESULT WINAPI audio_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1253
{
1254
struct audio_stream *stream = impl_from_IMemInputPin(iface);
1255
return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1256
}
1257
1258
static ULONG WINAPI audio_meminput_AddRef(IMemInputPin *iface)
1259
{
1260
struct audio_stream *stream = impl_from_IMemInputPin(iface);
1261
return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1262
}
1263
1264
static ULONG WINAPI audio_meminput_Release(IMemInputPin *iface)
1265
{
1266
struct audio_stream *stream = impl_from_IMemInputPin(iface);
1267
return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1268
}
1269
1270
static HRESULT WINAPI audio_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1271
{
1272
struct audio_stream *stream = impl_from_IMemInputPin(iface);
1273
1274
TRACE("stream %p, allocator %p.\n", stream, allocator);
1275
1276
if (stream->allocator)
1277
{
1278
IMemAllocator_AddRef(*allocator = stream->allocator);
1279
return S_OK;
1280
}
1281
1282
*allocator = NULL;
1283
return VFW_E_NO_ALLOCATOR;
1284
}
1285
1286
static HRESULT WINAPI audio_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1287
{
1288
struct audio_stream *stream = impl_from_IMemInputPin(iface);
1289
1290
TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1291
1292
if (!allocator)
1293
return E_POINTER;
1294
1295
if (allocator)
1296
IMemAllocator_AddRef(allocator);
1297
if (stream->allocator)
1298
IMemAllocator_Release(stream->allocator);
1299
stream->allocator = allocator;
1300
1301
return S_OK;
1302
}
1303
1304
static HRESULT WINAPI audio_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1305
{
1306
TRACE("iface %p, props %p.\n", iface, props);
1307
return E_NOTIMPL;
1308
}
1309
1310
static HRESULT WINAPI audio_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
1311
{
1312
struct audio_stream *stream = impl_from_IMemInputPin(iface);
1313
struct queued_receive *receive;
1314
REFERENCE_TIME start_time = 0;
1315
REFERENCE_TIME end_time = 0;
1316
BYTE *pointer;
1317
HRESULT hr;
1318
1319
TRACE("stream %p, sample %p.\n", stream, sample);
1320
1321
EnterCriticalSection(&stream->cs);
1322
1323
if (stream->state == State_Stopped)
1324
{
1325
LeaveCriticalSection(&stream->cs);
1326
return VFW_E_WRONG_STATE;
1327
}
1328
if (stream->flushing)
1329
{
1330
LeaveCriticalSection(&stream->cs);
1331
return S_FALSE;
1332
}
1333
1334
hr = IMediaSample_GetPointer(sample, &pointer);
1335
if (FAILED(hr))
1336
{
1337
LeaveCriticalSection(&stream->cs);
1338
return hr;
1339
}
1340
1341
IMediaSample_GetTime(sample, &start_time, &end_time);
1342
1343
receive = calloc(1, sizeof(*receive));
1344
if (!receive)
1345
{
1346
LeaveCriticalSection(&stream->cs);
1347
return E_OUTOFMEMORY;
1348
}
1349
1350
receive->length = IMediaSample_GetActualDataLength(sample);
1351
receive->pointer = pointer;
1352
receive->sample = sample;
1353
receive->start_time = start_time + stream->segment_start;
1354
IMediaSample_AddRef(receive->sample);
1355
list_add_tail(&stream->receive_queue, &receive->entry);
1356
1357
process_updates(stream);
1358
1359
LeaveCriticalSection(&stream->cs);
1360
1361
return S_OK;
1362
}
1363
1364
static HRESULT WINAPI audio_meminput_ReceiveMultiple(IMemInputPin *iface,
1365
IMediaSample **samples, LONG count, LONG *processed)
1366
{
1367
FIXME("iface %p, samples %p, count %lu, processed %p, stub!\n", iface, samples, count, processed);
1368
return E_NOTIMPL;
1369
}
1370
1371
static HRESULT WINAPI audio_meminput_ReceiveCanBlock(IMemInputPin *iface)
1372
{
1373
TRACE("iface %p.\n", iface);
1374
return S_OK;
1375
}
1376
1377
static const IMemInputPinVtbl audio_meminput_vtbl =
1378
{
1379
audio_meminput_QueryInterface,
1380
audio_meminput_AddRef,
1381
audio_meminput_Release,
1382
audio_meminput_GetAllocator,
1383
audio_meminput_NotifyAllocator,
1384
audio_meminput_GetAllocatorRequirements,
1385
audio_meminput_Receive,
1386
audio_meminput_ReceiveMultiple,
1387
audio_meminput_ReceiveCanBlock,
1388
};
1389
1390
HRESULT audio_stream_create(IUnknown *outer, void **out)
1391
{
1392
struct audio_stream *object;
1393
1394
if (outer)
1395
return CLASS_E_NOAGGREGATION;
1396
1397
if (!(object = calloc(1, sizeof(*object))))
1398
return E_OUTOFMEMORY;
1399
1400
object->IAMMediaStream_iface.lpVtbl = &audio_IAMMediaStream_vtbl;
1401
object->IAudioMediaStream_iface.lpVtbl = &audio_IAudioMediaStream_vtbl;
1402
object->IMemInputPin_iface.lpVtbl = &audio_meminput_vtbl;
1403
object->IPin_iface.lpVtbl = &audio_sink_vtbl;
1404
object->ref = 1;
1405
1406
InitializeCriticalSection(&object->cs);
1407
list_init(&object->receive_queue);
1408
list_init(&object->update_queue);
1409
1410
TRACE("Created audio stream %p.\n", object);
1411
1412
*out = &object->IAMMediaStream_iface;
1413
1414
return S_OK;
1415
}
1416
1417