blob: 2365cfd52b9145bffc3d5731bb4b140790097291 [file] [log] [blame]
/* GStreamer
* Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "nicetransport.h"
#include "icestream.h"
#define GST_CAT_DEFAULT gst_webrtc_nice_transport_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define gst_webrtc_nice_transport_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstWebRTCNiceTransport, gst_webrtc_nice_transport,
GST_TYPE_WEBRTC_ICE_TRANSPORT,
GST_DEBUG_CATEGORY_INIT (gst_webrtc_nice_transport_debug,
"webrtcnicetransport", 0, "webrtcnicetransport");
);
enum
{
SIGNAL_0,
LAST_SIGNAL,
};
enum
{
PROP_0,
PROP_STREAM,
};
//static guint gst_webrtc_nice_transport_signals[LAST_SIGNAL] = { 0 };
struct _GstWebRTCNiceTransportPrivate
{
gboolean running;
};
static NiceComponentType
_gst_component_to_nice (GstWebRTCICEComponent component)
{
switch (component) {
case GST_WEBRTC_ICE_COMPONENT_RTP:
return NICE_COMPONENT_TYPE_RTP;
case GST_WEBRTC_ICE_COMPONENT_RTCP:
return NICE_COMPONENT_TYPE_RTCP;
default:
g_assert_not_reached ();
return 0;
}
}
static GstWebRTCICEComponent
_nice_component_to_gst (NiceComponentType component)
{
switch (component) {
case NICE_COMPONENT_TYPE_RTP:
return GST_WEBRTC_ICE_COMPONENT_RTP;
case NICE_COMPONENT_TYPE_RTCP:
return GST_WEBRTC_ICE_COMPONENT_RTCP;
default:
g_assert_not_reached ();
return 0;
}
}
static GstWebRTCICEConnectionState
_nice_component_state_to_gst (NiceComponentState state)
{
switch (state) {
case NICE_COMPONENT_STATE_DISCONNECTED:
return GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED;
case NICE_COMPONENT_STATE_GATHERING:
return GST_WEBRTC_ICE_CONNECTION_STATE_NEW;
case NICE_COMPONENT_STATE_CONNECTING:
return GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING;
case NICE_COMPONENT_STATE_CONNECTED:
return GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED;
case NICE_COMPONENT_STATE_READY:
return GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED;
case NICE_COMPONENT_STATE_FAILED:
return GST_WEBRTC_ICE_CONNECTION_STATE_FAILED;
default:
g_assert_not_reached ();
return 0;
}
}
static void
gst_webrtc_nice_transport_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
switch (prop_id) {
case PROP_STREAM:
if (nice->stream)
gst_object_unref (nice->stream);
nice->stream = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_webrtc_nice_transport_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
switch (prop_id) {
case PROP_STREAM:
g_value_set_object (value, nice->stream);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_webrtc_nice_transport_finalize (GObject * object)
{
GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
gst_object_unref (nice->stream);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
_on_new_selected_pair (NiceAgent * agent, guint stream_id,
NiceComponentType component, NiceCandidate * lcandidate,
NiceCandidate * rcandidate, GstWebRTCNiceTransport * nice)
{
GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (nice);
GstWebRTCICEComponent comp = _nice_component_to_gst (component);
guint our_stream_id;
g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
if (stream_id != our_stream_id)
return;
if (comp != ice->component)
return;
gst_webrtc_ice_transport_selected_pair_change (ice);
}
static void
_on_component_state_changed (NiceAgent * agent, guint stream_id,
NiceComponentType component, NiceComponentState state,
GstWebRTCNiceTransport * nice)
{
GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (nice);
GstWebRTCICEComponent comp = _nice_component_to_gst (component);
guint our_stream_id;
g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
if (stream_id != our_stream_id)
return;
if (comp != ice->component)
return;
GST_DEBUG_OBJECT (ice, "%u %u %s", stream_id, component,
nice_component_state_to_string (state));
gst_webrtc_ice_transport_connection_state_change (ice,
_nice_component_state_to_gst (state));
}
static void
gst_webrtc_nice_transport_constructed (GObject * object)
{
GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (object);
NiceComponentType component = _gst_component_to_nice (ice->component);
gboolean controlling_mode;
guint our_stream_id;
NiceAgent *agent;
g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
g_object_get (nice->stream->ice, "agent", &agent, NULL);
g_object_get (agent, "controlling-mode", &controlling_mode, NULL);
ice->role =
controlling_mode ? GST_WEBRTC_ICE_ROLE_CONTROLLING :
GST_WEBRTC_ICE_ROLE_CONTROLLED;
g_signal_connect (agent, "component-state-changed",
G_CALLBACK (_on_component_state_changed), nice);
g_signal_connect (agent, "new-selected-pair-full",
G_CALLBACK (_on_new_selected_pair), nice);
ice->src = gst_element_factory_make ("nicesrc", NULL);
if (ice->src) {
g_object_set (ice->src, "agent", agent, "stream", our_stream_id,
"component", component, NULL);
}
ice->sink = gst_element_factory_make ("nicesink", NULL);
if (ice->sink) {
g_object_set (ice->sink, "agent", agent, "stream", our_stream_id,
"component", component, "async", FALSE, "enable-last-sample", FALSE,
NULL);
if (ice->component == GST_WEBRTC_ICE_COMPONENT_RTCP)
g_object_set (ice->sink, "sync", FALSE, NULL);
}
g_object_unref (agent);
G_OBJECT_CLASS (parent_class)->constructed (object);
}
static void
gst_webrtc_nice_transport_class_init (GstWebRTCNiceTransportClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
g_type_class_add_private (klass, sizeof (GstWebRTCNiceTransportPrivate));
gobject_class->constructed = gst_webrtc_nice_transport_constructed;
gobject_class->get_property = gst_webrtc_nice_transport_get_property;
gobject_class->set_property = gst_webrtc_nice_transport_set_property;
gobject_class->finalize = gst_webrtc_nice_transport_finalize;
g_object_class_install_property (gobject_class,
PROP_STREAM,
g_param_spec_object ("stream",
"WebRTC ICE Stream", "ICE stream associated with this transport",
GST_TYPE_WEBRTC_ICE_STREAM,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
static void
gst_webrtc_nice_transport_init (GstWebRTCNiceTransport * nice)
{
nice->priv =
G_TYPE_INSTANCE_GET_PRIVATE ((nice), GST_TYPE_WEBRTC_NICE_TRANSPORT,
GstWebRTCNiceTransportPrivate);
}
GstWebRTCNiceTransport *
gst_webrtc_nice_transport_new (GstWebRTCICEStream * stream,
GstWebRTCICEComponent component)
{
return g_object_new (GST_TYPE_WEBRTC_NICE_TRANSPORT, "stream", stream,
"component", component, NULL);
}