[pulseaudio-commits] [Git][pulseaudio/pulseaudio][master] rtp: Enable support for OPUS

PulseAudio Marge Bot (@pulseaudio-merge-bot) gitlab at gitlab.freedesktop.org
Fri Jul 30 13:13:12 UTC 2021



PulseAudio Marge Bot pushed to branch master at PulseAudio / pulseaudio


Commits:
86d1dd0d by Sanchayan Maity at 2021-07-30T13:10:08+00:00
rtp: Enable support for OPUS

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/510>

- - - - -


8 changed files:

- src/modules/rtp/module-rtp-recv.c
- src/modules/rtp/module-rtp-send.c
- src/modules/rtp/rtp-common.c
- src/modules/rtp/rtp-gstreamer.c
- src/modules/rtp/rtp-native.c
- src/modules/rtp/rtp.h
- src/modules/rtp/sdp.c
- src/modules/rtp/sdp.h


Changes:

=====================================
src/modules/rtp/module-rtp-recv.c
=====================================
@@ -568,7 +568,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in
 
     pa_memblock_unref(silence.memblock);
 
-    if (!(s->rtp_context = pa_rtp_context_new_recv(fd, sdp_info->payload, &s->sdp_info.sample_spec)))
+    if (!(s->rtp_context = pa_rtp_context_new_recv(fd, sdp_info->payload, &s->sdp_info.sample_spec, sdp_info->enable_opus)))
         goto fail;
 
     pa_hashmap_put(s->userdata->by_origin, s->sdp_info.origin, s);


=====================================
src/modules/rtp/module-rtp-send.c
=====================================
@@ -67,6 +67,7 @@ PA_MODULE_USAGE(
         "ttl=<ttl value> "
         "inhibit_auto_suspend=<always|never|only_with_non_monitor_sources>"
         "stream_name=<name of the stream>"
+        "enable_opus=<enable OPUS codec>"
 );
 
 #define DEFAULT_PORT 46000
@@ -92,6 +93,7 @@ static const char* const valid_modargs[] = {
     "ttl",
     "inhibit_auto_suspend",
     "stream_name",
+    "enable_opus",
     NULL
 };
 
@@ -228,6 +230,7 @@ int pa__init(pa_module*m) {
     socklen_t k;
     char hn[128], *n;
     bool loop = false;
+    bool enable_opus = false;
     enum inhibit_auto_suspend inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ONLY_WITH_NON_MONITOR_SOURCES;
     const char *inhibit_auto_suspend_str;
     pa_source_output_new_data data;
@@ -249,6 +252,11 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (pa_modargs_get_value_boolean(ma, "enable_opus", &enable_opus) < 0) {
+        pa_log("Failed to parse \"use_opus\" parameter.");
+        goto fail;
+    }
+
     if ((inhibit_auto_suspend_str = pa_modargs_get_value(ma, "inhibit_auto_suspend", NULL))) {
         if (pa_streq(inhibit_auto_suspend_str, "always"))
             inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ALWAYS;
@@ -263,7 +271,7 @@ int pa__init(pa_module*m) {
     }
 
     ss = s->sample_spec;
-    pa_rtp_sample_spec_fixup(&ss);
+    pa_rtp_sample_spec_fixup(&ss, enable_opus);
     cm = s->channel_map;
     if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
         pa_log("Failed to parse sample specification");
@@ -275,6 +283,11 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (enable_opus && ss.rate != 48000) {
+        pa_log_warn("OPUS requires sample rate as 48 KHz. Setting rate=48000.");
+        ss.rate = 48000;
+    }
+
     if (ss.channels != cm.channels)
         pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_AIFF);
 
@@ -476,19 +489,19 @@ int pa__init(pa_module*m) {
         p = pa_sdp_build(af,
                      (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr,
                      (void*) &dst_sa4.sin_addr,
-                     n, (uint16_t) port, payload, &ss);
+                     n, (uint16_t) port, payload, &ss, enable_opus);
 #ifdef HAVE_IPV6
     } else {
         p = pa_sdp_build(af,
                      (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr,
                      (void*) &dst_sa6.sin6_addr,
-                     n, (uint16_t) port, payload, &ss);
+                     n, (uint16_t) port, payload, &ss, enable_opus);
 #endif
     }
 
     pa_xfree(n);
 
-    if (!(u->rtp_context = pa_rtp_context_new_send(fd, payload, mtu, &ss)))
+    if (!(u->rtp_context = pa_rtp_context_new_send(fd, payload, mtu, &ss, enable_opus)))
         goto fail;
     pa_sap_context_init_send(&u->sap_context, sap_fd, p);
 


=====================================
src/modules/rtp/rtp-common.c
=====================================
@@ -52,6 +52,12 @@ pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec
             ss->rate = 44100;
             break;
 
+        case 127:
+            ss->channels = 2;
+            ss->format = PA_SAMPLE_S16LE;
+            ss->rate = 48000;
+            break;
+
         default:
             return NULL;
     }
@@ -59,10 +65,12 @@ pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec
     return ss;
 }
 
-pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) {
+pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss, bool enable_opus) {
     pa_assert(ss);
 
-    if (!pa_rtp_sample_spec_valid(ss))
+    if (!pa_rtp_sample_spec_valid(ss) && enable_opus)
+        ss->format = PA_SAMPLE_S16LE;
+    else if (!pa_rtp_sample_spec_valid(ss) || !enable_opus)
         ss->format = PA_SAMPLE_S16BE;
 
     pa_assert(pa_rtp_sample_spec_valid(ss));
@@ -75,22 +83,25 @@ int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) {
     if (!pa_sample_spec_valid(ss))
         return 0;
 
-    return ss->format == PA_SAMPLE_S16BE;
+    return ss->format == PA_SAMPLE_S16BE || ss->format == PA_SAMPLE_S16LE;
 }
 
 const char* pa_rtp_format_to_string(pa_sample_format_t f) {
     switch (f) {
         case PA_SAMPLE_S16BE:
+        case PA_SAMPLE_S16LE:
             return "L16";
         default:
             return NULL;
     }
 }
 
-pa_sample_format_t pa_rtp_string_to_format(const char *s) {
+pa_sample_format_t pa_rtp_string_to_format(const char *s, bool enable_opus) {
     pa_assert(s);
 
-    if (pa_streq(s, "L16"))
+    if (pa_streq(s, "L16") && enable_opus)
+        return PA_SAMPLE_S16LE;
+    else if (pa_streq(s, "L16"))
         return PA_SAMPLE_S16BE;
     else
         return PA_SAMPLE_INVALID;


=====================================
src/modules/rtp/rtp-gstreamer.c
=====================================
@@ -45,6 +45,14 @@
 #define MAKE_ELEMENT(v, e) MAKE_ELEMENT_NAMED((v), (e), NULL)
 #define RTP_HEADER_SIZE    12
 
+/*
+ * As per RFC 7587, the RTP payload type for OPUS is to be assigned
+ * dynamically. Considering that pa_rtp_payload_from_sample_spec uses
+ * 127 for anything other than format == S16BE and rate == 44.1 KHz,
+ * we use 127 for OPUS here as rate == 48 KHz for OPUS.
+ */
+#define RTP_OPUS_PAYLOAD_TYPE 127
+
 struct pa_rtp_context {
     pa_fdsem *fdsem;
     pa_sample_spec ss;
@@ -61,20 +69,21 @@ struct pa_rtp_context {
     size_t mtu;
 };
 
-static GstCaps* caps_from_sample_spec(const pa_sample_spec *ss) {
-    if (ss->format != PA_SAMPLE_S16BE)
+static GstCaps* caps_from_sample_spec(const pa_sample_spec *ss, bool enable_opus) {
+    if (ss->format != PA_SAMPLE_S16BE && ss->format != PA_SAMPLE_S16LE)
         return NULL;
 
     return gst_caps_new_simple("audio/x-raw",
-            "format", G_TYPE_STRING, "S16BE",
+            "format", G_TYPE_STRING, enable_opus ? "S16LE" : "S16BE",
             "rate", G_TYPE_INT, (int) ss->rate,
             "channels", G_TYPE_INT, (int) ss->channels,
             "layout", G_TYPE_STRING, "interleaved",
             NULL);
 }
 
-static bool init_send_pipeline(pa_rtp_context *c, int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss) {
+static bool init_send_pipeline(pa_rtp_context *c, int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss, bool enable_opus) {
     GstElement *appsrc = NULL, *pay = NULL, *capsf = NULL, *rtpbin = NULL, *sink = NULL;
+    GstElement *opusenc = NULL;
     GstCaps *caps;
     GSocket *socket;
     GInetSocketAddress *addr;
@@ -83,7 +92,12 @@ static bool init_send_pipeline(pa_rtp_context *c, int fd, uint8_t payload, size_
     gchar *addr_str;
 
     MAKE_ELEMENT(appsrc, "appsrc");
-    MAKE_ELEMENT(pay, "rtpL16pay");
+    if (enable_opus) {
+        MAKE_ELEMENT(opusenc, "opusenc");
+        MAKE_ELEMENT(pay, "rtpopuspay");
+    } else {
+        MAKE_ELEMENT(pay, "rtpL16pay");
+    }
     MAKE_ELEMENT(capsf, "capsfilter");
     MAKE_ELEMENT(rtpbin, "rtpbin");
     MAKE_ELEMENT(sink, "udpsink");
@@ -92,7 +106,10 @@ static bool init_send_pipeline(pa_rtp_context *c, int fd, uint8_t payload, size_
 
     gst_bin_add_many(GST_BIN(c->pipeline), appsrc, pay, capsf, rtpbin, sink, NULL);
 
-    caps = caps_from_sample_spec(ss);
+    if (enable_opus)
+        gst_bin_add_many(GST_BIN(c->pipeline), opusenc, NULL);
+
+    caps = caps_from_sample_spec(ss, enable_opus);
     if (!caps) {
         pa_log("Unsupported format to payload");
         goto fail;
@@ -125,17 +142,33 @@ static bool init_send_pipeline(pa_rtp_context *c, int fd, uint8_t payload, size_
     gst_caps_unref(caps);
 
     /* Force the payload type that we want */
-    caps = gst_caps_new_simple("application/x-rtp", "payload", G_TYPE_INT, (int) payload, NULL);
+    if (enable_opus)
+        caps = gst_caps_new_simple("application/x-rtp", "payload", G_TYPE_INT, (int) RTP_OPUS_PAYLOAD_TYPE, "encoding-name", G_TYPE_STRING, "OPUS", NULL);
+    else
+        caps = gst_caps_new_simple("application/x-rtp", "payload", G_TYPE_INT, (int) payload, "encoding-name", G_TYPE_STRING, "L16", NULL);
+
     g_object_set(capsf, "caps", caps, NULL);
     gst_caps_unref(caps);
 
-    if (!gst_element_link(appsrc, pay) ||
-        !gst_element_link(pay, capsf) ||
-        !gst_element_link_pads(capsf, "src", rtpbin, "send_rtp_sink_0") ||
-        !gst_element_link_pads(rtpbin, "send_rtp_src_0", sink, "sink")) {
+    if (enable_opus) {
+        if (!gst_element_link(appsrc, opusenc) ||
+            !gst_element_link(opusenc, pay) ||
+            !gst_element_link(pay, capsf) ||
+            !gst_element_link_pads(capsf, "src", rtpbin, "send_rtp_sink_0") ||
+            !gst_element_link_pads(rtpbin, "send_rtp_src_0", sink, "sink")) {
 
-        pa_log("Could not set up send pipeline");
-        goto fail;
+            pa_log("Could not set up send pipeline");
+            goto fail;
+        }
+    } else {
+        if (!gst_element_link(appsrc, pay) ||
+            !gst_element_link(pay, capsf) ||
+            !gst_element_link_pads(capsf, "src", rtpbin, "send_rtp_sink_0") ||
+            !gst_element_link_pads(rtpbin, "send_rtp_src_0", sink, "sink")) {
+
+            pa_log("Could not set up send pipeline");
+            goto fail;
+        }
     }
 
     if (gst_element_set_state(c->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
@@ -154,6 +187,8 @@ fail:
         /* These weren't yet added to pipeline, so we still have a ref */
         if (appsrc)
             gst_object_unref(appsrc);
+        if (opusenc)
+            gst_object_unref(opusenc);
         if (pay)
             gst_object_unref(pay);
         if (capsf)
@@ -167,7 +202,7 @@ fail:
     return false;
 }
 
-pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss) {
+pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss, bool enable_opus) {
     pa_rtp_context *c = NULL;
     GError *error = NULL;
 
@@ -175,6 +210,9 @@ pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, con
 
     pa_log_info("Initialising GStreamer RTP backend for send");
 
+    if (enable_opus)
+        pa_log_info("Using OPUS encoding for RTP send");
+
     c = pa_xnew0(pa_rtp_context, 1);
 
     c->ss = *ss;
@@ -187,7 +225,7 @@ pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, con
         goto fail;
     }
 
-    if (!init_send_pipeline(c, fd, payload, mtu, ss))
+    if (!init_send_pipeline(c, fd, payload, mtu, ss, enable_opus))
         goto fail;
 
     return c;
@@ -313,10 +351,18 @@ int pa_rtp_send(pa_rtp_context *c, pa_memblockq *q) {
     return 0;
 }
 
-static GstCaps* rtp_caps_from_sample_spec(const pa_sample_spec *ss) {
-    if (ss->format != PA_SAMPLE_S16BE)
+static GstCaps* rtp_caps_from_sample_spec(const pa_sample_spec *ss, bool enable_opus) {
+    if (ss->format != PA_SAMPLE_S16BE && ss->format != PA_SAMPLE_S16LE)
         return NULL;
 
+    if (enable_opus)
+        return gst_caps_new_simple("application/x-rtp",
+                "media", G_TYPE_STRING, "audio",
+                "encoding-name", G_TYPE_STRING, "OPUS",
+                "clock-rate", G_TYPE_INT, (int) 48000,
+                "payload", G_TYPE_INT, (int) RTP_OPUS_PAYLOAD_TYPE,
+                NULL);
+
     return gst_caps_new_simple("application/x-rtp",
             "media", G_TYPE_STRING, "audio",
             "encoding-name", G_TYPE_STRING, "L16",
@@ -373,22 +419,32 @@ static GstPadProbeReturn udpsrc_buffer_probe(GstPad *pad, GstPadProbeInfo *info,
     return GST_PAD_PROBE_OK;
 }
 
-static bool init_receive_pipeline(pa_rtp_context *c, int fd, const pa_sample_spec *ss) {
+static bool init_receive_pipeline(pa_rtp_context *c, int fd, const pa_sample_spec *ss, bool enable_opus) {
     GstElement *udpsrc = NULL, *rtpbin = NULL, *depay = NULL, *appsink = NULL;
-    GstCaps *caps;
+    GstElement *resample = NULL, *opusdec = NULL;
+    GstCaps *caps, *sink_caps;
     GstPad *pad;
     GSocket *socket;
     GError *error = NULL;
 
     MAKE_ELEMENT(udpsrc, "udpsrc");
     MAKE_ELEMENT(rtpbin, "rtpbin");
-    MAKE_ELEMENT_NAMED(depay, "rtpL16depay", "depay");
+    if (enable_opus) {
+        MAKE_ELEMENT_NAMED(depay, "rtpopusdepay", "depay");
+        MAKE_ELEMENT(opusdec, "opusdec");
+        MAKE_ELEMENT(resample, "audioresample");
+    } else {
+        MAKE_ELEMENT_NAMED(depay, "rtpL16depay", "depay");
+    }
     MAKE_ELEMENT(appsink, "appsink");
 
     c->pipeline = gst_pipeline_new(NULL);
 
     gst_bin_add_many(GST_BIN(c->pipeline), udpsrc, rtpbin, depay, appsink, NULL);
 
+    if (enable_opus)
+        gst_bin_add_many(GST_BIN(c->pipeline), opusdec, resample, NULL);
+
     socket = g_socket_new_from_fd(fd, &error);
     if (error) {
         pa_log("Could not create socket: %s", error->message);
@@ -396,7 +452,7 @@ static bool init_receive_pipeline(pa_rtp_context *c, int fd, const pa_sample_spe
         goto fail;
     }
 
-    caps = rtp_caps_from_sample_spec(ss);
+    caps = rtp_caps_from_sample_spec(ss, enable_opus);
     if (!caps) {
         pa_log("Unsupported format to payload");
         goto fail;
@@ -406,14 +462,37 @@ static bool init_receive_pipeline(pa_rtp_context *c, int fd, const pa_sample_spe
     g_object_set(rtpbin, "latency", 0, "buffer-mode", 0 /* none */, NULL);
     g_object_set(appsink, "sync", FALSE, "enable-last-sample", FALSE, NULL);
 
+    if (enable_opus) {
+        sink_caps = gst_caps_new_simple("audio/x-raw",
+                "format", G_TYPE_STRING, "S16LE",
+                "layout", G_TYPE_STRING, "interleaved",
+                "clock-rate", G_TYPE_INT, (int) ss->rate,
+                "channels", G_TYPE_INT, (int) ss->channels,
+                NULL);
+        g_object_set(appsink, "caps", sink_caps, NULL);
+        g_object_set(opusdec, "plc", TRUE, NULL);
+        gst_caps_unref(sink_caps);
+    }
+
     gst_caps_unref(caps);
     g_object_unref(socket);
 
-    if (!gst_element_link_pads(udpsrc, "src", rtpbin, "recv_rtp_sink_0") ||
-        !gst_element_link(depay, appsink)) {
+    if (enable_opus) {
+        if (!gst_element_link_pads(udpsrc, "src", rtpbin, "recv_rtp_sink_0") ||
+            !gst_element_link(depay, opusdec) ||
+            !gst_element_link(opusdec, resample) ||
+            !gst_element_link(resample, appsink)) {
 
-        pa_log("Could not set up receive pipeline");
-        goto fail;
+            pa_log("Could not set up receive pipeline");
+            goto fail;
+        }
+    } else {
+        if (!gst_element_link_pads(udpsrc, "src", rtpbin, "recv_rtp_sink_0") ||
+            !gst_element_link(depay, appsink)) {
+
+            pa_log("Could not set up receive pipeline");
+            goto fail;
+        }
     }
 
     g_signal_connect(G_OBJECT(rtpbin), "pad-added", G_CALLBACK(on_pad_added), c);
@@ -446,6 +525,10 @@ fail:
             gst_object_unref(depay);
         if (rtpbin)
             gst_object_unref(rtpbin);
+        if (opusdec)
+            gst_object_unref(opusdec);
+        if (resample)
+            gst_object_unref(resample);
         if (appsink)
             gst_object_unref(appsink);
     }
@@ -469,7 +552,7 @@ static GstFlowReturn appsink_new_sample(GstAppSink *appsink, gpointer userdata)
     return GST_FLOW_OK;
 }
 
-pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss) {
+pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss, bool enable_opus) {
     pa_rtp_context *c = NULL;
     GstAppSinkCallbacks callbacks = { 0, };
     GError *error = NULL;
@@ -478,6 +561,9 @@ pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample
 
     pa_log_info("Initialising GStreamer RTP backend for receive");
 
+    if (enable_opus)
+        pa_log_info("Using OPUS encoding for RTP recv");
+
     c = pa_xnew0(pa_rtp_context, 1);
 
     c->fdsem = pa_fdsem_new();
@@ -491,7 +577,7 @@ pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample
         goto fail;
     }
 
-    if (!init_receive_pipeline(c, fd, ss))
+    if (!init_receive_pipeline(c, fd, ss, enable_opus))
         goto fail;
 
     callbacks.eos = appsink_eos;


=====================================
src/modules/rtp/rtp-native.c
=====================================
@@ -58,7 +58,7 @@ typedef struct pa_rtp_context {
     pa_memchunk memchunk;
 } pa_rtp_context;
 
-pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss) {
+pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss, bool enable_opus) {
     pa_rtp_context *c;
 
     pa_assert(fd >= 0);
@@ -171,7 +171,7 @@ int pa_rtp_send(pa_rtp_context *c, pa_memblockq *q) {
     return 0;
 }
 
-pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss) {
+pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss, bool enable_opus) {
     pa_rtp_context *c;
 
     pa_log_info("Initialising native RTP backend for receive");


=====================================
src/modules/rtp/rtp.h
=====================================
@@ -30,13 +30,13 @@
 typedef struct pa_rtp_context pa_rtp_context;
 
 int pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint8_t payload, size_t mtu, size_t frame_size);
-pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss);
+pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss, bool enable_opus);
 
 /* If the memblockq doesn't have a silence memchunk set, then the caller must
  * guarantee that the current read index doesn't point to a hole. */
 int pa_rtp_send(pa_rtp_context *c, pa_memblockq *q);
 
-pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss);
+pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss, bool enable_opus);
 int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_t *rtp_tstamp, struct timeval *tstamp);
 
 void pa_rtp_context_free(pa_rtp_context *c);
@@ -44,13 +44,13 @@ void pa_rtp_context_free(pa_rtp_context *c);
 size_t pa_rtp_context_get_frame_size(pa_rtp_context *c);
 pa_rtpoll_item* pa_rtp_context_get_rtpoll_item(pa_rtp_context *c, pa_rtpoll *rtpoll);
 
-pa_sample_spec* pa_rtp_sample_spec_fixup(pa_sample_spec *ss);
+pa_sample_spec* pa_rtp_sample_spec_fixup(pa_sample_spec *ss, bool enable_opus);
 int pa_rtp_sample_spec_valid(const pa_sample_spec *ss);
 
 uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss);
 pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss);
 
 const char* pa_rtp_format_to_string(pa_sample_format_t f);
-pa_sample_format_t pa_rtp_string_to_format(const char *s);
+pa_sample_format_t pa_rtp_string_to_format(const char *s, bool enable_opus);
 
 #endif


=====================================
src/modules/rtp/sdp.c
=====================================
@@ -39,8 +39,9 @@
 #include "sdp.h"
 #include "rtp.h"
 
-char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss) {
+char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss, bool enable_opus) {
     uint32_t ntp;
+    uint32_t rate, channels;
     char buf_src[64], buf_dst[64], un[64];
     const char *u, *f;
 
@@ -53,7 +54,15 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u
     pa_assert(af == AF_INET);
 #endif
 
-    pa_assert_se(f = pa_rtp_format_to_string(ss->format));
+    if (enable_opus) {
+        f = "OPUS";
+        rate = 48000;
+        channels = 2;
+    } else {
+        pa_assert_se(f = pa_rtp_format_to_string(ss->format));
+        rate = ss->rate;
+        channels = ss->channels;
+    }
 
     if (!(u = pa_get_user_name(un, sizeof(un))))
         u = "-";
@@ -78,7 +87,7 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u
             af == AF_INET ? "IP4" : "IP6", buf_dst,
             (unsigned long) ntp,
             port, payload,
-            payload, f, ss->rate, ss->channels);
+            payload, f, rate, channels);
 }
 
 static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) {
@@ -89,6 +98,9 @@ static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) {
     if (pa_startswith(c, "L16/")) {
         ss->format = PA_SAMPLE_S16BE;
         c += 4;
+    } else if (pa_startswith(c, "OPUS/")) {
+        ss->format = PA_SAMPLE_S16LE;
+        c += 5;
     } else
         return NULL;
 
@@ -218,6 +230,9 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
 
                         if (parse_sdp_sample_spec(&i->sample_spec, c))
                             ss_valid = true;
+
+                        if (pa_startswith(c, "OPUS/"))
+                            i->enable_opus = true;
                     }
                 }
             }


=====================================
src/modules/rtp/sdp.h
=====================================
@@ -37,9 +37,11 @@ typedef struct pa_sdp_info {
 
     pa_sample_spec sample_spec;
     uint8_t payload;
+
+    bool enable_opus;
 } pa_sdp_info;
 
-char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss);
+char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss, bool enable_opus);
 
 pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *info, int is_goodbye);
 



View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/commit/86d1dd0d70d6943cb67346c6187171444f764774

-- 
View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/commit/86d1dd0d70d6943cb67346c6187171444f764774
You're receiving this email because of your account on gitlab.freedesktop.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pulseaudio-commits/attachments/20210730/6d1cae5e/attachment-0001.htm>


More information about the pulseaudio-commits mailing list