From 597e3cc98d13ebc8ec195a9745bd2c4b36e1bd29 Mon Sep 17 00:00:00 2001 From: Bernhard Miller Date: Wed, 28 Aug 2013 14:26:04 +0200 Subject: bluez: support aac in avdtpsrc Signed-off-by: Bernhard Miller --- sys/bluez/a2dp-codecs.h | 39 ++++++++++++ sys/bluez/gstavdtpsrc.c | 42 ++++++++++++- sys/bluez/gstavdtputil.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++ 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; -- cgit v1.2.1