Remove trivial unused variables detected by CLang static analyzer.
[platform/upstream/gstreamer.git] / ext / speex / gstspeexenc.c
1 /* GStreamer Speex Encoder
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-speexenc
22  * @see_also: speexdec, oggmux
23  *
24  * This element encodes audio as a Speex stream.
25  * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
26  * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
27  * Foundation</ulink>.
28  *
29  * <refsect2>
30  * <title>Example pipelines</title>
31  * |[
32  * gst-launch audiotestsrc num-buffers=100 ! speexenc ! oggmux ! filesink location=beep.ogg
33  * ]| Encode an Ogg/Speex file.
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <math.h>
44 #include <speex/speex.h>
45 #include <speex/speex_stereo.h>
46
47 #include <gst/gsttagsetter.h>
48 #include <gst/tag/tag.h>
49 #include <gst/audio/audio.h>
50 #include "gstspeexenc.h"
51
52 GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
53 #define GST_CAT_DEFAULT speexenc_debug
54
55 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
56     GST_PAD_SINK,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS ("audio/x-raw-int, "
59         "rate = (int) [ 6000, 48000 ], "
60         "channels = (int) [ 1, 2 ], "
61         "endianness = (int) BYTE_ORDER, "
62         "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16")
63     );
64
65 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
66     GST_PAD_SRC,
67     GST_PAD_ALWAYS,
68     GST_STATIC_CAPS ("audio/x-speex, "
69         "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
70     );
71
72 static const GstElementDetails speexenc_details =
73 GST_ELEMENT_DETAILS ("Speex audio encoder",
74     "Codec/Encoder/Audio",
75     "Encodes audio in Speex format",
76     "Wim Taymans <wim@fluendo.com>");
77
78 #define DEFAULT_QUALITY         8.0
79 #define DEFAULT_BITRATE         0
80 #define DEFAULT_MODE            GST_SPEEX_ENC_MODE_AUTO
81 #define DEFAULT_VBR             FALSE
82 #define DEFAULT_ABR             0
83 #define DEFAULT_VAD             FALSE
84 #define DEFAULT_DTX             FALSE
85 #define DEFAULT_COMPLEXITY      3
86 #define DEFAULT_NFRAMES         1
87
88 enum
89 {
90   PROP_0,
91   PROP_QUALITY,
92   PROP_BITRATE,
93   PROP_MODE,
94   PROP_VBR,
95   PROP_ABR,
96   PROP_VAD,
97   PROP_DTX,
98   PROP_COMPLEXITY,
99   PROP_NFRAMES,
100   PROP_LAST_MESSAGE
101 };
102
103 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
104 static GType
105 gst_speex_enc_mode_get_type (void)
106 {
107   static GType speex_enc_mode_type = 0;
108   static const GEnumValue speex_enc_modes[] = {
109     {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
110     {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
111     {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
112     {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
113     {0, NULL, NULL},
114   };
115   if (G_UNLIKELY (speex_enc_mode_type == 0)) {
116     speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
117         speex_enc_modes);
118   }
119   return speex_enc_mode_type;
120 }
121
122 #if 0
123 static const GstFormat *
124 gst_speex_enc_get_formats (GstPad * pad)
125 {
126   static const GstFormat src_formats[] = {
127     GST_FORMAT_BYTES,
128     GST_FORMAT_TIME,
129     0
130   };
131   static const GstFormat sink_formats[] = {
132     GST_FORMAT_BYTES,
133     GST_FORMAT_DEFAULT,
134     GST_FORMAT_TIME,
135     0
136   };
137
138   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
139 }
140 #endif
141
142 static void gst_speex_enc_finalize (GObject * object);
143
144 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
145 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
146 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
147
148 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
149     GValue * value, GParamSpec * pspec);
150 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
151     const GValue * value, GParamSpec * pspec);
152 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
153     GstStateChange transition);
154
155 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
156
157 static void
158 gst_speex_enc_setup_interfaces (GType speexenc_type)
159 {
160   static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
161
162   g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
163       &tag_setter_info);
164
165   GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
166 }
167
168 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
169     gst_speex_enc_setup_interfaces);
170
171 static void
172 gst_speex_enc_base_init (gpointer g_class)
173 {
174   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
175
176   gst_element_class_add_pad_template (element_class,
177       gst_static_pad_template_get (&src_factory));
178   gst_element_class_add_pad_template (element_class,
179       gst_static_pad_template_get (&sink_factory));
180   gst_element_class_set_details (element_class, &speexenc_details);
181 }
182
183 static void
184 gst_speex_enc_class_init (GstSpeexEncClass * klass)
185 {
186   GObjectClass *gobject_class;
187   GstElementClass *gstelement_class;
188
189   gobject_class = (GObjectClass *) klass;
190   gstelement_class = (GstElementClass *) klass;
191
192   gobject_class->set_property = gst_speex_enc_set_property;
193   gobject_class->get_property = gst_speex_enc_get_property;
194
195   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
196       g_param_spec_float ("quality", "Quality", "Encoding quality",
197           0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
198   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
199       g_param_spec_int ("bitrate", "Encoding Bit-rate",
200           "Specify an encoding bit-rate (in bps). (0 = automatic)",
201           0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
202   g_object_class_install_property (gobject_class, PROP_MODE,
203       g_param_spec_enum ("mode", "Mode", "The encoding mode",
204           GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
205           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
206   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
207       g_param_spec_boolean ("vbr", "VBR",
208           "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
209   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
210       g_param_spec_int ("abr", "ABR",
211           "Enable average bit-rate (0 = disabled)",
212           0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
213   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
214       g_param_spec_boolean ("vad", "VAD",
215           "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
216   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
217       g_param_spec_boolean ("dtx", "DTX",
218           "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
219   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
220       g_param_spec_int ("complexity", "Complexity",
221           "Set encoding complexity",
222           0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
223   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
224       g_param_spec_int ("nframes", "NFrames",
225           "Number of frames per buffer",
226           0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
227   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
228       g_param_spec_string ("last-message", "last-message",
229           "The last status message", NULL, G_PARAM_READABLE));
230
231   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
232
233   gstelement_class->change_state =
234       GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
235 }
236
237 static void
238 gst_speex_enc_finalize (GObject * object)
239 {
240   GstSpeexEnc *enc;
241
242   enc = GST_SPEEX_ENC (object);
243
244   g_free (enc->last_message);
245   g_object_unref (enc->adapter);
246
247   G_OBJECT_CLASS (parent_class)->finalize (object);
248 }
249
250 static gboolean
251 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
252 {
253   GstSpeexEnc *enc;
254   GstStructure *structure;
255
256   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
257   enc->setup = FALSE;
258
259   structure = gst_caps_get_structure (caps, 0);
260   gst_structure_get_int (structure, "channels", &enc->channels);
261   gst_structure_get_int (structure, "rate", &enc->rate);
262
263   gst_speex_enc_setup (enc);
264
265   return enc->setup;
266 }
267
268
269 static GstCaps *
270 gst_speex_enc_sink_getcaps (GstPad * pad)
271 {
272   GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
273   GstCaps *peercaps = NULL;
274   GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
275
276   peercaps = gst_pad_peer_get_caps (enc->srcpad);
277
278   if (peercaps) {
279     if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
280       GstStructure *ps = gst_caps_get_structure (peercaps, 0);
281       GstStructure *s = gst_caps_get_structure (caps, 0);
282       gint rate, channels;
283
284       if (gst_structure_get_int (ps, "rate", &rate)) {
285         gst_structure_fixate_field_nearest_int (s, "rate", rate);
286       }
287
288       if (gst_structure_get_int (ps, "channels", &channels)) {
289         gst_structure_fixate_field_nearest_int (s, "channels", channels);
290       }
291     }
292     gst_caps_unref (peercaps);
293   }
294
295   gst_object_unref (enc);
296
297   return caps;
298 }
299
300
301 static gboolean
302 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
303     GstFormat * dest_format, gint64 * dest_value)
304 {
305   gboolean res = TRUE;
306   GstSpeexEnc *enc;
307   gint64 avg;
308
309   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
310
311   if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
312     return FALSE;
313
314   avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
315
316   switch (src_format) {
317     case GST_FORMAT_BYTES:
318       switch (*dest_format) {
319         case GST_FORMAT_TIME:
320           *dest_value = src_value * GST_SECOND / avg;
321           break;
322         default:
323           res = FALSE;
324       }
325       break;
326     case GST_FORMAT_TIME:
327       switch (*dest_format) {
328         case GST_FORMAT_BYTES:
329           *dest_value = src_value * avg / GST_SECOND;
330           break;
331         default:
332           res = FALSE;
333       }
334       break;
335     default:
336       res = FALSE;
337   }
338   return res;
339 }
340
341 static gboolean
342 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
343     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
344 {
345   gboolean res = TRUE;
346   guint scale = 1;
347   gint bytes_per_sample;
348   GstSpeexEnc *enc;
349
350   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
351
352   bytes_per_sample = enc->channels * 2;
353
354   switch (src_format) {
355     case GST_FORMAT_BYTES:
356       switch (*dest_format) {
357         case GST_FORMAT_DEFAULT:
358           if (bytes_per_sample == 0)
359             return FALSE;
360           *dest_value = src_value / bytes_per_sample;
361           break;
362         case GST_FORMAT_TIME:
363         {
364           gint byterate = bytes_per_sample * enc->rate;
365
366           if (byterate == 0)
367             return FALSE;
368           *dest_value = src_value * GST_SECOND / byterate;
369           break;
370         }
371         default:
372           res = FALSE;
373       }
374       break;
375     case GST_FORMAT_DEFAULT:
376       switch (*dest_format) {
377         case GST_FORMAT_BYTES:
378           *dest_value = src_value * bytes_per_sample;
379           break;
380         case GST_FORMAT_TIME:
381           if (enc->rate == 0)
382             return FALSE;
383           *dest_value = src_value * GST_SECOND / enc->rate;
384           break;
385         default:
386           res = FALSE;
387       }
388       break;
389     case GST_FORMAT_TIME:
390       switch (*dest_format) {
391         case GST_FORMAT_BYTES:
392           scale = bytes_per_sample;
393           /* fallthrough */
394         case GST_FORMAT_DEFAULT:
395           *dest_value = src_value * scale * enc->rate / GST_SECOND;
396           break;
397         default:
398           res = FALSE;
399       }
400       break;
401     default:
402       res = FALSE;
403   }
404   return res;
405 }
406
407 static gint64
408 gst_speex_enc_get_latency (GstSpeexEnc * enc)
409 {
410   return 30 * GST_MSECOND;
411 }
412
413 static const GstQueryType *
414 gst_speex_enc_get_query_types (GstPad * pad)
415 {
416   static const GstQueryType gst_speex_enc_src_query_types[] = {
417     GST_QUERY_POSITION,
418     GST_QUERY_DURATION,
419     GST_QUERY_CONVERT,
420     GST_QUERY_LATENCY,
421     0
422   };
423
424   return gst_speex_enc_src_query_types;
425 }
426
427 static gboolean
428 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
429 {
430   gboolean res = TRUE;
431   GstSpeexEnc *enc;
432
433   enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
434
435   switch (GST_QUERY_TYPE (query)) {
436     case GST_QUERY_POSITION:
437     {
438       GstFormat fmt, req_fmt;
439       gint64 pos, val;
440
441       gst_query_parse_position (query, &req_fmt, NULL);
442       if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
443         gst_query_set_position (query, req_fmt, val);
444         break;
445       }
446
447       fmt = GST_FORMAT_TIME;
448       if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
449         break;
450
451       if ((res =
452               gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
453                   &val)))
454         gst_query_set_position (query, req_fmt, val);
455
456       break;
457     }
458     case GST_QUERY_DURATION:
459     {
460       GstFormat fmt, req_fmt;
461       gint64 dur, val;
462
463       gst_query_parse_duration (query, &req_fmt, NULL);
464       if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
465         gst_query_set_duration (query, req_fmt, val);
466         break;
467       }
468
469       fmt = GST_FORMAT_TIME;
470       if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
471         break;
472
473       if ((res =
474               gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
475                   &val))) {
476         gst_query_set_duration (query, req_fmt, val);
477       }
478       break;
479     }
480     case GST_QUERY_CONVERT:
481     {
482       GstFormat src_fmt, dest_fmt;
483       gint64 src_val, dest_val;
484
485       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
486       if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
487                   &dest_val)))
488         goto error;
489       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
490       break;
491     }
492     case GST_QUERY_LATENCY:
493     {
494       gboolean live;
495       GstClockTime min_latency, max_latency;
496       gint64 latency;
497
498       if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
499         gst_query_parse_latency (query, &live, &min_latency, &max_latency);
500         GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query);
501
502         latency = gst_speex_enc_get_latency (enc);
503
504         /* add our latency */
505         min_latency += latency;
506         if (max_latency != -1)
507           max_latency += latency;
508
509         gst_query_set_latency (query, live, min_latency, max_latency);
510         GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query);
511       }
512       break;
513     }
514     default:
515       res = gst_pad_peer_query (enc->sinkpad, query);
516       break;
517   }
518
519 error:
520
521   gst_object_unref (enc);
522
523   return res;
524 }
525
526 static gboolean
527 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
528 {
529   gboolean res = TRUE;
530
531   switch (GST_QUERY_TYPE (query)) {
532     case GST_QUERY_CONVERT:
533     {
534       GstFormat src_fmt, dest_fmt;
535       gint64 src_val, dest_val;
536
537       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
538       if (!(res =
539               gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
540                   &dest_val)))
541         goto error;
542       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
543       break;
544     }
545     default:
546       res = gst_pad_query_default (pad, query);
547       break;
548   }
549
550 error:
551   return res;
552 }
553
554 static void
555 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
556 {
557   enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
558   gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
559   gst_pad_set_event_function (enc->sinkpad,
560       GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
561   gst_pad_set_chain_function (enc->sinkpad,
562       GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
563   gst_pad_set_setcaps_function (enc->sinkpad,
564       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
565   gst_pad_set_getcaps_function (enc->sinkpad,
566       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
567   gst_pad_set_query_function (enc->sinkpad,
568       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
569
570   enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
571   gst_pad_set_query_function (enc->srcpad,
572       GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
573   gst_pad_set_query_type_function (enc->srcpad,
574       GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
575   gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
576
577   enc->channels = -1;
578   enc->rate = -1;
579
580   enc->quality = DEFAULT_QUALITY;
581   enc->bitrate = DEFAULT_BITRATE;
582   enc->mode = DEFAULT_MODE;
583   enc->vbr = DEFAULT_VBR;
584   enc->abr = DEFAULT_ABR;
585   enc->vad = DEFAULT_VAD;
586   enc->dtx = DEFAULT_DTX;
587   enc->complexity = DEFAULT_COMPLEXITY;
588   enc->nframes = DEFAULT_NFRAMES;
589
590   enc->setup = FALSE;
591   enc->header_sent = FALSE;
592
593   enc->adapter = gst_adapter_new ();
594 }
595
596 static GstBuffer *
597 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
598 {
599   const GstTagList *user_tags;
600   GstTagList *merged_tags;
601   GstBuffer *comments = NULL;
602
603   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
604
605   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
606   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
607
608   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
609   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
610       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
611
612   if (merged_tags == NULL)
613     merged_tags = gst_tag_list_new ();
614
615   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
616   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
617       0, "Encoded with GStreamer Speexenc");
618   gst_tag_list_free (merged_tags);
619
620   GST_BUFFER_OFFSET (comments) = enc->bytes_out;
621   GST_BUFFER_OFFSET_END (comments) = 0;
622
623   return comments;
624 }
625
626 static void
627 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
628 {
629   g_free (enc->last_message);
630   enc->last_message = g_strdup (msg);
631   GST_WARNING_OBJECT (enc, "%s", msg);
632   g_object_notify (G_OBJECT (enc), "last-message");
633 }
634
635 static gboolean
636 gst_speex_enc_setup (GstSpeexEnc * enc)
637 {
638   enc->setup = FALSE;
639
640   switch (enc->mode) {
641     case GST_SPEEX_ENC_MODE_UWB:
642       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
643       enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
644       break;
645     case GST_SPEEX_ENC_MODE_WB:
646       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
647       enc->speex_mode = (SpeexMode *) & speex_wb_mode;
648       break;
649     case GST_SPEEX_ENC_MODE_NB:
650       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
651       enc->speex_mode = (SpeexMode *) & speex_nb_mode;
652       break;
653     case GST_SPEEX_ENC_MODE_AUTO:
654       /* fall through */
655       GST_LOG_OBJECT (enc, "finding best mode");
656     default:
657       break;
658   }
659
660   if (enc->rate > 25000) {
661     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
662       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
663       enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
664     } else {
665       if (enc->speex_mode != &speex_uwb_mode) {
666         gst_speex_enc_set_last_msg (enc,
667             "Warning: suggest to use ultra wide band mode for this rate");
668       }
669     }
670   } else if (enc->rate > 12500) {
671     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
672       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
673       enc->speex_mode = (SpeexMode *) & speex_wb_mode;
674     } else {
675       if (enc->speex_mode != &speex_wb_mode) {
676         gst_speex_enc_set_last_msg (enc,
677             "Warning: suggest to use wide band mode for this rate");
678       }
679     }
680   } else {
681     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
682       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
683       enc->speex_mode = (SpeexMode *) & speex_nb_mode;
684     } else {
685       if (enc->speex_mode != &speex_nb_mode) {
686         gst_speex_enc_set_last_msg (enc,
687             "Warning: suggest to use narrow band mode for this rate");
688       }
689     }
690   }
691
692   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
693     gst_speex_enc_set_last_msg (enc,
694         "Warning: speex is optimized for 8, 16 and 32 KHz");
695   }
696
697   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
698   enc->header.frames_per_packet = enc->nframes;
699   enc->header.vbr = enc->vbr;
700   enc->header.nb_channels = enc->channels;
701
702   /*Initialize Speex encoder */
703   enc->state = speex_encoder_init (enc->speex_mode);
704
705   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
706   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
707   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
708
709   if (enc->vbr)
710     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
711   else {
712     gint tmp = floor (enc->quality);
713
714     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
715   }
716   if (enc->bitrate) {
717     if (enc->quality >= 0.0 && enc->vbr) {
718       gst_speex_enc_set_last_msg (enc,
719           "Warning: bitrate option is overriding quality");
720     }
721     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
722   }
723   if (enc->vbr) {
724     gint tmp = 1;
725
726     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
727   } else if (enc->vad) {
728     gint tmp = 1;
729
730     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
731   }
732
733   if (enc->dtx) {
734     gint tmp = 1;
735
736     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
737   }
738
739   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
740     gst_speex_enc_set_last_msg (enc,
741         "Warning: dtx is useless without vad, vbr or abr");
742   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
743     gst_speex_enc_set_last_msg (enc,
744         "Warning: vad is already implied by vbr or abr");
745   }
746
747   if (enc->abr) {
748     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
749   }
750
751   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
752
753   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
754       enc->lookahead);
755
756   enc->setup = TRUE;
757
758   return TRUE;
759 }
760
761 /* prepare a buffer for transmission */
762 static GstBuffer *
763 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
764     gint data_len, guint64 granulepos)
765 {
766   GstBuffer *outbuf;
767
768   outbuf = gst_buffer_new_and_alloc (data_len);
769   memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
770   GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
771   GST_BUFFER_OFFSET_END (outbuf) = granulepos;
772
773   GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
774   return outbuf;
775 }
776
777
778 /* push out the buffer and do internal bookkeeping */
779 static GstFlowReturn
780 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
781 {
782   guint size;
783
784   size = GST_BUFFER_SIZE (buffer);
785
786   enc->bytes_out += size;
787
788   GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
789
790   return gst_pad_push (enc->srcpad, buffer);
791 }
792
793 static GstCaps *
794 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
795     GstBuffer * buf2)
796 {
797   GstStructure *structure = NULL;
798   GstBuffer *buf;
799   GValue array = { 0 };
800   GValue value = { 0 };
801
802   caps = gst_caps_make_writable (caps);
803   structure = gst_caps_get_structure (caps, 0);
804
805   g_assert (gst_buffer_is_metadata_writable (buf1));
806   g_assert (gst_buffer_is_metadata_writable (buf2));
807
808   /* mark buffers */
809   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
810   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
811
812   /* put buffers in a fixed list */
813   g_value_init (&array, GST_TYPE_ARRAY);
814   g_value_init (&value, GST_TYPE_BUFFER);
815   buf = gst_buffer_copy (buf1);
816   gst_value_set_buffer (&value, buf);
817   gst_buffer_unref (buf);
818   gst_value_array_append_value (&array, &value);
819   g_value_unset (&value);
820   g_value_init (&value, GST_TYPE_BUFFER);
821   buf = gst_buffer_copy (buf2);
822   gst_value_set_buffer (&value, buf);
823   gst_buffer_unref (buf);
824   gst_value_array_append_value (&array, &value);
825   gst_structure_set_value (structure, "streamheader", &array);
826   g_value_unset (&value);
827   g_value_unset (&array);
828
829   return caps;
830 }
831
832
833 static gboolean
834 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
835 {
836   gboolean res = TRUE;
837   GstSpeexEnc *enc;
838
839   enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
840
841   switch (GST_EVENT_TYPE (event)) {
842     case GST_EVENT_EOS:
843       gst_speex_enc_encode (enc, TRUE);
844       res = gst_pad_event_default (pad, event);
845       break;
846     case GST_EVENT_TAG:
847     {
848       GstTagList *list;
849
850       gst_event_parse_tag (event, &list);
851       if (enc->tags) {
852         gst_tag_list_insert (enc->tags, list,
853             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
854       }
855       res = gst_pad_event_default (pad, event);
856       break;
857     }
858     default:
859       res = gst_pad_event_default (pad, event);
860       break;
861   }
862
863   gst_object_unref (enc);
864
865   return res;
866 }
867
868 static GstFlowReturn
869 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
870 {
871   gint frame_size = enc->frame_size;
872   gint bytes = frame_size * 2 * enc->channels;
873   GstFlowReturn ret = GST_FLOW_OK;
874
875   if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
876     guint diff = gst_adapter_available (enc->adapter) % bytes;
877     GstBuffer *buf = gst_buffer_new_and_alloc (diff);
878
879     memset (GST_BUFFER_DATA (buf), 0, diff);
880     gst_adapter_push (enc->adapter, buf);
881   }
882
883   while (gst_adapter_available (enc->adapter) >= bytes) {
884     gint16 *data;
885     gint outsize, written;
886     GstBuffer *outbuf;
887
888     data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
889
890     enc->samples_in += frame_size;
891
892     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
893
894     if (enc->channels == 2) {
895       speex_encode_stereo_int (data, frame_size, &enc->bits);
896     }
897     speex_encode_int (enc->state, data, &enc->bits);
898
899     g_free (data);
900
901     enc->frameno++;
902     enc->frameno_out++;
903
904     if ((enc->frameno % enc->nframes) != 0)
905       continue;
906
907     speex_bits_insert_terminator (&enc->bits);
908     outsize = speex_bits_nbytes (&enc->bits);
909
910     ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
911         GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
912
913     if ((GST_FLOW_OK != ret))
914       goto done;
915
916     written = speex_bits_write (&enc->bits,
917         (gchar *) GST_BUFFER_DATA (outbuf), outsize);
918     g_assert (written == outsize);
919     speex_bits_reset (&enc->bits);
920
921     GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
922         gst_util_uint64_scale_int ((enc->frameno_out - 1) * frame_size -
923         enc->lookahead, GST_SECOND, enc->rate);
924     GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
925         GST_SECOND, enc->rate);
926     /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
927     GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
928         ((enc->frameno_out) * frame_size - enc->lookahead);
929     GST_BUFFER_OFFSET (outbuf) =
930         gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
931         enc->rate);
932
933     ret = gst_speex_enc_push_buffer (enc, outbuf);
934
935     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
936       goto done;
937   }
938
939 done:
940
941   return ret;
942 }
943
944 static GstFlowReturn
945 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
946 {
947   GstSpeexEnc *enc;
948   GstFlowReturn ret = GST_FLOW_OK;
949
950   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
951
952   if (!enc->setup)
953     goto not_setup;
954
955   if (!enc->header_sent) {
956     /* Speex streams begin with two headers; the initial header (with
957        most of the codec setup parameters) which is mandated by the Ogg
958        bitstream spec.  The second header holds any comment fields.
959        We merely need to make the headers, then pass them to libspeex 
960        one at a time; libspeex handles the additional Ogg bitstream 
961        constraints */
962     GstBuffer *buf1, *buf2;
963     GstCaps *caps;
964     guchar *data;
965     gint data_len;
966
967     /* create header buffer */
968     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
969     buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
970     free (data);
971
972     /* create comment buffer */
973     buf2 = gst_speex_enc_create_metadata_buffer (enc);
974
975     /* mark and put on caps */
976     caps = gst_pad_get_caps (enc->srcpad);
977     caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
978
979     gst_caps_set_simple (caps,
980         "rate", G_TYPE_INT, enc->rate,
981         "channels", G_TYPE_INT, enc->channels, NULL);
982
983     /* negotiate with these caps */
984     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
985     gst_pad_set_caps (enc->srcpad, caps);
986
987     gst_buffer_set_caps (buf1, caps);
988     gst_buffer_set_caps (buf2, caps);
989     gst_caps_unref (caps);
990
991     /* push out buffers */
992     ret = gst_speex_enc_push_buffer (enc, buf1);
993
994     if (ret != GST_FLOW_OK) {
995       gst_buffer_unref (buf2);
996       goto done;
997     }
998
999     ret = gst_speex_enc_push_buffer (enc, buf2);
1000
1001     if (ret != GST_FLOW_OK)
1002       goto done;
1003
1004     speex_bits_reset (&enc->bits);
1005
1006     enc->header_sent = TRUE;
1007   }
1008
1009   /* Save the timestamp of the first buffer. This will be later
1010    * used as offset for all following buffers */
1011   if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1012     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1013       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1014       enc->granulepos_offset = gst_util_uint64_scale
1015           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1016     } else {
1017       enc->start_ts = 0;
1018       enc->granulepos_offset = 0;
1019     }
1020   }
1021
1022   /* Check if we have a continous stream, if not drop some samples or the buffer or
1023    * insert some silence samples */
1024   if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1025       GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1026     guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1027     guint64 diff_bytes;
1028
1029     GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1030         "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1031         "), cannot handle. Clipping buffer.",
1032         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1033         GST_TIME_ARGS (enc->next_ts));
1034
1035     diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1036     if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1037       gst_buffer_unref (buf);
1038       return GST_FLOW_OK;
1039     }
1040     buf = gst_buffer_make_metadata_writable (buf);
1041     GST_BUFFER_DATA (buf) += diff_bytes;
1042     GST_BUFFER_SIZE (buf) -= diff_bytes;
1043
1044     GST_BUFFER_TIMESTAMP (buf) += diff;
1045     if (GST_BUFFER_DURATION_IS_VALID (buf))
1046       GST_BUFFER_DURATION (buf) -= diff;
1047   }
1048
1049   if (enc->next_ts != GST_CLOCK_TIME_NONE
1050       && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1051     guint64 max_diff =
1052         gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1053
1054     if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1055         GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1056       GST_WARNING_OBJECT (enc,
1057           "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1058           GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1059
1060       gst_speex_enc_encode (enc, TRUE);
1061
1062       enc->frameno_out = 0;
1063       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1064       enc->granulepos_offset = gst_util_uint64_scale
1065           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1066     }
1067   }
1068
1069   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1070       && GST_BUFFER_DURATION_IS_VALID (buf))
1071     enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1072   else
1073     enc->next_ts = GST_CLOCK_TIME_NONE;
1074
1075   GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1076
1077   /* push buffer to adapter */
1078   gst_adapter_push (enc->adapter, buf);
1079   buf = NULL;
1080
1081   ret = gst_speex_enc_encode (enc, FALSE);
1082
1083 done:
1084
1085   if (buf)
1086     gst_buffer_unref (buf);
1087
1088   return ret;
1089
1090   /* ERRORS */
1091 not_setup:
1092   {
1093     GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1094         ("encoder not initialized (input is not audio?)"));
1095     ret = GST_FLOW_NOT_NEGOTIATED;
1096     goto done;
1097   }
1098
1099 }
1100
1101
1102 static void
1103 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1104     GParamSpec * pspec)
1105 {
1106   GstSpeexEnc *enc;
1107
1108   enc = GST_SPEEX_ENC (object);
1109
1110   switch (prop_id) {
1111     case PROP_QUALITY:
1112       g_value_set_float (value, enc->quality);
1113       break;
1114     case PROP_BITRATE:
1115       g_value_set_int (value, enc->bitrate);
1116       break;
1117     case PROP_MODE:
1118       g_value_set_enum (value, enc->mode);
1119       break;
1120     case PROP_VBR:
1121       g_value_set_boolean (value, enc->vbr);
1122       break;
1123     case PROP_ABR:
1124       g_value_set_int (value, enc->abr);
1125       break;
1126     case PROP_VAD:
1127       g_value_set_boolean (value, enc->vad);
1128       break;
1129     case PROP_DTX:
1130       g_value_set_boolean (value, enc->dtx);
1131       break;
1132     case PROP_COMPLEXITY:
1133       g_value_set_int (value, enc->complexity);
1134       break;
1135     case PROP_NFRAMES:
1136       g_value_set_int (value, enc->nframes);
1137       break;
1138     case PROP_LAST_MESSAGE:
1139       g_value_set_string (value, enc->last_message);
1140       break;
1141     default:
1142       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1143       break;
1144   }
1145 }
1146
1147 static void
1148 gst_speex_enc_set_property (GObject * object, guint prop_id,
1149     const GValue * value, GParamSpec * pspec)
1150 {
1151   GstSpeexEnc *enc;
1152
1153   enc = GST_SPEEX_ENC (object);
1154
1155   switch (prop_id) {
1156     case PROP_QUALITY:
1157       enc->quality = g_value_get_float (value);
1158       break;
1159     case PROP_BITRATE:
1160       enc->bitrate = g_value_get_int (value);
1161       break;
1162     case PROP_MODE:
1163       enc->mode = g_value_get_enum (value);
1164       break;
1165     case PROP_VBR:
1166       enc->vbr = g_value_get_boolean (value);
1167       break;
1168     case PROP_ABR:
1169       enc->abr = g_value_get_int (value);
1170       break;
1171     case PROP_VAD:
1172       enc->vad = g_value_get_boolean (value);
1173       break;
1174     case PROP_DTX:
1175       enc->dtx = g_value_get_boolean (value);
1176       break;
1177     case PROP_COMPLEXITY:
1178       enc->complexity = g_value_get_int (value);
1179       break;
1180     case PROP_NFRAMES:
1181       enc->nframes = g_value_get_int (value);
1182       break;
1183     default:
1184       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1185       break;
1186   }
1187 }
1188
1189 static GstStateChangeReturn
1190 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1191 {
1192   GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1193   GstStateChangeReturn res;
1194
1195   switch (transition) {
1196     case GST_STATE_CHANGE_NULL_TO_READY:
1197       enc->tags = gst_tag_list_new ();
1198       break;
1199     case GST_STATE_CHANGE_READY_TO_PAUSED:
1200       speex_bits_init (&enc->bits);
1201       enc->frameno = 0;
1202       enc->frameno_out = 0;
1203       enc->samples_in = 0;
1204       enc->start_ts = GST_CLOCK_TIME_NONE;
1205       enc->next_ts = GST_CLOCK_TIME_NONE;
1206       enc->granulepos_offset = 0;
1207       break;
1208     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1209       /* fall through */
1210     default:
1211       break;
1212   }
1213
1214   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1215   if (res == GST_STATE_CHANGE_FAILURE)
1216     return res;
1217
1218   switch (transition) {
1219     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1220       break;
1221     case GST_STATE_CHANGE_PAUSED_TO_READY:
1222       enc->setup = FALSE;
1223       enc->header_sent = FALSE;
1224       if (enc->state) {
1225         speex_encoder_destroy (enc->state);
1226         enc->state = NULL;
1227       }
1228       speex_bits_destroy (&enc->bits);
1229       break;
1230     case GST_STATE_CHANGE_READY_TO_NULL:
1231       gst_tag_list_free (enc->tags);
1232       enc->tags = NULL;
1233     default:
1234       break;
1235   }
1236
1237   return res;
1238 }