speex: update for position/query/convert API changes
[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 #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 (buf) < enc->next_ts) {
1038     guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1039     guint64 diff_bytes;
1040
1041     GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1042         "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1043         "), cannot handle. Clipping buffer.",
1044         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1045         GST_TIME_ARGS (enc->next_ts));
1046
1047     diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1048     if (diff_bytes >= gst_buffer_get_size (buf)) {
1049       gst_buffer_unref (buf);
1050       return GST_FLOW_OK;
1051     }
1052     buf = gst_buffer_make_writable (buf);
1053     gst_buffer_resize (buf, diff_bytes, -1);
1054
1055     GST_BUFFER_TIMESTAMP (buf) += diff;
1056     if (GST_BUFFER_DURATION_IS_VALID (buf))
1057       GST_BUFFER_DURATION (buf) -= diff;
1058   }
1059
1060   if (enc->next_ts != GST_CLOCK_TIME_NONE
1061       && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1062     guint64 max_diff =
1063         gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1064
1065     if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1066         GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1067       GST_WARNING_OBJECT (enc,
1068           "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1069           GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1070
1071       gst_speex_enc_encode (enc, TRUE);
1072
1073       enc->frameno_out = 0;
1074       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1075       enc->granulepos_offset = gst_util_uint64_scale
1076           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1077     }
1078   }
1079
1080   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1081       && GST_BUFFER_DURATION_IS_VALID (buf))
1082     enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1083   else
1084     enc->next_ts = GST_CLOCK_TIME_NONE;
1085
1086   GST_DEBUG_OBJECT (enc, "received buffer of %u bytes",
1087       gst_buffer_get_size (buf));
1088
1089   /* push buffer to adapter */
1090   gst_adapter_push (enc->adapter, buf);
1091   buf = NULL;
1092
1093   ret = gst_speex_enc_encode (enc, FALSE);
1094
1095 done:
1096
1097   if (buf)
1098     gst_buffer_unref (buf);
1099
1100   return ret;
1101
1102   /* ERRORS */
1103 not_setup:
1104   {
1105     GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1106         ("encoder not initialized (input is not audio?)"));
1107     ret = GST_FLOW_NOT_NEGOTIATED;
1108     goto done;
1109   }
1110
1111 }
1112
1113
1114 static void
1115 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1116     GParamSpec * pspec)
1117 {
1118   GstSpeexEnc *enc;
1119
1120   enc = GST_SPEEX_ENC (object);
1121
1122   switch (prop_id) {
1123     case PROP_QUALITY:
1124       g_value_set_float (value, enc->quality);
1125       break;
1126     case PROP_BITRATE:
1127       g_value_set_int (value, enc->bitrate);
1128       break;
1129     case PROP_MODE:
1130       g_value_set_enum (value, enc->mode);
1131       break;
1132     case PROP_VBR:
1133       g_value_set_boolean (value, enc->vbr);
1134       break;
1135     case PROP_ABR:
1136       g_value_set_int (value, enc->abr);
1137       break;
1138     case PROP_VAD:
1139       g_value_set_boolean (value, enc->vad);
1140       break;
1141     case PROP_DTX:
1142       g_value_set_boolean (value, enc->dtx);
1143       break;
1144     case PROP_COMPLEXITY:
1145       g_value_set_int (value, enc->complexity);
1146       break;
1147     case PROP_NFRAMES:
1148       g_value_set_int (value, enc->nframes);
1149       break;
1150     case PROP_LAST_MESSAGE:
1151       g_value_set_string (value, enc->last_message);
1152       break;
1153     default:
1154       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1155       break;
1156   }
1157 }
1158
1159 static void
1160 gst_speex_enc_set_property (GObject * object, guint prop_id,
1161     const GValue * value, GParamSpec * pspec)
1162 {
1163   GstSpeexEnc *enc;
1164
1165   enc = GST_SPEEX_ENC (object);
1166
1167   switch (prop_id) {
1168     case PROP_QUALITY:
1169       enc->quality = g_value_get_float (value);
1170       break;
1171     case PROP_BITRATE:
1172       enc->bitrate = g_value_get_int (value);
1173       break;
1174     case PROP_MODE:
1175       enc->mode = g_value_get_enum (value);
1176       break;
1177     case PROP_VBR:
1178       enc->vbr = g_value_get_boolean (value);
1179       break;
1180     case PROP_ABR:
1181       enc->abr = g_value_get_int (value);
1182       break;
1183     case PROP_VAD:
1184       enc->vad = g_value_get_boolean (value);
1185       break;
1186     case PROP_DTX:
1187       enc->dtx = g_value_get_boolean (value);
1188       break;
1189     case PROP_COMPLEXITY:
1190       enc->complexity = g_value_get_int (value);
1191       break;
1192     case PROP_NFRAMES:
1193       enc->nframes = g_value_get_int (value);
1194       break;
1195     default:
1196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1197       break;
1198   }
1199 }
1200
1201 static GstStateChangeReturn
1202 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1203 {
1204   GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1205   GstStateChangeReturn res;
1206
1207   switch (transition) {
1208     case GST_STATE_CHANGE_NULL_TO_READY:
1209       enc->tags = gst_tag_list_new ();
1210       break;
1211     case GST_STATE_CHANGE_READY_TO_PAUSED:
1212       speex_bits_init (&enc->bits);
1213       enc->frameno = 0;
1214       enc->frameno_out = 0;
1215       enc->samples_in = 0;
1216       enc->start_ts = GST_CLOCK_TIME_NONE;
1217       enc->next_ts = GST_CLOCK_TIME_NONE;
1218       enc->granulepos_offset = 0;
1219       break;
1220     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1221       /* fall through */
1222     default:
1223       break;
1224   }
1225
1226   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1227   if (res == GST_STATE_CHANGE_FAILURE)
1228     return res;
1229
1230   switch (transition) {
1231     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1232       break;
1233     case GST_STATE_CHANGE_PAUSED_TO_READY:
1234       enc->setup = FALSE;
1235       enc->header_sent = FALSE;
1236       if (enc->state) {
1237         speex_encoder_destroy (enc->state);
1238         enc->state = NULL;
1239       }
1240       speex_bits_destroy (&enc->bits);
1241       break;
1242     case GST_STATE_CHANGE_READY_TO_NULL:
1243       gst_tag_list_free (enc->tags);
1244       enc->tags = NULL;
1245     default:
1246       break;
1247   }
1248
1249   return res;
1250 }