• 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 };
40 
41 using namespace OHOS::Media;
42 
43 #define gst_audio_capture_src_parent_class parent_class
44 G_DEFINE_TYPE(GstAudioCaptureSrc, gst_audio_capture_src, GST_TYPE_PUSH_SRC);
45 
46 static void gst_audio_capture_src_finalize(GObject *object);
47 static void gst_audio_capture_src_set_property(GObject *object, guint prop_id,
48     const GValue *value, GParamSpec *pspec);
49 static void gst_audio_capture_src_get_property(GObject *object, guint prop_id,
50     GValue *value, GParamSpec *pspec);
51 static GstFlowReturn gst_audio_capture_src_create(GstPushSrc *psrc, GstBuffer **outbuf);
52 static GstStateChangeReturn gst_audio_capture_src_change_state(GstElement *element, GstStateChange transition);
53 static gboolean gst_audio_capture_src_negotiate(GstBaseSrc *basesrc);
54 
55 #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)56 static GType gst_audio_capture_src_source_type_get_type(void)
57 {
58     static GType audio_capture_src_source_type = 0;
59     static const GEnumValue source_types[] = {
60         {AUDIO_SOURCE_TYPE_DEFAULT, "MIC", "MIC"},
61         {AUDIO_SOURCE_TYPE_MIC, "MIC", "MIC"},
62         {0, nullptr, nullptr}
63     };
64     if (!audio_capture_src_source_type) {
65         audio_capture_src_source_type = g_enum_register_static("AudioSourceType", source_types);
66     }
67     return audio_capture_src_source_type;
68 }
69 
gst_audio_capture_src_class_init(GstAudioCaptureSrcClass * klass)70 static void gst_audio_capture_src_class_init(GstAudioCaptureSrcClass *klass)
71 {
72     GObjectClass *gobject_class = reinterpret_cast<GObjectClass *>(klass);
73     GstElementClass *gstelement_class = reinterpret_cast<GstElementClass *>(klass);
74     GstBaseSrcClass *gstbasesrc_class = reinterpret_cast<GstBaseSrcClass *>(klass);
75     GstPushSrcClass *gstpushsrc_class = reinterpret_cast<GstPushSrcClass *>(klass);
76     g_return_if_fail((gobject_class != nullptr) && (gstelement_class != nullptr) &&
77         (gstbasesrc_class != nullptr) && gstpushsrc_class != nullptr);
78 
79     gobject_class->finalize = gst_audio_capture_src_finalize;
80     gobject_class->set_property = gst_audio_capture_src_set_property;
81     gobject_class->get_property = gst_audio_capture_src_get_property;
82 
83     g_object_class_install_property(gobject_class, PROP_SOURCE_TYPE,
84         g_param_spec_enum("source-type", "Source type",
85             "Source type", GST_TYPE_AUDIO_CAPTURE_SRC_SOURCE_TYPE, AUDIO_SOURCE_TYPE_MIC,
86             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
87 
88     g_object_class_install_property(gobject_class, PROP_SAMPLE_RATE,
89         g_param_spec_uint("sample-rate", "Sample-Rate",
90             "Audio sampling rate", 0, G_MAXINT32, 0,
91             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
92 
93     g_object_class_install_property(gobject_class, PROP_CHANNELS,
94         g_param_spec_uint("channels", "Channels",
95             "Number of audio channels", 0, G_MAXINT32, 0,
96             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
97 
98     g_object_class_install_property(gobject_class, PROP_BITRATE,
99         g_param_spec_uint("bitrate", "Bitrate",
100             "Audio bitrate", 0, G_MAXINT32, 0,
101             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
102 
103     gst_element_class_set_static_metadata(gstelement_class,
104         "Audio capture source", "Source/Audio",
105         "Retrieve audio frame from audio buffer queue", "OpenHarmony");
106 
107     gst_element_class_add_static_pad_template(gstelement_class, &gst_audio_capture_src_template);
108 
109     gstelement_class->change_state = gst_audio_capture_src_change_state;
110     gstbasesrc_class->negotiate = gst_audio_capture_src_negotiate;
111     gstpushsrc_class->create = gst_audio_capture_src_create;
112 }
113 
gst_audio_capture_src_init(GstAudioCaptureSrc * src)114 static void gst_audio_capture_src_init(GstAudioCaptureSrc *src)
115 {
116     g_return_if_fail(src != nullptr);
117     gst_base_src_set_format(GST_BASE_SRC(src), GST_FORMAT_TIME);
118     gst_base_src_set_live(GST_BASE_SRC(src), TRUE);
119     src->stream_type = AUDIO_STREAM_TYPE_UNKNOWN;
120     src->source_type = AUDIO_SOURCE_TYPE_MIC;
121     src->audio_capture = nullptr;
122     src->src_caps = nullptr;
123     src->bitrate = 0;
124     src->channels = 0;
125     src->sample_rate = 0;
126     src->is_start = FALSE;
127     src->need_caps_info = TRUE;
128     gst_base_src_set_blocksize(GST_BASE_SRC(src), 0);
129 }
130 
gst_audio_capture_src_finalize(GObject * object)131 static void gst_audio_capture_src_finalize(GObject *object)
132 {
133     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(object);
134     g_return_if_fail(src != nullptr);
135     if (src->src_caps != nullptr) {
136         gst_caps_unref(src->src_caps);
137         src->src_caps = nullptr;
138     }
139 }
140 
gst_audio_capture_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)141 static void gst_audio_capture_src_set_property(GObject *object, guint prop_id,
142     const GValue *value, GParamSpec *pspec)
143 {
144     (void)pspec;
145     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(object);
146     g_return_if_fail(src != nullptr);
147     switch (prop_id) {
148         case PROP_SOURCE_TYPE:
149             src->source_type = (AudioSourceType)g_value_get_enum(value);
150             break;
151         case PROP_SAMPLE_RATE:
152             src->sample_rate = g_value_get_uint(value);
153             break;
154         case PROP_CHANNELS:
155             src->channels = g_value_get_uint(value);
156             break;
157         case PROP_BITRATE:
158             src->bitrate = g_value_get_uint(value);
159             break;
160         default:
161             break;
162     }
163 }
164 
gst_audio_capture_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)165 static void gst_audio_capture_src_get_property(GObject *object, guint prop_id,
166     GValue *value, GParamSpec *pspec)
167 {
168     (void)pspec;
169     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(object);
170     g_return_if_fail(src != nullptr);
171     switch (prop_id) {
172         case PROP_SOURCE_TYPE:
173             g_value_set_enum(value, src->source_type);
174             break;
175         case PROP_SAMPLE_RATE:
176             g_value_set_uint(value, src->sample_rate);
177             break;
178         case PROP_CHANNELS:
179             g_value_set_uint(value, src->channels);
180             break;
181         case PROP_BITRATE:
182             g_value_set_uint(value, src->bitrate);
183             break;
184         default:
185             break;
186     }
187 }
188 
process_caps_info(GstAudioCaptureSrc * src)189 static gboolean process_caps_info(GstAudioCaptureSrc *src)
190 {
191     guint bitrate = 0;
192     guint sample_rate = 0;
193     guint channels = 0;
194     g_return_val_if_fail(src != nullptr, FALSE);
195     g_return_val_if_fail(src->audio_capture->GetCaptureParameter(bitrate, channels, sample_rate) == MSERR_OK, FALSE);
196 
197     gboolean is_valid_params = TRUE;
198     guint64 channel_mask = 0;
199     switch (channels) {
200         case 1: {
201             GstAudioChannelPosition positions[1] = {GST_AUDIO_CHANNEL_POSITION_MONO};
202             if (!gst_audio_channel_positions_to_mask(positions, channels, FALSE, &channel_mask)) {
203                 GST_ERROR_OBJECT(src, "invalid channel positions");
204                 is_valid_params = FALSE;
205             }
206             break;
207         }
208         case 2: { // 2 channels
209             GstAudioChannelPosition positions[2] = {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
210                                                     GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT};
211             if (!gst_audio_channel_positions_to_mask(positions, channels, FALSE, &channel_mask)) {
212                 GST_ERROR_OBJECT(src, "invalid channel positions");
213                 is_valid_params = FALSE;
214             }
215             break;
216         }
217         default: {
218             is_valid_params = FALSE;
219             GST_ERROR_OBJECT(src, "invalid channels %u", channels);
220             break;
221         }
222     }
223     g_return_val_if_fail(is_valid_params == TRUE, FALSE);
224     if (src->src_caps != nullptr) {
225         gst_caps_unref(src->src_caps);
226     }
227     src->src_caps = gst_caps_new_simple("audio/x-raw",
228                                         "rate", G_TYPE_INT, sample_rate,
229                                         "channels", G_TYPE_INT, channels,
230                                         "format", G_TYPE_STRING, "S16LE",
231                                         "channel-mask", GST_TYPE_BITMASK, channel_mask,
232                                         "layout", G_TYPE_STRING, "interleaved", nullptr);
233     GstBaseSrc *basesrc = GST_BASE_SRC_CAST(src);
234     basesrc->segment.start = 0;
235     return TRUE;
236 }
237 
gst_state_change_forward_direction(GstAudioCaptureSrc * src,GstStateChange transition)238 static GstStateChangeReturn gst_state_change_forward_direction(GstAudioCaptureSrc *src, GstStateChange transition)
239 {
240     switch (transition) {
241         case GST_STATE_CHANGE_NULL_TO_READY: {
242             src->audio_capture = OHOS::Media::AudioCaptureFactory::CreateAudioCapture(src->stream_type);
243             g_return_val_if_fail(src->audio_capture != nullptr, GST_STATE_CHANGE_FAILURE);
244             break;
245         }
246         case GST_STATE_CHANGE_READY_TO_PAUSED: {
247             g_return_val_if_fail(src->audio_capture != nullptr, GST_STATE_CHANGE_FAILURE);
248             if (src->audio_capture->SetCaptureParameter(src->bitrate, src->channels, src->sample_rate) != MSERR_OK) {
249                 return GST_STATE_CHANGE_FAILURE;
250             }
251             break;
252         }
253         case GST_STATE_CHANGE_PAUSED_TO_PLAYING: {
254             g_return_val_if_fail(src->audio_capture != nullptr, GST_STATE_CHANGE_FAILURE);
255             if (src->need_caps_info) {
256                 g_return_val_if_fail(process_caps_info(src) == TRUE, GST_STATE_CHANGE_FAILURE);
257                 src->need_caps_info = FALSE;
258             }
259             if (src->is_start == FALSE) {
260                 g_return_val_if_fail(src->audio_capture->StartAudioCapture() == MSERR_OK, GST_STATE_CHANGE_FAILURE);
261                 src->is_start = TRUE;
262             } else {
263                 g_return_val_if_fail(src->audio_capture->ResumeAudioCapture() == MSERR_OK, GST_STATE_CHANGE_FAILURE);
264             }
265             break;
266         }
267         default:
268             break;
269     }
270     return GST_STATE_CHANGE_SUCCESS;
271 }
272 
gst_audio_capture_src_change_state(GstElement * element,GstStateChange transition)273 static GstStateChangeReturn gst_audio_capture_src_change_state(GstElement *element, GstStateChange transition)
274 {
275     g_return_val_if_fail(element != nullptr, GST_STATE_CHANGE_FAILURE);
276     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(element);
277 
278     GstStateChangeReturn ret = gst_state_change_forward_direction(src, transition);
279     g_return_val_if_fail(ret == GST_STATE_CHANGE_SUCCESS, GST_STATE_CHANGE_FAILURE);
280 
281     ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
282 
283     switch (transition) {
284         case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
285             g_return_val_if_fail(src->audio_capture != nullptr, GST_STATE_CHANGE_FAILURE);
286             g_return_val_if_fail(src->audio_capture->PauseAudioCapture() == MSERR_OK, GST_STATE_CHANGE_FAILURE);
287             break;
288         case GST_STATE_CHANGE_PAUSED_TO_READY:
289             src->is_start = FALSE;
290             g_return_val_if_fail(src->audio_capture != nullptr, GST_STATE_CHANGE_FAILURE);
291             g_return_val_if_fail(src->audio_capture->StopAudioCapture() == MSERR_OK, GST_STATE_CHANGE_FAILURE);
292             break;
293         case GST_STATE_CHANGE_READY_TO_NULL:
294             src->audio_capture = nullptr;
295             break;
296         default:
297             break;
298     }
299     return ret;
300 }
301 
gst_audio_capture_src_create(GstPushSrc * psrc,GstBuffer ** outbuf)302 static GstFlowReturn gst_audio_capture_src_create(GstPushSrc *psrc, GstBuffer **outbuf)
303 {
304     g_return_val_if_fail((psrc != nullptr) && (outbuf != nullptr), GST_FLOW_ERROR);
305     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(psrc);
306     g_return_val_if_fail(src != nullptr, GST_FLOW_ERROR);
307     if (src->is_start == FALSE) {
308         return GST_FLOW_EOS;
309     }
310     g_return_val_if_fail(src->audio_capture != nullptr, GST_FLOW_ERROR);
311 
312     std::shared_ptr<AudioBuffer> audio_buffer = src->audio_capture->GetBuffer();
313     g_return_val_if_fail(audio_buffer != nullptr, GST_FLOW_ERROR);
314     gst_base_src_set_blocksize(GST_BASE_SRC_CAST(src), audio_buffer->dataLen);
315 
316     *outbuf = audio_buffer->gstBuffer;
317     GST_BUFFER_DURATION(*outbuf) = audio_buffer->duration;
318     GST_BUFFER_TIMESTAMP(*outbuf) = audio_buffer->timestamp;
319     return GST_FLOW_OK;
320 }
321 
gst_audio_capture_src_negotiate(GstBaseSrc * basesrc)322 static gboolean gst_audio_capture_src_negotiate(GstBaseSrc *basesrc)
323 {
324     g_return_val_if_fail(basesrc != nullptr, false);
325     GstAudioCaptureSrc *src = GST_AUDIO_CAPTURE_SRC(basesrc);
326     g_return_val_if_fail(src != nullptr, FALSE);
327     (void)gst_base_src_wait_playing(basesrc);
328     g_return_val_if_fail(src->src_caps != nullptr, FALSE);
329     return gst_base_src_set_caps(basesrc, src->src_caps);
330 }
331 
plugin_init(GstPlugin * plugin)332 static gboolean plugin_init(GstPlugin *plugin)
333 {
334     g_return_val_if_fail(plugin != nullptr, false);
335     return gst_element_register(plugin, "audiocapturesrc", GST_RANK_PRIMARY, GST_TYPE_AUDIO_CAPTURE_SRC);
336 }
337 
338 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
339     GST_VERSION_MINOR,
340     _audio_capture_src,
341     "GStreamer Audio Capture Source",
342     plugin_init,
343     PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
344