Merge branch 'master' into 0.11
[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 #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         "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2 ]")
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 #if 0
117 static const GstFormat *
118 gst_speex_enc_get_formats (GstPad * pad)
119 {
120   static const GstFormat src_formats[] = {
121     GST_FORMAT_BYTES,
122     GST_FORMAT_TIME,
123     0
124   };
125   static const GstFormat sink_formats[] = {
126     GST_FORMAT_BYTES,
127     GST_FORMAT_DEFAULT,
128     GST_FORMAT_TIME,
129     0
130   };
131
132   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
133 }
134 #endif
135
136 static void gst_speex_enc_finalize (GObject * object);
137
138 static gboolean gst_speex_enc_sink_event (GstPad * pad, GstEvent * event);
139 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
140 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
141
142 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
143     GValue * value, GParamSpec * pspec);
144 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
145     const GValue * value, GParamSpec * pspec);
146 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
147     GstStateChange transition);
148
149 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
150
151 #define gst_speex_enc_parent_class parent_class
152 G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_ELEMENT,
153     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
154     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
155
156 static void
157 gst_speex_enc_class_init (GstSpeexEncClass * klass)
158 {
159   GObjectClass *gobject_class;
160   GstElementClass *gstelement_class;
161
162   gobject_class = (GObjectClass *) klass;
163   gstelement_class = (GstElementClass *) klass;
164
165   gobject_class->finalize = gst_speex_enc_finalize;
166   gobject_class->set_property = gst_speex_enc_set_property;
167   gobject_class->get_property = gst_speex_enc_get_property;
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_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_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_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_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_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_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_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_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_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   gstelement_class->change_state =
215       GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
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   g_object_unref (enc->adapter);
237
238   G_OBJECT_CLASS (parent_class)->finalize (object);
239 }
240
241 static gboolean
242 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
243 {
244   GstSpeexEnc *enc;
245   GstStructure *structure;
246
247   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
248   enc->setup = FALSE;
249
250   structure = gst_caps_get_structure (caps, 0);
251   gst_structure_get_int (structure, "channels", &enc->channels);
252   gst_structure_get_int (structure, "rate", &enc->rate);
253
254   gst_speex_enc_setup (enc);
255
256   return enc->setup;
257 }
258
259
260 static GstCaps *
261 gst_speex_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
262 {
263   GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
264   GstCaps *peercaps = NULL;
265   GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
266
267   peercaps = gst_pad_peer_get_caps (enc->srcpad, filter);
268
269   if (peercaps) {
270     if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
271       GstStructure *ps = gst_caps_get_structure (peercaps, 0);
272       GstStructure *s = gst_caps_get_structure (caps, 0);
273       gint rate, channels;
274
275       if (gst_structure_get_int (ps, "rate", &rate)) {
276         gst_structure_fixate_field_nearest_int (s, "rate", rate);
277       }
278
279       if (gst_structure_get_int (ps, "channels", &channels)) {
280         gst_structure_fixate_field_nearest_int (s, "channels", channels);
281       }
282     }
283     gst_caps_unref (peercaps);
284   }
285
286   gst_object_unref (enc);
287
288   return caps;
289 }
290
291
292 static gboolean
293 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
294     GstFormat dest_format, gint64 * dest_value)
295 {
296   gboolean res = TRUE;
297   GstSpeexEnc *enc;
298   gint64 avg;
299
300   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
301
302   if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
303     return FALSE;
304
305   avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
306
307   switch (src_format) {
308     case GST_FORMAT_BYTES:
309       switch (dest_format) {
310         case GST_FORMAT_TIME:
311           *dest_value = src_value * GST_SECOND / avg;
312           break;
313         default:
314           res = FALSE;
315       }
316       break;
317     case GST_FORMAT_TIME:
318       switch (dest_format) {
319         case GST_FORMAT_BYTES:
320           *dest_value = src_value * avg / GST_SECOND;
321           break;
322         default:
323           res = FALSE;
324       }
325       break;
326     default:
327       res = FALSE;
328   }
329   return res;
330 }
331
332 static gboolean
333 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
334     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
335 {
336   gboolean res = TRUE;
337   guint scale = 1;
338   gint bytes_per_sample;
339   GstSpeexEnc *enc;
340
341   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
342
343   bytes_per_sample = enc->channels * 2;
344
345   switch (src_format) {
346     case GST_FORMAT_BYTES:
347       switch (*dest_format) {
348         case GST_FORMAT_DEFAULT:
349           if (bytes_per_sample == 0)
350             return FALSE;
351           *dest_value = src_value / bytes_per_sample;
352           break;
353         case GST_FORMAT_TIME:
354         {
355           gint byterate = bytes_per_sample * enc->rate;
356
357           if (byterate == 0)
358             return FALSE;
359           *dest_value = src_value * GST_SECOND / byterate;
360           break;
361         }
362         default:
363           res = FALSE;
364       }
365       break;
366     case GST_FORMAT_DEFAULT:
367       switch (*dest_format) {
368         case GST_FORMAT_BYTES:
369           *dest_value = src_value * bytes_per_sample;
370           break;
371         case GST_FORMAT_TIME:
372           if (enc->rate == 0)
373             return FALSE;
374           *dest_value = src_value * GST_SECOND / enc->rate;
375           break;
376         default:
377           res = FALSE;
378       }
379       break;
380     case GST_FORMAT_TIME:
381       switch (*dest_format) {
382         case GST_FORMAT_BYTES:
383           scale = bytes_per_sample;
384           /* fallthrough */
385         case GST_FORMAT_DEFAULT:
386           *dest_value = src_value * scale * enc->rate / GST_SECOND;
387           break;
388         default:
389           res = FALSE;
390       }
391       break;
392     default:
393       res = FALSE;
394   }
395   return res;
396 }
397
398 static gint64
399 gst_speex_enc_get_latency (GstSpeexEnc * enc)
400 {
401   /* See the Speex manual section "Latency and algorithmic delay" */
402   if (enc->rate == 8000)
403     return 30 * GST_MSECOND;
404   else
405     return 34 * GST_MSECOND;
406 }
407
408 static const GstQueryType *
409 gst_speex_enc_get_query_types (GstPad * pad)
410 {
411   static const GstQueryType gst_speex_enc_src_query_types[] = {
412     GST_QUERY_POSITION,
413     GST_QUERY_DURATION,
414     GST_QUERY_CONVERT,
415     GST_QUERY_LATENCY,
416     0
417   };
418
419   return gst_speex_enc_src_query_types;
420 }
421
422 static gboolean
423 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
424 {
425   gboolean res = TRUE;
426   GstSpeexEnc *enc;
427
428   enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
429
430   switch (GST_QUERY_TYPE (query)) {
431     case GST_QUERY_POSITION:
432     {
433       GstFormat req_fmt;
434       gint64 pos, val;
435
436       gst_query_parse_position (query, &req_fmt, NULL);
437       if ((res = gst_pad_query_peer_position (enc->sinkpad, req_fmt, &val))) {
438         gst_query_set_position (query, req_fmt, val);
439         break;
440       }
441
442       res = gst_pad_query_peer_position (enc->sinkpad, GST_FORMAT_TIME, &pos);
443       if (!res)
444         break;
445
446       if ((res =
447               gst_pad_query_peer_convert (enc->sinkpad, GST_FORMAT_TIME, pos,
448                   req_fmt, &val))) {
449         gst_query_set_position (query, req_fmt, val);
450       }
451       break;
452     }
453     case GST_QUERY_DURATION:
454     {
455       GstFormat req_fmt;
456       gint64 dur, val;
457
458       gst_query_parse_duration (query, &req_fmt, NULL);
459       if ((res = gst_pad_query_peer_duration (enc->sinkpad, req_fmt, &val))) {
460         gst_query_set_duration (query, req_fmt, val);
461         break;
462       }
463
464       res = gst_pad_query_peer_duration (enc->sinkpad, GST_FORMAT_TIME, &dur);
465       if (!res)
466         break;
467
468       if ((res =
469               gst_pad_query_peer_convert (enc->sinkpad, GST_FORMAT_TIME, dur,
470                   req_fmt, &val))) {
471         gst_query_set_duration (query, req_fmt, val);
472       }
473       break;
474     }
475     case GST_QUERY_CONVERT:
476     {
477       GstFormat src_fmt, dest_fmt;
478       gint64 src_val, dest_val;
479
480       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
481       if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, dest_fmt,
482                   &dest_val)))
483         goto error;
484       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
485       break;
486     }
487     case GST_QUERY_LATENCY:
488     {
489       gboolean live;
490       GstClockTime min_latency, max_latency;
491       gint64 latency;
492
493       if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
494         gst_query_parse_latency (query, &live, &min_latency, &max_latency);
495         GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query);
496
497         latency = gst_speex_enc_get_latency (enc);
498
499         /* add our latency */
500         min_latency += latency;
501         if (max_latency != -1)
502           max_latency += latency;
503
504         gst_query_set_latency (query, live, min_latency, max_latency);
505         GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query);
506       }
507       break;
508     }
509     default:
510       res = gst_pad_peer_query (enc->sinkpad, query);
511       break;
512   }
513
514 error:
515
516   gst_object_unref (enc);
517
518   return res;
519 }
520
521 static gboolean
522 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
523 {
524   gboolean res = TRUE;
525
526   switch (GST_QUERY_TYPE (query)) {
527     case GST_QUERY_CONVERT:
528     {
529       GstFormat src_fmt, dest_fmt;
530       gint64 src_val, dest_val;
531
532       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
533       if (!(res =
534               gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
535                   &dest_val)))
536         goto error;
537       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
538       break;
539     }
540     default:
541       res = gst_pad_query_default (pad, query);
542       break;
543   }
544
545 error:
546   return res;
547 }
548
549 static void
550 gst_speex_enc_init (GstSpeexEnc * enc)
551 {
552   enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
553   gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
554   gst_pad_set_event_function (enc->sinkpad,
555       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event));
556   gst_pad_set_chain_function (enc->sinkpad,
557       GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
558   gst_pad_set_getcaps_function (enc->sinkpad,
559       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
560   gst_pad_set_query_function (enc->sinkpad,
561       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
562
563   enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
564   gst_pad_set_query_function (enc->srcpad,
565       GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
566   gst_pad_set_query_type_function (enc->srcpad,
567       GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
568   gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
569
570   enc->channels = -1;
571   enc->rate = -1;
572
573   enc->quality = DEFAULT_QUALITY;
574   enc->bitrate = DEFAULT_BITRATE;
575   enc->mode = DEFAULT_MODE;
576   enc->vbr = DEFAULT_VBR;
577   enc->abr = DEFAULT_ABR;
578   enc->vad = DEFAULT_VAD;
579   enc->dtx = DEFAULT_DTX;
580   enc->complexity = DEFAULT_COMPLEXITY;
581   enc->nframes = DEFAULT_NFRAMES;
582
583   enc->setup = FALSE;
584   enc->header_sent = FALSE;
585
586   enc->adapter = gst_adapter_new ();
587 }
588
589 static GstBuffer *
590 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
591 {
592   const GstTagList *user_tags;
593   GstTagList *merged_tags;
594   GstBuffer *comments = NULL;
595
596   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
597
598   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
599   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
600
601   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
602   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
603       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
604
605   if (merged_tags == NULL)
606     merged_tags = gst_tag_list_new ();
607
608   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
609   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
610       0, "Encoded with GStreamer Speexenc");
611   gst_tag_list_free (merged_tags);
612
613   GST_BUFFER_OFFSET (comments) = enc->bytes_out;
614   GST_BUFFER_OFFSET_END (comments) = 0;
615
616   return comments;
617 }
618
619 static void
620 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
621 {
622   g_free (enc->last_message);
623   enc->last_message = g_strdup (msg);
624   GST_WARNING_OBJECT (enc, "%s", msg);
625   g_object_notify (G_OBJECT (enc), "last-message");
626 }
627
628 static gboolean
629 gst_speex_enc_setup (GstSpeexEnc * enc)
630 {
631   enc->setup = FALSE;
632
633   switch (enc->mode) {
634     case GST_SPEEX_ENC_MODE_UWB:
635       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
636       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
637       break;
638     case GST_SPEEX_ENC_MODE_WB:
639       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
640       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
641       break;
642     case GST_SPEEX_ENC_MODE_NB:
643       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
644       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
645       break;
646     case GST_SPEEX_ENC_MODE_AUTO:
647       /* fall through */
648       GST_LOG_OBJECT (enc, "finding best mode");
649     default:
650       break;
651   }
652
653   if (enc->rate > 25000) {
654     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
655       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
656       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
657     } else {
658       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
659         gst_speex_enc_set_last_msg (enc,
660             "Warning: suggest to use ultra wide band mode for this rate");
661       }
662     }
663   } else if (enc->rate > 12500) {
664     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
665       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
666       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
667     } else {
668       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
669         gst_speex_enc_set_last_msg (enc,
670             "Warning: suggest to use wide band mode for this rate");
671       }
672     }
673   } else {
674     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
675       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
676       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
677     } else {
678       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
679         gst_speex_enc_set_last_msg (enc,
680             "Warning: suggest to use narrow band mode for this rate");
681       }
682     }
683   }
684
685   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
686     gst_speex_enc_set_last_msg (enc,
687         "Warning: speex is optimized for 8, 16 and 32 KHz");
688   }
689
690   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
691   enc->header.frames_per_packet = enc->nframes;
692   enc->header.vbr = enc->vbr;
693   enc->header.nb_channels = enc->channels;
694
695   /*Initialize Speex encoder */
696   enc->state = speex_encoder_init (enc->speex_mode);
697
698   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
699   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
700   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
701
702   if (enc->vbr)
703     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
704   else {
705     gint tmp = floor (enc->quality);
706
707     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
708   }
709   if (enc->bitrate) {
710     if (enc->quality >= 0.0 && enc->vbr) {
711       gst_speex_enc_set_last_msg (enc,
712           "Warning: bitrate option is overriding quality");
713     }
714     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
715   }
716   if (enc->vbr) {
717     gint tmp = 1;
718
719     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
720   } else if (enc->vad) {
721     gint tmp = 1;
722
723     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
724   }
725
726   if (enc->dtx) {
727     gint tmp = 1;
728
729     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
730   }
731
732   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
733     gst_speex_enc_set_last_msg (enc,
734         "Warning: dtx is useless without vad, vbr or abr");
735   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
736     gst_speex_enc_set_last_msg (enc,
737         "Warning: vad is already implied by vbr or abr");
738   }
739
740   if (enc->abr) {
741     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
742   }
743
744   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
745
746   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
747       enc->lookahead);
748
749   enc->setup = TRUE;
750
751   return TRUE;
752 }
753
754 /* prepare a buffer for transmission */
755 static GstBuffer *
756 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
757     gint data_len, guint64 granulepos)
758 {
759   GstBuffer *outbuf;
760
761   outbuf = gst_buffer_new_and_alloc (data_len);
762   gst_buffer_fill (outbuf, 0, data, data_len);
763   GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
764   GST_BUFFER_OFFSET_END (outbuf) = granulepos;
765
766   GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", data_len);
767   return outbuf;
768 }
769
770
771 /* push out the buffer and do internal bookkeeping */
772 static GstFlowReturn
773 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
774 {
775   guint size;
776
777   size = gst_buffer_get_size (buffer);
778   enc->bytes_out += size;
779
780   GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
781
782   return gst_pad_push (enc->srcpad, buffer);
783 }
784
785 static GstCaps *
786 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
787     GstBuffer * buf2)
788 {
789   GstStructure *structure = NULL;
790   GstBuffer *buf;
791   GValue array = { 0 };
792   GValue value = { 0 };
793
794   caps = gst_caps_make_writable (caps);
795   structure = gst_caps_get_structure (caps, 0);
796
797   g_assert (gst_buffer_is_writable (buf1));
798   g_assert (gst_buffer_is_writable (buf2));
799
800   /* mark buffers */
801   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
802   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
803
804   /* put buffers in a fixed list */
805   g_value_init (&array, GST_TYPE_ARRAY);
806   g_value_init (&value, GST_TYPE_BUFFER);
807   buf = gst_buffer_copy (buf1);
808   gst_value_set_buffer (&value, buf);
809   gst_buffer_unref (buf);
810   gst_value_array_append_value (&array, &value);
811   g_value_unset (&value);
812   g_value_init (&value, GST_TYPE_BUFFER);
813   buf = gst_buffer_copy (buf2);
814   gst_value_set_buffer (&value, buf);
815   gst_buffer_unref (buf);
816   gst_value_array_append_value (&array, &value);
817   gst_structure_set_value (structure, "streamheader", &array);
818   g_value_unset (&value);
819   g_value_unset (&array);
820
821   return caps;
822 }
823
824
825 static gboolean
826 gst_speex_enc_sink_event (GstPad * pad, GstEvent * event)
827 {
828   gboolean res = TRUE;
829   GstSpeexEnc *enc;
830
831   enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
832
833   switch (GST_EVENT_TYPE (event)) {
834     case GST_EVENT_CAPS:
835     {
836       GstCaps *caps;
837
838       gst_event_parse_caps (event, &caps);
839       res = gst_speex_enc_sink_setcaps (pad, caps);
840       gst_event_unref (event);
841       break;
842     }
843     case GST_EVENT_EOS:
844       if (enc->setup)
845         gst_speex_enc_encode (enc, TRUE);
846       res = gst_pad_event_default (pad, event);
847       break;
848     case GST_EVENT_TAG:
849     {
850       if (enc->tags) {
851         GstTagList *list;
852
853         gst_event_parse_tag (event, &list);
854         gst_tag_list_insert (enc->tags, list,
855             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
856       } else {
857         g_assert_not_reached ();
858       }
859       res = gst_pad_event_default (pad, event);
860       break;
861     }
862     default:
863       res = gst_pad_event_default (pad, event);
864       break;
865   }
866
867   gst_object_unref (enc);
868
869   return res;
870 }
871
872 static GstFlowReturn
873 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
874 {
875   gint frame_size = enc->frame_size;
876   gint bytes = frame_size * 2 * enc->channels;
877   GstFlowReturn ret = GST_FLOW_OK;
878
879   if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
880     guint diff = gst_adapter_available (enc->adapter) % bytes;
881     GstBuffer *buf = gst_buffer_new_and_alloc (diff);
882     gst_buffer_memset (buf, 0, 0, diff);
883     gst_adapter_push (enc->adapter, buf);
884   }
885
886   while (gst_adapter_available (enc->adapter) >= bytes) {
887     gint16 *data;
888     gint outsize, written, dtx_ret;
889     GstBuffer *outbuf;
890     gchar *outdata;
891
892     data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
893
894     enc->samples_in += frame_size;
895
896     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
897
898     if (enc->channels == 2) {
899       speex_encode_stereo_int (data, frame_size, &enc->bits);
900     }
901     dtx_ret = speex_encode_int (enc->state, data, &enc->bits);
902
903     g_free (data);
904
905     enc->frameno++;
906     enc->frameno_out++;
907
908     if ((enc->frameno % enc->nframes) != 0)
909       continue;
910
911     speex_bits_insert_terminator (&enc->bits);
912     outsize = speex_bits_nbytes (&enc->bits);
913
914 #if 0
915     ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
916         GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
917     if ((GST_FLOW_OK != ret))
918       goto done;
919 #endif
920     outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
921
922     outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
923     written = speex_bits_write (&enc->bits, outdata, outsize);
924
925     if (G_UNLIKELY (written != outsize)) {
926       GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
927     }
928     gst_buffer_unmap (outbuf, outdata, written);
929
930     speex_bits_reset (&enc->bits);
931
932     if (!dtx_ret)
933       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
934
935     GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
936         gst_util_uint64_scale_int ((enc->frameno_out -
937             enc->nframes) * frame_size - enc->lookahead, GST_SECOND, enc->rate);
938     GST_BUFFER_DURATION (outbuf) =
939         gst_util_uint64_scale_int (frame_size * enc->nframes, GST_SECOND,
940         enc->rate);
941     /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
942     GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
943         ((enc->frameno_out) * frame_size - enc->lookahead);
944     GST_BUFFER_OFFSET (outbuf) =
945         gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
946         enc->rate);
947
948     ret = gst_speex_enc_push_buffer (enc, outbuf);
949
950     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
951       goto done;
952   }
953
954 done:
955
956   return ret;
957 }
958
959 static GstFlowReturn
960 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
961 {
962   GstSpeexEnc *enc;
963   GstFlowReturn ret = GST_FLOW_OK;
964
965   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
966
967   if (!enc->setup)
968     goto not_setup;
969
970   if (!enc->header_sent) {
971     /* Speex streams begin with two headers; the initial header (with
972        most of the codec setup parameters) which is mandated by the Ogg
973        bitstream spec.  The second header holds any comment fields.
974        We merely need to make the headers, then pass them to libspeex 
975        one at a time; libspeex handles the additional Ogg bitstream 
976        constraints */
977     GstBuffer *buf1, *buf2;
978     GstCaps *caps;
979     guchar *data;
980     gint data_len;
981
982     /* create header buffer */
983     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
984     buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
985     free (data);
986
987     /* create comment buffer */
988     buf2 = gst_speex_enc_create_metadata_buffer (enc);
989
990     /* mark and put on caps */
991     caps = gst_pad_get_caps (enc->srcpad, NULL);
992     caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
993
994     gst_caps_set_simple (caps,
995         "rate", G_TYPE_INT, enc->rate,
996         "channels", G_TYPE_INT, enc->channels, NULL);
997
998     /* negotiate with these caps */
999     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
1000     gst_pad_set_caps (enc->srcpad, caps);
1001     gst_caps_unref (caps);
1002
1003     /* push out buffers */
1004     ret = gst_speex_enc_push_buffer (enc, buf1);
1005
1006     if (ret != GST_FLOW_OK) {
1007       gst_buffer_unref (buf2);
1008       goto done;
1009     }
1010
1011     ret = gst_speex_enc_push_buffer (enc, buf2);
1012
1013     if (ret != GST_FLOW_OK)
1014       goto done;
1015
1016     speex_bits_reset (&enc->bits);
1017
1018     enc->header_sent = TRUE;
1019   }
1020
1021   /* Save the timestamp of the first buffer. This will be later
1022    * used as offset for all following buffers */
1023   if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1024     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1025       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1026       enc->granulepos_offset = gst_util_uint64_scale
1027           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1028     } else {
1029       enc->start_ts = 0;
1030       enc->granulepos_offset = 0;
1031     }
1032   }
1033
1034   /* Check if we have a continous stream, if not drop some samples or the buffer or
1035    * insert some silence samples */
1036   if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1037       GST_BUFFER_TIMESTAMP_IS_VALID (buf) &&
1038       GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1039     guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1040     guint64 diff_bytes;
1041
1042     GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1043         "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1044         "), cannot handle. Clipping buffer.",
1045         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1046         GST_TIME_ARGS (enc->next_ts));
1047
1048     diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1049     if (diff_bytes >= gst_buffer_get_size (buf)) {
1050       gst_buffer_unref (buf);
1051       return GST_FLOW_OK;
1052     }
1053     buf = gst_buffer_make_writable (buf);
1054     gst_buffer_resize (buf, diff_bytes, -1);
1055
1056     GST_BUFFER_TIMESTAMP (buf) += diff;
1057     if (GST_BUFFER_DURATION_IS_VALID (buf))
1058       GST_BUFFER_DURATION (buf) -= diff;
1059   }
1060
1061   if (enc->next_ts != GST_CLOCK_TIME_NONE
1062       && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1063     guint64 max_diff =
1064         gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1065
1066     if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1067         GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1068       GST_WARNING_OBJECT (enc,
1069           "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1070           GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1071
1072       gst_speex_enc_encode (enc, TRUE);
1073
1074       enc->frameno_out = 0;
1075       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1076       enc->granulepos_offset = gst_util_uint64_scale
1077           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1078     }
1079   }
1080
1081   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1082       && GST_BUFFER_DURATION_IS_VALID (buf))
1083     enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1084   else
1085     enc->next_ts = GST_CLOCK_TIME_NONE;
1086
1087   GST_DEBUG_OBJECT (enc, "received buffer of %u bytes",
1088       gst_buffer_get_size (buf));
1089
1090   /* push buffer to adapter */
1091   gst_adapter_push (enc->adapter, buf);
1092   buf = NULL;
1093
1094   ret = gst_speex_enc_encode (enc, FALSE);
1095
1096 done:
1097
1098   if (buf)
1099     gst_buffer_unref (buf);
1100
1101   return ret;
1102
1103   /* ERRORS */
1104 not_setup:
1105   {
1106     GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1107         ("encoder not initialized (input is not audio?)"));
1108     ret = GST_FLOW_NOT_NEGOTIATED;
1109     goto done;
1110   }
1111
1112 }
1113
1114
1115 static void
1116 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1117     GParamSpec * pspec)
1118 {
1119   GstSpeexEnc *enc;
1120
1121   enc = GST_SPEEX_ENC (object);
1122
1123   switch (prop_id) {
1124     case PROP_QUALITY:
1125       g_value_set_float (value, enc->quality);
1126       break;
1127     case PROP_BITRATE:
1128       g_value_set_int (value, enc->bitrate);
1129       break;
1130     case PROP_MODE:
1131       g_value_set_enum (value, enc->mode);
1132       break;
1133     case PROP_VBR:
1134       g_value_set_boolean (value, enc->vbr);
1135       break;
1136     case PROP_ABR:
1137       g_value_set_int (value, enc->abr);
1138       break;
1139     case PROP_VAD:
1140       g_value_set_boolean (value, enc->vad);
1141       break;
1142     case PROP_DTX:
1143       g_value_set_boolean (value, enc->dtx);
1144       break;
1145     case PROP_COMPLEXITY:
1146       g_value_set_int (value, enc->complexity);
1147       break;
1148     case PROP_NFRAMES:
1149       g_value_set_int (value, enc->nframes);
1150       break;
1151     case PROP_LAST_MESSAGE:
1152       g_value_set_string (value, enc->last_message);
1153       break;
1154     default:
1155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1156       break;
1157   }
1158 }
1159
1160 static void
1161 gst_speex_enc_set_property (GObject * object, guint prop_id,
1162     const GValue * value, GParamSpec * pspec)
1163 {
1164   GstSpeexEnc *enc;
1165
1166   enc = GST_SPEEX_ENC (object);
1167
1168   switch (prop_id) {
1169     case PROP_QUALITY:
1170       enc->quality = g_value_get_float (value);
1171       break;
1172     case PROP_BITRATE:
1173       enc->bitrate = g_value_get_int (value);
1174       break;
1175     case PROP_MODE:
1176       enc->mode = g_value_get_enum (value);
1177       break;
1178     case PROP_VBR:
1179       enc->vbr = g_value_get_boolean (value);
1180       break;
1181     case PROP_ABR:
1182       enc->abr = g_value_get_int (value);
1183       break;
1184     case PROP_VAD:
1185       enc->vad = g_value_get_boolean (value);
1186       break;
1187     case PROP_DTX:
1188       enc->dtx = g_value_get_boolean (value);
1189       break;
1190     case PROP_COMPLEXITY:
1191       enc->complexity = g_value_get_int (value);
1192       break;
1193     case PROP_NFRAMES:
1194       enc->nframes = g_value_get_int (value);
1195       break;
1196     default:
1197       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1198       break;
1199   }
1200 }
1201
1202 static GstStateChangeReturn
1203 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1204 {
1205   GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1206   GstStateChangeReturn res;
1207
1208   switch (transition) {
1209     case GST_STATE_CHANGE_NULL_TO_READY:
1210       enc->tags = gst_tag_list_new ();
1211       break;
1212     case GST_STATE_CHANGE_READY_TO_PAUSED:
1213       speex_bits_init (&enc->bits);
1214       enc->frameno = 0;
1215       enc->frameno_out = 0;
1216       enc->samples_in = 0;
1217       enc->start_ts = GST_CLOCK_TIME_NONE;
1218       enc->next_ts = GST_CLOCK_TIME_NONE;
1219       enc->granulepos_offset = 0;
1220       break;
1221     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1222       /* fall through */
1223     default:
1224       break;
1225   }
1226
1227   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1228   if (res == GST_STATE_CHANGE_FAILURE)
1229     return res;
1230
1231   switch (transition) {
1232     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1233       break;
1234     case GST_STATE_CHANGE_PAUSED_TO_READY:
1235       enc->setup = FALSE;
1236       enc->header_sent = FALSE;
1237       if (enc->state) {
1238         speex_encoder_destroy (enc->state);
1239         enc->state = NULL;
1240       }
1241       speex_bits_destroy (&enc->bits);
1242       break;
1243     case GST_STATE_CHANGE_READY_TO_NULL:
1244       gst_tag_list_free (enc->tags);
1245       enc->tags = NULL;
1246     default:
1247       break;
1248   }
1249
1250   return res;
1251 }