bluez: avdtpsink: Add support for LDAC to avdtpsink

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1621>
This commit is contained in:
Arun Raghavan 2020-09-30 13:28:08 +05:30 committed by Sanchayan Maity
parent a576814553
commit ef3085c743
4 changed files with 146 additions and 10 deletions

View file

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

View file

@ -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__ */

View file

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

View file

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