• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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