sbc: import sbc decoder/encoder from bluez and port to 1.0
authorTim-Philipp Müller <tim.muller@collabora.co.uk>
Wed, 16 Jan 2013 11:36:25 +0000 (11:36 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Wed, 27 Mar 2013 22:40:56 +0000 (22:40 +0000)
https://bugzilla.gnome.org/show_bug.cgi?id=690582

configure.ac
ext/Makefile.am
ext/sbc/Makefile.am [new file with mode: 0644]
ext/sbc/gstsbcdec.c
ext/sbc/gstsbcdec.h
ext/sbc/gstsbcenc.c
ext/sbc/gstsbcenc.h
ext/sbc/gstsbcutil.c
ext/sbc/gstsbcutil.h
ext/sbc/sbc-plugin.c [new file with mode: 0644]

index b4cba5feb5b89911e5dee5fd3073c9e7a65061a2..5534694015129c8141124eb415a519d90ecf9565 100644 (file)
@@ -2082,6 +2082,14 @@ AG_GST_CHECK_FEATURE(VDPAU, [VDPAU], vdpau, [
   fi
 ])
 
+dnl *** sbc ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_SBC, true)
+AG_GST_CHECK_FEATURE(SBC, [SBC bluetooth audio codec], sbc, [
+  AG_GST_PKG_CHECK_MODULES(SBC, [sbc >= 1.0 sbc <= 1.0])
+  AC_MSG_NOTICE([Disabling sbc plugin for now, not working yet])
+  HAVE_SBC=no
+])
+
 dnl *** schroedinger ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_SCHRO, true)
 AG_GST_CHECK_FEATURE(SCHRO, [Schroedinger video codec], schro, [
@@ -2456,6 +2464,7 @@ ext/opus/Makefile
 ext/rsvg/Makefile
 ext/resindvd/Makefile
 ext/rtmp/Makefile
+ext/sbc/Makefile
 ext/schroedinger/Makefile
 ext/sdl/Makefile
 ext/sndfile/Makefile
index 5d5592b7bad8b730ad8f7ad76231ff958e095b47..7d373999756119855cd0248cb03aa3d460f106e3 100644 (file)
@@ -274,6 +274,12 @@ if USE_FLUIDSYNTH
 FLUIDSYNTH_DIR=fluidsynth
 endif
 
+if USE_SBC
+SBC_DIR=sbc
+else
+SBC_DIR=
+endif
+
 if USE_SCHRO
 SCHRO_DIR=schroedinger
 else
@@ -417,6 +423,7 @@ SUBDIRS=\
        $(OPENJPEG_DIR) \
        $(OPUS_DIR) \
        $(RSVG_DIR) \
+       $(SBC_DIR) \
        $(SCHRO_DIR) \
        $(SDL_DIR) \
        $(SMOOTHWAVE_DIR) \
@@ -476,6 +483,7 @@ DIST_SUBDIRS = \
        opus \
        rsvg \
        resindvd \
+       sbc \
        schroedinger \
        sdl \
        sndfile \
diff --git a/ext/sbc/Makefile.am b/ext/sbc/Makefile.am
new file mode 100644 (file)
index 0000000..3d4da05
--- /dev/null
@@ -0,0 +1,24 @@
+
+plugin_LTLIBRARIES = libgstsbc.la
+
+noinst_HEADERS = \
+       gstsbcdec.h \
+       gstsbcenc.h \
+       gstsbcutil.h
+
+libgstsbc_la_SOURCES = \
+       gstsbcdec.c \
+       gstsbcenc.c \
+       gstsbcutil.c \
+       sbc-plugin.c
+libgstsbc_la_CFLAGS = \
+       $(GST_PLUGINS_BASE_CFLAGS) \
+       $(GST_BASE_CFLAGS) \
+       $(GST_CFLAGS) \
+       $(SBC_CFLAGS)
+libgstsbc_la_LIBADD = \
+       $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_API_VERSION@ \
+       $(GST_BASE_LIBS) $(GST_LIBS) \
+       $(SBC_LIBS)
+libgstsbc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstsbc_la_LIBTOOLFLAGS = --tag=disable-static
index 12245f9d7a86a5633a04979b5804302cca72b331..1176a2cdf7b34c1ca699a64a5f127e1ac835e7a6 100644 (file)
@@ -1,5 +1,4 @@
-/*
- *
+/*  GStreamer SBC audio decoder
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
 #include <string.h>
 
-#include "gstpragma.h"
 #include "gstsbcutil.h"
 #include "gstsbcdec.h"
+#include <gst/audio/audio.h>
 
+/* FIXME: where does this come from? how is it derived? */
 #define BUF_SIZE 8192
 
 GST_DEBUG_CATEGORY_STATIC (sbc_dec_debug);
@@ -38,13 +38,9 @@ GST_DEBUG_CATEGORY_STATIC (sbc_dec_debug);
 
 static void gst_sbc_dec_finalize (GObject * obj);
 
-GST_BOILERPLATE (GstSbcDec, gst_sbc_dec, GstElement, GST_TYPE_ELEMENT);
-
-static const GstElementDetails sbc_dec_details =
-GST_ELEMENT_DETAILS ("Bluetooth SBC decoder",
-    "Codec/Decoder/Audio",
-    "Decode a SBC audio stream",
-    "Marcel Holtmann <marcel@holtmann.org>");
+/* FIXME: port to GstAudioDecoder base class */
+#define parent_class gst_sbc_dec_parent_class
+G_DEFINE_TYPE (GstSbcDec, gst_sbc_dec, GST_TYPE_ELEMENT);
 
 static GstStaticPadTemplate sbc_dec_sink_factory =
 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
@@ -52,11 +48,9 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
 
 static GstStaticPadTemplate sbc_dec_src_factory =
 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-raw-int, "
+    GST_STATIC_CAPS ("audio/x-raw, format=" GST_AUDIO_NE (S16) ", "
         "rate = (int) { 16000, 32000, 44100, 48000 }, "
-        "channels = (int) [ 1, 2 ], "
-        "endianness = (int) BYTE_ORDER, "
-        "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16"));
+        "channels = (int) [ 1, 2 ], layout=interleaved"));
 
 static GstFlowReturn
 gst_sbc_dec_flush (GstSbcDec * dec, GstBuffer * outbuf,
@@ -65,24 +59,19 @@ gst_sbc_dec_flush (GstSbcDec * dec, GstBuffer * outbuf,
   GstClockTime outtime, duration;
 
   /* we will reuse the same caps object */
-  if (dec->outcaps == NULL) {
+  if (dec->send_caps) {
     GstCaps *caps;
-    GstPadTemplate *template;
-
-    caps = gst_caps_new_simple ("audio/x-raw-int",
-        "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
 
-    template = gst_static_pad_template_get (&sbc_dec_src_factory);
+    caps = gst_caps_new_simple ("audio/x-raw",
+        "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+        "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels,
+        "layout", G_TYPE_STRING, "interleaved", NULL);
 
-    dec->outcaps = gst_caps_intersect (caps,
-        gst_pad_template_get_caps (template));
+    gst_pad_push_event (dec->srcpad, gst_event_new_caps (caps));
 
     gst_caps_unref (caps);
-    gst_object_unref (template);
   }
 
-  gst_buffer_set_caps (outbuf, dec->outcaps);
-
   /* calculate duration */
   outtime = GST_BUFFER_TIMESTAMP (outbuf);
   if (dec->next_timestamp != (guint64) - 1 && outtime != (guint64) - 1) {
@@ -95,23 +84,23 @@ gst_sbc_dec_flush (GstSbcDec * dec, GstBuffer * outbuf,
     duration = GST_CLOCK_TIME_NONE;
   }
   GST_BUFFER_DURATION (outbuf) = duration;
-  GST_BUFFER_SIZE (outbuf) = outoffset;
+  gst_buffer_resize (outbuf, 0, outoffset);
 
   return gst_pad_push (dec->srcpad, outbuf);
 
 }
 
 static GstFlowReturn
-sbc_dec_chain (GstPad * pad, GstBuffer * buffer)
+sbc_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 {
-  GstSbcDec *dec = GST_SBC_DEC (gst_pad_get_parent (pad));
+  GstSbcDec *dec = GST_SBC_DEC (parent);
   GstFlowReturn res = GST_FLOW_OK;
   const guint8 *indata;
   guint insize;
   GstClockTime timestamp;
   gboolean discont;
+  GstMapInfo out_map;
   GstBuffer *outbuf;
-  guint8 *outdata;
   guint inoffset, outoffset;
   gint rate, channels;
 
@@ -130,8 +119,7 @@ sbc_dec_chain (GstPad * pad, GstBuffer * buffer)
     dec->next_timestamp = timestamp;
 
   insize = gst_adapter_available (dec->adapter);
-  indata = gst_adapter_peek (dec->adapter, insize);
-
+  indata = gst_adapter_map (dec->adapter, insize);
 
   inoffset = 0;
   outbuf = NULL;
@@ -143,11 +131,7 @@ sbc_dec_chain (GstPad * pad, GstBuffer * buffer)
     size_t outconsumed;
 
     if (outbuf == NULL) {
-      res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad,
-          GST_BUFFER_OFFSET_NONE, BUF_SIZE, NULL, &outbuf);
-
-      if (res != GST_FLOW_OK)
-        goto done;
+      outbuf = gst_buffer_new_and_alloc (BUF_SIZE);
 
       if (discont) {
         GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
@@ -155,8 +139,9 @@ sbc_dec_chain (GstPad * pad, GstBuffer * buffer)
       }
 
       GST_BUFFER_TIMESTAMP (outbuf) = dec->next_timestamp;
-      outdata = GST_BUFFER_DATA (outbuf);
-      outsize = GST_BUFFER_SIZE (outbuf);
+
+      gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);
+      outsize = out_map.size;
       outoffset = 0;
     }
 
@@ -164,7 +149,7 @@ sbc_dec_chain (GstPad * pad, GstBuffer * buffer)
         insize, outoffset, outsize);
 
     inconsumed = sbc_decode (&dec->sbc, indata + inoffset, insize,
-        outdata + outoffset, outsize, &outconsumed);
+        out_map.data + outoffset, outsize, &outconsumed);
 
     GST_INFO_OBJECT (dec, "consumed %d, produced %d", inconsumed, outconsumed);
 
@@ -209,21 +194,27 @@ sbc_dec_chain (GstPad * pad, GstBuffer * buffer)
     /* check for space, push outbuf buffer */
     outlen = sbc_get_codesize (&dec->sbc);
     if (outsize < outlen) {
+      gst_buffer_unmap (outbuf, &out_map);
+
       res = gst_sbc_dec_flush (dec, outbuf, outoffset, channels, rate);
-      if (res != GST_FLOW_OK)
-        goto done;
 
       outbuf = NULL;
-    }
 
+      if (res != GST_FLOW_OK)
+        goto done;
+    }
   }
 
-  if (outbuf)
+  if (outbuf) {
+    gst_buffer_unmap (outbuf, &out_map);
+
     res = gst_sbc_dec_flush (dec, outbuf, outoffset, channels, rate);
+  }
 
-  gst_adapter_flush (dec->adapter, inoffset);
 done:
-  gst_object_unref (dec);
+
+  gst_adapter_unmap (dec->adapter);
+  gst_adapter_flush (dec->adapter, inoffset);
 
   return res;
 }
@@ -238,24 +229,21 @@ gst_sbc_dec_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       GST_DEBUG ("Setup subband codec");
       sbc_init (&dec->sbc, 0);
-      dec->outcaps = NULL;
+      dec->send_caps = TRUE;
       dec->next_sample = -1;
       break;
     default:
       break;
   }
 
-  result = parent_class->change_state (element, transition);
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
   switch (transition) {
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       GST_DEBUG ("Finish subband codec");
       gst_adapter_clear (dec->adapter);
       sbc_finish (&dec->sbc);
-      if (dec->outcaps) {
-        gst_caps_unref (dec->outcaps);
-        dec->outcaps = NULL;
-      }
+      dec->send_caps = TRUE;
       break;
 
     default:
@@ -266,9 +254,14 @@ gst_sbc_dec_change_state (GstElement * element, GstStateChange transition)
 }
 
 static void
-gst_sbc_dec_base_init (gpointer g_class)
+gst_sbc_dec_class_init (GstSbcDecClass * klass)
 {
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  object_class->finalize = gst_sbc_dec_finalize;
+
+  element_class->change_state = GST_DEBUG_FUNCPTR (gst_sbc_dec_change_state);
 
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&sbc_dec_sink_factory));
@@ -276,26 +269,15 @@ gst_sbc_dec_base_init (gpointer g_class)
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&sbc_dec_src_factory));
 
-  gst_element_class_set_details (element_class, &sbc_dec_details);
-}
-
-static void
-gst_sbc_dec_class_init (GstSbcDecClass * klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  object_class->finalize = GST_DEBUG_FUNCPTR (gst_sbc_dec_finalize);
-
-  element_class->change_state = GST_DEBUG_FUNCPTR (gst_sbc_dec_change_state);
+  gst_element_class_set_static_metadata (element_class,
+      "Bluetooth SBC audio decoder", "Codec/Decoder/Audio",
+      "Decode an SBC audio stream", "Marcel Holtmann <marcel@holtmann.org>");
 
   GST_DEBUG_CATEGORY_INIT (sbc_dec_debug, "sbcdec", 0, "SBC decoding element");
 }
 
 static void
-gst_sbc_dec_init (GstSbcDec * self, GstSbcDecClass * klass)
+gst_sbc_dec_init (GstSbcDec * self)
 {
   self->sinkpad =
       gst_pad_new_from_static_template (&sbc_dec_sink_factory, "sink");
@@ -306,7 +288,7 @@ gst_sbc_dec_init (GstSbcDec * self, GstSbcDecClass * klass)
   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
 
   self->adapter = gst_adapter_new ();
-  self->outcaps = NULL;
+  self->send_caps = TRUE;
 }
 
 static void
@@ -315,14 +297,7 @@ gst_sbc_dec_finalize (GObject * obj)
   GstSbcDec *self = GST_SBC_DEC (obj);
 
   g_object_unref (self->adapter);
+  self->adapter = NULL;
 
   G_OBJECT_CLASS (parent_class)->finalize (obj);
-
-}
-
-gboolean
-gst_sbc_dec_plugin_init (GstPlugin * plugin)
-{
-  return gst_element_register (plugin, "sbcdec", GST_RANK_PRIMARY,
-      GST_TYPE_SBC_DEC);
 }
index f5b9416a98a3fc91657975ac91b7c6245b546fa7..c7c43eea11726be4a859a74f6280c1f158a78b26 100644 (file)
@@ -1,5 +1,4 @@
-/*
- *
+/*  GStreamer SBC audio decoder
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 #include <gst/gst.h>
 #include <gst/base/gstadapter.h>
 
-#include "sbc.h"
+#include <sbc/sbc.h>
 
 G_BEGIN_DECLS
 
 #define GST_TYPE_SBC_DEC \
-       (gst_sbc_dec_get_type())
+    (gst_sbc_dec_get_type())
 #define GST_SBC_DEC(obj) \
-       (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_DEC,GstSbcDec))
+    (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_DEC,GstSbcDec))
 #define GST_SBC_DEC_CLASS(klass) \
-       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_DEC,GstSbcDecClass))
+    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_DEC,GstSbcDecClass))
 #define GST_IS_SBC_DEC(obj) \
-       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_DEC))
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_DEC))
 #define GST_IS_SBC_DEC_CLASS(obj) \
-       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_DEC))
+    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_DEC))
 
 typedef struct _GstSbcDec GstSbcDec;
 typedef struct _GstSbcDecClass GstSbcDecClass;
 
 struct _GstSbcDec {
-       GstElement element;
+    GstElement element;
 
-       GstPad *sinkpad;
-       GstPad *srcpad;
+    GstPad *sinkpad;
+    GstPad *srcpad;
 
-       GstAdapter *adapter;
+    GstAdapter *adapter;
 
-       /* caps for outgoing buffers */
-       GstCaps *outcaps;
+    gboolean send_caps;
 
-       sbc_t sbc;
-        guint64 next_sample;
-        guint64 next_timestamp;
+    sbc_t sbc;
+    guint64 next_sample;
+    guint64 next_timestamp;
 };
 
 struct _GstSbcDecClass {
-       GstElementClass parent_class;
+    GstElementClass parent_class;
 };
 
-GType gst_sbc_dec_get_type(void);
-
-gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin);
+GType gst_sbc_dec_get_type (void);
 
 G_END_DECLS
index 6f80959d705fcd4118fc71fc551fbd940788012b..812a3724f80c7e91a4881109c21da075e6d59e0e 100644 (file)
@@ -1,5 +1,4 @@
-/*
- *
+/*  GStreamer SBC audio encoder
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
 #include <string.h>
 
-#include "gstpragma.h"
 #include "gstsbcutil.h"
 #include "gstsbcenc.h"
 
-#define SBC_ENC_DEFAULT_MODE SBC_MODE_AUTO
+#include <gst/audio/audio.h>
+
+#define SBC_ENC_DEFAULT_CHANNEL_MODE SBC_MODE_AUTO
 #define SBC_ENC_DEFAULT_BLOCKS 0
 #define SBC_ENC_DEFAULT_SUB_BANDS 0
-#define SBC_ENC_DEFAULT_ALLOCATION SBC_AM_AUTO
+#define SBC_ENC_DEFAULT_ALLOCATION_METHOD SBC_AM_AUTO
 #define SBC_ENC_DEFAULT_RATE 0
 #define SBC_ENC_DEFAULT_CHANNELS 0
 
 GST_DEBUG_CATEGORY_STATIC (sbc_enc_debug);
 #define GST_CAT_DEFAULT sbc_enc_debug
 
-#define GST_TYPE_SBC_MODE (gst_sbc_mode_get_type())
+#define GST_TYPE_SBC_CHANNEL_MODE (gst_sbc_channel_mode_get_type())
 
 static GType
-gst_sbc_mode_get_type (void)
+gst_sbc_channel_mode_get_type (void)
 {
-  static GType sbc_mode_type = 0;
-  static GEnumValue sbc_modes[] = {
+  static GType sbc_channel_mode_type = 0;
+  static GEnumValue sbc_channel_modes[] = {
     {SBC_MODE_MONO, "Mono", "mono"},
-    {SBC_MODE_DUAL_CHANNEL, "Dual Channel", "dual"},
+    {SBC_MODE_DUAL_CHANNEL, "Dual", "dual"},
     {SBC_MODE_STEREO, "Stereo", "stereo"},
     {SBC_MODE_JOINT_STEREO, "Joint Stereo", "joint"},
     {SBC_MODE_AUTO, "Auto", "auto"},
     {-1, NULL, NULL}
   };
 
-  if (!sbc_mode_type)
-    sbc_mode_type = g_enum_register_static ("GstSbcMode", sbc_modes);
+  if (!sbc_channel_mode_type) {
+    sbc_channel_mode_type =
+        g_enum_register_static ("GstSbcChannelMode", sbc_channel_modes);
+  }
 
-  return sbc_mode_type;
+  return sbc_channel_mode_type;
 }
 
-#define GST_TYPE_SBC_ALLOCATION (gst_sbc_allocation_get_type())
+#define GST_TYPE_SBC_ALLOCATION_METHOD (gst_sbc_allocation_method_get_type())
 
 static GType
-gst_sbc_allocation_get_type (void)
+gst_sbc_allocation_method_get_type (void)
 {
-  static GType sbc_allocation_type = 0;
-  static GEnumValue sbc_allocations[] = {
+  static GType sbc_allocation_method_type = 0;
+  static GEnumValue sbc_allocation_methods[] = {
     {SBC_AM_LOUDNESS, "Loudness", "loudness"},
     {SBC_AM_SNR, "SNR", "snr"},
     {SBC_AM_AUTO, "Auto", "auto"},
     {-1, NULL, NULL}
   };
 
-  if (!sbc_allocation_type)
-    sbc_allocation_type =
-        g_enum_register_static ("GstSbcAllocation", sbc_allocations);
+  if (!sbc_allocation_method_type)
+    sbc_allocation_method_type =
+        g_enum_register_static ("GstSbcAllocationMethod",
+        sbc_allocation_methods);
 
-  return sbc_allocation_type;
+  return sbc_allocation_method_type;
 }
 
 #define GST_TYPE_SBC_BLOCKS (gst_sbc_blocks_get_type())
@@ -138,36 +141,35 @@ enum
   PROP_BITPOOL
 };
 
-GST_BOILERPLATE (GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT);
-
-static const GstElementDetails sbc_enc_details =
-GST_ELEMENT_DETAILS ("Bluetooth SBC encoder",
-    "Codec/Encoder/Audio",
-    "Encode a SBC audio stream",
-    "Marcel Holtmann <marcel@holtmann.org>");
+/* FIXME: rewrite based on GstAudioEncoder base class */
+#define parent_class gst_sbc_enc_parent_class
+G_DEFINE_TYPE (GstSbcEnc, gst_sbc_enc, GST_TYPE_ELEMENT);
 
 static GstStaticPadTemplate sbc_enc_sink_factory =
 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-raw-int, "
+    GST_STATIC_CAPS ("audio/x-raw, format=" GST_AUDIO_NE (S16) ", "
         "rate = (int) { 16000, 32000, 44100, 48000 }, "
-        "channels = (int) [ 1, 2 ], "
-        "endianness = (int) BYTE_ORDER, "
-        "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16"));
+        "channels = (int) [ 1, 2 ]"));
 
 static GstStaticPadTemplate sbc_enc_src_factory =
 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("audio/x-sbc, "
         "rate = (int) { 16000, 32000, 44100, 48000 }, "
         "channels = (int) [ 1, 2 ], "
-        "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
+        "channel-mode = (string) { mono, dual, stereo, joint }, "
         "blocks = (int) { 4, 8, 12, 16 }, "
         "subbands = (int) { 4, 8 }, "
-        "allocation = (string) { \"snr\", \"loudness\" }, "
+        "allocation-method = (string) { snr, loudness }, "
         "bitpool = (int) [ " SBC_ENC_BITPOOL_MIN_STR
         ", " SBC_ENC_BITPOOL_MAX_STR " ]"));
 
-gboolean gst_sbc_enc_fill_sbc_params (GstSbcEnc * enc, GstCaps * caps);
 
+static gboolean gst_sbc_enc_fill_sbc_params (GstSbcEnc * enc, GstCaps * caps);
+
+static gboolean gst_sbc_enc_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+/* FIXME does this make sense? */
 static GstCaps *
 sbc_enc_generate_srcpad_caps (GstSbcEnc * enc)
 {
@@ -180,6 +182,7 @@ sbc_enc_generate_srcpad_caps (GstSbcEnc * enc)
   src_caps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad));
   structure = gst_caps_get_structure (src_caps, 0);
 
+  /* FIXME: use gst_structure_set() */
   value = g_new0 (GValue, 1);
 
   if (enc->rate != 0)
@@ -201,18 +204,18 @@ sbc_enc_generate_srcpad_caps (GstSbcEnc * enc)
     gst_sbc_util_set_structure_int_param (structure, "bitpool",
         enc->bitpool, value);
 
-  if (enc->mode != SBC_ENC_DEFAULT_MODE) {
-    enum_class = g_type_class_ref (GST_TYPE_SBC_MODE);
+  if (enc->mode != SBC_ENC_DEFAULT_CHANNEL_MODE) {
+    enum_class = g_type_class_ref (GST_TYPE_SBC_CHANNEL_MODE);
     enum_value = g_enum_get_value (enum_class, enc->mode);
-    gst_sbc_util_set_structure_string_param (structure, "mode",
+    gst_sbc_util_set_structure_string_param (structure, "channel-mode",
         enum_value->value_nick, value);
     g_type_class_unref (enum_class);
   }
 
   if (enc->allocation != SBC_AM_AUTO) {
-    enum_class = g_type_class_ref (GST_TYPE_SBC_ALLOCATION);
+    enum_class = g_type_class_ref (GST_TYPE_SBC_ALLOCATION_METHOD);
     enum_value = g_enum_get_value (enum_class, enc->allocation);
-    gst_sbc_util_set_structure_string_param (structure, "allocation",
+    gst_sbc_util_set_structure_string_param (structure, "allocation-method",
         enum_value->value_nick, value);
     g_type_class_unref (enum_class);
   }
@@ -233,70 +236,84 @@ sbc_enc_src_getcaps (GstPad * pad)
 }
 
 static gboolean
-sbc_enc_src_setcaps (GstPad * pad, GstCaps * caps)
-{
-  GstSbcEnc *enc = GST_SBC_ENC (GST_PAD_PARENT (pad));
-
-  GST_LOG_OBJECT (enc, "setting srcpad caps");
-
-  return gst_sbc_enc_fill_sbc_params (enc, caps);
-}
-
-static GstCaps *
-sbc_enc_src_caps_fixate (GstSbcEnc * enc, GstCaps * caps)
+sbc_enc_negotiate_output_caps (GstSbcEnc * enc, GstCaps * in_caps)
 {
-  gchar *error_message = NULL;
-  GstCaps *result;
-
-  result = gst_sbc_util_caps_fixate (caps, &error_message);
-
-  if (!result) {
-    GST_WARNING_OBJECT (enc, "Invalid input caps caused parsing "
-        "error: %s", error_message);
-    g_free (error_message);
-    return NULL;
-  }
-
-  return result;
-}
+  GstStructure *s;
+  GstCaps *caps, *filter_caps;
+  GstCaps *output_caps;
 
-static GstCaps *
-sbc_enc_get_fixed_srcpad_caps (GstSbcEnc * enc)
-{
-  GstCaps *caps;
-  gboolean res = TRUE;
-  GstCaps *result_caps = NULL;
+  GST_INFO_OBJECT (enc, "input caps %" GST_PTR_FORMAT, in_caps);
 
   caps = gst_pad_get_allowed_caps (enc->srcpad);
   if (caps == NULL)
     caps = sbc_enc_src_getcaps (enc->srcpad);
 
   if (caps == GST_CAPS_NONE || gst_caps_is_empty (caps)) {
-    res = FALSE;
-    goto done;
+    gst_caps_unref (caps);
+    return FALSE;
   }
 
-  result_caps = sbc_enc_src_caps_fixate (enc, caps);
-
-done:
+  /* fixate output caps */
+  filter_caps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT,
+      enc->rate, "channels", G_TYPE_INT, enc->channels, NULL);
+  output_caps = gst_caps_intersect (caps, filter_caps);
+  gst_caps_unref (filter_caps);
+
+  if (output_caps == NULL || gst_caps_is_empty (output_caps)) {
+    GST_DEBUG_OBJECT (enc, "Couldn't negotiate output caps with input rate %d "
+        "and input channels %d and allowed output caps %" GST_PTR_FORMAT,
+        enc->rate, enc->channels, caps);
+    if (output_caps)
+      gst_caps_unref (output_caps);
+    gst_caps_unref (caps);
+    return FALSE;
+  }
   gst_caps_unref (caps);
 
-  if (!res)
-    return NULL;
+  GST_DEBUG_OBJECT (enc, "fixating caps %" GST_PTR_FORMAT, output_caps);
+  output_caps = gst_caps_truncate (output_caps);
+  s = gst_caps_get_structure (output_caps, 0);
+  if (enc->channels == 1) {
+    if (!gst_structure_fixate_field_string (s, "channel-mode", "mono")) {
+      GST_DEBUG_OBJECT (enc, "Failed to fixate channel-mode to mono");
+      gst_caps_unref (output_caps);
+      return FALSE;
+    }
+  } else {
+    if (gst_structure_fixate_field_string (s, "channel-mode", "joint")
+        || gst_structure_fixate_field_string (s, "channel-mode", "stereo")) {
+      gst_structure_fixate_field_string (s, "channel-mode", "dual");
+    }
+  }
+
+  gst_structure_fixate_field_nearest_int (s, "bitpool", 64);
+  gst_structure_fixate_field_nearest_int (s, "blocks", 16);
+  gst_structure_fixate_field_nearest_int (s, "subbands", 8);
+  gst_structure_fixate_field_string (s, "allocation-method", "loudness");
+  s = NULL;
+
+  /* in case there's anything else left to fixate */
+  output_caps = gst_caps_fixate (output_caps);
+
+  GST_INFO_OBJECT (enc, "output caps %" GST_PTR_FORMAT, output_caps);
+  if (!gst_sbc_enc_fill_sbc_params (enc, output_caps)) {
+    GST_WARNING_OBJECT (enc, "failed to configure encoder from output "
+        "caps %" GST_PTR_FORMAT, output_caps);
+    return FALSE;
+  }
+
+  gst_pad_send_event (enc->sinkpad, gst_event_new_caps (output_caps));
+  gst_caps_unref (output_caps);
 
-  return result_caps;
+  return TRUE;
 }
 
 static gboolean
-sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
+sbc_enc_sink_setcaps (GstSbcEnc * enc, GstCaps * caps)
 {
-  GstSbcEnc *enc;
   GstStructure *structure;
-  GstCaps *src_caps;
   gint rate, channels;
-  gboolean res;
 
-  enc = GST_SBC_ENC (GST_PAD_PARENT (pad));
   structure = gst_caps_get_structure (caps, 0);
 
   if (!gst_structure_get_int (structure, "rate", &rate))
@@ -307,20 +324,37 @@ sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
   enc->rate = rate;
   enc->channels = channels;
 
-  src_caps = sbc_enc_get_fixed_srcpad_caps (enc);
-  if (!src_caps)
-    return FALSE;
-  res = gst_pad_set_caps (enc->srcpad, src_caps);
-  gst_caps_unref (src_caps);
+  return sbc_enc_negotiate_output_caps (enc, caps);
+}
 
-  return res;
+static gboolean
+gst_sbc_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstSbcEnc *enc = GST_SBC_ENC (parent);
+  gboolean ret;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:{
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = sbc_enc_sink_setcaps (enc, caps);
+      break;
+    }
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
 }
 
-gboolean
+/* configure encoder based on output caps */
+static gboolean
 gst_sbc_enc_fill_sbc_params (GstSbcEnc * enc, GstCaps * caps)
 {
   if (!gst_caps_is_fixed (caps)) {
-    GST_DEBUG_OBJECT (enc, "didn't receive fixed caps, " "returning false");
+    GST_DEBUG_OBJECT (enc, "output caps %" GST_PTR_FORMAT " not fixed!", caps);
     return FALSE;
   }
 
@@ -343,7 +377,7 @@ gst_sbc_enc_fill_sbc_params (GstSbcEnc * enc, GstCaps * caps)
       && gst_sbc_parse_subbands_from_sbc (enc->sbc.subbands) != enc->subbands)
     goto fail;
 
-  if (enc->mode != SBC_ENC_DEFAULT_MODE && enc->sbc.mode != enc->mode)
+  if (enc->mode != SBC_ENC_DEFAULT_CHANNEL_MODE && enc->sbc.mode != enc->mode)
     goto fail;
 
   if (enc->allocation != SBC_AM_AUTO && enc->sbc.allocation != enc->allocation)
@@ -367,51 +401,61 @@ fail:
 }
 
 static GstFlowReturn
-sbc_enc_chain (GstPad * pad, GstBuffer * buffer)
+sbc_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 {
-  GstSbcEnc *enc = GST_SBC_ENC (gst_pad_get_parent (pad));
+  GstSbcEnc *enc = GST_SBC_ENC (parent);
   GstAdapter *adapter = enc->adapter;
   GstFlowReturn res = GST_FLOW_OK;
 
+  if (enc->codesize == 0)
+    goto not_negotiated;
+
   gst_adapter_push (adapter, buffer);
 
-  while (gst_adapter_available (adapter) >= enc->codesize && res == GST_FLOW_OK) {
-    GstBuffer *output;
-    GstCaps *caps;
+  while (gst_adapter_available (adapter) >= enc->codesize) {
+    GstMapInfo out_map;
+    GstBuffer *outbuf;
     const guint8 *data;
     gint consumed;
 
-    caps = GST_PAD_CAPS (enc->srcpad);
-    res = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
-        GST_BUFFER_OFFSET_NONE, enc->frame_length, caps, &output);
-    if (res != GST_FLOW_OK)
-      goto done;
+    outbuf = gst_buffer_new_and_alloc (enc->frame_length);
+    gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);
 
-    data = gst_adapter_peek (adapter, enc->codesize);
+    data = gst_adapter_map (adapter, enc->codesize);
 
     consumed = sbc_encode (&enc->sbc, (gpointer) data,
-        enc->codesize,
-        GST_BUFFER_DATA (output), GST_BUFFER_SIZE (output), NULL);
+        enc->codesize, out_map.data, out_map.size, NULL);
+
+    gst_adapter_unmap (adapter);
+    gst_buffer_unmap (outbuf, &out_map);
+
     if (consumed <= 0) {
-      GST_DEBUG_OBJECT (enc, "comsumed < 0, codesize: %d", enc->codesize);
+      GST_DEBUG_OBJECT (enc, "consumed < 0, codesize: %d", enc->codesize);
+      gst_buffer_unref (outbuf);
       break;
     }
     gst_adapter_flush (adapter, consumed);
 
-    GST_BUFFER_TIMESTAMP (output) = GST_BUFFER_TIMESTAMP (buffer);
+    /* FIXME: this is not right if we don't have a 1:1 mapping of
+     * input and output data */
+    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
     /* we have only 1 frame */
-    GST_BUFFER_DURATION (output) = enc->frame_duration;
+    GST_BUFFER_DURATION (outbuf) = enc->frame_duration;
 
-    res = gst_pad_push (enc->srcpad, output);
+    res = gst_pad_push (enc->srcpad, outbuf);
 
     if (res != GST_FLOW_OK)
-      goto done;
+      break;
   }
 
-done:
-  gst_object_unref (enc);
-
   return res;
+
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (enc, "output caps not negotiated yet");
+    gst_buffer_unref (buffer);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
 }
 
 static GstStateChangeReturn
@@ -434,32 +478,20 @@ sbc_enc_change_state (GstElement * element, GstStateChange transition)
       break;
   }
 
-  return parent_class->change_state (element, transition);
+  return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 }
 
 static void
-gst_sbc_enc_dispose (GObject * object)
+gst_sbc_enc_finalize (GObject * object)
 {
   GstSbcEnc *enc = GST_SBC_ENC (object);
 
-  if (enc->adapter != NULL)
-    g_object_unref (G_OBJECT (enc->adapter));
-
-  enc->adapter = NULL;
-}
-
-static void
-gst_sbc_enc_base_init (gpointer g_class)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&sbc_enc_sink_factory));
-
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&sbc_enc_src_factory));
+  if (enc->adapter != NULL) {
+    g_object_unref (enc->adapter);
+    enc->adapter = NULL;
+  }
 
-  gst_element_class_set_details (element_class, &sbc_enc_details);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static void
@@ -529,21 +561,21 @@ gst_sbc_enc_class_init (GstSbcEncClass * klass)
 
   parent_class = g_type_class_peek_parent (klass);
 
-  object_class->set_property = GST_DEBUG_FUNCPTR (gst_sbc_enc_set_property);
-  object_class->get_property = GST_DEBUG_FUNCPTR (gst_sbc_enc_get_property);
-  object_class->dispose = GST_DEBUG_FUNCPTR (gst_sbc_enc_dispose);
+  object_class->set_property = gst_sbc_enc_set_property;
+  object_class->get_property = gst_sbc_enc_get_property;
+  object_class->finalize = gst_sbc_enc_finalize;
 
   element_class->change_state = GST_DEBUG_FUNCPTR (sbc_enc_change_state);
 
   g_object_class_install_property (object_class, PROP_MODE,
-      g_param_spec_enum ("mode", "Mode",
-          "Encoding mode", GST_TYPE_SBC_MODE,
-          SBC_ENC_DEFAULT_MODE, G_PARAM_READWRITE));
+      g_param_spec_enum ("channel-mode", "Channel Mode",
+          "Channel mode", GST_TYPE_SBC_CHANNEL_MODE,
+          SBC_ENC_DEFAULT_CHANNEL_MODE, G_PARAM_READWRITE));
 
   g_object_class_install_property (object_class, PROP_ALLOCATION,
-      g_param_spec_enum ("allocation", "Allocation",
-          "Allocation method", GST_TYPE_SBC_ALLOCATION,
-          SBC_ENC_DEFAULT_ALLOCATION, G_PARAM_READWRITE));
+      g_param_spec_enum ("allocation-method", "Allocation Method",
+          "Allocation method", GST_TYPE_SBC_ALLOCATION_METHOD,
+          SBC_ENC_DEFAULT_ALLOCATION_METHOD, G_PARAM_READWRITE));
 
   g_object_class_install_property (object_class, PROP_BLOCKS,
       g_param_spec_enum ("blocks", "Blocks",
@@ -561,31 +593,41 @@ gst_sbc_enc_class_init (GstSbcEncClass * klass)
           SBC_ENC_BITPOOL_AUTO, SBC_ENC_BITPOOL_MAX,
           SBC_ENC_BITPOOL_AUTO, G_PARAM_READWRITE));
 
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sbc_enc_sink_factory));
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sbc_enc_src_factory));
+
+  gst_element_class_set_static_metadata (element_class,
+      "Bluetooth SBC audio encoder", "Codec/Encoder/Audio",
+      "Encode an SBC audio stream", "Marcel Holtmann <marcel@holtmann.org>");
+
   GST_DEBUG_CATEGORY_INIT (sbc_enc_debug, "sbcenc", 0, "SBC encoding element");
 }
 
 static void
-gst_sbc_enc_init (GstSbcEnc * self, GstSbcEncClass * klass)
+gst_sbc_enc_init (GstSbcEnc * self)
 {
   self->sinkpad =
       gst_pad_new_from_static_template (&sbc_enc_sink_factory, "sink");
-  gst_pad_set_setcaps_function (self->sinkpad,
-      GST_DEBUG_FUNCPTR (sbc_enc_sink_setcaps));
+  gst_pad_set_event_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_sbc_enc_sink_event));
   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
 
   self->srcpad = gst_pad_new_from_static_template (&sbc_enc_src_factory, "src");
+#if 0
   gst_pad_set_getcaps_function (self->srcpad,
       GST_DEBUG_FUNCPTR (sbc_enc_src_getcaps));
-  gst_pad_set_setcaps_function (self->srcpad,
-      GST_DEBUG_FUNCPTR (sbc_enc_src_setcaps));
+#endif
   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
 
   gst_pad_set_chain_function (self->sinkpad, GST_DEBUG_FUNCPTR (sbc_enc_chain));
 
   self->subbands = SBC_ENC_DEFAULT_SUB_BANDS;
   self->blocks = SBC_ENC_DEFAULT_BLOCKS;
-  self->mode = SBC_ENC_DEFAULT_MODE;
-  self->allocation = SBC_ENC_DEFAULT_ALLOCATION;
+  self->mode = SBC_ENC_DEFAULT_CHANNEL_MODE;
+  self->allocation = SBC_ENC_DEFAULT_ALLOCATION_METHOD;
   self->rate = SBC_ENC_DEFAULT_RATE;
   self->channels = SBC_ENC_DEFAULT_CHANNELS;
   self->bitpool = SBC_ENC_BITPOOL_AUTO;
index 0329351fa6815f996a64760285fcf52a40c6ff7d..7904c3ef13b5c25ff447bbeb23daa39815f7e2f6 100644 (file)
@@ -24,7 +24,7 @@
 #include <gst/gst.h>
 #include <gst/base/gstadapter.h>
 
-#include "sbc.h"
+#include <sbc/sbc.h>
 
 G_BEGIN_DECLS
 
index 47e997cec98105e39315e364ac42c2fd8d8dfb1f..63fef55020af74e865f779bdce575f938a297c08 100644 (file)
@@ -1,5 +1,4 @@
-/*
- *
+/*  SBC audio utilities
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
@@ -317,155 +316,18 @@ gst_sbc_parse_caps_from_sbc (sbc_t * sbc)
       gst_sbc_parse_rate_from_sbc (sbc->frequency),
       "channels", G_TYPE_INT,
       gst_sbc_get_channel_number (sbc->mode),
-      "mode", G_TYPE_STRING, mode_str,
+      "channel-mode", G_TYPE_STRING, mode_str,
       "subbands", G_TYPE_INT,
       gst_sbc_parse_subbands_from_sbc (sbc->subbands),
       "blocks", G_TYPE_INT,
       gst_sbc_parse_blocks_from_sbc (sbc->blocks),
-      "allocation", G_TYPE_STRING, allocation_str,
+      "allocation-method", G_TYPE_STRING, allocation_str,
       "bitpool", G_TYPE_INT, sbc->bitpool, NULL);
 
   return caps;
 }
 
-/*
- * Given a GstCaps, this will return a fixed GstCaps on successful conversion.
- * If an error occurs, it will return NULL and error_message will contain the
- * error message.
- *
- * error_message must be passed NULL, if an error occurs, the caller has the
- * ownership of the error_message, it must be freed after use.
- */
-GstCaps *
-gst_sbc_util_caps_fixate (GstCaps * caps, gchar ** error_message)
-{
-  GstCaps *result;
-  GstStructure *structure;
-  const GValue *value;
-  gboolean error = FALSE;
-  gint temp, rate, channels, blocks, subbands, bitpool;
-  const gchar *allocation = NULL;
-  const gchar *mode = NULL;
-
-  g_assert (*error_message == NULL);
-
-  structure = gst_caps_get_structure (caps, 0);
-
-  if (!gst_structure_has_field (structure, "rate")) {
-    error = TRUE;
-    *error_message = g_strdup ("no rate");
-    goto error;
-  } else {
-    value = gst_structure_get_value (structure, "rate");
-    if (GST_VALUE_HOLDS_LIST (value))
-      temp = gst_sbc_select_rate_from_list (value);
-    else
-      temp = g_value_get_int (value);
-    rate = temp;
-  }
-
-  if (!gst_structure_has_field (structure, "channels")) {
-    error = TRUE;
-    *error_message = g_strdup ("no channels");
-    goto error;
-  } else {
-    value = gst_structure_get_value (structure, "channels");
-    if (GST_VALUE_HOLDS_INT_RANGE (value))
-      temp = gst_sbc_select_channels_from_range (value);
-    else
-      temp = g_value_get_int (value);
-    channels = temp;
-  }
-
-  if (!gst_structure_has_field (structure, "blocks")) {
-    error = TRUE;
-    *error_message = g_strdup ("no blocks.");
-    goto error;
-  } else {
-    value = gst_structure_get_value (structure, "blocks");
-    if (GST_VALUE_HOLDS_LIST (value))
-      temp = gst_sbc_select_blocks_from_list (value);
-    else
-      temp = g_value_get_int (value);
-    blocks = temp;
-  }
-
-  if (!gst_structure_has_field (structure, "subbands")) {
-    error = TRUE;
-    *error_message = g_strdup ("no subbands");
-    goto error;
-  } else {
-    value = gst_structure_get_value (structure, "subbands");
-    if (GST_VALUE_HOLDS_LIST (value))
-      temp = gst_sbc_select_subbands_from_list (value);
-    else
-      temp = g_value_get_int (value);
-    subbands = temp;
-  }
-
-  if (!gst_structure_has_field (structure, "bitpool")) {
-    error = TRUE;
-    *error_message = g_strdup ("no bitpool");
-    goto error;
-  } else {
-    value = gst_structure_get_value (structure, "bitpool");
-    if (GST_VALUE_HOLDS_INT_RANGE (value))
-      temp = gst_sbc_select_bitpool_from_range (value);
-    else
-      temp = g_value_get_int (value);
-    bitpool = temp;
-  }
-
-  if (!gst_structure_has_field (structure, "allocation")) {
-    error = TRUE;
-    *error_message = g_strdup ("no allocation");
-    goto error;
-  } else {
-    value = gst_structure_get_value (structure, "allocation");
-    if (GST_VALUE_HOLDS_LIST (value))
-      allocation = gst_sbc_get_allocation_from_list (value);
-    else
-      allocation = g_value_get_string (value);
-  }
-
-  if (!gst_structure_has_field (structure, "mode")) {
-    error = TRUE;
-    *error_message = g_strdup ("no mode");
-    goto error;
-  } else {
-    value = gst_structure_get_value (structure, "mode");
-    if (GST_VALUE_HOLDS_LIST (value)) {
-      mode = gst_sbc_get_mode_from_list (value, channels);
-    } else
-      mode = g_value_get_string (value);
-  }
-
-  /* perform validation
-   * if channels is 1, we must have channel mode = mono
-   * if channels is 2, we can't have channel mode = mono */
-  if ((channels == 1 && (strcmp (mode, "mono") != 0)) ||
-      (channels == 2 && (strcmp (mode, "mono") == 0))) {
-    *error_message = g_strdup_printf ("Invalid combination of "
-        "channels (%d) and channel mode (%s)", channels, mode);
-    error = TRUE;
-  }
-
-error:
-  if (error)
-    return NULL;
-
-  result = gst_caps_new_simple ("audio/x-sbc",
-      "rate", G_TYPE_INT, rate,
-      "channels", G_TYPE_INT, channels,
-      "mode", G_TYPE_STRING, mode,
-      "blocks", G_TYPE_INT, blocks,
-      "subbands", G_TYPE_INT, subbands,
-      "allocation", G_TYPE_STRING, allocation,
-      "bitpool", G_TYPE_INT, bitpool, NULL);
-
-  return result;
-}
-
+/* FIXME: this function is not needed, just use gst_structure_set() */
 /**
  * Sets the int field_value to the  param "field" on the structure.
  * value is used to do the operation, it must be a uninitialized (zero-filled)
@@ -519,9 +381,9 @@ gst_sbc_util_fill_sbc_params (sbc_t * sbc, GstCaps * caps)
   if (!gst_structure_get_int (structure, "bitpool", &bitpool))
     return FALSE;
 
-  if (!(mode = gst_structure_get_string (structure, "mode")))
+  if (!(mode = gst_structure_get_string (structure, "channel-mode")))
     return FALSE;
-  if (!(allocation = gst_structure_get_string (structure, "allocation")))
+  if (!(allocation = gst_structure_get_string (structure, "allocation-method")))
     return FALSE;
 
   if (channels == 1 && strcmp (mode, "mono") != 0)
index 962532f7866decc3c3cb1c2baa7788952c740379..8d594c0fa8beb408878d2872b7a727c8f1145e89 100644 (file)
@@ -1,5 +1,4 @@
-/*
- *
+/*  SBC audio utilities
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
@@ -23,7 +22,7 @@
 
 #include <gst/gst.h>
 
-#include "sbc.h"
+#include <sbc/sbc.h>
 #include <string.h>
 
 #define SBC_AM_AUTO 0x02
@@ -61,8 +60,6 @@ gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation);
 
 GstCaps *gst_sbc_parse_caps_from_sbc(sbc_t *sbc);
 
-GstCaps *gst_sbc_util_caps_fixate(GstCaps *caps, gchar **error_message);
-
 void gst_sbc_util_set_structure_int_param(GstStructure *structure,
                        const gchar *field, gint field_value,
                        GValue *value);
diff --git a/ext/sbc/sbc-plugin.c b/ext/sbc/sbc-plugin.c
new file mode 100644 (file)
index 0000000..7020753
--- /dev/null
@@ -0,0 +1,41 @@
+/* GStreamer SBC audio plugin
+ * Copyright (C) 2013 Tim-Philipp Müller <tim@centricular.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstsbcdec.h"
+#include "gstsbcenc.h"
+
+#include <string.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gst_element_register (plugin, "sbcdec", GST_RANK_NONE, GST_TYPE_SBC_DEC);
+  gst_element_register (plugin, "sbcenc", GST_RANK_NONE, GST_TYPE_SBC_ENC);
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    sbc,
+    "SBC bluetooth audio support",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);