From 2c8cba4b96602d4cdfdc79e0e0683140ca497c4f Mon Sep 17 00:00:00 2001 From: Daniel Pocock Date: Thu, 23 Sep 2021 00:16:58 +0200 Subject: [PATCH] basertpendpoint: add externalIPv4 and externalIPv6 parameters, similar to WebRtcEndpoint --- src/gst-plugins/commons/kmsbasertpendpoint.c | 125 ++++++++++++------ src/server/config/BaseRtpEndpoint.conf.ini | 12 ++ .../objects/BaseRtpEndpointImpl.cpp | 107 +++++++++++++-- .../objects/BaseRtpEndpointImpl.hpp | 6 + 4 files changed, 197 insertions(+), 53 deletions(-) diff --git a/src/gst-plugins/commons/kmsbasertpendpoint.c b/src/gst-plugins/commons/kmsbasertpendpoint.c index 53803fce6..0e27459eb 100644 --- a/src/gst-plugins/commons/kmsbasertpendpoint.c +++ b/src/gst-plugins/commons/kmsbasertpendpoint.c @@ -240,6 +240,8 @@ struct _KmsBaseRtpEndpointPrivate /* RTP settings */ guint mtu; + gchar *external_ipv4; + gchar *external_ipv6; /* RTP statistics */ KmsBaseRTPStats stats; @@ -274,9 +276,11 @@ static guint obj_signals[LAST_SIGNAL] = { 0 }; #define DEFAULT_RTCP_REMB FALSE #define DEFAULT_TARGET_BITRATE 0 #define MIN_VIDEO_RECV_BW_DEFAULT 0 -#define MIN_VIDEO_SEND_BW_DEFAULT 100 // kbps -#define MAX_VIDEO_SEND_BW_DEFAULT 500 // kbps -#define DEFAULT_MTU 1200 // Bytes +#define MIN_VIDEO_SEND_BW_DEFAULT 100 // kbps +#define MAX_VIDEO_SEND_BW_DEFAULT 500 // kbps +#define DEFAULT_MTU 1200 // Bytes +#define DEFAULT_EXTERNAL_IPV4 NULL +#define DEFAULT_EXTERNAL_IPV6 NULL enum { @@ -295,6 +299,8 @@ enum PROP_SUPPORT_FEC, PROP_OFFER_DIR, PROP_MTU, + PROP_EXTERNAL_IPV4, + PROP_EXTERNAL_IPV6, PROP_LAST }; @@ -1037,8 +1043,8 @@ kms_base_rtp_endpoint_get_connection_state (KmsBaseRtpEndpoint * self, } static void -kms_base_rtp_endpoint_create_remb_manager (KmsBaseRtpEndpoint *self, - KmsBaseRtpSession *sess) +kms_base_rtp_endpoint_create_remb_manager (KmsBaseRtpEndpoint * self, + KmsBaseRtpSession * sess) { GstPad *pad; @@ -1046,13 +1052,15 @@ kms_base_rtp_endpoint_create_remb_manager (KmsBaseRtpEndpoint *self, /* TODO: support more than one media with REMB */ GST_WARNING_OBJECT (self, "Only support for one media with REMB"); - typedef struct { + typedef struct + { void *p; guint ssrc; - } Dummy; // Same as KmsRlRemoteSession + } Dummy; // Same as KmsRlRemoteSession Dummy *rlrs = g_slist_nth_data (self->priv->rl->remote_sessions, 0); + GST_WARNING_OBJECT (self, "REMB is already in use for remote video SSRC %u", - rlrs->ssrc); + rlrs->ssrc); return; } @@ -1060,11 +1068,15 @@ kms_base_rtp_endpoint_create_remb_manager (KmsBaseRtpEndpoint *self, guint id = base_sess->id; gchar *id_str = base_sess->id_str; guint32 remote_video_ssrc = sess->remote_video_ssrc; - GST_INFO_OBJECT (self, "Creating REMB for session ID %u (%s) and remote video SSRC %u", - id, id_str, remote_video_ssrc); - GObject *rtpsession = kms_base_rtp_endpoint_get_internal_session ( - KMS_BASE_RTP_ENDPOINT(self), VIDEO_RTP_SESSION); + GST_INFO_OBJECT (self, + "Creating REMB for session ID %u (%s) and remote video SSRC %u", id, + id_str, remote_video_ssrc); + + GObject *rtpsession = + kms_base_rtp_endpoint_get_internal_session (KMS_BASE_RTP_ENDPOINT (self), + VIDEO_RTP_SESSION); + if (rtpsession == NULL) { return; } @@ -1077,6 +1089,7 @@ kms_base_rtp_endpoint_create_remb_manager (KmsBaseRtpEndpoint *self, RTCP_MIN_INTERVAL * GST_MSECOND, NULL); guint max_recv_bw; + g_object_get (self, "max-video-recv-bandwidth", &max_recv_bw, NULL); self->priv->rl = kms_remb_local_create (rtpsession, self->priv->min_video_recv_bw, @@ -1084,11 +1097,12 @@ kms_base_rtp_endpoint_create_remb_manager (KmsBaseRtpEndpoint *self, kms_remb_local_add_remote_session (self->priv->rl, rtpsession, sess->remote_video_ssrc); - pad = gst_element_get_static_pad (self->priv->rtpbin, VIDEO_RTPBIN_SEND_RTP_SINK); + pad = + gst_element_get_static_pad (self->priv->rtpbin, + VIDEO_RTPBIN_SEND_RTP_SINK); self->priv->rm = - kms_remb_remote_create (rtpsession, - self->priv->video_config->local_ssrc, self->priv->min_video_send_bw, - self->priv->max_video_send_bw, pad); + kms_remb_remote_create (rtpsession, self->priv->video_config->local_ssrc, + self->priv->min_video_send_bw, self->priv->max_video_send_bw, pad); g_object_unref (pad); g_object_unref (rtpsession); @@ -1110,11 +1124,13 @@ kms_base_rtp_endpoint_start_transport_send (KmsBaseSdpEndpoint * kms_base_rtp_session_start_transport_send (base_rtp_sess, offerer); guint len = gst_sdp_message_medias_len (sess->neg_sdp); + for (guint i = 0; i < len; i++) { const GstSDPMedia *media = gst_sdp_message_get_media (sess->neg_sdp, i); if (sdp_utils_media_has_remb (media)) { const gchar *media_str = gst_sdp_media_get_media (media); + GST_INFO_OBJECT (self, "Media '%s' has REMB", media_str); kms_base_rtp_endpoint_create_remb_manager (self, base_rtp_sess); } @@ -1678,13 +1694,14 @@ complement_caps_with_fmtp_attrs (GstCaps * caps, const gchar * fmtp_attr) } const gintptr index_ptr = index_of (vars[i], '='); + if (index_ptr < 0) { // vars[i] == "onlykey" // Skip, not a "key=value" attribute continue; } - const gsize index = (gsize)index_ptr; + const gsize index = (gsize) index_ptr; gchar *key = g_strndup (vars[i], index); gchar *value = g_strndup (vars[i] + index + 1, @@ -1941,8 +1958,7 @@ kms_base_rtp_endpoint_sync_rtp_probe (GstPad * pad, GstPadProbeInfo * info, buffer = gst_buffer_make_writable (buffer); kms_rtp_synchronizer_process_rtp_buffer_writable (sync, buffer, NULL); GST_PAD_PROBE_INFO_DATA (info) = buffer; - } - else if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER_LIST) { + } else if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER_LIST) { GstBufferList *list = gst_pad_probe_info_get_buffer_list (info); list = gst_buffer_list_make_writable (list); @@ -1986,8 +2002,7 @@ kms_base_rtp_endpoint_sync_rtcp_probe (GstPad * pad, GstPadProbeInfo * info, GstBuffer *buffer = gst_pad_probe_info_get_buffer (info); kms_rtp_synchronizer_process_rtcp_buffer (sync, buffer, NULL); - } - else if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER_LIST) { + } else if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER_LIST) { GstBufferList *list = gst_pad_probe_info_get_buffer_list (info); gst_buffer_list_foreach (list, @@ -2020,11 +2035,11 @@ kms_base_rtp_endpoint_rtpbin_new_jitterbuffer (GstElement * rtpbin, KmsRTPSessionStats *rtp_stats; KmsSSRCStats *ssrc_stats; - g_object_set (jitterbuffer, "mode", 4 /* synced */, "do-lost", TRUE, + g_object_set (jitterbuffer, "mode", 4 /* synced */ , "do-lost", TRUE, "latency", JB_INITIAL_LATENCY, NULL); switch (session) { - case AUDIO_RTP_SESSION: { + case AUDIO_RTP_SESSION:{ kms_base_rtp_endpoint_jitterbuffer_set_latency (jitterbuffer, JB_READY_AUDIO_LATENCY); @@ -2037,7 +2052,7 @@ kms_base_rtp_endpoint_rtpbin_new_jitterbuffer (GstElement * rtpbin, break; } - case VIDEO_RTP_SESSION: { + case VIDEO_RTP_SESSION:{ kms_base_rtp_endpoint_jitterbuffer_set_latency (jitterbuffer, JB_READY_VIDEO_LATENCY); @@ -2245,10 +2260,10 @@ append_rtp_session_stats (gpointer * session, KmsRTPSessionStats * rtp_stats, const gchar *id; // FIXME 'g_value_array_get_nth' is deprecated: Use 'GArray' instead - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" val = g_value_array_get_nth (arr, i); - #pragma GCC diagnostic pop +#pragma GCC diagnostic pop source = g_value_get_object (val); @@ -2317,10 +2332,10 @@ append_rtp_session_stats (gpointer * session, KmsRTPSessionStats * rtp_stats, } // FIXME 'g_value_array_free' is deprecated: Use 'GArray' instead - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" g_value_array_free (arr); - #pragma GCC diagnostic pop +#pragma GCC diagnostic pop str_session = g_strdup_printf ("session-%u", GPOINTER_TO_UINT (session)); gst_structure_set (stats, str_session, GST_TYPE_STRUCTURE, session_stats, @@ -2391,6 +2406,7 @@ kms_base_rtp_endpoint_set_property (GObject * object, guint property_id, guint v = g_value_get_uint (value); guint max_recv_bw; + g_object_get (self, "max-video-recv-bandwidth", &max_recv_bw, NULL); if (max_recv_bw != 0 && v > max_recv_bw) { @@ -2448,7 +2464,8 @@ kms_base_rtp_endpoint_set_property (GObject * object, guint property_id, if (v >= self->priv->max_port) { v = self->priv->max_port - 1; GST_WARNING_OBJECT (object, - "Trying to set min-port >= max-port. Setting %" G_GUINT32_FORMAT, v); + "Trying to set min-port >= max-port. Setting %" G_GUINT32_FORMAT, + v); } if (v < DEFAULT_MIN_PORT) { @@ -2466,7 +2483,8 @@ kms_base_rtp_endpoint_set_property (GObject * object, guint property_id, if (v <= self->priv->min_port) { v = self->priv->min_port + 1; GST_WARNING_OBJECT (object, - "Trying to set max-port <= min-port. Setting %" G_GUINT32_FORMAT, v); + "Trying to set max-port <= min-port. Setting %" G_GUINT32_FORMAT, + v); } if (v > DEFAULT_MAX_PORT) { @@ -2481,6 +2499,14 @@ kms_base_rtp_endpoint_set_property (GObject * object, guint property_id, case PROP_MTU: self->priv->mtu = g_value_get_uint (value); break; + case PROP_EXTERNAL_IPV4: + g_free (self->priv->external_ipv4); + self->priv->external_ipv4 = g_value_dup_string (value); + break; + case PROP_EXTERNAL_IPV6: + g_free (self->priv->external_ipv6); + self->priv->external_ipv6 = g_value_dup_string (value); + break; case PROP_OFFER_DIR: self->priv->offer_dir = g_value_get_enum (value); break; @@ -2550,6 +2576,12 @@ kms_base_rtp_endpoint_get_property (GObject * object, guint property_id, case PROP_MTU: g_value_set_uint (value, self->priv->mtu); break; + case PROP_EXTERNAL_IPV4: + g_value_set_string (value, self->priv->external_ipv4); + break; + case PROP_EXTERNAL_IPV6: + g_value_set_string (value, self->priv->external_ipv6); + break; case PROP_SUPPORT_FEC: g_value_set_boolean (value, self->priv->support_fec); break; @@ -2882,9 +2914,9 @@ kms_base_rtp_endpoint_constructed (GObject * gobject) self->priv->sync_video = kms_rtp_synchronizer_new (TRUE, video_name); self->priv->perform_video_sync = TRUE; - g_free(video_name); - g_free(audio_name); - g_free(self_name); + g_free (video_name); + g_free (audio_name); + g_free (self_name); } static void @@ -3010,6 +3042,18 @@ kms_base_rtp_endpoint_class_init (KmsBaseRtpEndpointClass * klass) 0, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_EXTERNAL_IPV4, + g_param_spec_string ("external-ipv4", + "externalIPv4", + "External (public) IPv4 address of the media server", + DEFAULT_EXTERNAL_IPV4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_EXTERNAL_IPV6, + g_param_spec_string ("external-ipv6", + "externalIPv6", + "External (public) IPv6 address of the media server", + DEFAULT_EXTERNAL_IPV6, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_SUPPORT_FEC, g_param_spec_boolean ("support-fec", "Forward error correction supported", "Forward error correction supported", FALSE, @@ -3491,22 +3535,23 @@ kms_base_rtp_endpoint_init (KmsBaseRtpEndpoint * self) self->priv->max_port = DEFAULT_MAX_PORT; self->priv->mtu = DEFAULT_MTU; + self->priv->external_ipv4 = DEFAULT_EXTERNAL_IPV4; + self->priv->external_ipv6 = DEFAULT_EXTERNAL_IPV6; self->priv->offer_dir = DEFAULT_OFFER_DIR; } GObject * -kms_base_rtp_endpoint_get_internal_session (KmsBaseRtpEndpoint *self, +kms_base_rtp_endpoint_get_internal_session (KmsBaseRtpEndpoint * self, guint session_id) { - GstElement *rtpbin = self->priv->rtpbin; // GstRtpBin* - GObject *rtpsession = NULL; // RTPSession* from GstRtpBin->GstRtpSession + GstElement *rtpbin = self->priv->rtpbin; // GstRtpBin* + GObject *rtpsession = NULL; // RTPSession* from GstRtpBin->GstRtpSession g_signal_emit_by_name (rtpbin, "get-internal-session", session_id, &rtpsession); if (rtpsession == NULL) { - GST_WARNING_OBJECT (self, "GstRtpBin: No RTP session, id: %u", - session_id); + GST_WARNING_OBJECT (self, "GstRtpBin: No RTP session, id: %u", session_id); } return rtpsession; diff --git a/src/server/config/BaseRtpEndpoint.conf.ini b/src/server/config/BaseRtpEndpoint.conf.ini index 067f5b7b6..018e268d2 100644 --- a/src/server/config/BaseRtpEndpoint.conf.ini +++ b/src/server/config/BaseRtpEndpoint.conf.ini @@ -40,3 +40,15 @@ ;; * Unit: Bytes. ;; * Default: 1200. ;mtu=1200 + +;; External IPv4 and IPv6 addresses of the media server. +;; +;; Forces the stack to use a specific address. +;; +;; If not specified then an address is selected at random. +;; +;; is a single IPv4 address. +;; is a single IPv6 address. +;; +;externalIPv4=198.51.100.1 +;externalIPv6=2001:0db8:85a3:0000:0000:8a2e:0370:7334 diff --git a/src/server/implementation/objects/BaseRtpEndpointImpl.cpp b/src/server/implementation/objects/BaseRtpEndpointImpl.cpp index 6eee6bef8..804fb4582 100644 --- a/src/server/implementation/objects/BaseRtpEndpointImpl.cpp +++ b/src/server/implementation/objects/BaseRtpEndpointImpl.cpp @@ -50,10 +50,14 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); #define PARAM_MIN_PORT "minPort" #define PARAM_MAX_PORT "maxPort" #define PARAM_MTU "mtu" +#define PARAM_EXTERNAL_IPV4 "externalIPv4" +#define PARAM_EXTERNAL_IPV6 "externalIPv6" #define PROP_MIN_PORT "min-port" #define PROP_MAX_PORT "max-port" #define PROP_MTU "mtu" +#define PROP_EXTERNAL_IPV4 "external-ipv4" +#define PROP_EXTERNAL_IPV6 "external-ipv6" /* Fixed point conversion macros */ #define FRIC 65536. /* 2^16 as a double */ @@ -97,22 +101,49 @@ BaseRtpEndpointImpl::BaseRtpEndpointImpl (const boost::property_tree::ptree connStateChangedHandlerId = 0; guint minPort = 0; - if (getConfigValue (&minPort, PARAM_MIN_PORT)) { + + if (getConfigValue (&minPort, PARAM_MIN_PORT) ) { g_object_set (getGstreamerElement (), PROP_MIN_PORT, minPort, NULL); } guint maxPort = 0; - if (getConfigValue (&maxPort, PARAM_MAX_PORT)) { + + if (getConfigValue (&maxPort, PARAM_MAX_PORT) ) { g_object_set (getGstreamerElement (), PROP_MAX_PORT, maxPort, NULL); } guint mtu; - if (getConfigValue (&mtu, PARAM_MTU)) { + + if (getConfigValue (&mtu, PARAM_MTU) ) { GST_INFO ("Predefined RTP MTU: %u", mtu); g_object_set (G_OBJECT (element), PROP_MTU, mtu, NULL); } else { GST_DEBUG ("No predefined RTP MTU found in config; using default"); } + + std::string externalIPv4; + + if (getConfigValue (&externalIPv4, + PARAM_EXTERNAL_IPV4) ) { + GST_INFO ("Predefined external IPv4 address: %s", externalIPv4.c_str() ); + g_object_set (G_OBJECT (element), PROP_EXTERNAL_IPV4, + externalIPv4.c_str(), NULL); + } else { + GST_DEBUG ("No predefined external IPv4 address found in config;" + " you can set one or default to random selection"); + } + + std::string externalIPv6; + + if (getConfigValue (&externalIPv6, + PARAM_EXTERNAL_IPV6) ) { + GST_INFO ("Predefined external IPv6 address: %s", externalIPv6.c_str() ); + g_object_set (G_OBJECT (element), PROP_EXTERNAL_IPV6, + externalIPv6.c_str(), NULL); + } else { + GST_DEBUG ("No predefined external IPv6 address found in config;" + " you can set one or default to random selection"); + } } BaseRtpEndpointImpl::~BaseRtpEndpointImpl () @@ -150,15 +181,16 @@ BaseRtpEndpointImpl::updateMediaState (guint new_state) if (old_state->getValue() != current_media_state->getValue() ) { GST_DEBUG_OBJECT (element, "MediaState changed to '%s'", - current_media_state->getString().c_str()); + current_media_state->getString().c_str() ); + try { MediaStateChanged event (shared_from_this (), - MediaStateChanged::getName (), old_state, current_media_state); - sigcSignalEmit(signalMediaStateChanged, event); + MediaStateChanged::getName (), old_state, current_media_state); + sigcSignalEmit (signalMediaStateChanged, event); } catch (const std::bad_weak_ptr &e) { // shared_from_this() GST_ERROR ("BUG creating %s: %s", MediaStateChanged::getName ().c_str (), - e.what ()); + e.what () ); } } } @@ -187,15 +219,16 @@ BaseRtpEndpointImpl::updateConnectionState (gchar *sessId, guint new_state) if (old_state->getValue() != current_conn_state->getValue() ) { GST_DEBUG_OBJECT (element, "ConnectionState changed to '%s'", - current_conn_state->getString().c_str()); + current_conn_state->getString().c_str() ); + try { ConnectionStateChanged event (shared_from_this(), - ConnectionStateChanged::getName (), old_state, current_conn_state); - sigcSignalEmit(signalConnectionStateChanged, event); + ConnectionStateChanged::getName (), old_state, current_conn_state); + sigcSignalEmit (signalConnectionStateChanged, event); } catch (const std::bad_weak_ptr &e) { // shared_from_this() GST_ERROR ("BUG creating %s: %s", - ConnectionStateChanged::getName ().c_str (), e.what ()); + ConnectionStateChanged::getName ().c_str (), e.what () ); } } } @@ -393,6 +426,54 @@ BaseRtpEndpointImpl::setMtu (int mtu) g_object_set (G_OBJECT (element), PROP_MTU, mtu, NULL); } +std::string +BaseRtpEndpointImpl::getExternalIPv4 () +{ + std::string externalIPv4; + gchar *ret; + + g_object_get (G_OBJECT (element), PROP_EXTERNAL_IPV4, &ret, NULL); + + if (ret != nullptr) { + externalIPv4 = std::string (ret); + g_free (ret); + } + + return externalIPv4; +} + +void +BaseRtpEndpointImpl::setExternalIPv4 (const std::string &externalIPv4) +{ + GST_INFO ("Set external IPv4 address: %s", externalIPv4.c_str() ); + g_object_set (G_OBJECT (element), PROP_EXTERNAL_IPV4, + externalIPv4.c_str(), NULL); +} + +std::string +BaseRtpEndpointImpl::getExternalIPv6 () +{ + std::string externalIPv6; + gchar *ret; + + g_object_get (G_OBJECT (element), PROP_EXTERNAL_IPV6, &ret, NULL); + + if (ret != nullptr) { + externalIPv6 = std::string (ret); + g_free (ret); + } + + return externalIPv6; +} + +void +BaseRtpEndpointImpl::setExternalIPv6 (const std::string &externalIPv6) +{ + GST_INFO ("Set external IPv6 address: %s", externalIPv6.c_str() ); + g_object_set (G_OBJECT (element), PROP_EXTERNAL_IPV6, + externalIPv6.c_str(), NULL); +} + /******************/ /* RTC statistics */ /******************/ @@ -612,9 +693,9 @@ setDeprecatedProperties (std::shared_ptr eStats) for (auto &inStat : inStats) { if (inStat->getName() == "sink_audio_default") { - eStats->setAudioE2ELatency(inStat->getAvg()); + eStats->setAudioE2ELatency (inStat->getAvg() ); } else if (inStat->getName() == "sink_video_default") { - eStats->setVideoE2ELatency(inStat->getAvg()); + eStats->setVideoE2ELatency (inStat->getAvg() ); } } } diff --git a/src/server/implementation/objects/BaseRtpEndpointImpl.hpp b/src/server/implementation/objects/BaseRtpEndpointImpl.hpp index 04d94a057..3b7da64fc 100644 --- a/src/server/implementation/objects/BaseRtpEndpointImpl.hpp +++ b/src/server/implementation/objects/BaseRtpEndpointImpl.hpp @@ -67,6 +67,12 @@ class BaseRtpEndpointImpl : public SdpEndpointImpl, virtual int getMtu (); virtual void setMtu (int mtu); + virtual std::string getExternalIPv4 (); + virtual void setExternalIPv4 (const std::string &externalIPv4); + + virtual std::string getExternalIPv6 (); + virtual void setExternalIPv6 (const std::string &externalIPv6); + sigc::signal signalMediaStateChanged; sigc::signal signalConnectionStateChanged;