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