• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "config.h"
17 #include "gst_audio_capture_src.h"
18 #include <gst/gst.h>
19 #include <gst/audio/audio.h>
20 #include "media_errors.h"
21 #include "audio_capture_factory.h"
22 
23 static GstStaticPadTemplate gst_audio_capture_src_template =
24 GST_STATIC_PAD_TEMPLATE("src",
25     GST_PAD_SRC,
26     GST_PAD_ALWAYS,
27     GST_STATIC_CAPS("audio/x-raw, "
28         "format = (string) S16LE, "
29         "rate = (int) [ 1, MAX ], "
30         "layout = (string) interleaved, "
31         "channels = (int) [ 1, MAX ]"));
32 
33 enum {
34     PROP_0,
35     PROP_SOURCE_TYPE,
36     PROP_SAMPLE_RATE,
37     PROP_CHANNELS,
38     PROP_BITRATE,
39     PROP_TOKEN_ID,
40     PROP_APP_UID,
41     PROP_APP_PID,
42     PROP_BYPASS_AUDIO_SERVICE,
43     PROP_SUPPORTED_AUDIO_PARAMS
44 };
45 
46 using namespace OHOS::Media;
47 
48 #define gst_audio_capture_src_parent_class parent_class
49 G_DEFINE_TYPE(GstAudioCaptureSrc, gst_audio_capture_src, GST_TYPE_PUSH_SRC);
50 
51 static void gst_audio_capture_src_finalize(GObject *object);
52 static void gst_audio_capture_src_set_property(GObject *object, guint prop_id,
53     const GValue *value, GParamSpec *pspec);
54 static void gst_audio_capture_src_get_property(GObject *object, guint prop_id,
55     GValue *value, GParamSpec *pspec);
56 static GstFlowReturn gst_audio_capture_src_create(GstPushSrc *psrc, GstBuffer **outbuf);
57 static GstStateChangeReturn gst_audio_capture_src_change_state(GstElement *element, GstStateChange transition);
58 static gboolean gst_audio_capture_src_negotiate(GstBaseSrc *basesrc);
59 static void gst_audio_capture_src_getbuffer_timeout(GstPushSrc *psrc);
60 static void gst_audio_capture_src_mgr_init(GstAudioCaptureSrc *src);
61 static void gst_audio_capture_src_mgr_enable_watchdog(GstAudioCaptureSrc *src);
62 static void gst_audio_capture_src_mgr_disable_watchdog(GstAudioCaptureSrc *src);
63 
Alarm()64 void AudioManager::Alarm()
65 {
66     gst_audio_capture_src_getbuffer_timeout(&owner_);
67 }
68 
69 #define GST_TYPE_AUDIO_CAPTURE_SRC_SOURCE_TYPE (gst_audio_capture_src_source_type_get_type())
gst_audio_capture_src_source_type_get_type(void)70 static GType gst_audio_capture_src_source_type_get_type(void)
71 {
72     static GType audio_capture_src_source_type = 0;
73     static const GEnumValue source_types[] = {
74         {AUDIO_SOURCE_TYPE_DEFAULT, "MIC", "MIC"},
75         {AUDIO_SOURCE_TYPE_MIC, "MIC", "MIC"},
76         {0, nullptr, nullptr}
77     };
78     if (!audio_capture_src_source_type) {
79         audio_capture_src_source_type = g_enum_register_static("AudioSourceType", source_types);
80     }
81     return audio_capture_src_source_type;
82 }
83 
gst_audio_capture_src_class_init(GstAudioCaptureSrcClass * klass)84 static void gst_audio_capture_src_class_init(GstAudioCaptureSrcClass *klass)
85 {
86     GObjectClass *gobject_class = reinterpret_cast<GObjectClass *>(klass);
87     GstElementClass *gstelement_class = reinterpret_cast<GstElementClass *>(klass);
88     GstBaseSrcClass *gstbasesrc_class = reinterpret_cast<GstBaseSrcClass *>(klass);
89     GstPushSrcClass *gstpushsrc_class = reinterpret_cast<GstPushSrcClass *>(klass);
90     g_return_if_fail((gobject_class != nullptr) && (gstelement_class != nullptr) &&
91         (gstbasesrc_class != nullptr) && gstpushsrc_class != nullptr);
92 
93     gobject_class->finalize = gst_audio_capture_src_finalize;
94     gobject_class->set_property = gst_audio_capture_src_set_property;
95     gobject_class->get_property = gst_audio_capture_src_get_property;
96 
97     g_object_class_install_property(gobject_class, PROP_SOURCE_TYPE,
98         g_param_spec_enum("source-type", "Source type",
99             "Source type", GST_TYPE_AUDIO_CAPTURE_SRC_SOURCE_TYPE, AUDIO_SOURCE_TYPE_MIC,
100             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
101 
102     g_object_class_install_property(gobject_class, PROP_SAMPLE_RATE,
103         g_param_spec_uint("sample-rate", "Sample-Rate", "Audio sampling rate", 0, G_MAXINT32, 0,
104             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
105 
106     g_object_class_install_property(gobject_class, PROP_CHANNELS,
107         g_param_spec_uint("channels", "Channels", "Number of audio channels", 0, G_MAXINT32, 0,
108             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
109 
110     g_object_class_install_property(gobject_class, PROP_BITRATE,
111         g_param_spec_uint("bitrate", "Bitrate", "Audio bitrate", 0, G_MAXINT32, 0,
112             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
113 
114     g_object_class_install_property(gobject_class, PROP_TOKEN_ID,
115         g_param_spec_uint("token-id", "TokenID", "Token ID", 0, G_MAXUINT32, 0,
116             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
117 
118     g_object_class_install_property(gobject_class, PROP_APP_UID,
119         g_param_spec_int("app-uid", "Appuid", "APP UID", 0, G_MAXINT32, 0,
120             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
121 
122     g_object_class_install_property(gobject_class, PROP_APP_PID,
123         g_param_spec_int("app-pid", "Apppid", "APP PID", 0, G_MAXINT32, 0,
124             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
125 
126     g_object_class_install_property(gobject_class, PROP_BYPASS_AUDIO_SERVICE,
127         g_param_spec_boolean("bypass-audio-service", "Bypass Audio Service",
128             "do not enable audio service", FALSE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
129 
130     g_object_class_install_property(gobject_class, PROP_SUPPORTED_AUDIO_PARAMS,
131         g_param_spec_boolean("supported-audio-params", "issupport audio params",
132             "issupport audio params", FALSE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
133 
134     gst_element_class_set_static_metadata(gstelement_class,
135         "Audio capture source", "Source/Audio",
136         "Retrieve audio frame from audio buffer queue", "OpenHarmony");
137 
138     gst_element_class_add_static_pad_template(gstelement_class, &gst_audio_capture_src_template);
139 
140     gstelement_class->change_state = gst_audio_capture_src_change_state;
141     gstbasesrc_class->negotiate = gst_audio_capture_src_negotiate;
142     gstpushsrc_class->create = gst_audio_capture_src_create;
143 }
144 
gst_audio_capture_src_init(GstAudioCaptureSrc * src)145 static void gst_audio_capture_src_init(GstAudioCaptureSrc *src)
146 {
147     g_return_if_fail(src != nullptr);
148     gst_base_src_set_format(GST_BASE_SRC(src), GST_FORMAT_TIME);
149     gst_base_src_set_live(GST_BASE_SRC(src), TRUE);
150     src->stream_type = AUDIO_STREAM_TYPE_UNKNOWN;
151     src->source_type = AUDIO_SOURCE_TYPE_MIC;
152     src->audio_capture = nullptr;
153     src->audio_mgr = nullptr;
154     src->src_caps = nullptr;
155     src->bitrate = 0;
156     src->channels = 0;
157     src->sample_rate = 0;
158     src->is_start = FALSE;
159     src->need_caps_info = TRUE;
160     src->token_id = 0;
161     src->appuid = 0;
162     src->apppid = 0;
163     src->bypass_audio = FALSE;
164     src->input_detection = TRUE;
165     gst_base_src_set_blocksize(GST_BASE_SRC(src), 0);
166 }
167 
gst_audio_capture_src_finalize(GObject * object)168 static void gst_audio_capture_src_finalize(GObject *object)
169 {
170     GST_DEBUG_OBJECT(object, "finalize");
171     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(object);
172     g_return_if_fail(src != nullptr);
173     if (src->src_caps != nullptr) {
174         gst_caps_unref(src->src_caps);
175         src->src_caps = nullptr;
176     }
177 
178     if (src->audio_capture) {
179         src->audio_capture = nullptr;
180     }
181 
182     G_OBJECT_CLASS(parent_class)->finalize(object);
183 }
184 
gst_audio_capture_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)185 static void gst_audio_capture_src_set_property(GObject *object, guint prop_id,
186     const GValue *value, GParamSpec *pspec)
187 {
188     (void)pspec;
189     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(object);
190     g_return_if_fail(src != nullptr);
191     switch (prop_id) {
192         case PROP_SOURCE_TYPE:
193             src->source_type = (AudioSourceType)g_value_get_enum(value);
194             break;
195         case PROP_SAMPLE_RATE:
196             src->sample_rate = g_value_get_uint(value);
197             break;
198         case PROP_CHANNELS:
199             src->channels = g_value_get_uint(value);
200             break;
201         case PROP_BITRATE:
202             src->bitrate = g_value_get_uint(value);
203             break;
204         case PROP_TOKEN_ID:
205             src->token_id = g_value_get_uint(value);
206             break;
207         case PROP_APP_UID:
208             src->appuid = g_value_get_int(value);
209             break;
210         case PROP_APP_PID:
211             src->apppid = g_value_get_int(value);
212             break;
213         case PROP_BYPASS_AUDIO_SERVICE:
214             src->bypass_audio = g_value_get_boolean(value);
215             if (src->bypass_audio) {
216                 // Mutually exclusive protection is provided at the frame layer
217                 if (src->audio_capture) {
218                     src->audio_capture->WakeUpAudioThreads();
219                 }
220             }
221             break;
222         default:
223             break;
224     }
225 }
226 
gst_audio_capture_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)227 static void gst_audio_capture_src_get_property(GObject *object, guint prop_id,
228     GValue *value, GParamSpec *pspec)
229 {
230     (void)pspec;
231     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(object);
232     g_return_if_fail(src != nullptr);
233     switch (prop_id) {
234         case PROP_SOURCE_TYPE:
235             g_value_set_enum(value, src->source_type);
236             break;
237         case PROP_SAMPLE_RATE:
238             g_value_set_uint(value, src->sample_rate);
239             break;
240         case PROP_CHANNELS:
241             g_value_set_uint(value, src->channels);
242             break;
243         case PROP_BITRATE:
244             g_value_set_uint(value, src->bitrate);
245             break;
246         case PROP_SUPPORTED_AUDIO_PARAMS:
247             if (src->audio_capture == nullptr) {
248                 src->audio_capture = OHOS::Media::AudioCaptureFactory::CreateAudioCapture(src->stream_type);
249                 g_return_if_fail(src->audio_capture != nullptr);
250             }
251             g_value_set_boolean(value, src->audio_capture->IsSupportedCaptureParameter(
252                 src->bitrate, src->channels, src->sample_rate));
253             break;
254         default:
255             break;
256     }
257 }
258 
process_caps_info(GstAudioCaptureSrc * src)259 static gboolean process_caps_info(GstAudioCaptureSrc *src)
260 {
261     guint bitrate = 0;
262     guint sample_rate = 0;
263     guint channels = 0;
264     g_return_val_if_fail(src != nullptr, FALSE);
265     g_return_val_if_fail(src->audio_capture->GetCaptureParameter(bitrate, channels, sample_rate) == MSERR_OK, FALSE);
266 
267     gboolean is_valid_params = TRUE;
268     guint64 channel_mask = 0;
269     switch (channels) {
270         case 1: {
271             GstAudioChannelPosition positions[1] = {GST_AUDIO_CHANNEL_POSITION_MONO};
272             if (!gst_audio_channel_positions_to_mask(positions, channels, FALSE, &channel_mask)) {
273                 GST_ERROR_OBJECT(src, "invalid channel positions");
274                 is_valid_params = FALSE;
275             }
276             break;
277         }
278         case 2: { // 2 channels
279             GstAudioChannelPosition positions[2] = {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
280                                                     GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT};
281             if (!gst_audio_channel_positions_to_mask(positions, channels, FALSE, &channel_mask)) {
282                 GST_ERROR_OBJECT(src, "invalid channel positions");
283                 is_valid_params = FALSE;
284             }
285             break;
286         }
287         default: {
288             is_valid_params = FALSE;
289             GST_ERROR_OBJECT(src, "invalid channels %u", channels);
290             break;
291         }
292     }
293     g_return_val_if_fail(is_valid_params == TRUE, FALSE);
294     if (src->src_caps != nullptr) {
295         gst_caps_unref(src->src_caps);
296     }
297     src->src_caps = gst_caps_new_simple("audio/x-raw",
298                                         "rate", G_TYPE_INT, sample_rate,
299                                         "channels", G_TYPE_INT, channels,
300                                         "format", G_TYPE_STRING, "S16LE",
301                                         "channel-mask", GST_TYPE_BITMASK, channel_mask,
302                                         "layout", G_TYPE_STRING, "interleaved", nullptr);
303     GstBaseSrc *basesrc = GST_BASE_SRC_CAST(src);
304     basesrc->segment.start = 0;
305     return TRUE;
306 }
307 
gst_state_change_forward_direction(GstAudioCaptureSrc * src,GstStateChange transition)308 static GstStateChangeReturn gst_state_change_forward_direction(GstAudioCaptureSrc *src, GstStateChange transition)
309 {
310     g_return_val_if_fail(src != nullptr, GST_STATE_CHANGE_FAILURE);
311     switch (transition) {
312         case GST_STATE_CHANGE_NULL_TO_READY: {
313             if (src->audio_capture == nullptr) {
314                 src->audio_capture = OHOS::Media::AudioCaptureFactory::CreateAudioCapture(src->stream_type);
315                 CHECK_AND_BREAK_REP_ERR(src->audio_capture != nullptr, src, "failed to CreateAudioCapture");
316             }
317             break;
318         }
319         case GST_STATE_CHANGE_READY_TO_PAUSED: {
320             CHECK_AND_BREAK_REP_ERR(src->audio_capture != nullptr, src, "audio_capture is nullptr");
321             AudioCapture::AppInfo appInfo = {};
322             appInfo.appUid = src->appuid;
323             appInfo.appPid = src->apppid;
324             appInfo.appTokenId = src->token_id;
325             CHECK_AND_BREAK_REP_ERR(src->audio_capture->SetCaptureParameter(src->bitrate, src->channels,
326                 src->sample_rate, appInfo) == MSERR_OK, src, "SetCaptureParameter failed");
327             break;
328         }
329         case GST_STATE_CHANGE_PAUSED_TO_PLAYING: {
330             CHECK_AND_BREAK_REP_ERR(src->audio_capture != nullptr, src, "audio_capture is nullptr");
331             if (src->need_caps_info) {
332                 CHECK_AND_BREAK_REP_ERR(process_caps_info(src) == TRUE, src, "process caps info failed");
333                 src->need_caps_info = FALSE;
334             }
335             if (src->is_start == FALSE) {
336                 CHECK_AND_BREAK_REP_ERR(src->audio_capture->StartAudioCapture() == MSERR_OK,
337                     src, "StartAudioCapture failed");
338                 gst_audio_capture_src_mgr_init(src);
339                 src->is_start = TRUE;
340             } else {
341                 if (!src->bypass_audio) {
342                     CHECK_AND_BREAK_REP_ERR(src->audio_capture->ResumeAudioCapture() == MSERR_OK,
343                         src, "ResumeAudioCapture failed");
344                     gst_audio_capture_src_mgr_enable_watchdog(src);
345                 } else {
346                     src->audio_mgr = nullptr;
347                     CHECK_AND_BREAK_REP_ERR(src->audio_capture->WakeUpAudioThreads() == MSERR_OK,
348                         src, "WakeUpAudioThreads failed");
349                 }
350             }
351             break;
352         }
353         default:
354             break;
355     }
356     return GST_STATE_CHANGE_SUCCESS;
357 }
358 
gst_audio_capture_src_change_state(GstElement * element,GstStateChange transition)359 static GstStateChangeReturn gst_audio_capture_src_change_state(GstElement *element, GstStateChange transition)
360 {
361     g_return_val_if_fail(element != nullptr, GST_STATE_CHANGE_FAILURE);
362     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(element);
363 
364     GstStateChangeReturn ret = gst_state_change_forward_direction(src, transition);
365     g_return_val_if_fail(ret == GST_STATE_CHANGE_SUCCESS, GST_STATE_CHANGE_FAILURE);
366 
367     ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
368 
369     switch (transition) {
370         case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
371             gst_audio_capture_src_mgr_disable_watchdog(src);
372             CHECK_AND_BREAK_REP_ERR(src->audio_capture != nullptr, src, "audio_capture is nullptr");
373             if (!src->bypass_audio) {
374                 CHECK_AND_BREAK_REP_ERR(src->audio_capture->PauseAudioCapture() == MSERR_OK,
375                     src, "PauseAudioCapture failed");
376             }
377             break;
378         case GST_STATE_CHANGE_PAUSED_TO_READY:
379             src->is_start = FALSE;
380             CHECK_AND_BREAK_REP_ERR(src->audio_capture != nullptr, src, "audio_capture is nullptr");
381             src->audio_mgr = nullptr;
382             CHECK_AND_BREAK_REP_ERR(src->audio_capture->StopAudioCapture() == MSERR_OK, src,
383                 "StopAudioCapture failed");
384             break;
385         case GST_STATE_CHANGE_READY_TO_NULL:
386             src->audio_capture = nullptr;
387             break;
388         default:
389             break;
390     }
391     return ret;
392 }
393 
gst_audio_capture_src_create(GstPushSrc * psrc,GstBuffer ** outbuf)394 static GstFlowReturn gst_audio_capture_src_create(GstPushSrc *psrc, GstBuffer **outbuf)
395 {
396     g_return_val_if_fail((psrc != nullptr) && (outbuf != nullptr), GST_FLOW_ERROR);
397     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(psrc);
398     g_return_val_if_fail(src != nullptr, GST_FLOW_ERROR);
399     if (src->is_start == FALSE) {
400         return GST_FLOW_EOS;
401     }
402     g_return_val_if_fail(src->audio_capture != nullptr, GST_FLOW_ERROR);
403 
404     if (src->input_detection && src->audio_mgr != nullptr) {
405         src->audio_mgr->ResumeWatchDog();
406     }
407     std::shared_ptr<AudioBuffer> audio_buffer = src->audio_capture->GetBuffer();
408     if (src->input_detection && src->audio_mgr != nullptr) {
409         src->audio_mgr->PauseWatchDog();
410     }
411     if (audio_buffer == nullptr) {
412         if ((!src->bypass_audio) && src->is_start) {
413             GST_ELEMENT_ERROR (src, STREAM, FAILED, ("Input stream error, return null."),
414                 ("Input stream error, return null."));
415         }
416         return GST_FLOW_ERROR;
417     }
418     gst_base_src_set_blocksize(GST_BASE_SRC_CAST(src), audio_buffer->dataLen);
419 
420     *outbuf = audio_buffer->gstBuffer;
421     GST_BUFFER_DURATION(*outbuf) = audio_buffer->duration;
422     GST_BUFFER_TIMESTAMP(*outbuf) = audio_buffer->timestamp;
423     return GST_FLOW_OK;
424 }
425 
gst_audio_capture_src_negotiate(GstBaseSrc * basesrc)426 static gboolean gst_audio_capture_src_negotiate(GstBaseSrc *basesrc)
427 {
428     g_return_val_if_fail(basesrc != nullptr, false);
429     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(basesrc);
430     g_return_val_if_fail(src != nullptr, FALSE);
431     (void)gst_base_src_wait_playing(basesrc);
432     g_return_val_if_fail(src->src_caps != nullptr, FALSE);
433     return gst_base_src_set_caps(basesrc, src->src_caps);
434 }
435 
gst_audio_capture_src_mgr_init(GstAudioCaptureSrc * src)436 static void gst_audio_capture_src_mgr_init(GstAudioCaptureSrc *src)
437 {
438     g_return_if_fail(src != nullptr);
439     if (src->input_detection && src->audio_mgr == nullptr) {
440         const guint32 timeoutMs = 3000; // Error will be reported if there is no data input in 3000ms by default.
441         GstPushSrc *psrc = GST_PUSH_SRC(src);
442         src->audio_mgr = std::make_shared<AudioManager>(*psrc, timeoutMs);
443         g_return_if_fail(src->audio_mgr != nullptr);
444     }
445 }
446 
gst_audio_capture_src_mgr_enable_watchdog(GstAudioCaptureSrc * src)447 static void gst_audio_capture_src_mgr_enable_watchdog(GstAudioCaptureSrc *src)
448 {
449     g_return_if_fail(src != nullptr);
450     if (src->input_detection && src->audio_mgr != nullptr) {
451         src->audio_mgr->EnableWatchDog();
452         src->audio_mgr->PauseWatchDog();
453     }
454 }
455 
gst_audio_capture_src_mgr_disable_watchdog(GstAudioCaptureSrc * src)456 static void gst_audio_capture_src_mgr_disable_watchdog(GstAudioCaptureSrc *src)
457 {
458     g_return_if_fail(src != nullptr);
459     if (src->audio_mgr != nullptr) {
460         src->audio_mgr->DisableWatchDog();
461     }
462 }
463 
gst_audio_capture_src_getbuffer_timeout(GstPushSrc * psrc)464 static void gst_audio_capture_src_getbuffer_timeout(GstPushSrc *psrc)
465 {
466     g_return_if_fail(psrc != nullptr);
467     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(psrc);
468     g_return_if_fail(src != nullptr);
469 
470     GST_ELEMENT_ERROR (src, RESOURCE, READ,
471         ("Audio input stream timeout, please confirm whether the input is normal."),
472         ("Audio input stream timeout, please confirm whether the input is normal."));
473 }
474 
plugin_init(GstPlugin * plugin)475 static gboolean plugin_init(GstPlugin *plugin)
476 {
477     g_return_val_if_fail(plugin != nullptr, false);
478     return gst_element_register(plugin, "audiocapturesrc", GST_RANK_PRIMARY, GST_TYPE_AUDIO_CAPTURE_SRC);
479 }
480 
481 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
482     GST_VERSION_MINOR,
483     _audio_capture_src,
484     "GStreamer Audio Capture Source",
485     plugin_init,
486     PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
487