• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2016 Iskratel d.o.o.
3  *   Author: Okrslar Ales <okrslar@iskratel.si>
4  * Copyright (C) 2016 Sebastian Dröge <sebastian@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "gsttonegeneratesrc.h"
27 
28 #undef IT_DBG
29 
30 GST_DEBUG_CATEGORY_STATIC (tone_generate_src_debug);
31 #define GST_CAT_DEFAULT tone_generate_src_debug
32 
33 #define DEFAULT_SAMPLES_PER_BUFFER   1024
34 #define DEFAULT_FREQ                 0
35 #define DEFAULT_VOLUME               0
36 #define DEFAULT_ON_TIME              1000
37 #define DEFAULT_OFF_TIME             1000
38 #define DEFAULT_REPEAT               FALSE
39 
40 enum
41 {
42   PROP_0,
43   PROP_SAMPLES_PER_BUFFER,
44   PROP_FREQ,
45   PROP_VOLUME,
46   PROP_FREQ2,
47   PROP_VOLUME2,
48   PROP_ON_TIME,
49   PROP_OFF_TIME,
50   PROP_ON_TIME2,
51   PROP_OFF_TIME2,
52   PROP_REPEAT,
53   PROP_LAST
54 };
55 
56 static GstStaticPadTemplate gst_tone_generate_src_src_template =
57 GST_STATIC_PAD_TEMPLATE ("src",
58     GST_PAD_SRC,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("audio/x-raw, "
61         "format = (string) " GST_AUDIO_NE (S16) ", "
62         "layout = (string) interleaved, " "rate = (int) 8000, " "channels = 1")
63     );
64 
65 #define gst_tone_generate_src_parent_class parent_class
66 G_DEFINE_TYPE (GstToneGenerateSrc, gst_tone_generate_src, GST_TYPE_PUSH_SRC);
67 
68 static void gst_tone_generate_src_finalize (GObject * object);
69 static void gst_tone_generate_src_set_property (GObject * object, guint prop_id,
70     const GValue * value, GParamSpec * pspec);
71 static void gst_tone_generate_src_get_property (GObject * object, guint prop_id,
72     GValue * value, GParamSpec * pspec);
73 static gboolean gst_tone_generate_src_start (GstBaseSrc * basesrc);
74 static gboolean gst_tone_generate_src_stop (GstBaseSrc * basesrc);
75 static GstFlowReturn gst_tone_generate_src_fill (GstPushSrc * basesrc,
76     GstBuffer * buffer);
77 
78 static void
gst_tone_generate_src_class_init(GstToneGenerateSrcClass * klass)79 gst_tone_generate_src_class_init (GstToneGenerateSrcClass * klass)
80 {
81   GObjectClass *gobject_class;
82   GstElementClass *gstelement_class;
83   GstBaseSrcClass *gstbasesrc_class;
84   GstPushSrcClass *gstpushsrc_class;
85 
86   gobject_class = (GObjectClass *) klass;
87   gstelement_class = (GstElementClass *) klass;
88   gstbasesrc_class = (GstBaseSrcClass *) klass;
89   gstpushsrc_class = (GstPushSrcClass *) klass;
90 
91   gobject_class->set_property = gst_tone_generate_src_set_property;
92   gobject_class->get_property = gst_tone_generate_src_get_property;
93   gobject_class->finalize = gst_tone_generate_src_finalize;
94 
95   g_object_class_install_property (gobject_class, PROP_SAMPLES_PER_BUFFER,
96       g_param_spec_int ("samplesperbuffer", "Samples per buffer",
97           "Number of samples in each outgoing buffer",
98           1, G_MAXINT, DEFAULT_SAMPLES_PER_BUFFER,
99           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
100 
101   g_object_class_install_property (gobject_class, PROP_FREQ,
102       g_param_spec_int ("freq", "Frequency", "Frequency of test signal",
103           0, 20000, DEFAULT_FREQ, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
104 
105   g_object_class_install_property (gobject_class, PROP_VOLUME,
106       g_param_spec_int ("volume", "Volume",
107           "Volume of first signal",
108           -50, 0, DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
109 
110   g_object_class_install_property (gobject_class, PROP_FREQ2,
111       g_param_spec_int ("freq2", "Second Frequency",
112           "Frequency of second telephony tone component",
113           0, 20000, DEFAULT_FREQ, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114 
115   g_object_class_install_property (gobject_class, PROP_VOLUME2,
116       g_param_spec_int ("volume2", "Volume2",
117           "Volume of second tone signal",
118           -50, 0, DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
119 
120   g_object_class_install_property (gobject_class, PROP_ON_TIME,
121       g_param_spec_int ("on-time", "Signal ON time first period",
122           "Time of the first period  when the tone signal is present", 1,
123           G_MAXINT, DEFAULT_ON_TIME, G_PARAM_READWRITE));
124 
125   g_object_class_install_property (gobject_class, PROP_OFF_TIME,
126       g_param_spec_int ("off-time", "Signal OFF time first period ",
127           "Time of the first period  when the tone signal is off", 0, G_MAXINT,
128           DEFAULT_OFF_TIME, G_PARAM_READWRITE));
129 
130   g_object_class_install_property (gobject_class, PROP_ON_TIME2,
131       g_param_spec_int ("on-time2", "Signal ON time second period",
132           "Time of the second period  when the tone signal is present", 1,
133           G_MAXINT, DEFAULT_ON_TIME, G_PARAM_READWRITE));
134 
135   g_object_class_install_property (gobject_class, PROP_OFF_TIME2,
136       g_param_spec_int ("off-time2", "Signal OFF time first period ",
137           "Time of the second period  when the tone signal is off", 0, G_MAXINT,
138           DEFAULT_ON_TIME, G_PARAM_READWRITE));
139 
140   g_object_class_install_property (gobject_class, PROP_REPEAT,
141       g_param_spec_boolean ("repeat", "Repeat the specified tone period ",
142           "Whether to repeat specified tone indefinitly", DEFAULT_REPEAT,
143           G_PARAM_READWRITE));
144 
145   gst_element_class_add_static_pad_template (gstelement_class,
146       &gst_tone_generate_src_src_template);
147 
148   gst_element_class_set_static_metadata (gstelement_class,
149       "Telephony Tone  Generator source", "Source/Audio",
150       "Creates telephony signals of given frequency, volume, cadence",
151       "Iskratel <www.iskratel.com>");
152 
153   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_tone_generate_src_start);
154   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_tone_generate_src_stop);
155   gstpushsrc_class->fill = GST_DEBUG_FUNCPTR (gst_tone_generate_src_fill);
156 }
157 
158 static void
gst_tone_generate_src_init(GstToneGenerateSrc * src)159 gst_tone_generate_src_init (GstToneGenerateSrc * src)
160 {
161   src->volume = DEFAULT_VOLUME;
162   src->freq = DEFAULT_FREQ;
163   src->on_time = DEFAULT_ON_TIME;
164   src->off_time = DEFAULT_OFF_TIME;
165   src->volume2 = DEFAULT_VOLUME;
166   src->freq2 = DEFAULT_FREQ;
167   src->on_time2 = DEFAULT_ON_TIME;
168   src->off_time2 = DEFAULT_OFF_TIME;
169   src->repeat = DEFAULT_REPEAT;
170 
171   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
172 
173   src->samples_per_buffer = DEFAULT_SAMPLES_PER_BUFFER;
174   gst_base_src_set_blocksize (GST_BASE_SRC (src), 2 * src->samples_per_buffer);
175 }
176 
177 static void
gst_tone_generate_src_finalize(GObject * object)178 gst_tone_generate_src_finalize (GObject * object)
179 {
180   GstToneGenerateSrc *src = GST_TONE_GENERATE_SRC (object);
181 
182   if (src->tone_desc) {
183     tone_gen_descriptor_free (src->tone_desc);
184     src->tone_desc = NULL;
185   }
186 
187   if (src->tone_state) {
188     tone_gen_free (src->tone_state);
189     src->tone_state = NULL;
190   }
191 
192   G_OBJECT_CLASS (parent_class)->finalize (object);
193 }
194 
195 static gboolean
gst_tone_generate_src_start(GstBaseSrc * basesrc)196 gst_tone_generate_src_start (GstBaseSrc * basesrc)
197 {
198   GstToneGenerateSrc *src = GST_TONE_GENERATE_SRC (basesrc);
199 
200   GST_OBJECT_LOCK (src);
201   src->properties_changed = FALSE;
202   GST_OBJECT_UNLOCK (src);
203 
204   src->next_sample = 0;
205   src->next_time = 0;
206 
207   return TRUE;
208 }
209 
210 static gboolean
gst_tone_generate_src_stop(GstBaseSrc * basesrc)211 gst_tone_generate_src_stop (GstBaseSrc * basesrc)
212 {
213   GstToneGenerateSrc *src = GST_TONE_GENERATE_SRC (basesrc);
214 
215   GST_OBJECT_LOCK (src);
216   if (src->tone_desc) {
217     tone_gen_descriptor_free (src->tone_desc);
218     src->tone_desc = NULL;
219   }
220 
221   if (src->tone_state) {
222     tone_gen_free (src->tone_state);
223     src->tone_state = NULL;
224   }
225   src->properties_changed = FALSE;
226   GST_OBJECT_UNLOCK (src);
227 
228   return TRUE;
229 }
230 
231 static GstFlowReturn
gst_tone_generate_src_fill(GstPushSrc * basesrc,GstBuffer * buffer)232 gst_tone_generate_src_fill (GstPushSrc * basesrc, GstBuffer * buffer)
233 {
234   GstToneGenerateSrc *src;
235   GstClockTime next_time;
236   gint64 next_sample;
237   gint bytes, samples;
238   GstMapInfo map;
239   const gint samplerate = 8000, bpf = 2;
240 
241   src = GST_TONE_GENERATE_SRC (basesrc);
242 
243   bytes = gst_buffer_get_size (buffer);
244   samples = bytes / bpf;
245 
246   /* calculate full buffer */
247   next_sample = src->next_sample + samples;
248 
249   next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, samplerate);
250 
251   GST_LOG_OBJECT (src, "samplerate %d", samplerate);
252   GST_LOG_OBJECT (src, "next_sample %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT,
253       next_sample, GST_TIME_ARGS (next_time));
254 
255   GST_BUFFER_OFFSET (buffer) = src->next_sample;
256   GST_BUFFER_OFFSET_END (buffer) = next_sample;
257   GST_BUFFER_TIMESTAMP (buffer) = src->next_time;
258   GST_BUFFER_DURATION (buffer) = next_time - src->next_time;
259 
260   gst_object_sync_values (GST_OBJECT (src), GST_BUFFER_TIMESTAMP (buffer));
261 
262   src->next_time = next_time;
263   src->next_sample = next_sample;
264 
265   GST_LOG_OBJECT (src, "generating %u samples at ts %" GST_TIME_FORMAT,
266       samples, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
267 
268   gst_buffer_map (buffer, &map, GST_MAP_WRITE);
269 
270   GST_OBJECT_LOCK (src);
271   if (!src->tone_state || src->properties_changed) {
272     src->tone_desc = tone_gen_descriptor_init (src->tone_desc,
273         src->freq,
274         src->volume,
275         src->freq2,
276         src->volume2,
277         src->on_time,
278         src->off_time, src->on_time2, src->off_time2, src->repeat);
279 
280     src->tone_state = tone_gen_init (src->tone_state, src->tone_desc);
281     src->properties_changed = FALSE;
282   }
283 
284   tone_gen (src->tone_state, (int16_t *) map.data, samples);
285   GST_OBJECT_UNLOCK (src);
286 
287   gst_buffer_unmap (buffer, &map);
288 
289   return GST_FLOW_OK;
290 }
291 
292 static void
gst_tone_generate_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)293 gst_tone_generate_src_set_property (GObject * object, guint prop_id,
294     const GValue * value, GParamSpec * pspec)
295 {
296   GstToneGenerateSrc *src = GST_TONE_GENERATE_SRC (object);
297 
298   switch (prop_id) {
299     case PROP_SAMPLES_PER_BUFFER:
300       src->samples_per_buffer = g_value_get_int (value);
301       gst_base_src_set_blocksize (GST_BASE_SRC_CAST (src),
302           2 * src->samples_per_buffer);
303       break;
304     case PROP_FREQ:
305       GST_OBJECT_LOCK (src);
306       src->freq = g_value_get_int (value);
307       src->properties_changed = TRUE;
308       GST_OBJECT_UNLOCK (src);
309       break;
310     case PROP_VOLUME:
311       GST_OBJECT_LOCK (src);
312       src->volume = g_value_get_int (value);
313       src->properties_changed = TRUE;
314       GST_OBJECT_UNLOCK (src);
315       break;
316     case PROP_FREQ2:
317       GST_OBJECT_LOCK (src);
318       src->freq2 = g_value_get_int (value);
319       src->properties_changed = TRUE;
320       GST_OBJECT_UNLOCK (src);
321       break;
322     case PROP_VOLUME2:
323       GST_OBJECT_LOCK (src);
324       src->volume2 = g_value_get_int (value);
325       src->properties_changed = TRUE;
326       GST_OBJECT_UNLOCK (src);
327       break;
328     case PROP_ON_TIME:
329       GST_OBJECT_LOCK (src);
330       src->on_time = g_value_get_int (value);
331       src->properties_changed = TRUE;
332       GST_OBJECT_UNLOCK (src);
333       break;
334     case PROP_ON_TIME2:
335       GST_OBJECT_LOCK (src);
336       src->on_time2 = g_value_get_int (value);
337       src->properties_changed = TRUE;
338       GST_OBJECT_UNLOCK (src);
339       break;
340     case PROP_OFF_TIME:
341       GST_OBJECT_LOCK (src);
342       src->off_time = g_value_get_int (value);
343       src->properties_changed = TRUE;
344       GST_OBJECT_UNLOCK (src);
345       break;
346     case PROP_OFF_TIME2:
347       GST_OBJECT_LOCK (src);
348       src->off_time2 = g_value_get_int (value);
349       src->properties_changed = TRUE;
350       GST_OBJECT_UNLOCK (src);
351       break;
352     case PROP_REPEAT:
353       GST_OBJECT_LOCK (src);
354       src->repeat = g_value_get_boolean (value);
355       src->properties_changed = TRUE;
356       GST_OBJECT_UNLOCK (src);
357       break;
358     default:
359       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
360       break;
361   }
362 }
363 
364 static void
gst_tone_generate_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)365 gst_tone_generate_src_get_property (GObject * object, guint prop_id,
366     GValue * value, GParamSpec * pspec)
367 {
368   GstToneGenerateSrc *src = GST_TONE_GENERATE_SRC (object);
369 
370   switch (prop_id) {
371     case PROP_SAMPLES_PER_BUFFER:
372       g_value_set_int (value, src->samples_per_buffer);
373       break;
374     case PROP_FREQ:
375       g_value_set_int (value, src->freq);
376       break;
377     case PROP_VOLUME:
378       g_value_set_int (value, src->volume);
379       break;
380     case PROP_FREQ2:
381       g_value_set_int (value, src->freq2);
382       break;
383     case PROP_VOLUME2:
384       g_value_set_int (value, src->volume2);
385       break;
386     case PROP_ON_TIME:
387       g_value_set_int (value, src->on_time);
388       break;
389     case PROP_OFF_TIME:
390       g_value_set_int (value, src->off_time);
391       break;
392     case PROP_ON_TIME2:
393       g_value_set_int (value, src->on_time2);
394       break;
395     case PROP_OFF_TIME2:
396       g_value_set_int (value, src->off_time2);
397       break;
398     case PROP_REPEAT:
399       g_value_set_boolean (value, src->repeat);
400       break;
401     default:
402       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
403       break;
404   }
405 }
406 
407 gboolean
gst_tone_generate_src_plugin_init(GstPlugin * plugin)408 gst_tone_generate_src_plugin_init (GstPlugin * plugin)
409 {
410   GST_DEBUG_CATEGORY_INIT (tone_generate_src_debug, "tonegeneratesrc", 0,
411       "Telephony Tone Test Source");
412 
413   return gst_element_register (plugin, "tonegeneratesrc",
414       GST_RANK_NONE, GST_TYPE_TONE_GENERATE_SRC);
415 }
416