summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernhard Miller <bernhard.miller@streamunlimited.com>2013-08-28 14:26:04 +0200
committerSebastian Dröge <slomo@circular-chaos.org>2013-08-29 10:17:07 +0200
commit597e3cc98d13ebc8ec195a9745bd2c4b36e1bd29 (patch)
tree0b4f3268e52fd4a0dea614fd683f821e59c376d9
parente39239677e3ca62b78438c157dc7eeee80fb072e (diff)
downloadgstreamer-plugins-bad-597e3cc98d13ebc8ec195a9745bd2c4b36e1bd29.tar.gz
bluez: support aac in avdtpsrc
Signed-off-by: Bernhard Miller <bernhard.miller@streamunlimited.com>
-rw-r--r--sys/bluez/a2dp-codecs.h39
-rw-r--r--sys/bluez/gstavdtpsrc.c42
-rw-r--r--sys/bluez/gstavdtputil.c153
3 files changed, 232 insertions, 2 deletions
diff --git a/sys/bluez/a2dp-codecs.h b/sys/bluez/a2dp-codecs.h
index b83687288..39e875d67 100644
--- a/sys/bluez/a2dp-codecs.h
+++ b/sys/bluez/a2dp-codecs.h
@@ -90,6 +90,27 @@
#define MPEG_BIT_RATE_32000 0x0002
#define MPEG_BIT_RATE_FREE 0x0001
+#define AAC_OBJECT_TYPE_MPEG2_AAC_LC 0x80
+#define AAC_OBJECT_TYPE_MPEG4_AAC_LC 0x40
+#define AAC_OBJECT_TYPE_MPEG4_AAC_LTP 0x20
+#define AAC_OBJECT_TYPE_MPEG4_AAC_SCALABLE 0x10
+
+#define AAC_SAMPLING_FREQ_8000 0x0800
+#define AAC_SAMPLING_FREQ_11025 0x0400
+#define AAC_SAMPLING_FREQ_12000 0x0200
+#define AAC_SAMPLING_FREQ_16000 0x0100
+#define AAC_SAMPLING_FREQ_22050 0x0080
+#define AAC_SAMPLING_FREQ_24000 0x0040
+#define AAC_SAMPLING_FREQ_32000 0x0020
+#define AAC_SAMPLING_FREQ_44100 0x0010
+#define AAC_SAMPLING_FREQ_48000 0x0008
+#define AAC_SAMPLING_FREQ_64000 0x0004
+#define AAC_SAMPLING_FREQ_88200 0x0002
+#define AAC_SAMPLING_FREQ_96000 0x0001
+
+#define AAC_CHANNELS_1 0x02
+#define AAC_CHANNELS_2 0x01
+
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
typedef struct {
@@ -112,6 +133,15 @@ typedef struct {
uint16_t bitrate;
} __attribute__ ((packed)) a2dp_mpeg_t;
+typedef struct {
+ uint8_t object_type;
+ uint16_t frequency;
+ uint8_t rfa;
+ uint8_t channels;
+ uint8_t vbr;
+ uint32_t bitrate;
+} __attribute__ ((packed)) a2dp_aac_t;
+
#elif G_BYTE_ORDER == G_BIG_ENDIAN
typedef struct {
@@ -134,6 +164,15 @@ typedef struct {
uint16_t bitrate;
} __attribute__ ((packed)) a2dp_mpeg_t;
+typedef struct {
+ uint8_t object_type;
+ uint16_t frequency:12;
+ uint8_t channels:2;
+ uint8_t rfa:2;
+ uint8_t vbr:1;
+ uint32_t bitrate:23;
+} __attribute__ ((packed)) a2dp_aac_t;
+
#else
#error "Unknown byte order"
#endif
diff --git a/sys/bluez/gstavdtpsrc.c b/sys/bluez/gstavdtpsrc.c
index f130151f2..311c407b7 100644
--- a/sys/bluez/gstavdtpsrc.c
+++ b/sys/bluez/gstavdtpsrc.c
@@ -52,7 +52,14 @@ static GstStaticPadTemplate gst_avdtp_src_template =
"payload = (int) "
GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
"clock-rate = (int) { 16000, 32000, "
- "44100, 48000 }, " "encoding-name = (string) \"SBC\"; "));
+ "44100, 48000 }, " "encoding-name = (string) \"SBC\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\","
+ "payload = (int) "
+ GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 8000, 11025, 12000, 16000, "
+ "22050, 2400, 32000, 44100, 48000, 64000, 88200, 96000 }, "
+ "encoding-name = (string) \"MP4A-LATM\"; "));
static void gst_avdtp_src_finalize (GObject * object);
static void gst_avdtp_src_get_property (GObject * object, guint prop_id,
@@ -184,7 +191,38 @@ gst_avdtp_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
"payload", GST_TYPE_INT_RANGE, 96, 127,
"encoding-name", G_TYPE_STRING, "SBC", NULL);
} else if (g_str_equal (format, "audio/mpeg")) {
- GST_ERROR_OBJECT (avdtpsrc, "Only SBC is supported at " "the moment");
+ caps = gst_caps_new_simple ("application/x-rtp",
+ "media", G_TYPE_STRING, "audio",
+ "payload", GST_TYPE_INT_RANGE, 96, 127,
+ "encoding-name", G_TYPE_STRING, "MP4A-LATM", NULL);
+
+ value = gst_structure_get_value (structure, "mpegversion");
+ if (!value || !G_VALUE_HOLDS_INT (value)) {
+ GST_ERROR_OBJECT (avdtpsrc, "Failed to get mpegversion");
+ goto fail;
+ }
+ gst_caps_set_simple (caps, "mpegversion", G_TYPE_INT,
+ g_value_get_int (value), NULL);
+
+ value = gst_structure_get_value (structure, "channels");
+ if (!value || !G_VALUE_HOLDS_INT (value)) {
+ GST_ERROR_OBJECT (avdtpsrc, "Failed to get channels");
+ goto fail;
+ }
+ gst_caps_set_simple (caps, "channels", G_TYPE_INT,
+ g_value_get_int (value), NULL);
+
+ value = gst_structure_get_value (structure, "base-profile");
+ if (!value || !G_VALUE_HOLDS_STRING (value)) {
+ GST_ERROR_OBJECT (avdtpsrc, "Failed to get base-profile");
+ goto fail;
+ }
+ gst_caps_set_simple (caps, "base-profile", G_TYPE_STRING,
+ g_value_get_string (value), NULL);
+
+ } else {
+ GST_ERROR_OBJECT (avdtpsrc,
+ "Only SBC and MPEG-2/4 are supported at the moment");
}
value = gst_structure_get_value (structure, "rate");
diff --git a/sys/bluez/gstavdtputil.c b/sys/bluez/gstavdtputil.c
index 61b5b17a2..07afd453a 100644
--- a/sys/bluez/gstavdtputil.c
+++ b/sys/bluez/gstavdtputil.c
@@ -604,6 +604,156 @@ gst_avdtp_util_parse_mpeg_raw (void *config)
return structure;
}
+static GstStructure *
+gst_avdtp_util_parse_aac_raw (void *config)
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ uint8_t *raw = (uint8_t *) config;
+ a2dp_aac_t aac_local = { 0 };
+ a2dp_aac_t *aac = &aac_local;
+ aac->object_type = raw[0];
+ aac->frequency = (raw[1] << 4) | ((raw[2] & 0xFF) >> 4);
+ aac->channels = (raw[2] >> 2) & 0x3;
+ aac->rfa = raw[2] & 0x3;
+ aac->vbr = (raw[3] >> 7) & 0x1;
+ aac->bitrate = (raw[4] << 16) | (raw[3] << 8) | raw[4];
+ aac->bitrate &= ~0x800000;
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ *aac = (a2dp_aac_t *) config;
+#else
+#error "Unknown byte order"
+#endif
+
+ GST_LOG ("aac objtype=%x freq=%x rfa=%x channels=%x vbr=%x bitrate=%x",
+ aac->object_type, aac->frequency, aac->rfa, aac->channels, aac->vbr,
+ aac->bitrate);
+
+ GstStructure *structure;
+ GValue value = G_VALUE_INIT;
+ GValue value_str = G_VALUE_INIT;
+ GValue listVersion = G_VALUE_INIT;
+ GValue listProfile = G_VALUE_INIT;
+ GValue listRate = G_VALUE_INIT;
+ GValue listChannels = G_VALUE_INIT;
+
+ structure = gst_structure_new_empty ("audio/mpeg");
+ g_value_init (&value, G_TYPE_INT);
+ g_value_init (&value_str, G_TYPE_STRING);
+
+ /* mpegversion */
+ g_value_init (&listVersion, GST_TYPE_LIST);
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) {
+ g_value_set_int (&value, 2);
+ gst_value_list_prepend_value (&listVersion, &value);
+ }
+ if ((aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC)
+ || (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP)
+ || (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCALABLE)) {
+ g_value_set_int (&value, 4);
+ gst_value_list_prepend_value (&listVersion, &value);
+ }
+ if (gst_value_list_get_size (&listVersion) == 1)
+ gst_structure_set_value (structure, "mpegversion", &value);
+ else
+ gst_structure_set_value (structure, "mpegversion", &listVersion);
+
+
+ /* base-profile */
+ g_value_init (&listProfile, GST_TYPE_LIST);
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC
+ || aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) {
+ g_value_set_string (&value_str, "lc");
+ gst_value_list_prepend_value (&listProfile, &value_str);
+ }
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP) {
+ g_value_set_string (&value_str, "ltp");
+ gst_value_list_prepend_value (&listProfile, &value_str);
+ }
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCALABLE) {
+ g_value_set_string (&value_str, "ssr");
+ gst_value_list_prepend_value (&listProfile, &value_str);
+ }
+ if (gst_value_list_get_size (&listProfile) == 1)
+ gst_structure_set_value (structure, "base-profile", &value_str);
+ else
+ gst_structure_set_value (structure, "base-profile", &listProfile);
+
+
+ /* rate */
+ g_value_init (&listRate, GST_TYPE_LIST);
+ if (aac->frequency & AAC_SAMPLING_FREQ_8000) {
+ g_value_set_int (&value, 8000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_11025) {
+ g_value_set_int (&value, 11025);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_12000) {
+ g_value_set_int (&value, 12000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_16000) {
+ g_value_set_int (&value, 16000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_22050) {
+ g_value_set_int (&value, 22050);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_24000) {
+ g_value_set_int (&value, 24000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_32000) {
+ g_value_set_int (&value, 32000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_44100) {
+ g_value_set_int (&value, 44100);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_48000) {
+ g_value_set_int (&value, 48000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_64000) {
+ g_value_set_int (&value, 64000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_88200) {
+ g_value_set_int (&value, 88200);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (aac->frequency & AAC_SAMPLING_FREQ_96000) {
+ g_value_set_int (&value, 96000);
+ gst_value_list_prepend_value (&listRate, &value);
+ }
+ if (gst_value_list_get_size (&listRate) == 1)
+ gst_structure_set_value (structure, "rate", &value);
+ else
+ gst_structure_set_value (structure, "rate", &listRate);
+
+ /* channels */
+ g_value_init (&listChannels, GST_TYPE_LIST);
+ if (aac->channels & AAC_CHANNELS_1) {
+ g_value_set_int (&value, 1);
+ gst_value_list_prepend_value (&listChannels, &value);
+ }
+ if (aac->channels & AAC_CHANNELS_2) {
+ g_value_set_int (&value, 2);
+ gst_value_list_prepend_value (&listChannels, &value);
+ }
+ if (gst_value_list_get_size (&listChannels) == 1)
+ gst_structure_set_value (structure, "channels", &value);
+ else
+ gst_structure_set_value (structure, "channels", &listChannels);
+
+ GST_LOG ("AAC caps: %" GST_PTR_FORMAT, structure);
+
+ return structure;
+}
+
GstCaps *
gst_avdtp_connection_get_caps (GstAvdtpConnection * conn)
{
@@ -620,6 +770,9 @@ gst_avdtp_connection_get_caps (GstAvdtpConnection * conn)
case A2DP_CODEC_MPEG12:
structure = gst_avdtp_util_parse_mpeg_raw (conn->data.config);
break;
+ case A2DP_CODEC_MPEG24:
+ structure = gst_avdtp_util_parse_aac_raw (conn->data.config);
+ break;
default:
GST_ERROR ("Unsupported configuration");
return NULL;