rtsp-server: fix memory leak
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / gst / rtp / gstrtpldacpay.c
1 /* GStreamer RTP LDAC payloader
2  * Copyright (C) 2020 Asymptotic <sanchayan@asymptotic.io>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * SECTION:element-rtpldacpay
22  * @title: rtpldacpay
23  *
24  * Payload LDAC encoded audio into RTP packets.
25  *
26  * LDAC does not have a public specification and concerns itself only with
27  * bluetooth transmission. Due to the unavailability of a specification, we
28  * consider the encoding-name as X-GST-LDAC.
29  *
30  * The best reference is [libldac](https://android.googlesource.com/platform/external/libldac/)
31  * and the A2DP LDAC implementation in Android's bluetooth stack [Flouride]
32  * (https://android.googlesource.com/platform/system/bt/+/refs/heads/master/stack/a2dp/a2dp_vendor_ldac_encoder.cc).
33  *
34  * ## Example pipeline
35  * |[
36  * gst-launch-1.0 -v audiotestsrc ! ldacenc ! rtpldacpay mtu=679 ! avdtpsink
37  * ]| This example pipeline will payload LDAC encoded audio.
38  *
39  * Since: 1.20
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45
46 #include <gst/audio/audio.h>
47 #include "gstrtpelements.h"
48 #include "gstrtpldacpay.h"
49 #include "gstrtputils.h"
50
51 #define GST_RTP_LDAC_PAYLOAD_HEADER_SIZE 1
52 /* MTU size required for LDAC A2DP streaming */
53 #define GST_LDAC_MTU_REQUIRED    679
54
55 GST_DEBUG_CATEGORY_STATIC (gst_rtp_ldac_pay_debug);
56 #define GST_CAT_DEFAULT gst_rtp_ldac_pay_debug
57
58 #define parent_class gst_rtp_ldac_pay_parent_class
59 G_DEFINE_TYPE (GstRtpLdacPay, gst_rtp_ldac_pay, GST_TYPE_RTP_BASE_PAYLOAD);
60 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (rtpldacpay, "rtpldacpay", GST_RANK_NONE,
61     GST_TYPE_RTP_LDAC_PAY, rtp_element_init (plugin));
62
63 static GstStaticPadTemplate gst_rtp_ldac_pay_sink_factory =
64 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
65     GST_STATIC_CAPS ("audio/x-ldac, "
66         "channels = (int) [ 1, 2 ], "
67         "eqmid = (int) { 0, 1, 2 }, "
68         "rate = (int) { 44100, 48000, 88200, 96000 }")
69     );
70
71 static GstStaticPadTemplate gst_rtp_ldac_pay_src_factory =
72 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
73     GST_STATIC_CAPS ("application/x-rtp, "
74         "media = (string) audio,"
75         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
76         "clock-rate = (int) { 44100, 48000, 88200, 96000 },"
77         "encoding-name = (string) \"X-GST-LDAC\"")
78     );
79
80 static gboolean gst_rtp_ldac_pay_set_caps (GstRTPBasePayload * payload,
81     GstCaps * caps);
82 static GstFlowReturn gst_rtp_ldac_pay_handle_buffer (GstRTPBasePayload *
83     payload, GstBuffer * buffer);
84
85 /**
86  * gst_rtp_ldac_pay_get_num_frames
87  * @eqmid: Encode Quality Mode Index
88  * @channels: Number of channels
89  *
90  * Returns: Number of LDAC frames per packet.
91  */
92 static guint8
93 gst_rtp_ldac_pay_get_num_frames (gint eqmid, gint channels)
94 {
95   g_assert (channels == 1 || channels == 2);
96
97   switch (eqmid) {
98       /* Encode setting for High Quality */
99     case 0:
100       return 4 / channels;
101       /* Encode setting for Standard Quality */
102     case 1:
103       return 6 / channels;
104       /* Encode setting for Mobile use Quality */
105     case 2:
106       return 12 / channels;
107     default:
108       break;
109   }
110
111   g_assert_not_reached ();
112
113   /* If assertion gets compiled out */
114   return 6 / channels;
115 }
116
117 static void
118 gst_rtp_ldac_pay_class_init (GstRtpLdacPayClass * klass)
119 {
120   GstRTPBasePayloadClass *payload_class = GST_RTP_BASE_PAYLOAD_CLASS (klass);
121   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
122
123   payload_class->set_caps = GST_DEBUG_FUNCPTR (gst_rtp_ldac_pay_set_caps);
124   payload_class->handle_buffer =
125       GST_DEBUG_FUNCPTR (gst_rtp_ldac_pay_handle_buffer);
126
127   gst_element_class_add_static_pad_template (element_class,
128       &gst_rtp_ldac_pay_sink_factory);
129   gst_element_class_add_static_pad_template (element_class,
130       &gst_rtp_ldac_pay_src_factory);
131
132   gst_element_class_set_static_metadata (element_class, "RTP packet payloader",
133       "Codec/Payloader/Network", "Payload LDAC audio as RTP packets",
134       "Sanchayan Maity <sanchayan@asymptotic.io>");
135
136   GST_DEBUG_CATEGORY_INIT (gst_rtp_ldac_pay_debug, "rtpldacpay", 0,
137       "RTP LDAC payloader");
138 }
139
140 static void
141 gst_rtp_ldac_pay_init (GstRtpLdacPay * self)
142 {
143
144 }
145
146 static gboolean
147 gst_rtp_ldac_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
148 {
149   GstRtpLdacPay *ldacpay = GST_RTP_LDAC_PAY (payload);
150   GstStructure *structure;
151   gint channels, eqmid, rate;
152
153   if (GST_RTP_BASE_PAYLOAD_MTU (ldacpay) < GST_LDAC_MTU_REQUIRED) {
154     GST_ERROR_OBJECT (ldacpay, "Invalid MTU %d, should be >= %d",
155         GST_RTP_BASE_PAYLOAD_MTU (ldacpay), GST_LDAC_MTU_REQUIRED);
156     return FALSE;
157   }
158
159   structure = gst_caps_get_structure (caps, 0);
160   if (!gst_structure_get_int (structure, "rate", &rate)) {
161     GST_ERROR_OBJECT (ldacpay, "Failed to get audio rate from caps");
162     return FALSE;
163   }
164
165   if (!gst_structure_get_int (structure, "channels", &channels)) {
166     GST_ERROR_OBJECT (ldacpay, "Failed to get audio rate from caps");
167     return FALSE;
168   }
169
170   if (!gst_structure_get_int (structure, "eqmid", &eqmid)) {
171     GST_ERROR_OBJECT (ldacpay, "Failed to get eqmid from caps");
172     return FALSE;
173   }
174
175   ldacpay->frame_count = gst_rtp_ldac_pay_get_num_frames (eqmid, channels);
176
177   gst_rtp_base_payload_set_options (payload, "audio", TRUE, "X-GST-LDAC", rate);
178
179   return gst_rtp_base_payload_set_outcaps (payload, NULL);
180 }
181
182 /*
183  * LDAC encoder does not handle split frames. Currently, the encoder will
184  * always emit 660 bytes worth of payload encapsulating multiple LDAC frames.
185  * This is as per eqmid and GST_LDAC_MTU_REQUIRED passed for configuring the
186  * encoder upstream. Since the encoder always emit full frames and we do not
187  * need to handle frame splitting, we do not use an adapter and also push out
188  * the buffer as it is received.
189  */
190 static GstFlowReturn
191 gst_rtp_ldac_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
192 {
193   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
194   GstRtpLdacPay *ldacpay = GST_RTP_LDAC_PAY (payload);
195   GstBuffer *outbuf;
196   GstClockTime outbuf_frame_duration, outbuf_pts;
197   guint8 *payload_data;
198   gsize buf_sz;
199
200   outbuf =
201       gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
202       (ldacpay), GST_RTP_LDAC_PAYLOAD_HEADER_SIZE, 0, 0);
203
204   /* Get payload */
205   gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
206
207   /* Write header and copy data into payload */
208   payload_data = gst_rtp_buffer_get_payload (&rtp);
209   /* Upper 3 fragment bits not used, ref A2DP v13, 4.3.4 */
210   payload_data[0] = ldacpay->frame_count & 0x0f;
211
212   gst_rtp_buffer_unmap (&rtp);
213
214   outbuf_pts = GST_BUFFER_PTS (buffer);
215   outbuf_frame_duration = GST_BUFFER_DURATION (buffer);
216   buf_sz = gst_buffer_get_size (buffer);
217
218   gst_rtp_copy_audio_meta (ldacpay, outbuf, buffer);
219   outbuf = gst_buffer_append (outbuf, buffer);
220
221   GST_BUFFER_PTS (outbuf) = outbuf_pts;
222   GST_BUFFER_DURATION (outbuf) = outbuf_frame_duration;
223   GST_DEBUG_OBJECT (ldacpay,
224       "Pushing %" G_GSIZE_FORMAT " bytes: %" GST_TIME_FORMAT, buf_sz,
225       GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)));
226
227   return gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (ldacpay), outbuf);
228 }