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_server_sink.h"
18 #include <cinttypes>
19 #include <gst/gst.h>
20 #include "gst/audio/audio.h"
21 #include "media_errors.h"
22 #include "media_log.h"
23 #include "audio_sink_factory.h"
24
25 static GstStaticPadTemplate g_sinktemplate = GST_STATIC_PAD_TEMPLATE("sink",
26 GST_PAD_SINK,
27 GST_PAD_ALWAYS,
28 GST_STATIC_CAPS("audio/x-raw, "
29 "format = (string) S16LE, "
30 "layout = (string) interleaved, "
31 "rate = (int) [ 1, MAX ], "
32 "channels = (int) [ 1, MAX ]"));
33
34 using namespace OHOS::Media;
35 namespace {
36 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "audio_server_sink"};
37 constexpr float DEFAULT_VOLUME = 1.0f;
38 constexpr uint32_t DEFAULT_BITS_PER_SAMPLE = 16;
39 }
40
41 enum {
42 PROP_0,
43 PROP_BITS_PER_SAMPLE,
44 PROP_CHANNELS,
45 PROP_SAMPLE_RATE,
46 PROP_VOLUME,
47 PROP_MAX_VOLUME,
48 PROP_MIN_VOLUME,
49 PROP_AUDIO_RENDERER_DESC
50 };
51
52 #define gst_audio_server_sink_parent_class parent_class
53 G_DEFINE_TYPE(GstAudioServerSink, gst_audio_server_sink, GST_TYPE_BASE_SINK);
54
55 static void gst_audio_server_sink_finalize(GObject *object);
56 static void gst_audio_server_sink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
57 static void gst_audio_server_sink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
58 static GstStateChangeReturn gst_audio_server_sink_change_state(GstElement *element, GstStateChange transition);
59 static GstCaps *gst_audio_server_sink_get_caps(GstBaseSink *basesink, GstCaps *caps);
60 static gboolean gst_audio_server_sink_set_caps(GstBaseSink *basesink, GstCaps *caps);
61 static gboolean gst_audio_server_sink_event(GstBaseSink *basesink, GstEvent *event);
62 static gboolean gst_audio_server_sink_start(GstBaseSink *basesink);
63 static gboolean gst_audio_server_sink_stop(GstBaseSink *basesink);
64 static GstFlowReturn gst_audio_server_sink_render(GstBaseSink *basesink, GstBuffer *buffer);
65 static void gst_audio_server_sink_clear_cache_buffer(GstAudioServerSink *sink);
66
gst_audio_server_sink_class_init(GstAudioServerSinkClass * klass)67 static void gst_audio_server_sink_class_init(GstAudioServerSinkClass *klass)
68 {
69 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
70 GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass);
71 GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS(klass);
72 g_return_if_fail((gobject_class != nullptr) && (gstelement_class != nullptr) && (gstbasesink_class != nullptr));
73
74 gobject_class->finalize = gst_audio_server_sink_finalize;
75 gobject_class->set_property = gst_audio_server_sink_set_property;
76 gobject_class->get_property = gst_audio_server_sink_get_property;
77
78 g_object_class_install_property(gobject_class, PROP_BITS_PER_SAMPLE,
79 g_param_spec_uint("bps", "Bits Per Sample",
80 "Audio Format", 0, G_MAXINT32, 0,
81 (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
82
83 g_object_class_install_property(gobject_class, PROP_CHANNELS,
84 g_param_spec_uint("channels", "Channels",
85 "Channels", 0, G_MAXINT32, 0,
86 (GParamFlags)(G_PARAM_READABLE | 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 "Sample Rate", 0, G_MAXINT32, 0,
91 (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
92
93 g_object_class_install_property(gobject_class, PROP_VOLUME,
94 g_param_spec_float("volume", "Volume",
95 "Volume", 0, G_MAXFLOAT, 0,
96 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
97
98 g_object_class_install_property(gobject_class, PROP_MAX_VOLUME,
99 g_param_spec_float("max-volume", "Maximum Volume",
100 "Maximum Volume", 0, G_MAXFLOAT, G_MAXFLOAT,
101 (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
102
103 g_object_class_install_property(gobject_class, PROP_MIN_VOLUME,
104 g_param_spec_float("min-volume", "Minimum Volume",
105 "Minimum Volume", 0, G_MAXFLOAT, 0,
106 (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
107
108 g_object_class_install_property(gobject_class, PROP_AUDIO_RENDERER_DESC,
109 g_param_spec_int("audio-renderer-desc", "Audio Renderer Desc",
110 "Audio Renderer Desc", 0, G_MAXINT32, 0,
111 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
112
113 gst_element_class_set_static_metadata(gstelement_class,
114 "Audio server sink", "Sink/Audio",
115 "Push pcm data to Audio server", "OpenHarmony");
116
117 gst_element_class_add_static_pad_template(gstelement_class, &g_sinktemplate);
118
119 gstelement_class->change_state = gst_audio_server_sink_change_state;
120
121 gstbasesink_class->get_caps = gst_audio_server_sink_get_caps;
122 gstbasesink_class->set_caps = gst_audio_server_sink_set_caps;
123 gstbasesink_class->event = gst_audio_server_sink_event;
124 gstbasesink_class->start = gst_audio_server_sink_start;
125 gstbasesink_class->stop = gst_audio_server_sink_stop;
126 gstbasesink_class->render = gst_audio_server_sink_render;
127 }
128
gst_audio_server_sink_init(GstAudioServerSink * sink)129 static void gst_audio_server_sink_init(GstAudioServerSink *sink)
130 {
131 g_return_if_fail(sink != nullptr);
132 sink->audio_sink = nullptr;
133 sink->bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
134 sink->channels = 0;
135 sink->sample_rate = 0;
136 sink->volume = DEFAULT_VOLUME;
137 sink->max_volume = G_MAXFLOAT;
138 sink->min_volume = 0;
139 sink->min_buffer_size = 0;
140 sink->min_frame_count = 0;
141 sink->cache_buffer = nullptr;
142 sink->pause_cache_buffer = nullptr;
143 sink->cache_size = 0;
144 sink->enable_cache = FALSE;
145 sink->frame_after_segment = FALSE;
146 g_mutex_init(&sink->render_lock);
147 }
148
gst_audio_server_sink_finalize(GObject * object)149 static void gst_audio_server_sink_finalize(GObject *object)
150 {
151 g_return_if_fail(object != nullptr);
152 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(object);
153 g_return_if_fail(sink != nullptr);
154 GST_INFO_OBJECT(sink, "gst_audio_server_sink_finalize in");
155
156 g_mutex_clear(&sink->render_lock);
157 if (sink->audio_sink != nullptr) {
158 (void)sink->audio_sink->Release();
159 sink->audio_sink = nullptr;
160 }
161 gst_audio_server_sink_clear_cache_buffer(sink);
162 }
163
gst_audio_server_sink_set_volume(GstAudioServerSink * sink,gfloat volume)164 static gboolean gst_audio_server_sink_set_volume(GstAudioServerSink *sink, gfloat volume)
165 {
166 gboolean ret = FALSE;
167 g_return_val_if_fail(sink != nullptr, FALSE);
168 g_return_val_if_fail(sink->audio_sink != nullptr, FALSE);
169 g_return_val_if_fail(volume <= sink->max_volume, FALSE);
170 g_return_val_if_fail(volume >= sink->min_volume, FALSE);
171
172 if (sink->audio_sink->SetVolume(volume) == MSERR_OK) {
173 sink->volume = volume;
174 ret = TRUE;
175 }
176
177 GST_INFO_OBJECT(sink, "set volume(%f) finish, ret=%d", volume, ret);
178 return ret;
179 }
180
gst_audio_server_sink_set_audio_renderer_desc(GstAudioServerSink * sink,gint param)181 static gboolean gst_audio_server_sink_set_audio_renderer_desc(GstAudioServerSink *sink, gint param)
182 {
183 gboolean ret = FALSE;
184 g_return_val_if_fail(sink != nullptr, FALSE);
185 g_return_val_if_fail(sink->audio_sink != nullptr, FALSE);
186
187 if (sink->audio_sink->SetParameter(param) == MSERR_OK) {
188 ret = TRUE;
189 }
190
191 GST_INFO_OBJECT(sink, "set renderer descriptor finish, ret=%d", ret);
192 return ret;
193 }
194
gst_audio_server_sink_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)195 static void gst_audio_server_sink_set_property(GObject *object, guint prop_id,
196 const GValue *value, GParamSpec *pspec)
197 {
198 g_return_if_fail(object != nullptr);
199 g_return_if_fail(value != nullptr);
200 (void)pspec;
201 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(object);
202 g_return_if_fail(sink != nullptr);
203 switch (prop_id) {
204 case PROP_VOLUME:
205 if (gst_audio_server_sink_set_volume(sink, g_value_get_float(value))) {
206 GST_INFO_OBJECT(sink, "set volume success!");
207 g_object_notify(G_OBJECT(sink), "volume");
208 }
209 break;
210 case PROP_AUDIO_RENDERER_DESC:
211 if (gst_audio_server_sink_set_audio_renderer_desc(sink, g_value_get_int(value))) {
212 GST_INFO_OBJECT(sink, "set renderer descriptor success!");
213 g_object_notify(G_OBJECT(sink), "audio-renderer-desc");
214 }
215 break;
216 default:
217 break;
218 }
219 }
220
gst_audio_server_sink_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)221 static void gst_audio_server_sink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
222 {
223 g_return_if_fail(object != nullptr);
224 g_return_if_fail(value != nullptr);
225 (void)pspec;
226 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(object);
227 g_return_if_fail(sink != nullptr);
228 switch (prop_id) {
229 case PROP_BITS_PER_SAMPLE:
230 g_value_set_uint(value, sink->bits_per_sample);
231 break;
232 case PROP_CHANNELS:
233 g_value_set_uint(value, sink->channels);
234 break;
235 case PROP_SAMPLE_RATE:
236 g_value_set_uint(value, sink->sample_rate);
237 break;
238 case PROP_VOLUME:
239 if (sink->audio_sink != nullptr) {
240 (void)sink->audio_sink->GetVolume(sink->volume);
241 }
242 g_value_set_float(value, sink->volume);
243 break;
244 case PROP_MAX_VOLUME:
245 g_value_set_float(value, sink->max_volume);
246 break;
247 case PROP_MIN_VOLUME:
248 g_value_set_float(value, sink->min_volume);
249 break;
250 default:
251 break;
252 }
253 }
254
gst_audio_server_sink_get_caps(GstBaseSink * basesink,GstCaps * caps)255 static GstCaps *gst_audio_server_sink_get_caps(GstBaseSink *basesink, GstCaps *caps)
256 {
257 (void)caps;
258 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(basesink);
259 g_return_val_if_fail(sink != nullptr, FALSE);
260 g_return_val_if_fail(sink->audio_sink != nullptr, FALSE);
261 return sink->audio_sink->GetCaps();
262 }
263
gst_audio_server_sink_set_caps(GstBaseSink * basesink,GstCaps * caps)264 static gboolean gst_audio_server_sink_set_caps(GstBaseSink *basesink, GstCaps *caps)
265 {
266 g_return_val_if_fail(basesink != nullptr, FALSE);
267 g_return_val_if_fail(caps != nullptr, FALSE);
268 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(basesink);
269 g_return_val_if_fail(sink != nullptr, FALSE);
270 g_return_val_if_fail(sink->audio_sink != nullptr, FALSE);
271
272 gchar *caps_str = gst_caps_to_string(caps);
273 GST_INFO_OBJECT(basesink, "caps=%s", caps_str);
274 GstStructure *structure = gst_caps_get_structure(caps, 0);
275 g_return_val_if_fail(structure != nullptr, FALSE);
276 gint channels = 0;
277 gint rate = 0;
278 if (!gst_structure_get_int(structure, "rate", &rate) || !gst_structure_get_int(structure, "channels", &channels)) {
279 GST_ERROR_OBJECT(basesink, "Incomplete caps");
280 return FALSE;
281 }
282 g_return_val_if_fail(channels > 0 && rate > 0, FALSE);
283 sink->sample_rate = static_cast<uint32_t>(rate);
284 sink->channels = static_cast<uint32_t>(channels);
285 g_return_val_if_fail(sink->audio_sink->SetParameters(sink->bits_per_sample, sink->channels,
286 sink->sample_rate) == MSERR_OK, FALSE);
287 g_return_val_if_fail(sink->audio_sink->SetVolume(sink->volume) == MSERR_OK, FALSE);
288 g_return_val_if_fail(sink->audio_sink->GetParameters(sink->bits_per_sample,
289 sink->channels, sink->sample_rate) == MSERR_OK, FALSE);
290 g_return_val_if_fail(sink->audio_sink->GetMinimumBufferSize(sink->min_buffer_size) == MSERR_OK, FALSE);
291 g_return_val_if_fail(sink->audio_sink->GetMinimumFrameCount(sink->min_frame_count) == MSERR_OK, FALSE);
292
293 return TRUE;
294 }
295
gst_audio_server_sink_event(GstBaseSink * basesink,GstEvent * event)296 static gboolean gst_audio_server_sink_event(GstBaseSink *basesink, GstEvent *event)
297 {
298 g_return_val_if_fail(basesink != nullptr, FALSE);
299 g_return_val_if_fail(event != nullptr, FALSE);
300 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(basesink);
301 g_return_val_if_fail(sink != nullptr, FALSE);
302 GstEventType type = GST_EVENT_TYPE(event);
303 switch (type) {
304 case GST_EVENT_EOS:
305 if (sink->audio_sink == nullptr) {
306 break;
307 }
308 if (sink->audio_sink->Drain() != MSERR_OK) {
309 GST_ERROR_OBJECT(basesink, "fail to call Drain when handling EOS event");
310 }
311 break;
312 case GST_EVENT_SEGMENT:
313 g_mutex_lock(&sink->render_lock);
314 sink->frame_after_segment = TRUE;
315 g_mutex_unlock(&sink->render_lock);
316 break;
317 case GST_EVENT_FLUSH_START:
318 gst_audio_server_sink_clear_cache_buffer(sink);
319 if (sink->audio_sink == nullptr) {
320 break;
321 }
322 if (sink->audio_sink->Flush() != MSERR_OK) {
323 GST_ERROR_OBJECT(basesink, "fail to call Flush when handling SEEK event");
324 }
325 GST_DEBUG_OBJECT(basesink, "received FLUSH_START");
326 break;
327 case GST_EVENT_FLUSH_STOP:
328 GST_DEBUG_OBJECT(basesink, "received FLUSH_STOP");
329 break;
330 default:
331 break;
332 }
333 return GST_BASE_SINK_CLASS(parent_class)->event(basesink, event);
334 }
335
gst_audio_server_sink_start(GstBaseSink * basesink)336 static gboolean gst_audio_server_sink_start(GstBaseSink *basesink)
337 {
338 g_return_val_if_fail(basesink != nullptr, FALSE);
339 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(basesink);
340 g_return_val_if_fail(sink != nullptr, FALSE);
341 sink->audio_sink = OHOS::Media::AudioSinkFactory::CreateAudioSink();
342 g_return_val_if_fail(sink->audio_sink != nullptr, FALSE);
343 g_return_val_if_fail(sink->audio_sink->Prepare() == MSERR_OK, FALSE);
344 g_return_val_if_fail(sink->audio_sink->GetMaxVolume(sink->max_volume) == MSERR_OK, FALSE);
345 g_return_val_if_fail(sink->audio_sink->GetMinVolume(sink->min_volume) == MSERR_OK, FALSE);
346
347 return TRUE;
348 }
349
gst_audio_server_sink_clear_cache_buffer(GstAudioServerSink * sink)350 static void gst_audio_server_sink_clear_cache_buffer(GstAudioServerSink *sink)
351 {
352 std::unique_lock<std::mutex> lock(sink->mutex_);
353 if (sink->pause_cache_buffer != nullptr) {
354 gst_buffer_unref(sink->pause_cache_buffer);
355 sink->pause_cache_buffer = nullptr;
356 }
357 }
358
gst_audio_server_sink_stop(GstBaseSink * basesink)359 static gboolean gst_audio_server_sink_stop(GstBaseSink *basesink)
360 {
361 g_return_val_if_fail(basesink != nullptr, FALSE);
362 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(basesink);
363 g_return_val_if_fail(sink != nullptr, FALSE);
364 g_return_val_if_fail(sink->audio_sink != nullptr, FALSE);
365 g_return_val_if_fail(sink->audio_sink->Stop() == MSERR_OK, FALSE);
366 g_return_val_if_fail(sink->audio_sink->Release() == MSERR_OK, FALSE);
367 sink->audio_sink = nullptr;
368
369 return TRUE;
370 }
371
gst_audio_server_sink_cache_render(GstAudioServerSink * sink,GstBuffer * buffer)372 static GstFlowReturn gst_audio_server_sink_cache_render(GstAudioServerSink *sink, GstBuffer *buffer)
373 {
374 GstMapInfo map;
375 if (gst_buffer_map(buffer, &map, GST_MAP_READ) != TRUE) {
376 return GST_FLOW_ERROR;
377 }
378 gsize size = map.size;
379
380 if (sink->cache_size == 0 && size >= sink->min_buffer_size) {
381 if (sink->audio_sink->Write(map.data, size) != MSERR_OK) {
382 gst_buffer_unmap(buffer, &map);
383 return GST_FLOW_ERROR;
384 }
385 gst_buffer_unmap(buffer, &map);
386 return GST_FLOW_OK;
387 }
388 gst_buffer_unmap(buffer, &map);
389
390 if (sink->cache_size == 0 && size < sink->min_buffer_size) {
391 sink->cache_size += static_cast<guint>(size);
392 sink->cache_buffer = gst_buffer_copy(buffer);
393 if (sink->cache_buffer == nullptr) {
394 return GST_FLOW_ERROR;
395 }
396 return GST_FLOW_OK;
397 }
398
399 sink->cache_size += static_cast<guint>(size);
400 GstBuffer *buf = gst_buffer_copy(sink->cache_buffer);
401 if (buf == nullptr) {
402 gst_buffer_unref(sink->cache_buffer);
403 return GST_FLOW_ERROR;
404 }
405 (void)gst_buffer_ref(buffer);
406 buf = gst_buffer_append(buf, buffer);
407 gst_buffer_unref(sink->cache_buffer);
408 sink->cache_buffer = buf;
409
410 if (sink->cache_size >= sink->min_buffer_size) {
411 if (gst_buffer_map(sink->cache_buffer, &map, GST_MAP_READ) != TRUE) {
412 gst_buffer_unref(sink->cache_buffer);
413 return GST_FLOW_ERROR;
414 }
415 int32_t ret = sink->audio_sink->Write(map.data, sink->cache_size);
416 gst_buffer_unmap(sink->cache_buffer, &map);
417 gst_buffer_unref(sink->cache_buffer);
418 sink->cache_size = 0;
419 sink->cache_buffer = nullptr;
420 if (ret != MSERR_OK) {
421 return GST_FLOW_ERROR;
422 }
423 return GST_FLOW_OK;
424 }
425 return GST_FLOW_OK;
426 }
427
gst_audio_server_sink_change_state(GstElement * element,GstStateChange transition)428 static GstStateChangeReturn gst_audio_server_sink_change_state(GstElement *element, GstStateChange transition)
429 {
430 g_return_val_if_fail(element != nullptr, GST_STATE_CHANGE_FAILURE);
431 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(element);
432 g_return_val_if_fail(sink != nullptr, GST_STATE_CHANGE_FAILURE);
433 GstBaseSink *basesink = GST_BASE_SINK(element);
434 g_return_val_if_fail(basesink != nullptr, GST_STATE_CHANGE_FAILURE);
435
436 switch (transition) {
437 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
438 MEDIA_LOGD("GST_STATE_CHANGE_PAUSED_TO_PLAYING");
439 g_return_val_if_fail(sink->audio_sink != nullptr, GST_STATE_CHANGE_FAILURE);
440 g_return_val_if_fail(sink->audio_sink->Start() == MSERR_OK, GST_STATE_CHANGE_FAILURE);
441 if (sink->pause_cache_buffer != nullptr) {
442 GST_INFO_OBJECT(basesink, "pause to play");
443 g_return_val_if_fail(gst_audio_server_sink_render(basesink,
444 sink->pause_cache_buffer) == GST_FLOW_OK, GST_STATE_CHANGE_FAILURE);
445 gst_buffer_unref(sink->pause_cache_buffer);
446 sink->pause_cache_buffer = nullptr;
447 }
448 break;
449 default:
450 break;
451 }
452 GstStateChangeReturn ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
453
454 switch (transition) {
455 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
456 MEDIA_LOGD("GST_STATE_CHANGE_PLAYING_TO_PAUSED");
457 {
458 std::unique_lock<std::mutex> lock(sink->mutex_);
459 g_return_val_if_fail(sink->audio_sink != nullptr, GST_STATE_CHANGE_FAILURE);
460 g_return_val_if_fail(sink->audio_sink->Pause() == MSERR_OK, GST_STATE_CHANGE_FAILURE);
461 }
462 break;
463 case GST_STATE_CHANGE_PAUSED_TO_READY:
464 MEDIA_LOGD("GST_STATE_CHANGE_PAUSED_TO_READY");
465 gst_audio_server_sink_clear_cache_buffer(sink);
466 break;
467 default:
468 break;
469 }
470
471 return ret;
472 }
473
gst_audio_server_sink_render(GstBaseSink * basesink,GstBuffer * buffer)474 static GstFlowReturn gst_audio_server_sink_render(GstBaseSink *basesink, GstBuffer *buffer)
475 {
476 g_return_val_if_fail(basesink != nullptr, GST_FLOW_ERROR);
477 g_return_val_if_fail(buffer != nullptr, GST_FLOW_ERROR);
478 g_return_val_if_fail(gst_buffer_get_size(buffer) != 0, GST_FLOW_OK);
479 GstAudioServerSink *sink = GST_AUDIO_SERVER_SINK(basesink);
480 g_return_val_if_fail(sink != nullptr, GST_FLOW_ERROR);
481 g_return_val_if_fail(sink->audio_sink != nullptr, GST_FLOW_ERROR);
482
483 if (sink->enable_cache) {
484 return gst_audio_server_sink_cache_render(sink, buffer);
485 }
486
487 {
488 std::unique_lock<std::mutex> lock(sink->mutex_);
489 if (!sink->audio_sink->Writeable()) {
490 if (sink->pause_cache_buffer == nullptr) {
491 sink->pause_cache_buffer = gst_buffer_ref(buffer);
492 g_return_val_if_fail(sink->pause_cache_buffer != nullptr, GST_FLOW_ERROR);
493 GST_INFO_OBJECT(basesink, "cache buffer for pause state");
494 return GST_FLOW_OK;
495 } else {
496 GST_ERROR_OBJECT(basesink, "cache buffer is not null");
497 }
498 }
499
500 GstMapInfo map;
501 if (gst_buffer_map(buffer, &map, GST_MAP_READ) != TRUE) {
502 GST_ERROR_OBJECT(basesink, "unknown error happened during gst_buffer_map");
503 return GST_FLOW_ERROR;
504 }
505 if (sink->audio_sink->Write(map.data, map.size) != MSERR_OK) {
506 GST_ERROR_OBJECT(basesink, "unknown error happened during Write");
507 gst_buffer_unmap(buffer, &map);
508 return GST_FLOW_ERROR;
509 }
510 gst_buffer_unmap(buffer, &map);
511 }
512
513 g_mutex_lock(&sink->render_lock);
514 if (sink->frame_after_segment) {
515 sink->frame_after_segment = FALSE;
516 uint64_t latency = 0;
517 GST_INFO_OBJECT(basesink, "the first audio frame after segment has been sent to audio server");
518 if (sink->audio_sink->GetLatency(latency) != MSERR_OK) {
519 GST_INFO_OBJECT(basesink, "fail to get latency");
520 } else {
521 GST_INFO_OBJECT(basesink, "frame render latency is (%" PRIu64 ")", latency);
522 }
523 }
524 g_mutex_unlock(&sink->render_lock);
525
526 return GST_FLOW_OK;
527 }
528
plugin_init(GstPlugin * plugin)529 static gboolean plugin_init(GstPlugin *plugin)
530 {
531 g_return_val_if_fail(plugin != nullptr, FALSE);
532 gboolean ret = gst_element_register(plugin, "audioserversink", GST_RANK_PRIMARY, GST_TYPE_AUDIO_SERVER_SINK);
533 return ret;
534 }
535
536 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
537 GST_VERSION_MINOR,
538 _audio_server_sink,
539 "GStreamer Audio Server Sink",
540 plugin_init,
541 PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
542