speex: Fix segfault when resetting the codecs multiple times
[platform/upstream/gst-plugins-good.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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * SECTION:element-speexenc
22  * @see_also: speexdec, oggmux
23  *
24  * This element encodes audio as a Speex stream.
25  * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
26  * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
27  * Foundation</ulink>.
28  *
29  * <refsect2>
30  * <title>Example pipelines</title>
31  * |[
32  * gst-launch-1.0 audiotestsrc num-buffers=100 ! speexenc ! oggmux ! filesink location=beep.ogg
33  * ]| Encode an Ogg/Speex file.
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <math.h>
44 #include <speex/speex.h>
45 #include <speex/speex_stereo.h>
46
47 #include <gst/gsttagsetter.h>
48 #include <gst/tag/tag.h>
49 #include <gst/audio/audio.h>
50 #include "gstspeexenc.h"
51
52 GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
53 #define GST_CAT_DEFAULT speexenc_debug
54
55 #define FORMAT_STR GST_AUDIO_NE(S16)
56
57 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
58     GST_PAD_SINK,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("audio/x-raw, "
61         "format = (string) " FORMAT_STR ", "
62         "layout = (string) interleaved, "
63         "rate = (int) [ 6000, 48000 ], "
64         "channels = (int) 1; "
65         "audio/x-raw, "
66         "format = (string) " FORMAT_STR ", "
67         "layout = (string) interleaved, "
68         "rate = (int) [ 6000, 48000 ], "
69         "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
70     );
71
72 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
73     GST_PAD_SRC,
74     GST_PAD_ALWAYS,
75     GST_STATIC_CAPS ("audio/x-speex, "
76         "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
77     );
78
79 #define DEFAULT_QUALITY         8.0
80 #define DEFAULT_BITRATE         0
81 #define DEFAULT_MODE            GST_SPEEX_ENC_MODE_AUTO
82 #define DEFAULT_VBR             FALSE
83 #define DEFAULT_ABR             0
84 #define DEFAULT_VAD             FALSE
85 #define DEFAULT_DTX             FALSE
86 #define DEFAULT_COMPLEXITY      3
87 #define DEFAULT_NFRAMES         1
88
89 enum
90 {
91   PROP_0,
92   PROP_QUALITY,
93   PROP_BITRATE,
94   PROP_MODE,
95   PROP_VBR,
96   PROP_ABR,
97   PROP_VAD,
98   PROP_DTX,
99   PROP_COMPLEXITY,
100   PROP_NFRAMES,
101   PROP_LAST_MESSAGE
102 };
103
104 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
105 static GType
106 gst_speex_enc_mode_get_type (void)
107 {
108   static GType speex_enc_mode_type = 0;
109   static const GEnumValue speex_enc_modes[] = {
110     {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
111     {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
112     {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
113     {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
114     {0, NULL, NULL},
115   };
116   if (G_UNLIKELY (speex_enc_mode_type == 0)) {
117     speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
118         speex_enc_modes);
119   }
120   return speex_enc_mode_type;
121 }
122
123 static void gst_speex_enc_finalize (GObject * object);
124
125 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
126
127 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
128     GValue * value, GParamSpec * pspec);
129 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
130     const GValue * value, GParamSpec * pspec);
131
132 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf);
133
134 static gboolean gst_speex_enc_start (GstAudioEncoder * enc);
135 static gboolean gst_speex_enc_stop (GstAudioEncoder * enc);
136 static gboolean gst_speex_enc_set_format (GstAudioEncoder * enc,
137     GstAudioInfo * info);
138 static GstFlowReturn gst_speex_enc_handle_frame (GstAudioEncoder * enc,
139     GstBuffer * in_buf);
140 static gboolean gst_speex_enc_sink_event (GstAudioEncoder * enc,
141     GstEvent * event);
142
143 #define gst_speex_enc_parent_class parent_class
144 G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
145     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
146     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
147
148 static void
149 gst_speex_enc_class_init (GstSpeexEncClass * klass)
150 {
151   GObjectClass *gobject_class;
152   GstElementClass *gstelement_class;
153   GstAudioEncoderClass *base_class;
154
155   gobject_class = (GObjectClass *) klass;
156   gstelement_class = (GstElementClass *) klass;
157   base_class = (GstAudioEncoderClass *) klass;
158
159   gobject_class->finalize = gst_speex_enc_finalize;
160   gobject_class->set_property = gst_speex_enc_set_property;
161   gobject_class->get_property = gst_speex_enc_get_property;
162
163   base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
164   base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
165   base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
166   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
167   base_class->sink_event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
168
169   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
170       g_param_spec_float ("quality", "Quality", "Encoding quality",
171           0.0, 10.0, DEFAULT_QUALITY,
172           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
173   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
174       g_param_spec_int ("bitrate", "Encoding Bit-rate",
175           "Specify an encoding bit-rate (in bps). (0 = automatic)",
176           0, G_MAXINT, DEFAULT_BITRATE,
177           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178   g_object_class_install_property (gobject_class, PROP_MODE,
179       g_param_spec_enum ("mode", "Mode", "The encoding mode",
180           GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
181           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
183       g_param_spec_boolean ("vbr", "VBR",
184           "Enable variable bit-rate", DEFAULT_VBR,
185           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
186   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
187       g_param_spec_int ("abr", "ABR",
188           "Enable average bit-rate (0 = disabled)",
189           0, G_MAXINT, DEFAULT_ABR,
190           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
191   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
192       g_param_spec_boolean ("vad", "VAD",
193           "Enable voice activity detection", DEFAULT_VAD,
194           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
195   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
196       g_param_spec_boolean ("dtx", "DTX",
197           "Enable discontinuous transmission", DEFAULT_DTX,
198           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
199   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
200       g_param_spec_int ("complexity", "Complexity",
201           "Set encoding complexity",
202           0, G_MAXINT, DEFAULT_COMPLEXITY,
203           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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,
208           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
210       g_param_spec_string ("last-message", "last-message",
211           "The last status message", NULL,
212           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
213
214   gst_element_class_add_pad_template (gstelement_class,
215       gst_static_pad_template_get (&src_factory));
216   gst_element_class_add_pad_template (gstelement_class,
217       gst_static_pad_template_get (&sink_factory));
218   gst_element_class_set_static_metadata (gstelement_class,
219       "Speex audio encoder", "Codec/Encoder/Audio",
220       "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
221
222   GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
223 }
224
225 static void
226 gst_speex_enc_finalize (GObject * object)
227 {
228   GstSpeexEnc *enc;
229
230   enc = GST_SPEEX_ENC (object);
231
232   g_free (enc->last_message);
233
234   G_OBJECT_CLASS (parent_class)->finalize (object);
235 }
236
237 static void
238 gst_speex_enc_init (GstSpeexEnc * enc)
239 {
240   GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
241
242   /* arrange granulepos marking (and required perfect ts) */
243   gst_audio_encoder_set_mark_granule (benc, TRUE);
244   gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
245 }
246
247 static gboolean
248 gst_speex_enc_start (GstAudioEncoder * benc)
249 {
250   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
251
252   GST_DEBUG_OBJECT (enc, "start");
253   speex_bits_init (&enc->bits);
254   enc->tags = gst_tag_list_new_empty ();
255   enc->header_sent = FALSE;
256
257   return TRUE;
258 }
259
260 static gboolean
261 gst_speex_enc_stop (GstAudioEncoder * benc)
262 {
263   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
264
265   GST_DEBUG_OBJECT (enc, "stop");
266   enc->header_sent = FALSE;
267   if (enc->state) {
268     speex_encoder_destroy (enc->state);
269     enc->state = NULL;
270   }
271   speex_bits_destroy (&enc->bits);
272   speex_bits_set_bit_buffer (&enc->bits, NULL, 0);
273   gst_tag_list_unref (enc->tags);
274   enc->tags = NULL;
275
276   gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
277
278   return TRUE;
279 }
280
281 static gint64
282 gst_speex_enc_get_latency (GstSpeexEnc * enc)
283 {
284   /* See the Speex manual section "Latency and algorithmic delay" */
285   if (enc->rate == 8000)
286     return 30 * GST_MSECOND;
287   else
288     return 34 * GST_MSECOND;
289 }
290
291 static gboolean
292 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
293 {
294   GstSpeexEnc *enc;
295
296   enc = GST_SPEEX_ENC (benc);
297
298   enc->channels = GST_AUDIO_INFO_CHANNELS (info);
299   enc->rate = GST_AUDIO_INFO_RATE (info);
300
301   /* handle reconfigure */
302   if (enc->state) {
303     speex_encoder_destroy (enc->state);
304     enc->state = NULL;
305   }
306
307   if (!gst_speex_enc_setup (enc))
308     return FALSE;
309
310   /* feedback to base class */
311   gst_audio_encoder_set_latency (benc,
312       gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
313   gst_audio_encoder_set_lookahead (benc, enc->lookahead);
314
315   if (enc->nframes == 0) {
316     /* as many frames as available input allows */
317     gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
318     gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
319     gst_audio_encoder_set_frame_max (benc, 0);
320   } else {
321     /* exactly as many frames as configured */
322     gst_audio_encoder_set_frame_samples_min (benc,
323         enc->frame_size * enc->nframes);
324     gst_audio_encoder_set_frame_samples_max (benc,
325         enc->frame_size * enc->nframes);
326     gst_audio_encoder_set_frame_max (benc, 1);
327   }
328
329   return TRUE;
330 }
331
332 static GstBuffer *
333 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
334 {
335   const GstTagList *user_tags;
336   GstTagList *merged_tags;
337   GstBuffer *comments = NULL;
338
339   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
340
341   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
342   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
343
344   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
345   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
346       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
347
348   if (merged_tags == NULL)
349     merged_tags = gst_tag_list_new_empty ();
350
351   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
352   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
353       0, "Encoded with GStreamer Speexenc");
354   gst_tag_list_unref (merged_tags);
355
356   GST_BUFFER_OFFSET (comments) = 0;
357   GST_BUFFER_OFFSET_END (comments) = 0;
358
359   return comments;
360 }
361
362 static void
363 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
364 {
365   g_free (enc->last_message);
366   enc->last_message = g_strdup (msg);
367   GST_WARNING_OBJECT (enc, "%s", msg);
368   g_object_notify (G_OBJECT (enc), "last-message");
369 }
370
371 static gboolean
372 gst_speex_enc_setup (GstSpeexEnc * enc)
373 {
374   switch (enc->mode) {
375     case GST_SPEEX_ENC_MODE_UWB:
376       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
377       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
378       break;
379     case GST_SPEEX_ENC_MODE_WB:
380       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
381       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
382       break;
383     case GST_SPEEX_ENC_MODE_NB:
384       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
385       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
386       break;
387     case GST_SPEEX_ENC_MODE_AUTO:
388       /* fall through */
389       GST_LOG_OBJECT (enc, "finding best mode");
390     default:
391       break;
392   }
393
394   if (enc->rate > 25000) {
395     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
396       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
397       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
398     } else {
399       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
400         gst_speex_enc_set_last_msg (enc,
401             "Warning: suggest to use ultra wide band mode for this rate");
402       }
403     }
404   } else if (enc->rate > 12500) {
405     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
406       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
407       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
408     } else {
409       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
410         gst_speex_enc_set_last_msg (enc,
411             "Warning: suggest to use wide band mode for this rate");
412       }
413     }
414   } else {
415     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
416       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
417       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
418     } else {
419       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
420         gst_speex_enc_set_last_msg (enc,
421             "Warning: suggest to use narrow band mode for this rate");
422       }
423     }
424   }
425
426   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
427     gst_speex_enc_set_last_msg (enc,
428         "Warning: speex is optimized for 8, 16 and 32 KHz");
429   }
430
431   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
432   enc->header.frames_per_packet = enc->nframes;
433   enc->header.vbr = enc->vbr;
434   enc->header.nb_channels = enc->channels;
435
436   /*Initialize Speex encoder */
437   enc->state = speex_encoder_init (enc->speex_mode);
438
439   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
440   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
441   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
442
443   if (enc->vbr)
444     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
445   else {
446     gint tmp = floor (enc->quality);
447
448     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
449   }
450   if (enc->bitrate) {
451     if (enc->quality >= 0.0 && enc->vbr) {
452       gst_speex_enc_set_last_msg (enc,
453           "Warning: bitrate option is overriding quality");
454     }
455     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
456   }
457   if (enc->vbr) {
458     gint tmp = 1;
459
460     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
461   } else if (enc->vad) {
462     gint tmp = 1;
463
464     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
465   }
466
467   if (enc->dtx) {
468     gint tmp = 1;
469
470     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
471   }
472
473   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
474     gst_speex_enc_set_last_msg (enc,
475         "Warning: dtx is useless without vad, vbr or abr");
476   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
477     gst_speex_enc_set_last_msg (enc,
478         "Warning: vad is already implied by vbr or abr");
479   }
480
481   if (enc->abr) {
482     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
483   }
484
485   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
486
487   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
488       enc->lookahead);
489
490   return TRUE;
491 }
492
493 static gboolean
494 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
495 {
496   GstSpeexEnc *enc;
497
498   enc = GST_SPEEX_ENC (benc);
499
500   switch (GST_EVENT_TYPE (event)) {
501     case GST_EVENT_TAG:
502     {
503       if (enc->tags) {
504         GstTagList *list;
505
506         gst_event_parse_tag (event, &list);
507         gst_tag_list_insert (enc->tags, list,
508             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
509       } else {
510         g_assert_not_reached ();
511       }
512       break;
513     }
514     default:
515       break;
516   }
517
518   /* we only peeked, let base class handle it */
519   return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
520 }
521
522 static GstFlowReturn
523 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
524 {
525   gint frame_size = enc->frame_size;
526   gint bytes = frame_size * 2 * enc->channels, samples;
527   gint outsize, written, dtx_ret = 0;
528   GstMapInfo map;
529   guint8 *data, *data0 = NULL, *bdata;
530   gsize bsize, size;
531   GstBuffer *outbuf;
532   GstFlowReturn ret = GST_FLOW_OK;
533
534   if (G_LIKELY (buf)) {
535     gst_buffer_map (buf, &map, GST_MAP_READ);
536     bdata = map.data;
537     bsize = map.size;
538
539     if (G_UNLIKELY (bsize % bytes)) {
540       GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
541
542       size = ((bsize / bytes) + 1) * bytes;
543       data0 = data = g_malloc0 (size);
544       memcpy (data, bdata, bsize);
545       gst_buffer_unmap (buf, &map);
546       bdata = NULL;
547     } else {
548       data = bdata;
549       size = bsize;
550     }
551   } else {
552     GST_DEBUG_OBJECT (enc, "nothing to drain");
553     goto done;
554   }
555
556   samples = size / (2 * enc->channels);
557   speex_bits_reset (&enc->bits);
558
559   /* FIXME what about dropped samples if DTS enabled ?? */
560
561   while (size) {
562     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
563
564     if (enc->channels == 2) {
565       speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
566     }
567     dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
568
569     data += bytes;
570     size -= bytes;
571   }
572
573   speex_bits_insert_terminator (&enc->bits);
574   outsize = speex_bits_nbytes (&enc->bits);
575
576   if (bdata)
577     gst_buffer_unmap (buf, &map);
578
579 #if 0
580   ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
581       GST_BUFFER_OFFSET_NONE, outsize,
582       GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
583
584   if ((GST_FLOW_OK != ret))
585     goto done;
586 #endif
587   outbuf = gst_buffer_new_allocate (NULL, outsize, NULL);
588   gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
589
590   written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);
591
592   if (G_UNLIKELY (written < outsize)) {
593     GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
594   } else if (G_UNLIKELY (written > outsize)) {
595     GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
596     written = outsize;
597   }
598   gst_buffer_unmap (outbuf, &map);
599   gst_buffer_resize (outbuf, 0, written);
600
601   if (!dtx_ret)
602     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
603
604   ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
605       outbuf, samples);
606
607 done:
608   g_free (data0);
609   return ret;
610 }
611
612 /*
613  * (really really) FIXME: move into core (dixit tpm)
614  */
615 /*
616  * _gst_caps_set_buffer_array:
617  * @caps: (transfer full): a #GstCaps
618  * @field: field in caps to set
619  * @buf: header buffers
620  *
621  * Adds given buffers to an array of buffers set as the given @field
622  * on the given @caps.  List of buffer arguments must be NULL-terminated.
623  *
624  * Returns: (transfer full): input caps with a streamheader field added, or NULL
625  *     if some error occurred
626  */
627 static GstCaps *
628 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
629     GstBuffer * buf, ...)
630 {
631   GstStructure *structure = NULL;
632   va_list va;
633   GValue array = { 0 };
634   GValue value = { 0 };
635
636   g_return_val_if_fail (caps != NULL, NULL);
637   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
638   g_return_val_if_fail (field != NULL, NULL);
639
640   caps = gst_caps_make_writable (caps);
641   structure = gst_caps_get_structure (caps, 0);
642
643   g_value_init (&array, GST_TYPE_ARRAY);
644
645   va_start (va, buf);
646   /* put buffers in a fixed list */
647   while (buf) {
648     g_assert (gst_buffer_is_writable (buf));
649
650     /* mark buffer */
651     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
652
653     g_value_init (&value, GST_TYPE_BUFFER);
654     buf = gst_buffer_copy (buf);
655     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
656     gst_value_set_buffer (&value, buf);
657     gst_buffer_unref (buf);
658     gst_value_array_append_value (&array, &value);
659     g_value_unset (&value);
660
661     buf = va_arg (va, GstBuffer *);
662   }
663   va_end (va);
664
665   gst_structure_set_value (structure, field, &array);
666   g_value_unset (&array);
667
668   return caps;
669 }
670
671 static GstFlowReturn
672 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
673 {
674   GstSpeexEnc *enc;
675   GstFlowReturn ret = GST_FLOW_OK;
676
677   enc = GST_SPEEX_ENC (benc);
678
679   if (!enc->header_sent) {
680     /* Speex streams begin with two headers; the initial header (with
681        most of the codec setup parameters) which is mandated by the Ogg
682        bitstream spec.  The second header holds any comment fields.
683        We merely need to make the headers, then pass them to libspeex 
684        one at a time; libspeex handles the additional Ogg bitstream 
685        constraints */
686     GstBuffer *buf1, *buf2;
687     GstCaps *caps;
688     guchar *data;
689     gint data_len;
690     GList *headers;
691
692     /* create header buffer */
693     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
694     buf1 = gst_buffer_new_wrapped (data, data_len);
695     GST_BUFFER_OFFSET_END (buf1) = 0;
696     GST_BUFFER_OFFSET (buf1) = 0;
697
698     /* create comment buffer */
699     buf2 = gst_speex_enc_create_metadata_buffer (enc);
700
701     /* mark and put on caps */
702     caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
703         "channels", G_TYPE_INT, enc->channels, NULL);
704     caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
705
706     /* negotiate with these caps */
707     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
708
709     gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
710     gst_caps_unref (caps);
711
712     /* push out buffers */
713     /* store buffers for later pre_push sending */
714     headers = NULL;
715     GST_DEBUG_OBJECT (enc, "storing header buffers");
716     headers = g_list_prepend (headers, buf2);
717     headers = g_list_prepend (headers, buf1);
718     gst_audio_encoder_set_headers (benc, headers);
719
720     enc->header_sent = TRUE;
721   }
722
723   GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
724       buf ? gst_buffer_get_size (buf) : 0);
725
726   ret = gst_speex_enc_encode (enc, buf);
727
728   return ret;
729 }
730
731 static void
732 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
733     GParamSpec * pspec)
734 {
735   GstSpeexEnc *enc;
736
737   enc = GST_SPEEX_ENC (object);
738
739   switch (prop_id) {
740     case PROP_QUALITY:
741       g_value_set_float (value, enc->quality);
742       break;
743     case PROP_BITRATE:
744       g_value_set_int (value, enc->bitrate);
745       break;
746     case PROP_MODE:
747       g_value_set_enum (value, enc->mode);
748       break;
749     case PROP_VBR:
750       g_value_set_boolean (value, enc->vbr);
751       break;
752     case PROP_ABR:
753       g_value_set_int (value, enc->abr);
754       break;
755     case PROP_VAD:
756       g_value_set_boolean (value, enc->vad);
757       break;
758     case PROP_DTX:
759       g_value_set_boolean (value, enc->dtx);
760       break;
761     case PROP_COMPLEXITY:
762       g_value_set_int (value, enc->complexity);
763       break;
764     case PROP_NFRAMES:
765       g_value_set_int (value, enc->nframes);
766       break;
767     case PROP_LAST_MESSAGE:
768       g_value_set_string (value, enc->last_message);
769       break;
770     default:
771       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
772       break;
773   }
774 }
775
776 static void
777 gst_speex_enc_set_property (GObject * object, guint prop_id,
778     const GValue * value, GParamSpec * pspec)
779 {
780   GstSpeexEnc *enc;
781
782   enc = GST_SPEEX_ENC (object);
783
784   switch (prop_id) {
785     case PROP_QUALITY:
786       enc->quality = g_value_get_float (value);
787       break;
788     case PROP_BITRATE:
789       enc->bitrate = g_value_get_int (value);
790       break;
791     case PROP_MODE:
792       enc->mode = g_value_get_enum (value);
793       break;
794     case PROP_VBR:
795       enc->vbr = g_value_get_boolean (value);
796       break;
797     case PROP_ABR:
798       enc->abr = g_value_get_int (value);
799       break;
800     case PROP_VAD:
801       enc->vad = g_value_get_boolean (value);
802       break;
803     case PROP_DTX:
804       enc->dtx = g_value_get_boolean (value);
805       break;
806     case PROP_COMPLEXITY:
807       enc->complexity = g_value_get_int (value);
808       break;
809     case PROP_NFRAMES:
810       enc->nframes = g_value_get_int (value);
811       break;
812     default:
813       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
814       break;
815   }
816 }