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