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