1 /* GStreamer
2 * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net>
3 *
4 * gstdshowaudiosrc.c:
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 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 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "gstdshowaudiosrc.h"
27
28 GST_DEBUG_CATEGORY_STATIC (dshowaudiosrc_debug);
29 #define GST_CAT_DEFAULT dshowaudiosrc_debug
30
31 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
32 GST_PAD_SRC,
33 GST_PAD_ALWAYS,
34 GST_STATIC_CAPS ("audio/x-raw, "
35 "format = (string){ "
36 GST_AUDIO_NE (S16) ", "
37 GST_AUDIO_NE (U16) ", "
38 GST_AUDIO_NE (S8) ", "
39 GST_AUDIO_NE (U8)
40 " }, "
41 "rate = " GST_AUDIO_RATE_RANGE ", "
42 "channels = (int) [ 1, 2 ]")
43 );
44
45 G_DEFINE_TYPE(GstDshowAudioSrc, gst_dshowaudiosrc, GST_TYPE_AUDIO_SRC);
46
47 enum
48 {
49 PROP_0,
50 PROP_DEVICE,
51 PROP_DEVICE_NAME,
52 PROP_DEVICE_INDEX
53 };
54
55 #define DEFAULT_PROP_DEVICE_INDEX 0
56
57
58 static void gst_dshowaudiosrc_dispose (GObject * gobject);
59 static void gst_dshowaudiosrc_set_property (GObject * object, guint prop_id,
60 const GValue * value, GParamSpec * pspec);
61 static void gst_dshowaudiosrc_get_property (GObject * object, guint prop_id,
62 GValue * value, GParamSpec * pspec);
63 static GstCaps *gst_dshowaudiosrc_get_caps (GstBaseSrc * src, GstCaps * filter);
64 static GstStateChangeReturn gst_dshowaudiosrc_change_state (GstElement *
65 element, GstStateChange transition);
66
67 static gboolean gst_dshowaudiosrc_open (GstAudioSrc * asrc);
68 static gboolean gst_dshowaudiosrc_prepare (GstAudioSrc * asrc,
69 GstAudioRingBufferSpec * spec);
70 static gboolean gst_dshowaudiosrc_unprepare (GstAudioSrc * asrc);
71 static gboolean gst_dshowaudiosrc_close (GstAudioSrc * asrc);
72 static guint gst_dshowaudiosrc_read (GstAudioSrc * asrc, gpointer data,
73 guint length, GstClockTime *timestamp);
74 static guint gst_dshowaudiosrc_delay (GstAudioSrc * asrc);
75 static void gst_dshowaudiosrc_reset (GstAudioSrc * asrc);
76
77 /* utils */
78 static GstCaps *gst_dshowaudiosrc_getcaps_from_streamcaps (GstDshowAudioSrc *
79 src, IPin * pin, IAMStreamConfig * streamcaps);
80 static gboolean gst_dshowaudiosrc_push_buffer (guint8 * buffer, guint size,
81 gpointer src_object, GstClockTime duration);
82
83 static void
gst_dshowaudiosrc_class_init(GstDshowAudioSrcClass * klass)84 gst_dshowaudiosrc_class_init (GstDshowAudioSrcClass * klass)
85 {
86 GObjectClass *gobject_class;
87 GstElementClass *gstelement_class;
88 GstBaseSrcClass *gstbasesrc_class;
89 GstAudioSrcClass *gstaudiosrc_class;
90
91 gobject_class = (GObjectClass *) klass;
92 gstelement_class = (GstElementClass *) klass;
93 gstbasesrc_class = (GstBaseSrcClass *) klass;
94 gstaudiosrc_class = (GstAudioSrcClass *) klass;
95
96 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_dispose);
97 gobject_class->set_property =
98 GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_set_property);
99 gobject_class->get_property =
100 GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_get_property);
101
102 gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_get_caps);
103
104 gstelement_class->change_state =
105 GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_change_state);
106
107 gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_open);
108 gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_prepare);
109 gstaudiosrc_class->unprepare =
110 GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_unprepare);
111 gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_close);
112 gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_read);
113 gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_delay);
114 gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_reset);
115
116 g_object_class_install_property
117 (gobject_class, PROP_DEVICE,
118 g_param_spec_string ("device", "Device",
119 "Directshow device reference (classID/name)", NULL,
120 static_cast < GParamFlags > (G_PARAM_READWRITE)));
121
122 g_object_class_install_property
123 (gobject_class, PROP_DEVICE_NAME,
124 g_param_spec_string ("device-name", "Device name",
125 "Human-readable name of the sound device", NULL,
126 static_cast < GParamFlags > (G_PARAM_READWRITE)));
127
128 g_object_class_install_property
129 (gobject_class, PROP_DEVICE_INDEX,
130 g_param_spec_int ("device-index", "Device index",
131 "Index of the enumerated audio device", 0, G_MAXINT,
132 DEFAULT_PROP_DEVICE_INDEX,
133 static_cast < GParamFlags > (G_PARAM_READWRITE)));
134
135 gst_element_class_add_static_pad_template (gstelement_class, &src_template);
136
137 gst_element_class_set_static_metadata (gstelement_class,
138 "Directshow audio capture source", "Source/Audio",
139 "Receive data from a directshow audio capture graph",
140 "Sebastien Moutte <sebastien@moutte.net>");
141
142 GST_DEBUG_CATEGORY_INIT (dshowaudiosrc_debug, "dshowaudiosrc", 0,
143 "Directshow audio source");
144 }
145
146 static void
gst_dshowaudiosrc_init(GstDshowAudioSrc * src)147 gst_dshowaudiosrc_init (GstDshowAudioSrc * src)
148 {
149 src->device = NULL;
150 src->device_name = NULL;
151 src->device_index = DEFAULT_PROP_DEVICE_INDEX;
152 src->audio_cap_filter = NULL;
153 src->dshow_fakesink = NULL;
154 src->media_filter = NULL;
155 src->filter_graph = NULL;
156 src->caps = NULL;
157 src->pins_mediatypes = NULL;
158
159 src->gbarray = g_byte_array_new ();
160 g_mutex_init(&src->gbarray_lock);
161
162 src->is_running = FALSE;
163
164 CoInitializeEx (NULL, COINIT_MULTITHREADED);
165 }
166
167 static void
gst_dshowaudiosrc_dispose(GObject * gobject)168 gst_dshowaudiosrc_dispose (GObject * gobject)
169 {
170 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (gobject);
171
172 if (src->device) {
173 g_free (src->device);
174 src->device = NULL;
175 }
176
177 if (src->device_name) {
178 g_free (src->device_name);
179 src->device_name = NULL;
180 }
181
182 if (src->caps) {
183 gst_caps_unref (src->caps);
184 src->caps = NULL;
185 }
186
187 if (src->pins_mediatypes) {
188 gst_dshow_free_pins_mediatypes (src->pins_mediatypes);
189 src->pins_mediatypes = NULL;
190 }
191
192 if (src->gbarray) {
193 g_byte_array_free (src->gbarray, TRUE);
194 src->gbarray = NULL;
195 }
196
197 g_mutex_clear(&src->gbarray_lock);
198
199 /* clean dshow */
200 if (src->audio_cap_filter)
201 src->audio_cap_filter->Release ();
202
203 CoUninitialize ();
204
205 G_OBJECT_CLASS (gst_dshowaudiosrc_parent_class)->dispose (gobject);
206 }
207
208
209 static void
gst_dshowaudiosrc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)210 gst_dshowaudiosrc_set_property (GObject * object, guint prop_id,
211 const GValue * value, GParamSpec * pspec)
212 {
213 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (object);
214
215 switch (prop_id) {
216 case PROP_DEVICE:
217 {
218 if (src->device) {
219 g_free (src->device);
220 src->device = NULL;
221 }
222 if (g_value_get_string (value)) {
223 src->device = g_value_dup_string (value);;
224 }
225 break;
226 }
227 case PROP_DEVICE_NAME:
228 {
229 if (src->device_name) {
230 g_free (src->device_name);
231 src->device_name = NULL;
232 }
233 if (g_value_get_string (value)) {
234 src->device_name = g_value_dup_string (value);;
235 }
236 break;
237 }
238 case PROP_DEVICE_INDEX:
239 {
240 src->device_index = g_value_get_int (value);
241 break;
242 }
243 default:
244 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
245 break;
246 }
247 }
248
249 static void
gst_dshowaudiosrc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)250 gst_dshowaudiosrc_get_property (GObject * object, guint prop_id,
251 GValue * value, GParamSpec * pspec)
252 {
253 GstDshowAudioSrc *src;
254
255 g_return_if_fail (GST_IS_DSHOWAUDIOSRC (object));
256 src = GST_DSHOWAUDIOSRC (object);
257
258 switch (prop_id) {
259 case PROP_DEVICE:
260 g_value_set_string (value, src->device);
261 break;
262 case PROP_DEVICE_NAME:
263 g_value_set_string (value, src->device_name);
264 break;
265 case PROP_DEVICE_INDEX:
266 g_value_set_int (value, src->device_index);
267 break;
268 default:
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270 break;
271 }
272 }
273
274 static GstCaps *
gst_dshowaudiosrc_get_caps(GstBaseSrc * basesrc,GstCaps * filter)275 gst_dshowaudiosrc_get_caps (GstBaseSrc * basesrc, GstCaps * filter)
276 {
277 HRESULT hres = S_OK;
278 IBindCtx *lpbc = NULL;
279 IMoniker *audiom = NULL;
280 DWORD dwEaten;
281 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (basesrc);
282 gunichar2 *unidevice = NULL;
283
284 if (src->device) {
285 g_free (src->device);
286 src->device = NULL;
287 }
288
289 src->device =
290 gst_dshow_getdevice_from_devicename (&CLSID_AudioInputDeviceCategory,
291 &src->device_name, &src->device_index);
292 if (!src->device) {
293 GST_ERROR ("No audio device found.");
294 return NULL;
295 }
296 unidevice =
297 g_utf8_to_utf16 (src->device, strlen (src->device), NULL, NULL, NULL);
298
299 if (!src->audio_cap_filter) {
300 hres = CreateBindCtx (0, &lpbc);
301 if (SUCCEEDED (hres)) {
302 hres =
303 MkParseDisplayName (lpbc, (LPCOLESTR) unidevice, &dwEaten, &audiom);
304 if (SUCCEEDED (hres)) {
305 hres = audiom->BindToObject (lpbc, NULL, IID_IBaseFilter,
306 (LPVOID *) & src->audio_cap_filter);
307 audiom->Release ();
308 }
309 lpbc->Release ();
310 }
311 }
312
313 if (src->audio_cap_filter && !src->caps) {
314 /* get the capture pins supported types */
315 IPin *capture_pin = NULL;
316 IEnumPins *enumpins = NULL;
317 HRESULT hres;
318
319 hres = src->audio_cap_filter->EnumPins (&enumpins);
320 if (SUCCEEDED (hres)) {
321 while (enumpins->Next (1, &capture_pin, NULL) == S_OK) {
322 IKsPropertySet *pKs = NULL;
323
324 hres =
325 capture_pin->QueryInterface (IID_IKsPropertySet, (LPVOID *) & pKs);
326 if (SUCCEEDED (hres) && pKs) {
327 DWORD cbReturned;
328 GUID pin_category;
329 RPC_STATUS rpcstatus;
330
331 hres =
332 pKs->Get (AMPROPSETID_Pin,
333 AMPROPERTY_PIN_CATEGORY, NULL, 0, &pin_category, sizeof (GUID),
334 &cbReturned);
335
336 /* we only want capture pins */
337 if (UuidCompare (&pin_category, (UUID *) & PIN_CATEGORY_CAPTURE,
338 &rpcstatus) == 0) {
339 IAMStreamConfig *streamcaps = NULL;
340
341 if (SUCCEEDED (capture_pin->QueryInterface (IID_IAMStreamConfig,
342 (LPVOID *) & streamcaps))) {
343 src->caps =
344 gst_dshowaudiosrc_getcaps_from_streamcaps (src, capture_pin,
345 streamcaps);
346 streamcaps->Release ();
347 }
348 }
349 pKs->Release ();
350 }
351 capture_pin->Release ();
352 }
353 enumpins->Release ();
354 }
355 }
356
357 if (unidevice) {
358 g_free (unidevice);
359 }
360
361 if (src->caps) {
362 GstCaps *caps;
363
364 if (filter) {
365 caps = gst_caps_intersect_full (filter, src->caps, GST_CAPS_INTERSECT_FIRST);
366 } else {
367 caps = gst_caps_ref (src->caps);
368 }
369
370 return caps;
371 }
372
373 return NULL;
374 }
375
376 static GstStateChangeReturn
gst_dshowaudiosrc_change_state(GstElement * element,GstStateChange transition)377 gst_dshowaudiosrc_change_state (GstElement * element, GstStateChange transition)
378 {
379 HRESULT hres = S_FALSE;
380 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (element);
381
382 switch (transition) {
383 case GST_STATE_CHANGE_NULL_TO_READY:
384 break;
385 case GST_STATE_CHANGE_READY_TO_PAUSED:
386 break;
387 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
388 if (src->media_filter) {
389 src->is_running = TRUE;
390 hres = src->media_filter->Run (0);
391 }
392 if (hres != S_OK) {
393 GST_ERROR ("Can't RUN the directshow capture graph (error=0x%x)", hres);
394 src->is_running = FALSE;
395 return GST_STATE_CHANGE_FAILURE;
396 }
397 break;
398 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
399 if (src->media_filter)
400 hres = src->media_filter->Stop ();
401 if (hres != S_OK) {
402 GST_ERROR ("Can't STOP the directshow capture graph (error=0x%x)",
403 hres);
404 return GST_STATE_CHANGE_FAILURE;
405 }
406 src->is_running = FALSE;
407
408 break;
409 case GST_STATE_CHANGE_PAUSED_TO_READY:
410 break;
411 case GST_STATE_CHANGE_READY_TO_NULL:
412 break;
413 default:
414 break;
415 }
416
417 return GST_ELEMENT_CLASS(gst_dshowaudiosrc_parent_class)->change_state(element, transition);
418 }
419
420 static gboolean
gst_dshowaudiosrc_open(GstAudioSrc * asrc)421 gst_dshowaudiosrc_open (GstAudioSrc * asrc)
422 {
423 HRESULT hres = S_FALSE;
424 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc);
425
426 hres = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
427 IID_IFilterGraph, (LPVOID *) & src->filter_graph);
428 if (hres != S_OK || !src->filter_graph) {
429 GST_ERROR
430 ("Can't create an instance of the directshow graph manager (error=0x%x)",
431 hres);
432 goto error;
433 }
434
435 hres =
436 src->filter_graph->QueryInterface (IID_IMediaFilter,
437 (LPVOID *) & src->media_filter);
438 if (hres != S_OK || !src->media_filter) {
439 GST_ERROR
440 ("Can't get IMediacontrol interface from the graph manager (error=0x%x)",
441 hres);
442 goto error;
443 }
444
445 src->dshow_fakesink = new CDshowFakeSink;
446 src->dshow_fakesink->AddRef ();
447
448 hres = src->filter_graph->AddFilter (src->audio_cap_filter, L"capture");
449 if (hres != S_OK) {
450 GST_ERROR
451 ("Can't add the directshow capture filter to the graph (error=0x%x)",
452 hres);
453 goto error;
454 }
455
456 hres = src->filter_graph->AddFilter (src->dshow_fakesink, L"fakesink");
457 if (hres != S_OK) {
458 GST_ERROR ("Can't add our fakesink filter to the graph (error=0x%x)", hres);
459 goto error;
460 }
461
462 return TRUE;
463
464 error:
465 if (src->dshow_fakesink) {
466 src->dshow_fakesink->Release ();
467 src->dshow_fakesink = NULL;
468 }
469
470 if (src->media_filter) {
471 src->media_filter->Release ();
472 src->media_filter = NULL;
473 }
474 if (src->filter_graph) {
475 src->filter_graph->Release ();
476 src->filter_graph = NULL;
477 }
478
479 return FALSE;
480 }
481
482 static gboolean
gst_dshowaudiosrc_prepare(GstAudioSrc * asrc,GstAudioRingBufferSpec * spec)483 gst_dshowaudiosrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
484 {
485 HRESULT hres;
486 IPin *input_pin = NULL;
487 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc);
488 GstCaps *current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (asrc));
489
490 if (current_caps) {
491 if (gst_caps_is_equal (spec->caps, current_caps)) {
492 gst_caps_unref (current_caps);
493 return TRUE;
494 }
495 gst_caps_unref (current_caps);
496 }
497 /* In 1.0, prepare() seems to be called in the PLAYING state. Most
498 of the time you can't do much on a running graph. */
499
500 gboolean was_running = src->is_running;
501 if (was_running) {
502 HRESULT hres = src->media_filter->Stop ();
503 if (hres != S_OK) {
504 GST_ERROR("Can't STOP the directshow capture graph for preparing (error=0x%x)", hres);
505 return FALSE;
506 }
507 src->is_running = FALSE;
508 }
509
510 /* search the negotiated caps in our caps list to get its index and the corresponding mediatype */
511 if (gst_caps_is_subset (spec->caps, src->caps)) {
512 guint i = 0;
513 gint res = -1;
514
515 for (; i < gst_caps_get_size (src->caps) && res == -1; i++) {
516 GstCaps *capstmp = gst_caps_copy_nth (src->caps, i);
517
518 if (gst_caps_is_subset (spec->caps, capstmp)) {
519 res = i;
520 }
521 gst_caps_unref (capstmp);
522 }
523
524 if (res != -1 && src->pins_mediatypes) {
525 /*get the corresponding media type and build the dshow graph */
526 GstCapturePinMediaType *pin_mediatype = NULL;
527 GList *type = g_list_nth (src->pins_mediatypes, res);
528
529 if (type) {
530 pin_mediatype = (GstCapturePinMediaType *) type->data;
531
532 src->dshow_fakesink->gst_set_media_type (pin_mediatype->mediatype);
533 src->dshow_fakesink->gst_set_buffer_callback (
534 (push_buffer_func) gst_dshowaudiosrc_push_buffer, src);
535
536 gst_dshow_get_pin_from_filter (src->dshow_fakesink, PINDIR_INPUT,
537 &input_pin);
538 if (!input_pin) {
539 GST_ERROR ("Can't get input pin from our directshow fakesink filter");
540 goto error;
541 }
542
543 spec->segsize = (gint) (spec->info.bpf * spec->info.rate * spec->latency_time /
544 GST_MSECOND);
545 spec->segtotal = (gint) ((gfloat) spec->buffer_time /
546 (gfloat) spec->latency_time + 0.5);
547 if (!gst_dshow_configure_latency (pin_mediatype->capture_pin,
548 spec->segsize))
549 {
550 GST_WARNING ("Could not change capture latency");
551 spec->segsize = spec->info.rate * spec->info.channels;
552 spec->segtotal = 2;
553 };
554 GST_INFO ("Configuring with segsize:%d segtotal:%d", spec->segsize, spec->segtotal);
555
556 if (gst_dshow_is_pin_connected (pin_mediatype->capture_pin)) {
557 GST_DEBUG_OBJECT (src,
558 "capture_pin already connected, disconnecting");
559 src->filter_graph->Disconnect (pin_mediatype->capture_pin);
560 }
561
562 if (gst_dshow_is_pin_connected (input_pin)) {
563 GST_DEBUG_OBJECT (src, "input_pin already connected, disconnecting");
564 src->filter_graph->Disconnect (input_pin);
565 }
566
567 hres = src->filter_graph->ConnectDirect (pin_mediatype->capture_pin,
568 input_pin, NULL);
569 input_pin->Release ();
570
571 if (hres != S_OK) {
572 GST_ERROR
573 ("Can't connect capture filter with fakesink filter (error=0x%x)",
574 hres);
575 goto error;
576 }
577
578 }
579 }
580 }
581
582 if (was_running) {
583 HRESULT hres = src->media_filter->Run (0);
584 if (hres != S_OK) {
585 GST_ERROR("Can't RUN the directshow capture graph after prepare (error=0x%x)", hres);
586 return FALSE;
587 }
588
589 src->is_running = TRUE;
590 }
591
592 return TRUE;
593
594 error:
595 /* Don't restart the graph, we're out anyway. */
596 return FALSE;
597 }
598
599 static gboolean
gst_dshowaudiosrc_unprepare(GstAudioSrc * asrc)600 gst_dshowaudiosrc_unprepare (GstAudioSrc * asrc)
601 {
602 IPin *input_pin = NULL, *output_pin = NULL;
603 HRESULT hres = S_FALSE;
604 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc);
605
606 /* disconnect filters */
607 gst_dshow_get_pin_from_filter (src->audio_cap_filter, PINDIR_OUTPUT,
608 &output_pin);
609 if (output_pin) {
610 hres = src->filter_graph->Disconnect (output_pin);
611 output_pin->Release ();
612 }
613
614 gst_dshow_get_pin_from_filter (src->dshow_fakesink, PINDIR_INPUT, &input_pin);
615 if (input_pin) {
616 hres = src->filter_graph->Disconnect (input_pin);
617 input_pin->Release ();
618 }
619
620 return TRUE;
621 }
622
623 static gboolean
gst_dshowaudiosrc_close(GstAudioSrc * asrc)624 gst_dshowaudiosrc_close (GstAudioSrc * asrc)
625 {
626 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc);
627
628 if (!src->filter_graph)
629 return TRUE;
630
631 /*remove filters from the graph */
632 src->filter_graph->RemoveFilter (src->audio_cap_filter);
633 src->filter_graph->RemoveFilter (src->dshow_fakesink);
634
635 /*release our gstreamer dshow sink */
636 src->dshow_fakesink->Release ();
637 src->dshow_fakesink = NULL;
638
639 /*release media filter interface */
640 src->media_filter->Release ();
641 src->media_filter = NULL;
642
643 /*release the filter graph manager */
644 src->filter_graph->Release ();
645 src->filter_graph = NULL;
646
647 return TRUE;
648 }
649
650 static guint
gst_dshowaudiosrc_read(GstAudioSrc * asrc,gpointer data,guint length,GstClockTime * timestamp)651 gst_dshowaudiosrc_read (GstAudioSrc * asrc, gpointer data, guint length, GstClockTime *timestamp)
652 {
653 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc);
654 guint ret = 0;
655
656 if (!src->is_running)
657 return -1;
658
659 if (src->gbarray) {
660 test:
661 if (src->gbarray->len >= length) {
662 g_mutex_lock (&src->gbarray_lock);
663 memcpy (data, src->gbarray->data + (src->gbarray->len - length), length);
664 g_byte_array_remove_range (src->gbarray, src->gbarray->len - length,
665 length);
666 ret = length;
667 g_mutex_unlock (&src->gbarray_lock);
668 } else {
669 if (src->is_running) {
670 Sleep (GST_AUDIO_BASE_SRC(src)->ringbuffer->spec.latency_time /
671 GST_MSECOND / 10);
672 goto test;
673 }
674 }
675 }
676
677 return ret;
678 }
679
680 static guint
gst_dshowaudiosrc_delay(GstAudioSrc * asrc)681 gst_dshowaudiosrc_delay (GstAudioSrc * asrc)
682 {
683 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc);
684 guint ret = 0;
685
686 if (src->gbarray) {
687 g_mutex_lock (&src->gbarray_lock);
688 if (src->gbarray->len) {
689 ret = src->gbarray->len / 4;
690 }
691 g_mutex_unlock (&src->gbarray_lock);
692 }
693
694 return ret;
695 }
696
697 static void
gst_dshowaudiosrc_reset(GstAudioSrc * asrc)698 gst_dshowaudiosrc_reset (GstAudioSrc * asrc)
699 {
700 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc);
701
702 g_mutex_lock (&src->gbarray_lock);
703 GST_DEBUG ("byte array size= %d", src->gbarray->len);
704 if (src->gbarray->len > 0)
705 g_byte_array_remove_range (src->gbarray, 0, src->gbarray->len);
706 g_mutex_unlock (&src->gbarray_lock);
707 }
708
709 static GstCaps *
gst_dshowaudiosrc_getcaps_from_streamcaps(GstDshowAudioSrc * src,IPin * pin,IAMStreamConfig * streamcaps)710 gst_dshowaudiosrc_getcaps_from_streamcaps (GstDshowAudioSrc * src, IPin * pin,
711 IAMStreamConfig * streamcaps)
712 {
713 GstCaps *caps = NULL;
714 HRESULT hres = S_OK;
715 int icount = 0;
716 int isize = 0;
717 AUDIO_STREAM_CONFIG_CAPS ascc;
718 int i = 0;
719
720 if (!streamcaps)
721 return NULL;
722
723 streamcaps->GetNumberOfCapabilities (&icount, &isize);
724
725 if (isize != sizeof (ascc))
726 return NULL;
727
728 for (; i < icount; i++) {
729 GstCapturePinMediaType *pin_mediatype = g_new0 (GstCapturePinMediaType, 1);
730
731 pin->AddRef ();
732 pin_mediatype->capture_pin = pin;
733
734 hres = streamcaps->GetStreamCaps (i, &pin_mediatype->mediatype,
735 (BYTE *) & ascc);
736 if (hres == S_OK && pin_mediatype->mediatype) {
737 GstCaps *mediacaps = NULL;
738
739 if (!caps)
740 caps = gst_caps_new_empty ();
741
742 if (gst_dshow_check_mediatype (pin_mediatype->mediatype, MEDIASUBTYPE_PCM,
743 FORMAT_WaveFormatEx)) {
744 GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
745 WAVEFORMATEX *wavformat =
746 (WAVEFORMATEX *) pin_mediatype->mediatype->pbFormat;
747
748 switch (wavformat->wFormatTag) {
749 case WAVE_FORMAT_PCM:
750 format = gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, wavformat->wBitsPerSample, wavformat->wBitsPerSample);
751 break;
752 default:
753 break;
754 }
755
756 if (format != GST_AUDIO_FORMAT_UNKNOWN) {
757 GstAudioInfo info;
758
759 gst_audio_info_init(&info);
760 gst_audio_info_set_format(&info,
761 format,
762 wavformat->nSamplesPerSec,
763 wavformat->nChannels,
764 NULL);
765 mediacaps = gst_audio_info_to_caps(&info);
766 }
767
768 if (mediacaps) {
769 src->pins_mediatypes =
770 g_list_append (src->pins_mediatypes, pin_mediatype);
771 gst_caps_append (caps, mediacaps);
772 } else {
773 gst_dshow_free_pin_mediatype (pin_mediatype);
774 }
775 } else {
776 gst_dshow_free_pin_mediatype (pin_mediatype);
777 }
778 } else {
779 gst_dshow_free_pin_mediatype (pin_mediatype);
780 }
781 }
782
783 if (caps && gst_caps_is_empty (caps)) {
784 gst_caps_unref (caps);
785 caps = NULL;
786 }
787
788 return caps;
789 }
790
791 static gboolean
gst_dshowaudiosrc_push_buffer(guint8 * buffer,guint size,gpointer src_object,GstClockTime duration)792 gst_dshowaudiosrc_push_buffer (guint8 * buffer, guint size, gpointer src_object,
793 GstClockTime duration)
794 {
795 GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (src_object);
796
797 if (!buffer || size == 0 || !src) {
798 return FALSE;
799 }
800
801 g_mutex_lock (&src->gbarray_lock);
802 g_byte_array_prepend (src->gbarray, buffer, size);
803 g_mutex_unlock (&src->gbarray_lock);
804
805 return TRUE;
806 }
807