bluez: support aac in avdtpsrc

Signed-off-by: Bernhard Miller <bernhard.miller@streamunlimited.com>
This commit is contained in:
Bernhard Miller 2013-08-28 14:26:04 +02:00 committed by Sebastian Dröge
parent e39239677e
commit 597e3cc98d
3 changed files with 232 additions and 2 deletions

View file

@ -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

View file

@ -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");

View file

@ -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;