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