speex: Update for the new raw audio caps
[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., 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 #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 static GstFlowReturn
143 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer);
144
145 #define gst_speex_enc_parent_class parent_class
146 G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
147     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
148     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
149
150 static void
151 gst_speex_enc_class_init (GstSpeexEncClass * klass)
152 {
153   GObjectClass *gobject_class;
154   GstElementClass *gstelement_class;
155   GstAudioEncoderClass *base_class;
156
157   gobject_class = (GObjectClass *) klass;
158   gstelement_class = (GstElementClass *) klass;
159   base_class = (GstAudioEncoderClass *) klass;
160
161   gobject_class->finalize = gst_speex_enc_finalize;
162   gobject_class->set_property = gst_speex_enc_set_property;
163   gobject_class->get_property = gst_speex_enc_get_property;
164
165   base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
166   base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
167   base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
168   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
169   base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
170   base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
171
172   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
173       g_param_spec_float ("quality", "Quality", "Encoding quality",
174           0.0, 10.0, DEFAULT_QUALITY,
175           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
176   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
177       g_param_spec_int ("bitrate", "Encoding Bit-rate",
178           "Specify an encoding bit-rate (in bps). (0 = automatic)",
179           0, G_MAXINT, DEFAULT_BITRATE,
180           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
181   g_object_class_install_property (gobject_class, PROP_MODE,
182       g_param_spec_enum ("mode", "Mode", "The encoding mode",
183           GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
184           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
185   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
186       g_param_spec_boolean ("vbr", "VBR",
187           "Enable variable bit-rate", DEFAULT_VBR,
188           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
189   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
190       g_param_spec_int ("abr", "ABR",
191           "Enable average bit-rate (0 = disabled)",
192           0, G_MAXINT, DEFAULT_ABR,
193           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
194   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
195       g_param_spec_boolean ("vad", "VAD",
196           "Enable voice activity detection", DEFAULT_VAD,
197           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
199       g_param_spec_boolean ("dtx", "DTX",
200           "Enable discontinuous transmission", DEFAULT_DTX,
201           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
203       g_param_spec_int ("complexity", "Complexity",
204           "Set encoding complexity",
205           0, G_MAXINT, DEFAULT_COMPLEXITY,
206           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
208       g_param_spec_int ("nframes", "NFrames",
209           "Number of frames per buffer",
210           0, G_MAXINT, DEFAULT_NFRAMES,
211           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
212   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
213       g_param_spec_string ("last-message", "last-message",
214           "The last status message", NULL,
215           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
216
217   gst_element_class_add_pad_template (gstelement_class,
218       gst_static_pad_template_get (&src_factory));
219   gst_element_class_add_pad_template (gstelement_class,
220       gst_static_pad_template_get (&sink_factory));
221   gst_element_class_set_details_simple (gstelement_class, "Speex audio encoder",
222       "Codec/Encoder/Audio",
223       "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
224
225   GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
226 }
227
228 static void
229 gst_speex_enc_finalize (GObject * object)
230 {
231   GstSpeexEnc *enc;
232
233   enc = GST_SPEEX_ENC (object);
234
235   g_free (enc->last_message);
236
237   G_OBJECT_CLASS (parent_class)->finalize (object);
238 }
239
240 static void
241 gst_speex_enc_init (GstSpeexEnc * enc)
242 {
243   GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
244
245   /* arrange granulepos marking (and required perfect ts) */
246   gst_audio_encoder_set_mark_granule (benc, TRUE);
247   gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
248 }
249
250 static gboolean
251 gst_speex_enc_start (GstAudioEncoder * benc)
252 {
253   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
254
255   GST_DEBUG_OBJECT (enc, "start");
256   speex_bits_init (&enc->bits);
257   enc->tags = gst_tag_list_new_empty ();
258   enc->header_sent = FALSE;
259
260   return TRUE;
261 }
262
263 static gboolean
264 gst_speex_enc_stop (GstAudioEncoder * benc)
265 {
266   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
267
268   GST_DEBUG_OBJECT (enc, "stop");
269   enc->header_sent = FALSE;
270   if (enc->state) {
271     speex_encoder_destroy (enc->state);
272     enc->state = NULL;
273   }
274   speex_bits_destroy (&enc->bits);
275   gst_tag_list_free (enc->tags);
276   enc->tags = NULL;
277   g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
278   enc->headers = NULL;
279
280   gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
281
282   return TRUE;
283 }
284
285 static gint64
286 gst_speex_enc_get_latency (GstSpeexEnc * enc)
287 {
288   /* See the Speex manual section "Latency and algorithmic delay" */
289   if (enc->rate == 8000)
290     return 30 * GST_MSECOND;
291   else
292     return 34 * GST_MSECOND;
293 }
294
295 static gboolean
296 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
297 {
298   GstSpeexEnc *enc;
299
300   enc = GST_SPEEX_ENC (benc);
301
302   enc->channels = GST_AUDIO_INFO_CHANNELS (info);
303   enc->rate = GST_AUDIO_INFO_RATE (info);
304
305   /* handle reconfigure */
306   if (enc->state) {
307     speex_encoder_destroy (enc->state);
308     enc->state = NULL;
309   }
310
311   if (!gst_speex_enc_setup (enc))
312     return FALSE;
313
314   /* feedback to base class */
315   gst_audio_encoder_set_latency (benc,
316       gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
317   gst_audio_encoder_set_lookahead (benc, enc->lookahead);
318
319   if (enc->nframes == 0) {
320     /* as many frames as available input allows */
321     gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
322     gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
323     gst_audio_encoder_set_frame_max (benc, 0);
324   } else {
325     /* exactly as many frames as configured */
326     gst_audio_encoder_set_frame_samples_min (benc,
327         enc->frame_size * enc->nframes);
328     gst_audio_encoder_set_frame_samples_max (benc,
329         enc->frame_size * enc->nframes);
330     gst_audio_encoder_set_frame_max (benc, 1);
331   }
332
333   return TRUE;
334 }
335
336 static GstBuffer *
337 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
338 {
339   const GstTagList *user_tags;
340   GstTagList *merged_tags;
341   GstBuffer *comments = NULL;
342
343   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
344
345   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
346   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
347
348   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
349   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
350       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
351
352   if (merged_tags == NULL)
353     merged_tags = gst_tag_list_new_empty ();
354
355   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
356   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
357       0, "Encoded with GStreamer Speexenc");
358   gst_tag_list_free (merged_tags);
359
360   GST_BUFFER_OFFSET (comments) = 0;
361   GST_BUFFER_OFFSET_END (comments) = 0;
362
363   return comments;
364 }
365
366 static void
367 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
368 {
369   g_free (enc->last_message);
370   enc->last_message = g_strdup (msg);
371   GST_WARNING_OBJECT (enc, "%s", msg);
372   g_object_notify (G_OBJECT (enc), "last-message");
373 }
374
375 static gboolean
376 gst_speex_enc_setup (GstSpeexEnc * enc)
377 {
378   switch (enc->mode) {
379     case GST_SPEEX_ENC_MODE_UWB:
380       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
381       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
382       break;
383     case GST_SPEEX_ENC_MODE_WB:
384       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
385       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
386       break;
387     case GST_SPEEX_ENC_MODE_NB:
388       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
389       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
390       break;
391     case GST_SPEEX_ENC_MODE_AUTO:
392       /* fall through */
393       GST_LOG_OBJECT (enc, "finding best mode");
394     default:
395       break;
396   }
397
398   if (enc->rate > 25000) {
399     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
400       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
401       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
402     } else {
403       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
404         gst_speex_enc_set_last_msg (enc,
405             "Warning: suggest to use ultra wide band mode for this rate");
406       }
407     }
408   } else if (enc->rate > 12500) {
409     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
410       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
411       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
412     } else {
413       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
414         gst_speex_enc_set_last_msg (enc,
415             "Warning: suggest to use wide band mode for this rate");
416       }
417     }
418   } else {
419     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
420       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
421       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
422     } else {
423       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
424         gst_speex_enc_set_last_msg (enc,
425             "Warning: suggest to use narrow band mode for this rate");
426       }
427     }
428   }
429
430   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
431     gst_speex_enc_set_last_msg (enc,
432         "Warning: speex is optimized for 8, 16 and 32 KHz");
433   }
434
435   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
436   enc->header.frames_per_packet = enc->nframes;
437   enc->header.vbr = enc->vbr;
438   enc->header.nb_channels = enc->channels;
439
440   /*Initialize Speex encoder */
441   enc->state = speex_encoder_init (enc->speex_mode);
442
443   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
444   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
445   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
446
447   if (enc->vbr)
448     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
449   else {
450     gint tmp = floor (enc->quality);
451
452     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
453   }
454   if (enc->bitrate) {
455     if (enc->quality >= 0.0 && enc->vbr) {
456       gst_speex_enc_set_last_msg (enc,
457           "Warning: bitrate option is overriding quality");
458     }
459     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
460   }
461   if (enc->vbr) {
462     gint tmp = 1;
463
464     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
465   } else if (enc->vad) {
466     gint tmp = 1;
467
468     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
469   }
470
471   if (enc->dtx) {
472     gint tmp = 1;
473
474     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
475   }
476
477   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
478     gst_speex_enc_set_last_msg (enc,
479         "Warning: dtx is useless without vad, vbr or abr");
480   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
481     gst_speex_enc_set_last_msg (enc,
482         "Warning: vad is already implied by vbr or abr");
483   }
484
485   if (enc->abr) {
486     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
487   }
488
489   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
490
491   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
492       enc->lookahead);
493
494   return TRUE;
495 }
496
497 /* push out the buffer */
498 static GstFlowReturn
499 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
500 {
501   GST_DEBUG_OBJECT (enc, "pushing output buffer of size %" G_GSIZE_FORMAT,
502       gst_buffer_get_size (buffer));
503
504   return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
505 }
506
507 static gboolean
508 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
509 {
510   GstSpeexEnc *enc;
511
512   enc = GST_SPEEX_ENC (benc);
513
514   switch (GST_EVENT_TYPE (event)) {
515     case GST_EVENT_TAG:
516     {
517       if (enc->tags) {
518         GstTagList *list;
519
520         gst_event_parse_tag (event, &list);
521         gst_tag_list_insert (enc->tags, list,
522             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
523       } else {
524         g_assert_not_reached ();
525       }
526       break;
527     }
528     default:
529       break;
530   }
531
532   /* we only peeked, let base class handle it */
533   return FALSE;
534 }
535
536 static GstFlowReturn
537 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
538 {
539   gint frame_size = enc->frame_size;
540   gint bytes = frame_size * 2 * enc->channels, samples;
541   gint outsize, written, dtx_ret = 0;
542   guint8 *data, *data0 = NULL, *bdata, *outdata;
543   gsize bsize, size;
544   GstBuffer *outbuf;
545   GstFlowReturn ret = GST_FLOW_OK;
546
547   if (G_LIKELY (buf)) {
548     bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
549
550     if (G_UNLIKELY (bsize % bytes)) {
551       GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
552
553       size = ((bsize / bytes) + 1) * bytes;
554       data0 = data = g_malloc0 (size);
555       memcpy (data, bdata, bsize);
556       gst_buffer_unmap (buf, bdata, bsize);
557       bdata = NULL;
558     } else {
559       data = bdata;
560       size = bsize;
561     }
562   } else {
563     GST_DEBUG_OBJECT (enc, "nothing to drain");
564     goto done;
565   }
566
567   samples = size / (2 * enc->channels);
568   speex_bits_reset (&enc->bits);
569
570   /* FIXME what about dropped samples if DTS enabled ?? */
571
572   while (size) {
573     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
574
575     if (enc->channels == 2) {
576       speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
577     }
578     dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
579
580     data += bytes;
581     size -= bytes;
582   }
583
584   speex_bits_insert_terminator (&enc->bits);
585   outsize = speex_bits_nbytes (&enc->bits);
586
587   if (bdata)
588     gst_buffer_unmap (buf, bdata, bsize);
589
590 #if 0
591   ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
592       GST_BUFFER_OFFSET_NONE, outsize,
593       GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
594
595   if ((GST_FLOW_OK != ret))
596     goto done;
597 #endif
598   outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
599   outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
600
601   written = speex_bits_write (&enc->bits, (gchar *) outdata, outsize);
602
603   if (G_UNLIKELY (written < outsize)) {
604     GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
605   } else if (G_UNLIKELY (written > outsize)) {
606     GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
607     written = outsize;
608   }
609   gst_buffer_unmap (outbuf, outdata, written);
610
611   if (!dtx_ret)
612     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
613
614   ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
615       outbuf, samples);
616
617 done:
618   g_free (data0);
619   return ret;
620 }
621
622 /*
623  * (really really) FIXME: move into core (dixit tpm)
624  */
625 /**
626  * _gst_caps_set_buffer_array:
627  * @caps: a #GstCaps
628  * @field: field in caps to set
629  * @buf: header buffers
630  *
631  * Adds given buffers to an array of buffers set as the given @field
632  * on the given @caps.  List of buffer arguments must be NULL-terminated.
633  *
634  * Returns: input caps with a streamheader field added, or NULL if some error
635  */
636 static GstCaps *
637 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
638     GstBuffer * buf, ...)
639 {
640   GstStructure *structure = NULL;
641   va_list va;
642   GValue array = { 0 };
643   GValue value = { 0 };
644
645   g_return_val_if_fail (caps != NULL, NULL);
646   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
647   g_return_val_if_fail (field != NULL, NULL);
648
649   caps = gst_caps_make_writable (caps);
650   structure = gst_caps_get_structure (caps, 0);
651
652   g_value_init (&array, GST_TYPE_ARRAY);
653
654   va_start (va, buf);
655   /* put buffers in a fixed list */
656   while (buf) {
657     g_assert (gst_buffer_is_writable (buf));
658
659     /* mark buffer */
660     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
661
662     g_value_init (&value, GST_TYPE_BUFFER);
663     buf = gst_buffer_copy (buf);
664     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
665     gst_value_set_buffer (&value, buf);
666     gst_buffer_unref (buf);
667     gst_value_array_append_value (&array, &value);
668     g_value_unset (&value);
669
670     buf = va_arg (va, GstBuffer *);
671   }
672
673   gst_structure_set_value (structure, field, &array);
674   g_value_unset (&array);
675
676   return caps;
677 }
678
679 static GstFlowReturn
680 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
681 {
682   GstSpeexEnc *enc;
683   GstFlowReturn ret = GST_FLOW_OK;
684
685   enc = GST_SPEEX_ENC (benc);
686
687   if (!enc->header_sent) {
688     /* Speex streams begin with two headers; the initial header (with
689        most of the codec setup parameters) which is mandated by the Ogg
690        bitstream spec.  The second header holds any comment fields.
691        We merely need to make the headers, then pass them to libspeex 
692        one at a time; libspeex handles the additional Ogg bitstream 
693        constraints */
694     GstBuffer *buf1, *buf2;
695     GstCaps *caps;
696     guchar *data;
697     gint data_len;
698
699     /* create header buffer */
700     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
701     buf1 = gst_buffer_new_wrapped (data, data_len);
702     GST_BUFFER_OFFSET_END (buf1) = 0;
703     GST_BUFFER_OFFSET (buf1) = 0;
704
705     /* create comment buffer */
706     buf2 = gst_speex_enc_create_metadata_buffer (enc);
707
708     /* mark and put on caps */
709     caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
710         "channels", G_TYPE_INT, enc->channels, NULL);
711     caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
712
713     /* negotiate with these caps */
714     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
715
716     gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
717     gst_caps_unref (caps);
718
719     /* push out buffers */
720     /* store buffers for later pre_push sending */
721     g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
722     enc->headers = NULL;
723     GST_DEBUG_OBJECT (enc, "storing header buffers");
724     enc->headers = g_slist_prepend (enc->headers, buf2);
725     enc->headers = g_slist_prepend (enc->headers, buf1);
726
727     enc->header_sent = TRUE;
728   }
729
730   GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
731       buf ? gst_buffer_get_size (buf) : 0);
732
733   ret = gst_speex_enc_encode (enc, buf);
734
735   return ret;
736 }
737
738 static GstFlowReturn
739 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
740 {
741   GstSpeexEnc *enc;
742   GstFlowReturn ret = GST_FLOW_OK;
743
744   enc = GST_SPEEX_ENC (benc);
745
746   /* FIXME 0.11 ? get rid of this special ogg stuff and have it
747    * put and use 'codec data' in caps like anything else,
748    * with all the usual out-of-band advantage etc */
749   if (G_UNLIKELY (enc->headers)) {
750     GSList *header = enc->headers;
751
752     /* try to push all of these, if we lose one, might as well lose all */
753     while (header) {
754       if (ret == GST_FLOW_OK)
755         ret = gst_speex_enc_push_buffer (enc, header->data);
756       else
757         gst_speex_enc_push_buffer (enc, header->data);
758       header = g_slist_next (header);
759     }
760
761     g_slist_free (enc->headers);
762     enc->headers = NULL;
763   }
764
765   return ret;
766 }
767
768 static void
769 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
770     GParamSpec * pspec)
771 {
772   GstSpeexEnc *enc;
773
774   enc = GST_SPEEX_ENC (object);
775
776   switch (prop_id) {
777     case PROP_QUALITY:
778       g_value_set_float (value, enc->quality);
779       break;
780     case PROP_BITRATE:
781       g_value_set_int (value, enc->bitrate);
782       break;
783     case PROP_MODE:
784       g_value_set_enum (value, enc->mode);
785       break;
786     case PROP_VBR:
787       g_value_set_boolean (value, enc->vbr);
788       break;
789     case PROP_ABR:
790       g_value_set_int (value, enc->abr);
791       break;
792     case PROP_VAD:
793       g_value_set_boolean (value, enc->vad);
794       break;
795     case PROP_DTX:
796       g_value_set_boolean (value, enc->dtx);
797       break;
798     case PROP_COMPLEXITY:
799       g_value_set_int (value, enc->complexity);
800       break;
801     case PROP_NFRAMES:
802       g_value_set_int (value, enc->nframes);
803       break;
804     case PROP_LAST_MESSAGE:
805       g_value_set_string (value, enc->last_message);
806       break;
807     default:
808       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
809       break;
810   }
811 }
812
813 static void
814 gst_speex_enc_set_property (GObject * object, guint prop_id,
815     const GValue * value, GParamSpec * pspec)
816 {
817   GstSpeexEnc *enc;
818
819   enc = GST_SPEEX_ENC (object);
820
821   switch (prop_id) {
822     case PROP_QUALITY:
823       enc->quality = g_value_get_float (value);
824       break;
825     case PROP_BITRATE:
826       enc->bitrate = g_value_get_int (value);
827       break;
828     case PROP_MODE:
829       enc->mode = g_value_get_enum (value);
830       break;
831     case PROP_VBR:
832       enc->vbr = g_value_get_boolean (value);
833       break;
834     case PROP_ABR:
835       enc->abr = g_value_get_int (value);
836       break;
837     case PROP_VAD:
838       enc->vad = g_value_get_boolean (value);
839       break;
840     case PROP_DTX:
841       enc->dtx = g_value_get_boolean (value);
842       break;
843     case PROP_COMPLEXITY:
844       enc->complexity = g_value_get_int (value);
845       break;
846     case PROP_NFRAMES:
847       enc->nframes = g_value_get_int (value);
848       break;
849     default:
850       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
851       break;
852   }
853 }