summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/plugins/gst_plugins_cache.json2
-rw-r--r--sys/bluez/a2dp-codecs.h26
-rw-r--r--sys/bluez/gstavdtpsink.c19
-rw-r--r--sys/bluez/gstavdtputil.c109
4 files changed, 146 insertions, 10 deletions
diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json
index 7b8580a89..833735a59 100644
--- a/docs/plugins/gst_plugins_cache.json
+++ b/docs/plugins/gst_plugins_cache.json
@@ -2332,7 +2332,7 @@
"long-name": "Bluetooth AVDTP sink",
"pad-templates": {
"sink": {
- "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n encoding-name: SBC\napplication/x-rtp:\n media: audio\n payload: 14\n clock-rate: 90000\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MPA\n",
+ "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n encoding-name: SBC\napplication/x-rtp:\n media: audio\n payload: 14\n clock-rate: 90000\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MPA\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)44100, (int)48000, (int)88200, (int)96000 }\n encoding-name: X-GST-LDAC\n",
"direction": "sink",
"presence": "always"
}
diff --git a/sys/bluez/a2dp-codecs.h b/sys/bluez/a2dp-codecs.h
index 39e875d67..825b92d5e 100644
--- a/sys/bluez/a2dp-codecs.h
+++ b/sys/bluez/a2dp-codecs.h
@@ -111,6 +111,26 @@
#define AAC_CHANNELS_1 0x02
#define AAC_CHANNELS_2 0x01
+#define SONY_VENDOR_ID 0x0000012d
+#define LDAC_CODEC_ID 0x00aa
+
+#define LDAC_SAMPLING_FREQ_44100 0x20
+#define LDAC_SAMPLING_FREQ_48000 0x10
+#define LDAC_SAMPLING_FREQ_88200 0x08
+#define LDAC_SAMPLING_FREQ_96000 0x04
+
+#define LDAC_CHANNEL_MODE_MONO 0x04
+#define LDAC_CHANNEL_MODE_DUAL 0x02
+#define LDAC_CHANNEL_MODE_STEREO 0x01
+
+#define A2DP_GET_VENDOR_ID(a) ( \
+ (((uint32_t)(a).vendor_id[0]) << 0) | \
+ (((uint32_t)(a).vendor_id[1]) << 8) | \
+ (((uint32_t)(a).vendor_id[2]) << 16) | \
+ (((uint32_t)(a).vendor_id[3]) << 24) \
+ )
+#define A2DP_GET_CODEC_ID(a) ((a).codec_id[0] | (((uint16_t)(a).codec_id[1]) << 8))
+
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
typedef struct {
@@ -182,4 +202,10 @@ typedef struct {
uint8_t codec_id[2];
} __attribute__ ((packed)) a2dp_vendor_codec_t;
+typedef struct {
+ a2dp_vendor_codec_t info;
+ uint8_t frequency;
+ uint8_t channel_mode;
+} __attribute__ ((packed)) a2dp_ldac_t;
+
#endif /* #define __GST_BLUEZ_A2DP_CODECS_H_INCLUDED__ */
diff --git a/sys/bluez/gstavdtpsink.c b/sys/bluez/gstavdtpsink.c
index c6463d59b..dc909aa83 100644
--- a/sys/bluez/gstavdtpsink.c
+++ b/sys/bluez/gstavdtpsink.c
@@ -74,21 +74,22 @@ static GstStaticPadTemplate avdtp_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp, "
"media = (string) \"audio\","
- "payload = (int) "
- GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
- "clock-rate = (int) { 16000, 32000, "
- "44100, 48000 }, "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 16000, 32000, 44100, 48000 }, "
"encoding-name = (string) \"SBC\"; "
"application/x-rtp, "
"media = (string) \"audio\", "
- "payload = (int) "
- GST_RTP_PAYLOAD_MPA_STRING ", "
+ "payload = (int) " GST_RTP_PAYLOAD_MPA_STRING ", "
"clock-rate = (int) 90000; "
"application/x-rtp, "
"media = (string) \"audio\", "
- "payload = (int) "
- GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
- "clock-rate = (int) 90000, " "encoding-name = (string) \"MPA\""));
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"MPA\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 44100, 48000, 88200, 96000 }, "
+ "encoding-name = (string) \"X-GST-LDAC\""));
static gboolean
gst_avdtp_sink_stop (GstBaseSink * basesink)
diff --git a/sys/bluez/gstavdtputil.c b/sys/bluez/gstavdtputil.c
index 3a11bd275..5bf135fb6 100644
--- a/sys/bluez/gstavdtputil.c
+++ b/sys/bluez/gstavdtputil.c
@@ -690,6 +690,112 @@ gst_avdtp_util_parse_aac_raw (void *config)
return structure;
}
+static GstStructure *
+gst_avdtp_util_parse_ldac_raw (void *config)
+{
+ /* We assume the vendor/codec ID have been verified already */
+ a2dp_ldac_t *ldac = (a2dp_ldac_t *) config;
+ GstStructure *structure;
+ GValue value = G_VALUE_INIT;
+ GValue list = G_VALUE_INIT;
+ gboolean mono, stereo;
+
+ structure = gst_structure_new_empty ("audio/x-ldac");
+
+ g_value_init (&list, GST_TYPE_LIST);
+ g_value_init (&value, G_TYPE_INT);
+
+ /* rate */
+ if (ldac->frequency & LDAC_SAMPLING_FREQ_44100) {
+ g_value_set_int (&value, 44100);
+ gst_value_list_prepend_value (&list, &value);
+ }
+ if (ldac->frequency & LDAC_SAMPLING_FREQ_48000) {
+ g_value_set_int (&value, 48000);
+ gst_value_list_prepend_value (&list, &value);
+ }
+ if (ldac->frequency & LDAC_SAMPLING_FREQ_88200) {
+ g_value_set_int (&value, 88200);
+ gst_value_list_prepend_value (&list, &value);
+ }
+ if (ldac->frequency & LDAC_SAMPLING_FREQ_96000) {
+ g_value_set_int (&value, 96000);
+ gst_value_list_prepend_value (&list, &value);
+ }
+
+ if (gst_value_list_get_size (&list) == 1)
+ gst_structure_set_value (structure, "rate", &value);
+ else
+ gst_structure_set_value (structure, "rate", &list);
+
+ g_value_unset (&value);
+ g_value_reset (&list);
+
+ /* channels */
+ mono = FALSE;
+ stereo = FALSE;
+ if (ldac->channel_mode & LDAC_CHANNEL_MODE_MONO)
+ mono = TRUE;
+ if ((ldac->channel_mode & LDAC_CHANNEL_MODE_STEREO) ||
+ (ldac->channel_mode & LDAC_CHANNEL_MODE_DUAL))
+ stereo = TRUE;
+
+ if (mono && stereo) {
+ g_value_init (&value, GST_TYPE_INT_RANGE);
+ gst_value_set_int_range (&value, 1, 2);
+ } else {
+ g_value_init (&value, G_TYPE_INT);
+ if (mono)
+ g_value_set_int (&value, 1);
+ else if (stereo)
+ g_value_set_int (&value, 2);
+ else {
+ GST_ERROR ("Unexpected number of channels");
+ g_value_set_int (&value, 0);
+ }
+ }
+ gst_structure_set_value (structure, "channels", &value);
+
+ g_value_unset (&value);
+ g_value_init (&value, G_TYPE_STRING);
+
+ /* channel mode */
+ if (ldac->channel_mode & LDAC_CHANNEL_MODE_MONO) {
+ g_value_set_static_string (&value, "mono");
+ gst_value_list_prepend_value (&list, &value);
+ }
+ if (ldac->channel_mode & LDAC_CHANNEL_MODE_STEREO) {
+ g_value_set_static_string (&value, "stereo");
+ gst_value_list_prepend_value (&list, &value);
+ }
+ if (ldac->channel_mode & LDAC_CHANNEL_MODE_DUAL) {
+ g_value_set_static_string (&value, "dual");
+ gst_value_list_prepend_value (&list, &value);
+ }
+
+ if (gst_value_list_get_size (&list) == 1)
+ gst_structure_set_value (structure, "channel-mode", &value);
+ else
+ gst_structure_take_value (structure, "channel-mode", &list);
+
+ g_value_unset (&value);
+ g_value_unset (&list);
+
+ return structure;
+}
+
+static GstStructure *
+gst_avdtp_util_parse_vendor_raw (void *config)
+{
+ a2dp_vendor_codec_t *vendor = (a2dp_vendor_codec_t *) config;
+
+ if (A2DP_GET_VENDOR_ID (*vendor) == SONY_VENDOR_ID &&
+ A2DP_GET_CODEC_ID (*vendor) == LDAC_CODEC_ID)
+ return gst_avdtp_util_parse_ldac_raw (config);
+ else
+ return NULL;
+}
+
GstCaps *
gst_avdtp_connection_get_caps (GstAvdtpConnection * conn)
{
@@ -709,6 +815,9 @@ gst_avdtp_connection_get_caps (GstAvdtpConnection * conn)
case A2DP_CODEC_MPEG24:
structure = gst_avdtp_util_parse_aac_raw (conn->data.config);
break;
+ case A2DP_CODEC_VENDOR:
+ structure = gst_avdtp_util_parse_vendor_raw (conn->data.config);
+ break;
default:
GST_ERROR ("Unsupported configuration");
return NULL;