1 /*
2 * GStreamer
3 * Copyright (C) 2017 Collabora Inc.
4 * Copyright (C) 2021 Igalia S.L.
5 * Author: Philippe Normand <philn@igalia.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 /**
24 * SECTION:element-fakeaudiosink
25 * @title: fakeaudiosink
26 *
27 * This element is the same as fakesink but will pretend to act as an audio sink
28 * supporting the `GstStreamVolume` interface. This is useful for throughput
29 * testing while creating a new pipeline or for CI purposes on machines not
30 * running a real audio daemon.
31 *
32 * ## Example launch lines
33 * |[
34 * gst-launch-1.0 audiotestsrc ! fakeaudiosink
35 * ]|
36 *
37 * Since: 1.20
38 */
39
40 #include "gstdebugutilsbadelements.h"
41 #include "gstfakeaudiosink.h"
42 #include "gstfakesinkutils.h"
43
44 #include <gst/audio/audio.h>
45
46 enum
47 {
48 PROP_0,
49 PROP_VOLUME,
50 PROP_MUTE,
51 PROP_LAST
52 };
53
54
55 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
56 GST_PAD_SINK,
57 GST_PAD_ALWAYS,
58 GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL)));
59
60 G_DEFINE_TYPE_WITH_CODE (GstFakeAudioSink, gst_fake_audio_sink, GST_TYPE_BIN,
61 G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL););
62 GST_ELEMENT_REGISTER_DEFINE (fakeaudiosink, "fakeaudiosink",
63 GST_RANK_NONE, gst_fake_audio_sink_get_type ());
64
65 static void
gst_fake_audio_sink_proxy_properties(GstFakeAudioSink * self,GstElement * child)66 gst_fake_audio_sink_proxy_properties (GstFakeAudioSink * self,
67 GstElement * child)
68 {
69 static gsize initialized = 0;
70
71 if (g_once_init_enter (&initialized)) {
72 gst_fake_sink_proxy_properties (GST_ELEMENT_CAST (self), child, PROP_LAST);
73 g_once_init_leave (&initialized, 1);
74 }
75 }
76
77 static void
gst_fake_audio_sink_init(GstFakeAudioSink * self)78 gst_fake_audio_sink_init (GstFakeAudioSink * self)
79 {
80 GstElement *child;
81 GstPadTemplate *template = gst_static_pad_template_get (&sink_factory);
82
83 self->volume = 1.0;
84 self->mute = FALSE;
85
86 child = gst_element_factory_make ("fakesink", "sink");
87
88 if (child) {
89 GstPad *sink_pad = gst_element_get_static_pad (child, "sink");
90 GstPad *ghost_pad;
91
92 /* mimic GstAudioSink base class */
93 g_object_set (child, "qos", TRUE, "sync", TRUE, NULL);
94
95 gst_bin_add (GST_BIN_CAST (self), child);
96
97 ghost_pad = gst_ghost_pad_new_from_template ("sink", sink_pad, template);
98 gst_object_unref (template);
99 gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);
100 gst_object_unref (sink_pad);
101
102 self->child = child;
103
104 gst_fake_audio_sink_proxy_properties (self, child);
105 } else {
106 g_warning ("Check your GStreamer installation, "
107 "core element 'fakesink' is missing.");
108 }
109 }
110
111 static void
gst_fake_audio_sink_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)112 gst_fake_audio_sink_get_property (GObject * object, guint property_id,
113 GValue * value, GParamSpec * pspec)
114 {
115 GstFakeAudioSink *self = GST_FAKE_AUDIO_SINK (object);
116
117 switch (property_id) {
118 case PROP_VOLUME:
119 g_value_set_double (value, self->volume);
120 break;
121 case PROP_MUTE:
122 g_value_set_boolean (value, self->mute);
123 break;
124 default:
125 g_object_get_property (G_OBJECT (self->child), pspec->name, value);
126 break;
127 }
128 }
129
130 static void
gst_fake_audio_sink_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)131 gst_fake_audio_sink_set_property (GObject * object, guint property_id,
132 const GValue * value, GParamSpec * pspec)
133 {
134 GstFakeAudioSink *self = GST_FAKE_AUDIO_SINK (object);
135
136 switch (property_id) {
137 case PROP_VOLUME:
138 self->volume = g_value_get_double (value);
139 break;
140 case PROP_MUTE:
141 self->mute = g_value_get_boolean (value);
142 break;
143 default:
144 g_object_set_property (G_OBJECT (self->child), pspec->name, value);
145 break;
146 }
147 }
148
149 static void
gst_fake_audio_sink_class_init(GstFakeAudioSinkClass * klass)150 gst_fake_audio_sink_class_init (GstFakeAudioSinkClass * klass)
151 {
152 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
153 GObjectClass *object_class = G_OBJECT_CLASS (klass);
154
155 object_class->get_property = gst_fake_audio_sink_get_property;
156 object_class->set_property = gst_fake_audio_sink_set_property;
157
158
159 /**
160 * GstFakeAudioSink:volume
161 *
162 * Control the audio volume
163 *
164 * Since: 1.20
165 */
166 g_object_class_install_property (object_class, PROP_VOLUME,
167 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
168 0, 10, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
169
170 /**
171 * GstFakeAudioSink:mute
172 *
173 * Control the mute state
174 *
175 * Since: 1.20
176 */
177 g_object_class_install_property (object_class, PROP_MUTE,
178 g_param_spec_boolean ("mute", "Mute",
179 "Mute the audio channel without changing the volume", FALSE,
180 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
181
182
183 gst_element_class_add_static_pad_template (element_class, &sink_factory);
184 gst_element_class_set_static_metadata (element_class, "Fake Audio Sink",
185 "Audio/Sink", "Fake audio renderer",
186 "Philippe Normand <philn@igalia.com>");
187 }
188