rtp: ldac: Set frame count information in payload
authorSanchayan Maity <sanchayan@asymptotic.io>
Thu, 24 Feb 2022 14:58:23 +0000 (20:28 +0530)
committerSanchayan Maity <sanchayan@asymptotic.io>
Sat, 26 Feb 2022 15:39:57 +0000 (21:09 +0530)
The RTP payload seems to be required as it carries the frame count
information. Also, gst_rtp_base_payload_allocate_output_buffer had
the second argument incorrect.

Strangely some devices like Shanling MP4 and Sony XM3 would still
work without this while some like the Sony XM4 do not.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1797>

subprojects/gst-plugins-good/docs/gst_plugins_cache.json
subprojects/gst-plugins-good/gst/rtp/gstrtpldacpay.c
subprojects/gst-plugins-good/gst/rtp/gstrtpldacpay.h

index 88bff47..003546d 100644 (file)
                 "long-name": "RTP packet payloader",
                 "pad-templates": {
                     "sink": {
-                        "caps": "audio/x-ldac:\n       channels: [ 1, 2 ]\n           rate: { (int)44100, (int)48000, (int)88200, (int)96000 }\n",
+                        "caps": "audio/x-ldac:\n       channels: [ 1, 2 ]\n          eqmid: { (int)0, (int)1, (int)2 }\n           rate: { (int)44100, (int)48000, (int)88200, (int)96000 }\n",
                         "direction": "sink",
                         "presence": "always"
                     },
index 2b14b74..aa30673 100644 (file)
@@ -48,7 +48,7 @@
 #include "gstrtpldacpay.h"
 #include "gstrtputils.h"
 
-#define GST_RTP_HEADER_LENGTH    12
+#define GST_RTP_LDAC_PAYLOAD_HEADER_SIZE 1
 /* MTU size required for LDAC A2DP streaming */
 #define GST_LDAC_MTU_REQUIRED    679
 
@@ -64,6 +64,7 @@ static GstStaticPadTemplate gst_rtp_ldac_pay_sink_factory =
 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("audio/x-ldac, "
         "channels = (int) [ 1, 2 ], "
+        "eqmid = (int) { 0, 1, 2 }, "
         "rate = (int) { 44100, 48000, 88200, 96000 }")
     );
 
@@ -81,6 +82,38 @@ static gboolean gst_rtp_ldac_pay_set_caps (GstRTPBasePayload * payload,
 static GstFlowReturn gst_rtp_ldac_pay_handle_buffer (GstRTPBasePayload *
     payload, GstBuffer * buffer);
 
+/**
+ * gst_rtp_ldac_pay_get_num_frames
+ * @eqmid: Encode Quality Mode Index
+ * @channels: Number of channels
+ *
+ * Returns: Number of LDAC frames per packet.
+ */
+static guint8
+gst_rtp_ldac_pay_get_num_frames (gint eqmid, gint channels)
+{
+  g_assert (channels == 1 || channels == 2);
+
+  switch (eqmid) {
+      /* Encode setting for High Quality */
+    case 0:
+      return 4 / channels;
+      /* Encode setting for Standard Quality */
+    case 1:
+      return 6 / channels;
+      /* Encode setting for Mobile use Quality */
+    case 2:
+      return 12 / channels;
+    default:
+      break;
+  }
+
+  g_assert_not_reached ();
+
+  /* If assertion gets compiled out */
+  return 6 / channels;
+}
+
 static void
 gst_rtp_ldac_pay_class_init (GstRtpLdacPayClass * klass)
 {
@@ -115,7 +148,7 @@ gst_rtp_ldac_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
 {
   GstRtpLdacPay *ldacpay = GST_RTP_LDAC_PAY (payload);
   GstStructure *structure;
-  gint rate;
+  gint channels, eqmid, rate;
 
   if (GST_RTP_BASE_PAYLOAD_MTU (ldacpay) < GST_LDAC_MTU_REQUIRED) {
     GST_ERROR_OBJECT (ldacpay, "Invalid MTU %d, should be >= %d",
@@ -129,6 +162,18 @@ gst_rtp_ldac_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
     return FALSE;
   }
 
+  if (!gst_structure_get_int (structure, "channels", &channels)) {
+    GST_ERROR_OBJECT (ldacpay, "Failed to get audio rate from caps");
+    return FALSE;
+  }
+
+  if (!gst_structure_get_int (structure, "eqmid", &eqmid)) {
+    GST_ERROR_OBJECT (ldacpay, "Failed to get eqmid from caps");
+    return FALSE;
+  }
+
+  ldacpay->frame_count = gst_rtp_ldac_pay_get_num_frames (eqmid, channels);
+
   gst_rtp_base_payload_set_options (payload, "audio", TRUE, "X-GST-LDAC", rate);
 
   return gst_rtp_base_payload_set_outcaps (payload, NULL);
@@ -145,14 +190,26 @@ gst_rtp_ldac_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
 static GstFlowReturn
 gst_rtp_ldac_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
 {
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
   GstRtpLdacPay *ldacpay = GST_RTP_LDAC_PAY (payload);
   GstBuffer *outbuf;
   GstClockTime outbuf_frame_duration, outbuf_pts;
+  guint8 *payload_data;
   gsize buf_sz;
 
   outbuf =
       gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
-      (ldacpay), GST_RTP_HEADER_LENGTH, 0, 0);
+      (ldacpay), GST_RTP_LDAC_PAYLOAD_HEADER_SIZE, 0, 0);
+
+  /* Get payload */
+  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+  /* Write header and copy data into payload */
+  payload_data = gst_rtp_buffer_get_payload (&rtp);
+  /* Upper 3 fragment bits not used, ref A2DP v13, 4.3.4 */
+  payload_data[0] = ldacpay->frame_count & 0x0f;
+
+  gst_rtp_buffer_unmap (&rtp);
 
   outbuf_pts = GST_BUFFER_PTS (buffer);
   outbuf_frame_duration = GST_BUFFER_DURATION (buffer);
index 0865ce7..0134491 100644 (file)
@@ -42,6 +42,7 @@ typedef struct _GstRtpLdacPayClass GstRtpLdacPayClass;
 
 struct _GstRtpLdacPay {
   GstRTPBasePayload base;
+  guint8 frame_count;
 };
 
 struct _GstRtpLdacPayClass {