Use <speex.h> everywhere instead of sometimes <speex.h> and sometimes <speex/speex.h>
[platform/upstream/gstreamer.git] / ext / speex / gstspeexenc.c
1 /* GStreamer
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.h>
29 #include <speex_stereo.h>
30
31 #include <gst/gsttaginterface.h>
32 #include <gst/tag/tag.h>
33 #include "gstspeexenc.h"
34
35 GST_DEBUG_CATEGORY (speexenc_debug);
36 #define GST_CAT_DEFAULT speexenc_debug
37
38 static GstPadTemplate *gst_speexenc_src_template, *gst_speexenc_sink_template;
39
40 /* elementfactory information */
41 GstElementDetails speexenc_details = {
42   "Speex encoder",
43   "Codec/Encoder/Audio",
44   "Encodes audio in Speex format",
45   "Wim Taymans <wim@fluendo.com>",
46 };
47
48 /* GstSpeexEnc signals and args */
49 enum
50 {
51   /* FILL ME */
52   LAST_SIGNAL
53 };
54
55 #define DEFAULT_QUALITY         8.0
56 #define DEFAULT_BITRATE         0
57 #define DEFAULT_VBR             FALSE
58 #define DEFAULT_ABR             0
59 #define DEFAULT_VAD             FALSE
60 #define DEFAULT_DTX             FALSE
61 #define DEFAULT_COMPLEXITY      3
62 #define DEFAULT_NFRAMES         1
63
64 enum
65 {
66   ARG_0,
67   ARG_QUALITY,
68   ARG_BITRATE,
69   ARG_VBR,
70   ARG_ABR,
71   ARG_VAD,
72   ARG_DTX,
73   ARG_COMPLEXITY,
74   ARG_NFRAMES,
75   ARG_LAST_MESSAGE
76 };
77
78 static const GstFormat *
79 gst_speexenc_get_formats (GstPad * pad)
80 {
81   static const GstFormat src_formats[] = {
82     GST_FORMAT_BYTES,
83     GST_FORMAT_TIME,
84     0
85   };
86   static const GstFormat sink_formats[] = {
87     GST_FORMAT_BYTES,
88     GST_FORMAT_DEFAULT,
89     GST_FORMAT_TIME,
90     0
91   };
92
93   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
94 }
95
96 static void gst_speexenc_base_init (gpointer g_class);
97 static void gst_speexenc_class_init (GstSpeexEncClass * klass);
98 static void gst_speexenc_init (GstSpeexEnc * speexenc);
99
100 static void gst_speexenc_chain (GstPad * pad, GstData * _data);
101 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
102
103 static void gst_speexenc_get_property (GObject * object, guint prop_id,
104     GValue * value, GParamSpec * pspec);
105 static void gst_speexenc_set_property (GObject * object, guint prop_id,
106     const GValue * value, GParamSpec * pspec);
107 static GstElementStateReturn gst_speexenc_change_state (GstElement * element);
108
109 static GstElementClass *parent_class = NULL;
110
111 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
112
113 GType
114 gst_speexenc_get_type (void)
115 {
116   static GType speexenc_type = 0;
117
118   if (!speexenc_type) {
119     static const GTypeInfo speexenc_info = {
120       sizeof (GstSpeexEncClass),
121       gst_speexenc_base_init,
122       NULL,
123       (GClassInitFunc) gst_speexenc_class_init,
124       NULL,
125       NULL,
126       sizeof (GstSpeexEnc),
127       0,
128       (GInstanceInitFunc) gst_speexenc_init,
129     };
130     static const GInterfaceInfo tag_setter_info = {
131       NULL,
132       NULL,
133       NULL
134     };
135
136     speexenc_type =
137         g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
138         0);
139
140     g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
141         &tag_setter_info);
142
143     GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
144   }
145   return speexenc_type;
146 }
147
148 static GstCaps *
149 speex_caps_factory (void)
150 {
151   return gst_caps_new_simple ("audio/x-speex", NULL);
152 }
153
154 static GstCaps *
155 raw_caps_factory (void)
156 {
157   return
158       gst_caps_new_simple ("audio/x-raw-int",
159       "rate", GST_TYPE_INT_RANGE, 6000, 48000,
160       "channels", GST_TYPE_INT_RANGE, 1, 2,
161       "endianness", G_TYPE_INT, G_BYTE_ORDER,
162       "signed", G_TYPE_BOOLEAN, TRUE,
163       "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
164 }
165
166 static void
167 gst_speexenc_base_init (gpointer g_class)
168 {
169   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
170   GstCaps *raw_caps, *speex_caps;
171
172   raw_caps = raw_caps_factory ();
173   speex_caps = speex_caps_factory ();
174
175   gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
176       GST_PAD_ALWAYS, raw_caps);
177   gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
178       GST_PAD_ALWAYS, speex_caps);
179   gst_element_class_add_pad_template (element_class,
180       gst_speexenc_sink_template);
181   gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
182   gst_element_class_set_details (element_class, &speexenc_details);
183 }
184
185 static void
186 gst_speexenc_class_init (GstSpeexEncClass * klass)
187 {
188   GObjectClass *gobject_class;
189   GstElementClass *gstelement_class;
190
191   gobject_class = (GObjectClass *) klass;
192   gstelement_class = (GstElementClass *) klass;
193
194   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
195       g_param_spec_float ("quality", "Quality", "Encoding quality",
196           0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
197   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
198       g_param_spec_int ("bitrate", "Encoding Bit-rate",
199           "Specify an encoding bit-rate (in bps). ",
200           0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
201   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
202       g_param_spec_boolean ("vbr", "VBR",
203           "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
204   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
205       g_param_spec_int ("abr", "ABR",
206           "Enable average bit-rate (0 = disabled)",
207           0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
208   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
209       g_param_spec_boolean ("vad", "VAD",
210           "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
211   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
212       g_param_spec_boolean ("dtx", "DTX",
213           "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
214   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
215       g_param_spec_int ("complexity", "Complexity",
216           "Set encoding complexity",
217           0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
218   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
219       g_param_spec_int ("nframes", "NFrames",
220           "Number of frames per buffer",
221           0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
222   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
223       g_param_spec_string ("last-message", "last-message",
224           "The last status message", NULL, G_PARAM_READABLE));
225
226   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
227
228   gobject_class->set_property = gst_speexenc_set_property;
229   gobject_class->get_property = gst_speexenc_get_property;
230
231   gstelement_class->change_state = gst_speexenc_change_state;
232 }
233
234 static GstPadLinkReturn
235 gst_speexenc_sinkconnect (GstPad * pad, const GstCaps * caps)
236 {
237   GstSpeexEnc *speexenc;
238   GstStructure *structure;
239
240   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
241   speexenc->setup = FALSE;
242
243   structure = gst_caps_get_structure (caps, 0);
244   gst_structure_get_int (structure, "channels", &speexenc->channels);
245   gst_structure_get_int (structure, "rate", &speexenc->rate);
246
247   gst_speexenc_setup (speexenc);
248
249   if (speexenc->setup)
250     return GST_PAD_LINK_OK;
251
252   return GST_PAD_LINK_REFUSED;
253 }
254
255 static gboolean
256 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
257     GstFormat * dest_format, gint64 * dest_value)
258 {
259   gboolean res = TRUE;
260   GstSpeexEnc *speexenc;
261   gint64 avg;
262
263   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
264
265   if (speexenc->samples_in == 0 ||
266       speexenc->bytes_out == 0 || speexenc->rate == 0)
267     return FALSE;
268
269   avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
270
271   switch (src_format) {
272     case GST_FORMAT_BYTES:
273       switch (*dest_format) {
274         case GST_FORMAT_TIME:
275           *dest_value = src_value * GST_SECOND / avg;
276           break;
277         default:
278           res = FALSE;
279       }
280       break;
281     case GST_FORMAT_TIME:
282       switch (*dest_format) {
283         case GST_FORMAT_BYTES:
284           *dest_value = src_value * avg / GST_SECOND;
285           break;
286         default:
287           res = FALSE;
288       }
289       break;
290     default:
291       res = FALSE;
292   }
293   return res;
294 }
295
296 static gboolean
297 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
298     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
299 {
300   gboolean res = TRUE;
301   guint scale = 1;
302   gint bytes_per_sample;
303   GstSpeexEnc *speexenc;
304
305   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
306
307   bytes_per_sample = speexenc->channels * 2;
308
309   switch (src_format) {
310     case GST_FORMAT_BYTES:
311       switch (*dest_format) {
312         case GST_FORMAT_DEFAULT:
313           if (bytes_per_sample == 0)
314             return FALSE;
315           *dest_value = src_value / bytes_per_sample;
316           break;
317         case GST_FORMAT_TIME:
318         {
319           gint byterate = bytes_per_sample * speexenc->rate;
320
321           if (byterate == 0)
322             return FALSE;
323           *dest_value = src_value * GST_SECOND / byterate;
324           break;
325         }
326         default:
327           res = FALSE;
328       }
329       break;
330     case GST_FORMAT_DEFAULT:
331       switch (*dest_format) {
332         case GST_FORMAT_BYTES:
333           *dest_value = src_value * bytes_per_sample;
334           break;
335         case GST_FORMAT_TIME:
336           if (speexenc->rate == 0)
337             return FALSE;
338           *dest_value = src_value * GST_SECOND / speexenc->rate;
339           break;
340         default:
341           res = FALSE;
342       }
343       break;
344     case GST_FORMAT_TIME:
345       switch (*dest_format) {
346         case GST_FORMAT_BYTES:
347           scale = bytes_per_sample;
348           /* fallthrough */
349         case GST_FORMAT_DEFAULT:
350           *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
351           break;
352         default:
353           res = FALSE;
354       }
355       break;
356     default:
357       res = FALSE;
358   }
359   return res;
360 }
361
362 static const GstQueryType *
363 gst_speexenc_get_query_types (GstPad * pad)
364 {
365   static const GstQueryType gst_speexenc_src_query_types[] = {
366     GST_QUERY_TOTAL,
367     GST_QUERY_POSITION,
368     0
369   };
370
371   return gst_speexenc_src_query_types;
372 }
373
374 static gboolean
375 gst_speexenc_src_query (GstPad * pad, GstQueryType type,
376     GstFormat * format, gint64 * value)
377 {
378   gboolean res = TRUE;
379   GstSpeexEnc *speexenc;
380
381   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
382
383   switch (type) {
384     case GST_QUERY_TOTAL:
385     {
386       switch (*format) {
387         case GST_FORMAT_BYTES:
388         case GST_FORMAT_TIME:
389         {
390           gint64 peer_value;
391           const GstFormat *peer_formats;
392
393           res = FALSE;
394
395           peer_formats = gst_pad_get_formats (GST_PAD_PEER (speexenc->sinkpad));
396
397           while (peer_formats && *peer_formats && !res) {
398
399             GstFormat peer_format = *peer_formats;
400
401             /* do the probe */
402             if (gst_pad_query (GST_PAD_PEER (speexenc->sinkpad),
403                     GST_QUERY_TOTAL, &peer_format, &peer_value)) {
404               GstFormat conv_format;
405
406               /* convert to TIME */
407               conv_format = GST_FORMAT_TIME;
408               res = gst_pad_convert (speexenc->sinkpad,
409                   peer_format, peer_value, &conv_format, value);
410               /* and to final format */
411               res &= gst_pad_convert (pad,
412                   GST_FORMAT_TIME, *value, format, value);
413             }
414             peer_formats++;
415           }
416           break;
417         }
418         default:
419           res = FALSE;
420           break;
421       }
422       break;
423     }
424     case GST_QUERY_POSITION:
425       switch (*format) {
426         default:
427         {
428           /* we only know about our samples, convert to requested format */
429           res = gst_pad_convert (pad,
430               GST_FORMAT_BYTES, speexenc->bytes_out, format, value);
431           break;
432         }
433       }
434       break;
435     default:
436       res = FALSE;
437       break;
438   }
439   return res;
440 }
441
442 static void
443 gst_speexenc_init (GstSpeexEnc * speexenc)
444 {
445   speexenc->sinkpad =
446       gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
447   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
448   gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
449   gst_pad_set_link_function (speexenc->sinkpad, gst_speexenc_sinkconnect);
450   gst_pad_set_convert_function (speexenc->sinkpad,
451       GST_DEBUG_FUNCPTR (gst_speexenc_convert_sink));
452   gst_pad_set_formats_function (speexenc->sinkpad,
453       GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
454
455   speexenc->srcpad =
456       gst_pad_new_from_template (gst_speexenc_src_template, "src");
457   gst_pad_set_query_function (speexenc->srcpad,
458       GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
459   gst_pad_set_query_type_function (speexenc->srcpad,
460       GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
461   gst_pad_set_convert_function (speexenc->srcpad,
462       GST_DEBUG_FUNCPTR (gst_speexenc_convert_src));
463   gst_pad_set_formats_function (speexenc->srcpad,
464       GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
465   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
466
467   speexenc->channels = -1;
468   speexenc->rate = -1;
469
470   speexenc->quality = DEFAULT_QUALITY;
471   speexenc->bitrate = DEFAULT_BITRATE;
472   speexenc->vbr = DEFAULT_VBR;
473   speexenc->abr = DEFAULT_ABR;
474   speexenc->vad = DEFAULT_VAD;
475   speexenc->dtx = DEFAULT_DTX;
476   speexenc->complexity = DEFAULT_COMPLEXITY;
477   speexenc->nframes = DEFAULT_NFRAMES;
478
479   speexenc->setup = FALSE;
480   speexenc->eos = FALSE;
481   speexenc->header_sent = FALSE;
482
483   speexenc->tags = gst_tag_list_new ();
484   speexenc->adapter = gst_adapter_new ();
485
486   /* we're chained and we can deal with events */
487   GST_FLAG_SET (speexenc, GST_ELEMENT_EVENT_AWARE);
488 }
489
490
491 static gchar *
492 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
493     int index)
494 {
495   gchar *speexvalue = NULL;
496
497   if (tag == NULL) {
498     return NULL;
499   }
500
501   /* get tag name right */
502   if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
503       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
504       || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
505       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
506     guint track_no;
507
508     if (!gst_tag_list_get_uint_index (list, tag, index, &track_no))
509       g_assert_not_reached ();
510     speexvalue = g_strdup_printf ("%u", track_no);
511   } else if (strcmp (tag, GST_TAG_DATE) == 0) {
512     /* FIXME: how are dates represented in speex files? */
513     GDate *date;
514     guint u;
515
516     if (!gst_tag_list_get_uint_index (list, tag, index, &u))
517       g_assert_not_reached ();
518     date = g_date_new_julian (u);
519     speexvalue =
520         g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
521         (gint) g_date_get_month (date), (gint) g_date_get_day (date));
522     g_date_free (date);
523   } else if (gst_tag_get_type (tag) == G_TYPE_STRING) {
524     if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
525       g_assert_not_reached ();
526   }
527
528   return speexvalue;
529 }
530
531 /*
532  *  Comments will be stored in the Vorbis style.
533  *  It is describled in the "Structure" section of
534  *  http://www.xiph.org/ogg/vorbis/doc/v-comment.html
535  *
536  *  The comment header is decoded as follows:
537  *  1) [vendor_length] = read an unsigned integer of 32 bits
538  *  2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
539  *  3) [user_comment_list_length] = read an unsigned integer of 32 bits
540  *  4) iterate [user_comment_list_length] times {
541  *     5) [length] = read an unsigned integer of 32 bits
542  *     6) this iteration's user comment = read a UTF-8 vector as [length] octets
543  *     }
544  *  7) [framing_bit] = read a single bit as boolean
545  *  8) if ( [framing_bit]  unset or end of packet ) then ERROR
546  *  9) done.
547  *
548  *  If you have troubles, please write to ymnk@jcraft.com.
549  */
550 #define readint(buf, base) (((buf[base+3]<<24) & 0xff000000)| \
551                             ((buf[base+2]<<16) & 0xff0000)|   \
552                             ((buf[base+1]<< 8) & 0xff00)|     \
553                              (buf[base  ]      & 0xff))
554 #define writeint(buf, base, val) do{ buf[base+3] = ((val)>>24) & 0xff; \
555                                      buf[base+2] = ((val)>>16) & 0xff; \
556                                      buf[base+1] = ((val)>> 8) & 0xff; \
557                                      buf[base  ] =  (val)      & 0xff; \
558                                   }while(0)
559
560 static void
561 comment_init (char **comments, int *length, char *vendor_string)
562 {
563   int vendor_length = strlen (vendor_string);
564   int user_comment_list_length = 0;
565   int len = 4 + vendor_length + 4;
566   char *p = (char *) malloc (len);
567
568   if (p == NULL) {
569   }
570   writeint (p, 0, vendor_length);
571   memcpy (p + 4, vendor_string, vendor_length);
572   writeint (p, 4 + vendor_length, user_comment_list_length);
573   *length = len;
574   *comments = p;
575 }
576 static void
577 comment_add (char **comments, int *length, const char *tag, char *val)
578 {
579   char *p = *comments;
580   int vendor_length = readint (p, 0);
581   int user_comment_list_length = readint (p, 4 + vendor_length);
582   int tag_len = (tag ? strlen (tag) : 0);
583   int val_len = strlen (val);
584   int len = (*length) + 4 + tag_len + val_len;
585
586   p = (char *) realloc (p, len);
587
588   writeint (p, *length, tag_len + val_len);     /* length of comment */
589   if (tag)
590     memcpy (p + *length + 4, tag, tag_len);     /* comment */
591   memcpy (p + *length + 4 + tag_len, val, val_len);     /* comment */
592   writeint (p, 4 + vendor_length, user_comment_list_length + 1);
593
594   *comments = p;
595   *length = len;
596 }
597
598 #undef readint
599 #undef writeint
600
601 static void
602 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
603     gpointer speexenc)
604 {
605   const gchar *speextag = NULL;
606   gchar *speexvalue = NULL;
607   guint i, count;
608   GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
609
610   speextag = gst_tag_to_vorbis_tag (tag);
611   if (speextag == NULL) {
612     return;
613   }
614
615   count = gst_tag_list_get_tag_size (list, tag);
616   for (i = 0; i < count; i++) {
617     speexvalue = gst_speexenc_get_tag_value (list, tag, i);
618
619     if (speexvalue != NULL) {
620       comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
621     }
622   }
623 }
624
625 static void
626 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
627 {
628   GstTagList *copy;
629   const GstTagList *user_tags;
630
631   user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
632   if (!(speexenc->tags || user_tags))
633     return;
634
635   comment_init (&speexenc->comments, &speexenc->comment_len,
636       "Encoded with GStreamer Speexenc");
637   copy =
638       gst_tag_list_merge (user_tags, speexenc->tags,
639       gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
640   gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
641   gst_tag_list_free (copy);
642 }
643
644 static gboolean
645 gst_speexenc_setup (GstSpeexEnc * speexenc)
646 {
647   speexenc->setup = FALSE;
648
649   switch (speexenc->mode) {
650     case GST_SPEEXENC_MODE_UWB:
651       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
652       break;
653     case GST_SPEEXENC_MODE_WB:
654       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
655       break;
656     case GST_SPEEXENC_MODE_NB:
657       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
658       break;
659     case GST_SPEEXENC_MODE_AUTO:
660     default:
661       break;
662   }
663
664   if (speexenc->rate > 25000) {
665     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
666       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
667     } else {
668       if (speexenc->speex_mode != &speex_uwb_mode) {
669         speexenc->last_message =
670             g_strdup_printf
671             ("Warning: suggest to use ultra wide band mode for this rate");
672         g_object_notify (G_OBJECT (speexenc), "last_message");
673       }
674     }
675   } else if (speexenc->rate > 12500) {
676     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
677       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
678     } else {
679       if (speexenc->speex_mode != &speex_wb_mode) {
680         speexenc->last_message =
681             g_strdup_printf
682             ("Warning: suggest to use wide band mode for this rate");
683         g_object_notify (G_OBJECT (speexenc), "last_message");
684       }
685     }
686   } else {
687     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
688       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
689     } else {
690       if (speexenc->speex_mode != &speex_nb_mode) {
691         speexenc->last_message =
692             g_strdup_printf
693             ("Warning: suggest to use narrow band mode for this rate");
694         g_object_notify (G_OBJECT (speexenc), "last_message");
695       }
696     }
697   }
698
699   if (speexenc->rate != 8000 && speexenc->rate != 16000
700       && speexenc->rate != 32000) {
701     speexenc->last_message =
702         g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
703     g_object_notify (G_OBJECT (speexenc), "last_message");
704   }
705
706   speex_init_header (&speexenc->header, speexenc->rate, 1,
707       speexenc->speex_mode);
708   speexenc->header.frames_per_packet = speexenc->nframes;
709   speexenc->header.vbr = speexenc->vbr;
710   speexenc->header.nb_channels = speexenc->channels;
711
712   /*Initialize Speex encoder */
713   speexenc->state = speex_encoder_init (speexenc->speex_mode);
714
715   speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
716       &speexenc->frame_size);
717   speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
718       &speexenc->complexity);
719   speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
720
721   if (speexenc->vbr)
722     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
723         &speexenc->quality);
724   else {
725     gint tmp = floor (speexenc->quality);
726
727     speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
728   }
729   if (speexenc->bitrate) {
730     if (speexenc->quality >= 0.0 && speexenc->vbr) {
731       speexenc->last_message =
732           g_strdup_printf ("Warning: bitrate option is overriding quality");
733       g_object_notify (G_OBJECT (speexenc), "last_message");
734     }
735     speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
736   }
737   if (speexenc->vbr) {
738     gint tmp = 1;
739
740     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
741   } else if (speexenc->vad) {
742     gint tmp = 1;
743
744     speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
745   }
746
747   if (speexenc->dtx) {
748     gint tmp = 1;
749
750     speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
751   }
752
753   if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
754     speexenc->last_message =
755         g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
756     g_object_notify (G_OBJECT (speexenc), "last_message");
757   } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
758     speexenc->last_message =
759         g_strdup_printf ("Warning: vad is already implied by vbr or abr");
760     g_object_notify (G_OBJECT (speexenc), "last_message");
761   }
762
763   if (speexenc->abr) {
764     speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
765   }
766
767   speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
768       &speexenc->lookahead);
769
770   speexenc->setup = TRUE;
771
772   return TRUE;
773 }
774
775 /* prepare a buffer for transmission */
776 static GstBuffer *
777 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
778     gint data_len, guint64 granulepos)
779 {
780   GstBuffer *outbuf;
781
782   outbuf = gst_buffer_new_and_alloc (data_len);
783   memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
784   GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
785   GST_BUFFER_OFFSET_END (outbuf) = granulepos;
786
787   GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
788   return outbuf;
789 }
790
791 /* push out the buffer and do internal bookkeeping */
792 static void
793 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
794 {
795   speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
796
797   if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
798     gst_pad_push (speexenc->srcpad, GST_DATA (buffer));
799   } else {
800     gst_buffer_unref (buffer);
801   }
802 }
803
804 static void
805 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
806     GstBuffer * buf2)
807 {
808   GstStructure *structure = gst_caps_get_structure (caps, 0);
809   GValue list = { 0 };
810   GValue value = { 0 };
811
812   /* mark buffers */
813   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_IN_CAPS);
814   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_IN_CAPS);
815
816   /* put buffers in a fixed list */
817   g_value_init (&list, GST_TYPE_FIXED_LIST);
818   g_value_init (&value, GST_TYPE_BUFFER);
819   g_value_set_boxed (&value, buf1);
820   gst_value_list_append_value (&list, &value);
821   g_value_unset (&value);
822   g_value_init (&value, GST_TYPE_BUFFER);
823   g_value_set_boxed (&value, buf2);
824   gst_value_list_append_value (&list, &value);
825   gst_structure_set_value (structure, "streamheader", &list);
826   g_value_unset (&value);
827   g_value_unset (&list);
828 }
829
830 static void
831 gst_speexenc_chain (GstPad * pad, GstData * _data)
832 {
833   GstBuffer *buf = GST_BUFFER (_data);
834   GstSpeexEnc *speexenc;
835
836   g_return_if_fail (pad != NULL);
837   g_return_if_fail (GST_IS_PAD (pad));
838   g_return_if_fail (buf != NULL);
839
840   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
841
842   if (GST_IS_EVENT (buf)) {
843     GstEvent *event = GST_EVENT (buf);
844
845     switch (GST_EVENT_TYPE (event)) {
846       case GST_EVENT_EOS:
847         speexenc->eos = TRUE;
848         gst_event_unref (event);
849         break;
850       case GST_EVENT_TAG:
851         if (speexenc->tags) {
852           gst_tag_list_insert (speexenc->tags, gst_event_tag_get_list (event),
853               gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
854         } else {
855           g_assert_not_reached ();
856         }
857         gst_pad_event_default (pad, event);
858         return;
859       default:
860         gst_pad_event_default (pad, event);
861         return;
862     }
863   } else {
864     if (!speexenc->setup) {
865       gst_buffer_unref (buf);
866       GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
867           ("encoder not initialized (input is not audio?)"));
868       return;
869     }
870
871     if (!speexenc->header_sent) {
872       /* Speex streams begin with two headers; the initial header (with
873          most of the codec setup parameters) which is mandated by the Ogg
874          bitstream spec.  The second header holds any comment fields.
875          We merely need to make the headers, then pass them to libspeex 
876          one at a time; libspeex handles the additional Ogg bitstream 
877          constraints */
878       GstBuffer *buf1, *buf2;
879       GstCaps *caps;
880       guchar *data;
881       gint data_len;
882
883       gst_speexenc_set_metadata (speexenc);
884
885       /* create header buffer */
886       data = speex_header_to_packet (&speexenc->header, &data_len);
887       buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
888
889       /* create comment buffer */
890       buf2 =
891           gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
892           speexenc->comment_len, 0);
893
894       /* mark and put on caps */
895       caps = gst_pad_get_caps (speexenc->srcpad);
896       gst_speexenc_set_header_on_caps (caps, buf1, buf2);
897
898       /* negotiate with these caps */
899       GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
900       gst_pad_try_set_caps (speexenc->srcpad, caps);
901
902       /* push out buffers */
903       gst_speexenc_push_buffer (speexenc, buf1);
904       gst_speexenc_push_buffer (speexenc, buf2);
905
906       speex_bits_init (&speexenc->bits);
907       speex_bits_reset (&speexenc->bits);
908
909       speexenc->header_sent = TRUE;
910     }
911
912     {
913       gint frame_size = speexenc->frame_size;
914       gint bytes = frame_size * 2 * speexenc->channels;
915
916       /* push buffer to adapter */
917       gst_adapter_push (speexenc->adapter, buf);
918
919       while (gst_adapter_available (speexenc->adapter) >= bytes) {
920         gint16 *data;
921         gint i;
922         gint outsize, written;
923         GstBuffer *outbuf;
924
925         data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
926
927         for (i = 0; i < frame_size * speexenc->channels; i++) {
928           speexenc->input[i] = (gfloat) data[i];
929         }
930         gst_adapter_flush (speexenc->adapter, bytes);
931
932         speexenc->samples_in += frame_size;
933
934         if (speexenc->channels == 2) {
935           speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
936         }
937         speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
938
939         speexenc->frameno++;
940
941         if ((speexenc->frameno % speexenc->nframes) != 0)
942           continue;
943
944         speex_bits_insert_terminator (&speexenc->bits);
945         outsize = speex_bits_nbytes (&speexenc->bits);
946         outbuf =
947             gst_pad_alloc_buffer (speexenc->srcpad, GST_BUFFER_OFFSET_NONE,
948             outsize);
949         written =
950             speex_bits_write (&speexenc->bits, GST_BUFFER_DATA (outbuf),
951             outsize);
952         g_assert (written == outsize);
953         speex_bits_reset (&speexenc->bits);
954
955         GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
956         GST_BUFFER_OFFSET_END (outbuf) =
957             speexenc->frameno * frame_size - speexenc->lookahead;
958
959         gst_speexenc_push_buffer (speexenc, outbuf);
960       }
961     }
962   }
963
964   if (speexenc->eos) {
965     /* clean up and exit. */
966     gst_pad_push (speexenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
967     gst_element_set_eos (GST_ELEMENT (speexenc));
968   }
969 }
970
971 static void
972 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
973     GParamSpec * pspec)
974 {
975   GstSpeexEnc *speexenc;
976
977   /* it's not null if we got it, but it might not be ours */
978   g_return_if_fail (GST_IS_SPEEXENC (object));
979
980   speexenc = GST_SPEEXENC (object);
981
982   switch (prop_id) {
983     case ARG_QUALITY:
984       g_value_set_float (value, speexenc->quality);
985       break;
986     case ARG_BITRATE:
987       g_value_set_int (value, speexenc->bitrate);
988       break;
989     case ARG_VBR:
990       g_value_set_boolean (value, speexenc->vbr);
991       break;
992     case ARG_ABR:
993       g_value_set_int (value, speexenc->abr);
994       break;
995     case ARG_VAD:
996       g_value_set_boolean (value, speexenc->vad);
997       break;
998     case ARG_DTX:
999       g_value_set_boolean (value, speexenc->dtx);
1000       break;
1001     case ARG_COMPLEXITY:
1002       g_value_set_int (value, speexenc->complexity);
1003       break;
1004     case ARG_NFRAMES:
1005       g_value_set_int (value, speexenc->nframes);
1006       break;
1007     case ARG_LAST_MESSAGE:
1008       g_value_set_string (value, speexenc->last_message);
1009       break;
1010     default:
1011       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1012       break;
1013   }
1014 }
1015
1016 static void
1017 gst_speexenc_set_property (GObject * object, guint prop_id,
1018     const GValue * value, GParamSpec * pspec)
1019 {
1020   GstSpeexEnc *speexenc;
1021
1022   /* it's not null if we got it, but it might not be ours */
1023   g_return_if_fail (GST_IS_SPEEXENC (object));
1024
1025   speexenc = GST_SPEEXENC (object);
1026
1027   switch (prop_id) {
1028     case ARG_QUALITY:
1029       speexenc->quality = g_value_get_float (value);
1030       break;
1031     case ARG_BITRATE:
1032       speexenc->bitrate = g_value_get_int (value);
1033       break;
1034     case ARG_VBR:
1035       speexenc->vbr = g_value_get_boolean (value);
1036       break;
1037     case ARG_ABR:
1038       speexenc->abr = g_value_get_int (value);
1039       break;
1040     case ARG_VAD:
1041       speexenc->vad = g_value_get_boolean (value);
1042       break;
1043     case ARG_DTX:
1044       speexenc->dtx = g_value_get_boolean (value);
1045       break;
1046     case ARG_COMPLEXITY:
1047       speexenc->complexity = g_value_get_int (value);
1048       break;
1049     case ARG_NFRAMES:
1050       speexenc->nframes = g_value_get_int (value);
1051       break;
1052     default:
1053       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1054       break;
1055   }
1056 }
1057
1058 static GstElementStateReturn
1059 gst_speexenc_change_state (GstElement * element)
1060 {
1061   GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1062
1063   switch (GST_STATE_TRANSITION (element)) {
1064     case GST_STATE_NULL_TO_READY:
1065       break;
1066     case GST_STATE_READY_TO_PAUSED:
1067       speexenc->eos = FALSE;
1068       speexenc->frameno = 0;
1069       speexenc->samples_in = 0;
1070       break;
1071     case GST_STATE_PAUSED_TO_PLAYING:
1072     case GST_STATE_PLAYING_TO_PAUSED:
1073       break;
1074     case GST_STATE_PAUSED_TO_READY:
1075       speexenc->setup = FALSE;
1076       speexenc->header_sent = FALSE;
1077       gst_tag_list_free (speexenc->tags);
1078       speexenc->tags = gst_tag_list_new ();
1079       break;
1080     case GST_STATE_READY_TO_NULL:
1081     default:
1082       break;
1083   }
1084
1085   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1086     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1087
1088   return GST_STATE_SUCCESS;
1089 }