diff options
-rw-r--r-- | audio/gsta2dpsink.c | 13 | ||||
-rw-r--r-- | audio/gstsbcenc.c | 177 | ||||
-rw-r--r-- | audio/gstsbcenc.h | 2 | ||||
-rw-r--r-- | audio/gstsbcutil.c | 64 | ||||
-rw-r--r-- | audio/gstsbcutil.h | 3 |
5 files changed, 181 insertions, 78 deletions
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c index 6595d0b5..4ff30b84 100644 --- a/audio/gsta2dpsink.c +++ b/audio/gsta2dpsink.c @@ -109,12 +109,12 @@ static GstElement* gst_a2dp_sink_init_element(GstA2dpSink *self, element = gst_element_factory_make(elementname, name); if (element == NULL) { - GST_ERROR_OBJECT(self, "Couldn't create %s", elementname); + GST_DEBUG_OBJECT(self, "Couldn't create %s", elementname); return NULL; } if (!gst_bin_add(GST_BIN(self), element)) { - GST_ERROR_OBJECT(self, "failed to add %s to the bin", + GST_DEBUG_OBJECT(self, "failed to add %s to the bin", elementname); goto cleanup_and_fail; } @@ -122,14 +122,15 @@ static GstElement* gst_a2dp_sink_init_element(GstA2dpSink *self, state = gst_a2dp_sink_get_state(self); if (gst_element_set_state(element, state) == GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT(self, "%s failed to go to playing", + GST_DEBUG_OBJECT(self, "%s failed to go to playing", elementname); goto remove_element_and_fail; } if (link_to != NULL) if (!gst_element_link(link_to, element)) { - GST_ERROR_OBJECT(self, "couldn't link %s", elementname); + GST_DEBUG_OBJECT(self, "couldn't link %s", + elementname); goto remove_element_and_fail; } @@ -293,10 +294,8 @@ static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, break; } - if (ret == GST_STATE_CHANGE_FAILURE) { - g_mutex_unlock(self->cb_mutex); + if (ret == GST_STATE_CHANGE_FAILURE) return ret; - } ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 08ddc14f..88737475 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -34,11 +34,16 @@ #define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_AUTO #define SBC_ENC_DEFAULT_BLOCKS 0 #define SBC_ENC_DEFAULT_SUB_BANDS 0 -#define SBC_ENC_DEFAULT_BITPOOL 0 #define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_AUTO #define SBC_ENC_DEFAULT_RATE 0 #define SBC_ENC_DEFAULT_CHANNELS 0 +#define SBC_ENC_BITPOOL_AUTO 1 +#define SBC_ENC_BITPOOL_MIN 2 +#define SBC_ENC_BITPOOL_MIN_STR "2" +#define SBC_ENC_BITPOOL_MAX 64 +#define SBC_ENC_BITPOOL_MAX_STR "64" + GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); #define GST_CAT_DEFAULT sbc_enc_debug @@ -81,12 +86,53 @@ static GType gst_sbc_allocation_get_type(void) return sbc_allocation_type; } +#define GST_TYPE_SBC_BLOCKS (gst_sbc_blocks_get_type()) + +static GType gst_sbc_blocks_get_type(void) +{ + static GType sbc_blocks_type = 0; + static GEnumValue sbc_blocks[] = { + { 0, "Auto", "auto" }, + { 4, "4", "4" }, + { 8, "8", "8" }, + { 12, "12", "12" }, + { 16, "16", "16" }, + { -1, NULL, NULL} + }; + + if (!sbc_blocks_type) + sbc_blocks_type = g_enum_register_static( + "GstSbcBlocks", sbc_blocks); + + return sbc_blocks_type; +} + +#define GST_TYPE_SBC_SUBBANDS (gst_sbc_subbands_get_type()) + +static GType gst_sbc_subbands_get_type(void) +{ + static GType sbc_subbands_type = 0; + static GEnumValue sbc_subbands[] = { + { 0, "Auto", "auto" }, + { 4, "4 subbands", "4" }, + { 8, "8 subbands", "8" }, + { -1, NULL, NULL} + }; + + if (!sbc_subbands_type) + sbc_subbands_type = g_enum_register_static( + "GstSbcSubbands", sbc_subbands); + + return sbc_subbands_type; +} + enum { PROP_0, PROP_MODE, PROP_ALLOCATION, PROP_BLOCKS, - PROP_SUBBANDS + PROP_SUBBANDS, + PROP_BITPOOL }; GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT); @@ -116,7 +162,8 @@ static GstStaticPadTemplate sbc_enc_src_factory = "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " "allocation = (string) { snr, loudness }," - "bitpool = (int) [ 2, 64 ]")); + "bitpool = (int) [ " SBC_ENC_BITPOOL_MIN_STR + ", " SBC_ENC_BITPOOL_MAX_STR " ]")); gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps); @@ -150,6 +197,10 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) gst_sbc_util_set_structure_int_param(structure, "blocks", enc->blocks, value); + if (enc->bitpool != SBC_ENC_BITPOOL_AUTO) + gst_sbc_util_set_structure_int_param(structure, "bitpool", + enc->bitpool, value); + if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) { enum_class = g_type_class_ref(GST_TYPE_SBC_MODE); enum_value = g_enum_get_value(enum_class, enc->mode); @@ -201,7 +252,7 @@ static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) result = gst_sbc_util_caps_fixate(caps, &error_message); if (!result) { - GST_ERROR_OBJECT (enc, "Invalid input caps caused parsing " + GST_WARNING_OBJECT (enc, "Invalid input caps caused parsing " "error: %s", error_message); g_free(error_message); return NULL; @@ -212,18 +263,13 @@ static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) static GstCaps* sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc) { - GstCaps *peer_caps; - GstCaps *src_caps; GstCaps *caps; gboolean res = TRUE; GstCaps *result_caps = NULL; - peer_caps = gst_pad_peer_get_caps(enc->srcpad); - if (!peer_caps) - return NULL; - - src_caps = sbc_enc_generate_srcpad_caps(enc); - caps = gst_caps_intersect(src_caps, peer_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; @@ -233,9 +279,6 @@ static GstCaps* sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc) result_caps = sbc_enc_src_caps_fixate(enc, caps); done: - - gst_caps_unref(src_caps); - gst_caps_unref(peer_caps); gst_caps_unref(caps); if (!res) @@ -256,45 +299,71 @@ static gboolean sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps) structure = gst_caps_get_structure(caps, 0); if (!gst_structure_get_int(structure, "rate", &rate)) - goto error; + return FALSE; if (!gst_structure_get_int(structure, "channels", &channels)) - goto error; + return FALSE; enc->rate = rate; enc->channels = channels; src_caps = sbc_enc_get_fixed_srcpad_caps(enc); if (!src_caps) - goto error; + return FALSE; res = gst_pad_set_caps(enc->srcpad, src_caps); gst_caps_unref(src_caps); return res; - -error: - GST_ERROR_OBJECT (enc, "invalid input caps"); - return FALSE; } gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) { + gint mode; + + if (!gst_caps_is_fixed(caps)) { + GST_DEBUG_OBJECT(enc, "didn't receive fixed caps, " + "returning false"); + return FALSE; + } if (!gst_sbc_util_fill_sbc_params(&enc->sbc, caps)) return FALSE; - enc->rate = enc->sbc.rate; - enc->channels = enc->sbc.channels; - enc->blocks = enc->sbc.blocks; - enc->subbands = enc->sbc.subbands; - enc->mode = enc->sbc.joint; - enc->allocation = enc->sbc.allocation; + if (enc->rate != 0 && enc->sbc.rate != enc->rate) + goto fail; + + if (enc->channels != 0 && enc->sbc.channels != enc->channels) + goto fail; + + if (enc->blocks != 0 && enc->sbc.blocks != enc->blocks) + goto fail; + + if (enc->subbands != 0 && enc->sbc.subbands != enc->subbands) + goto fail; + + mode = gst_sbc_get_mode_int_from_sbc_t(&enc->sbc); + if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO && mode != enc->mode) + goto fail; + + if (enc->allocation != BT_A2DP_ALLOCATION_AUTO && + enc->sbc.allocation != enc->allocation) + goto fail; + + if (enc->bitpool != SBC_ENC_BITPOOL_AUTO && + enc->sbc.bitpool != enc->bitpool) + goto fail; + enc->codesize = sbc_get_codesize(&enc->sbc); enc->frame_length = sbc_get_frame_length(&enc->sbc); enc->frame_duration = sbc_get_frame_duration(&enc->sbc); + GST_DEBUG("codesize: %d, frame_length: %d, frame_duration: %d", enc->codesize, enc->frame_length, enc->frame_duration); return TRUE; + +fail: + memset(&enc->sbc, 0, sizeof(sbc_t)); + return FALSE; } static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) @@ -393,23 +462,6 @@ static void gst_sbc_enc_base_init(gpointer g_class) gst_element_class_set_details(element_class, &sbc_enc_details); } -static gboolean sbc_enc_set_blocks(GstSbcEnc *enc, gint value) -{ - if (value != 4 && value != 8 && value != 12 && - value != 16 && value != 0) - return FALSE; - enc->blocks = value; - return TRUE; -} - -static gboolean sbc_enc_set_subbands(GstSbcEnc *enc, gint value) -{ - if (value != 4 && value != 8 && value != 0) - return FALSE; - enc->subbands = value; - return TRUE; -} - static void gst_sbc_enc_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { @@ -426,14 +478,13 @@ static void gst_sbc_enc_set_property(GObject *object, guint prop_id, enc->allocation = g_value_get_enum(value); break; case PROP_BLOCKS: - if (!sbc_enc_set_blocks(enc, g_value_get_int(value))) - GST_WARNING_OBJECT(enc, "invalid value %d for " - "blocks property", g_value_get_int(value)); + enc->blocks = g_value_get_enum(value); break; case PROP_SUBBANDS: - if (!sbc_enc_set_subbands(enc, g_value_get_int(value))) - GST_WARNING_OBJECT(enc, "invalid value %d for " - "subbands property", g_value_get_int(value)); + enc->subbands = g_value_get_enum(value); + break; + case PROP_BITPOOL: + enc->bitpool = g_value_get_int(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -454,10 +505,13 @@ static void gst_sbc_enc_get_property(GObject *object, guint prop_id, g_value_set_enum(value, enc->allocation); break; case PROP_BLOCKS: - g_value_set_int(value, enc->blocks); + g_value_set_enum(value, enc->blocks); break; case PROP_SUBBANDS: - g_value_set_int(value, enc->subbands); + g_value_set_enum(value, enc->subbands); + break; + case PROP_BITPOOL: + g_value_set_int(value, enc->bitpool); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -485,19 +539,25 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) g_object_class_install_property(object_class, PROP_ALLOCATION, g_param_spec_enum("allocation", "Allocation", - "Allocation mode", GST_TYPE_SBC_ALLOCATION, + "Allocation method", GST_TYPE_SBC_ALLOCATION, SBC_ENC_DEFAULT_ALLOCATION, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_BLOCKS, - g_param_spec_int("blocks", "Blocks", - "Blocks", 0, G_MAXINT, + g_param_spec_enum("blocks", "Blocks", + "Blocks", GST_TYPE_SBC_BLOCKS, SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_SUBBANDS, - g_param_spec_int("subbands", "Sub Bands", - "Sub Bands", 0, G_MAXINT, + g_param_spec_enum("subbands", "Sub bands", + "Number of sub bands", GST_TYPE_SBC_SUBBANDS, SBC_ENC_DEFAULT_SUB_BANDS, G_PARAM_READWRITE)); + g_object_class_install_property(object_class, PROP_BITPOOL, + g_param_spec_int("bitpool", "Bitpool", + "Bitpool (use 1 for automatic selection)", + SBC_ENC_BITPOOL_AUTO, SBC_ENC_BITPOOL_MAX, + SBC_ENC_BITPOOL_AUTO, G_PARAM_READWRITE)); + GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0, "SBC encoding element"); } @@ -527,6 +587,7 @@ static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) self->allocation = SBC_ENC_DEFAULT_ALLOCATION; self->rate = SBC_ENC_DEFAULT_RATE; self->channels = SBC_ENC_DEFAULT_CHANNELS; + self->bitpool = SBC_ENC_BITPOOL_AUTO; self->frame_length = 0; self->frame_duration = 0; diff --git a/audio/gstsbcenc.h b/audio/gstsbcenc.h index c7b21638..41417507 100644 --- a/audio/gstsbcenc.h +++ b/audio/gstsbcenc.h @@ -55,6 +55,8 @@ struct _GstSbcEnc { gint blocks; gint allocation; gint subbands; + gint bitpool; + gint codesize; gint frame_length; gint frame_duration; diff --git a/audio/gstsbcutil.c b/audio/gstsbcutil.c index e5d21af0..7c47dbca 100644 --- a/audio/gstsbcutil.c +++ b/audio/gstsbcutil.c @@ -90,21 +90,39 @@ const gchar *gst_sbc_get_allocation_from_list(const GValue *value) /* * Selects one mode from the ones on the list */ -const gchar *gst_sbc_get_mode_from_list(const GValue *list) +const gchar *gst_sbc_get_mode_from_list(const GValue *list, gint channels) { int i; const GValue *value; const gchar *aux; + gboolean joint, stereo, dual, mono; + joint = stereo = dual = mono = FALSE; guint size = gst_value_list_get_size(list); + for (i = 0; i < size; i++) { value = gst_value_list_get_value(list, i); aux = g_value_get_string(value); - if (strcmp("joint", aux) == 0) { + if (strcmp("joint", aux) == 0) + joint = TRUE; + else if (strcmp("stereo", aux) == 0) + stereo = TRUE; + else if (strcmp("dual", aux) == 0) + dual = TRUE; + else if (strcmp("mono", aux) == 0) + mono = TRUE; + } + + if (channels == 1 && mono) + return "mono"; + else if (channels == 2) { + if (joint) return "joint"; - } + else if (stereo) + return "stereo"; } - return g_value_get_string(gst_value_list_get_value(list, size-1)); + + return NULL; } gint gst_sbc_get_allocation_mode_int(const gchar *allocation) @@ -148,7 +166,20 @@ gboolean gst_sbc_get_mode_int_for_sbc_t(const gchar *mode) return -1; } -const gchar *gst_sbc_get_mode_string(int joint) +gint gst_sbc_get_mode_int_from_sbc_t(const sbc_t *sbc) +{ + /* TODO define constants */ + if (sbc->channels == 2 && sbc->joint == 1) + return 4; + else if (sbc->channels == 2 && sbc->joint == 0) + return 3; + else if (sbc->channels == 1) + return 1; + else + return -1; +} + +const gchar *gst_sbc_get_mode_string(gint joint) { switch (joint) { case BT_A2DP_CHANNEL_MODE_MONO: @@ -166,7 +197,7 @@ const gchar *gst_sbc_get_mode_string(int joint) } } -const gchar *gst_sbc_get_allocation_string(int alloc) +const gchar *gst_sbc_get_allocation_string(gint alloc) { switch (alloc) { case BT_A2DP_ALLOCATION_LOUDNESS: @@ -190,7 +221,7 @@ const gchar *gst_sbc_get_allocation_string(int alloc) #define SBC_AM_LOUDNESS 0x00 #define SBC_AM_SNR 0x01 -const gchar *gst_sbc_get_mode_string_from_sbc_t(int channels, int joint) +const gchar *gst_sbc_get_mode_string_from_sbc_t(gint channels, gint joint) { if (channels == 2 && joint == 1) return "joint"; @@ -202,7 +233,7 @@ const gchar *gst_sbc_get_mode_string_from_sbc_t(int channels, int joint) return NULL; } -const gchar *gst_sbc_get_allocation_string_from_sbc_t(int alloc) +const gchar *gst_sbc_get_allocation_string_from_sbc_t(gint alloc) { switch (alloc) { case SBC_AM_LOUDNESS: @@ -365,14 +396,23 @@ GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message) } else { value = gst_structure_get_value(structure, "mode"); if (GST_VALUE_HOLDS_LIST(value)) { - if (channels == 1) - mode = "mono"; - else - mode = gst_sbc_get_mode_from_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, dual */ + if ( (channels == 1 && (strcmp(mode, "mono") != 0) ) || + ( channels == 2 && ( strcmp(mode, "mono") == 0 || + strcmp(mode, "dual") == 0 ) )) { + *error_message = g_strdup_printf("Invalid combination of " + "channels (%d) and channel mode (%s)", + channels, mode); + error = TRUE; + } + error: if (error) return NULL; diff --git a/audio/gstsbcutil.h b/audio/gstsbcutil.h index 4bdb5ac5..9e81af1a 100644 --- a/audio/gstsbcutil.h +++ b/audio/gstsbcutil.h @@ -42,8 +42,9 @@ const gchar *gst_sbc_get_allocation_from_list(const GValue *value); gint gst_sbc_get_allocation_mode_int(const gchar *allocation); const gchar *gst_sbc_get_allocation_string(int alloc); -const gchar *gst_sbc_get_mode_from_list(const GValue *value); +const gchar *gst_sbc_get_mode_from_list(const GValue *value, gint channels); gint gst_sbc_get_mode_int(const gchar *mode); +gint gst_sbc_get_mode_int_from_sbc_t(const sbc_t *sbc); const gchar *gst_sbc_get_mode_string(int joint); GstCaps* gst_sbc_caps_from_sbc(sbc_capabilities_t *sbc, gint channels); |