• 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_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