gst_rtsp_stream_join_bin
gst_rtsp_stream_leave_bin
gst_rtsp_stream_get_rtpinfo
+gst_rtsp_stream_get_caps
gst_rtsp_stream_recv_rtcp
gst_rtsp_stream_recv_rtp
gst_rtsp_stream_add_transport
g_print ("removing all sessions\n");
pool = gst_rtsp_server_get_session_pool (server);
- gst_rtsp_session_pool_filter (pool, (GstRTSPSessionFilterFunc) remove_func,
- server);
+ gst_rtsp_session_pool_filter (pool,
+ (GstRTSPSessionPoolFilterFunc) remove_func, server);
g_object_unref (pool);
return FALSE;
#include "rtsp-auth.h"
+#define GST_RTSP_AUTH_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate))
+
+struct _GstRTSPAuthPrivate
+{
+ GMutex lock;
+ gchar *basic;
+ GstRTSPMethod methods;
+};
+
enum
{
PROP_0,
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_auth_get_property;
static void
gst_rtsp_auth_init (GstRTSPAuth * auth)
{
- g_mutex_init (&auth->lock);
+ auth->priv = GST_RTSP_AUTH_GET_PRIVATE (auth);
+
+ g_mutex_init (&auth->priv->lock);
/* bitwise or of all methods that need authentication */
- auth->methods = GST_RTSP_DESCRIBE |
+ auth->priv->methods = GST_RTSP_DESCRIBE |
GST_RTSP_ANNOUNCE |
GST_RTSP_GET_PARAMETER |
GST_RTSP_SET_PARAMETER |
gst_rtsp_auth_finalize (GObject * obj)
{
GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
+ GstRTSPAuthPrivate *priv = auth->priv;
GST_INFO ("finalize auth %p", auth);
- g_free (auth->basic);
- g_mutex_clear (&auth->lock);
+ g_free (priv->basic);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
}
void
gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
{
+ GstRTSPAuthPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_AUTH (auth));
- g_mutex_lock (&auth->lock);
- g_free (auth->basic);
- auth->basic = g_strdup (basic);
- g_mutex_unlock (&auth->lock);
+ priv = auth->priv;
+
+ g_mutex_lock (&priv->lock);
+ g_free (priv->basic);
+ priv->basic = g_strdup (basic);
+ g_mutex_unlock (&priv->lock);
}
static gboolean
default_check_method (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
+ GstRTSPAuthPrivate *priv = auth->priv;
gboolean result = TRUE;
GstRTSPResult res;
- if ((state->method & auth->methods) != 0) {
+ if ((state->method & priv->methods) != 0) {
gchar *authorization;
result = FALSE;
/* parse type */
if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
GST_DEBUG_OBJECT (auth, "check Basic auth");
- g_mutex_lock (&auth->lock);
- if (auth->basic && strcmp (&authorization[6], auth->basic) == 0)
+ g_mutex_lock (&priv->lock);
+ if (priv->basic && strcmp (&authorization[6], priv->basic) == 0)
result = TRUE;
- g_mutex_unlock (&auth->lock);
+ g_mutex_unlock (&priv->lock);
} else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
GST_DEBUG_OBJECT (auth, "check Digest auth");
/* not implemented yet */
typedef struct _GstRTSPAuth GstRTSPAuth;
typedef struct _GstRTSPAuthClass GstRTSPAuthClass;
+typedef struct _GstRTSPAuthPrivate GstRTSPAuthPrivate;
#include "rtsp-client.h"
struct _GstRTSPAuth {
GObject parent;
- /*< private >*/
- GMutex lock;
- gchar *basic;
- GstRTSPMethod methods;
+ GstRTSPAuthPrivate *priv;
};
struct _GstRTSPAuthClass {
#include "rtsp-sdp.h"
#include "rtsp-params.h"
+#define GST_RTSP_CLIENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate))
+
+struct _GstRTSPClientPrivate
+{
+ GMutex lock;
+ GstRTSPConnection *connection;
+ GstRTSPWatch *watch;
+ guint close_seq;
+ gchar *server_ip;
+ gboolean is_ipv6;
+ gboolean use_client_settings;
+
+ GstRTSPClientSendFunc send_func;
+ gpointer send_data;
+ GDestroyNotify send_notify;
+
+ GstRTSPSessionPool *session_pool;
+ GstRTSPMountPoints *mount_points;
+ GstRTSPAuth *auth;
+
+ GstRTSPUrl *uri;
+ GstRTSPMedia *media;
+
+ GList *transports;
+ GList *sessions;
+};
+
static GMutex tunnels_lock;
static GHashTable *tunnels;
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPClientPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_client_get_property;
static void
gst_rtsp_client_init (GstRTSPClient * client)
{
- g_mutex_init (&client->lock);
- client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS;
- client->close_seq = 0;
+ GstRTSPClientPrivate *priv = GST_RTSP_CLIENT_GET_PRIVATE (client);
+
+ client->priv = priv;
+
+ g_mutex_init (&priv->lock);
+ priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS;
+ priv->close_seq = 0;
+}
+
+static GstRTSPFilterResult
+filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * media,
+ gpointer user_data)
+{
+ GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
+
+ gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
+ unlink_session_transports (client, sess, media);
+
+ /* unmanage the media in the session */
+ return GST_RTSP_FILTER_REMOVE;
}
static void
client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
{
/* unlink all media managed in this session */
- while (session->medias) {
- GstRTSPSessionMedia *media = session->medias->data;
-
- gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
- unlink_session_transports (client, session, media);
- /* unmanage the media in the session. this will modify session->medias */
- gst_rtsp_session_release_media (session, media);
- }
+ gst_rtsp_session_filter (session, filter_session, client);
}
static void
client_cleanup_sessions (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv = client->priv;
GList *sessions;
/* remove weak-ref from sessions */
- for (sessions = client->sessions; sessions; sessions = g_list_next (sessions)) {
+ for (sessions = priv->sessions; sessions; sessions = g_list_next (sessions)) {
GstRTSPSession *session = (GstRTSPSession *) sessions->data;
g_object_weak_unref (G_OBJECT (session),
(GWeakNotify) client_session_finalized, client);
client_unlink_session (client, session);
}
- g_list_free (client->sessions);
- client->sessions = NULL;
+ g_list_free (priv->sessions);
+ priv->sessions = NULL;
}
/* A client is finalized when the connection is broken */
gst_rtsp_client_finalize (GObject * obj)
{
GstRTSPClient *client = GST_RTSP_CLIENT (obj);
+ GstRTSPClientPrivate *priv = client->priv;
GST_INFO ("finalize client %p", client);
- if (client->watch)
- g_source_destroy ((GSource *) client->watch);
+ if (priv->watch)
+ g_source_destroy ((GSource *) priv->watch);
- if (client->send_notify)
- client->send_notify (client->send_data);
+ if (priv->send_notify)
+ priv->send_notify (priv->send_data);
client_cleanup_sessions (client);
- if (client->connection)
- gst_rtsp_connection_free (client->connection);
- if (client->session_pool)
- g_object_unref (client->session_pool);
- if (client->mount_points)
- g_object_unref (client->mount_points);
- if (client->auth)
- g_object_unref (client->auth);
+ if (priv->connection)
+ gst_rtsp_connection_free (priv->connection);
+ if (priv->session_pool)
+ g_object_unref (priv->session_pool);
+ if (priv->mount_points)
+ g_object_unref (priv->mount_points);
+ if (priv->auth)
+ g_object_unref (priv->auth);
- if (client->uri)
- gst_rtsp_url_free (client->uri);
- if (client->media) {
- gst_rtsp_media_unprepare (client->media);
- g_object_unref (client->media);
+ if (priv->uri)
+ gst_rtsp_url_free (priv->uri);
+ if (priv->media) {
+ gst_rtsp_media_unprepare (priv->media);
+ g_object_unref (priv->media);
}
- g_free (client->server_ip);
- g_mutex_clear (&client->lock);
+ g_free (priv->server_ip);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
}
send_response (GstRTSPClient * client, GstRTSPSession * session,
GstRTSPMessage * response, gboolean close)
{
+ GstRTSPClientPrivate *priv = client->priv;
+
gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER,
"GStreamer RTSP server");
if (close)
gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close");
- if (client->send_func)
- client->send_func (client, response, close, client->send_data);
+ if (priv->send_func)
+ priv->send_func (client, response, close, priv->send_data);
gst_rtsp_message_unset (response);
}
static GstRTSPMedia *
find_media (GstRTSPClient * client, GstRTSPClientState * state)
{
+ GstRTSPClientPrivate *priv = client->priv;
GstRTSPMediaFactory *factory;
GstRTSPMedia *media;
GstRTSPAuth *auth;
- if (!compare_uri (client->uri, state->uri)) {
+ if (!compare_uri (priv->uri, state->uri)) {
/* remove any previously cached values before we try to construct a new
* media for uri */
- if (client->uri)
- gst_rtsp_url_free (client->uri);
- client->uri = NULL;
- if (client->media) {
- gst_rtsp_media_unprepare (client->media);
- g_object_unref (client->media);
+ if (priv->uri)
+ gst_rtsp_url_free (priv->uri);
+ priv->uri = NULL;
+ if (priv->media) {
+ gst_rtsp_media_unprepare (priv->media);
+ g_object_unref (priv->media);
}
- client->media = NULL;
+ priv->media = NULL;
- if (!client->mount_points)
+ if (!priv->mount_points)
goto no_mount_points;
/* find the factory for the uri first */
if (!(factory =
- gst_rtsp_mount_points_find_factory (client->mount_points,
+ gst_rtsp_mount_points_find_factory (priv->mount_points,
state->uri)))
goto no_factory;
g_object_unref (factory);
factory = NULL;
- /* set ipv6 on the media before preparing */
- media->is_ipv6 = client->is_ipv6;
/* prepare the media */
if (!(gst_rtsp_media_prepare (media)))
goto no_prepare;
/* now keep track of the uri and the media */
- client->uri = gst_rtsp_url_copy (state->uri);
- client->media = media;
+ priv->uri = gst_rtsp_url_copy (state->uri);
+ priv->media = media;
state->media = media;
} else {
/* we have seen this uri before, used cached media */
- media = client->media;
+ media = priv->media;
state->media = media;
GST_INFO ("reusing cached media %p", media);
}
static gboolean
do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv = client->priv;
GstRTSPMessage message = { 0 };
GstMapInfo map_info;
guint8 *data;
gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
- if (client->send_func)
- client->send_func (client, &message, FALSE, client->send_data);
+ if (priv->send_func)
+ priv->send_func (client, &message, FALSE, priv->send_data);
gst_rtsp_message_steal_body (&message, &data, &usize);
gst_buffer_unmap (buffer, &map_info);
link_transport (GstRTSPClient * client, GstRTSPSession * session,
GstRTSPStreamTransport * trans)
{
+ GstRTSPClientPrivate *priv = client->priv;
+
GST_DEBUG ("client %p: linking transport %p", client, trans);
+
gst_rtsp_stream_transport_set_callbacks (trans,
(GstRTSPSendFunc) do_send_data,
(GstRTSPSendFunc) do_send_data, client, NULL);
- client->transports = g_list_prepend (client->transports, trans);
+ priv->transports = g_list_prepend (priv->transports, trans);
/* make sure our session can't expire */
gst_rtsp_session_prevent_expire (session);
unlink_transport (GstRTSPClient * client, GstRTSPSession * session,
GstRTSPStreamTransport * trans)
{
+ GstRTSPClientPrivate *priv = client->priv;
+
GST_DEBUG ("client %p: unlinking transport %p", client, trans);
+
gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL);
- client->transports = g_list_remove (client->transports, trans);
+ priv->transports = g_list_remove (priv->transports, trans);
/* our session can now expire */
gst_rtsp_session_allow_expire (session);
{
guint n_streams, i;
- n_streams = gst_rtsp_media_n_streams (media->media);
+ n_streams =
+ gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media));
for (i = 0; i < n_streams; i++) {
GstRTSPStreamTransport *trans;
- GstRTSPTransport *tr;
+ const GstRTSPTransport *tr;
/* get the transport, if there is no transport configured, skip this stream */
trans = gst_rtsp_session_media_get_transport (media, i);
if (trans == NULL)
continue;
- tr = trans->transport;
+ tr = gst_rtsp_stream_transport_get_transport (trans);
if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
/* for TCP, unlink the stream from the TCP connection of the client */
static void
close_connection (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv = client->priv;
const gchar *tunnelid;
GST_DEBUG ("client %p: closing connection", client);
- if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
+ if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
g_mutex_lock (&tunnels_lock);
/* remove from tunnelids */
g_hash_table_remove (tunnels, tunnelid);
g_mutex_unlock (&tunnels_lock);
}
- gst_rtsp_connection_close (client->connection);
+ gst_rtsp_connection_close (priv->connection);
}
static gboolean
handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state)
{
+ GstRTSPClientPrivate *priv = client->priv;
GstRTSPSession *session;
GstRTSPSessionMedia *media;
GstRTSPStatusCode code;
/* remove the session from the watched sessions */
g_object_weak_unref (G_OBJECT (session),
(GWeakNotify) client_session_finalized, client);
- client->sessions = g_list_remove (client->sessions, session);
+ priv->sessions = g_list_remove (priv->sessions, session);
gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
* are torn down. */
if (!gst_rtsp_session_release_media (session, media)) {
/* remove the session */
- gst_rtsp_session_pool_remove (client->session_pool, session);
+ gst_rtsp_session_pool_remove (priv->session_pool, session);
}
/* construct the response now */
code = GST_RTSP_STS_OK;
GstRTSPSession *session;
GstRTSPSessionMedia *media;
GstRTSPStatusCode code;
+ GstRTSPState rtspstate;
if (!(session = state->session))
goto no_session;
state->sessmedia = media;
+ rtspstate = gst_rtsp_session_media_get_rtsp_state (media);
/* the session state must be playing or recording */
- if (media->state != GST_RTSP_STATE_PLAYING &&
- media->state != GST_RTSP_STATE_RECORDING)
+ if (rtspstate != GST_RTSP_STATE_PLAYING &&
+ rtspstate != GST_RTSP_STATE_RECORDING)
goto invalid_state;
/* unlink the all TCP callbacks */
send_response (client, session, state->response, FALSE);
/* the state is now READY */
- media->state = GST_RTSP_STATE_READY;
+ gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_READY);
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST],
0, state);
gchar *str;
GstRTSPTimeRange *range;
GstRTSPResult res;
+ GstRTSPState rtspstate;
if (!(session = state->session))
goto no_session;
state->sessmedia = media;
/* the session state must be playing or ready */
- if (media->state != GST_RTSP_STATE_PLAYING &&
- media->state != GST_RTSP_STATE_READY)
+ rtspstate = gst_rtsp_session_media_get_rtsp_state (media);
+ if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
goto invalid_state;
/* parse the range header if we have one */
if (res == GST_RTSP_OK) {
if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
/* we have a range, seek to the position */
- gst_rtsp_media_seek (media->media, range);
+ gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range);
gst_rtsp_range_free (range);
}
}
/* grab RTPInfo from the payloaders now */
rtpinfo = g_string_new ("");
- n_streams = gst_rtsp_media_n_streams (media->media);
+ n_streams =
+ gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media));
for (i = 0, infocount = 0; i < n_streams; i++) {
GstRTSPStreamTransport *trans;
- GstRTSPTransport *tr;
+ GstRTSPStream *stream;
+ const GstRTSPTransport *tr;
gchar *uristr;
guint rtptime, seq;
GST_INFO ("stream %d is not configured", i);
continue;
}
- tr = trans->transport;
+ tr = gst_rtsp_stream_transport_get_transport (trans);
if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
/* for TCP, link the stream to the TCP connection of the client */
link_transport (client, session, trans);
}
- if (gst_rtsp_stream_get_rtpinfo (trans->stream, &rtptime, &seq)) {
+ stream = gst_rtsp_stream_transport_get_stream (trans);
+ if (gst_rtsp_stream_get_rtpinfo (stream, &rtptime, &seq)) {
if (infocount > 0)
g_string_append (rtpinfo, ", ");
}
/* add the range */
- str = gst_rtsp_media_get_range_string (media->media, TRUE);
+ str =
+ gst_rtsp_media_get_range_string (gst_rtsp_session_media_get_media (media),
+ TRUE);
gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str);
send_response (client, session, state->response, FALSE);
/* start playing after sending the request */
gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
- media->state = GST_RTSP_STATE_PLAYING;
+ gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_PLAYING);
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST],
0, state);
configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
GstRTSPTransport * ct)
{
+ GstRTSPClientPrivate *priv = client->priv;
+
/* we have a valid transport now, set the destination of the client. */
if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
- if (ct->destination == NULL || !client->use_client_settings) {
+ if (ct->destination == NULL || !priv->use_client_settings) {
GstRTSPAddress *addr;
addr = gst_rtsp_stream_get_address (state->stream);
} else {
GstRTSPUrl *url;
- url = gst_rtsp_connection_get_url (client->connection);
+ url = gst_rtsp_connection_get_url (priv->connection);
g_free (ct->destination);
ct->destination = g_strdup (url->host);
switch (st->lower_transport) {
case GST_RTSP_LOWER_TRANS_UDP:
st->client_port = ct->client_port;
- st->server_port = state->stream->server_port;
+ gst_rtsp_stream_get_server_port (state->stream, &st->server_port);
break;
case GST_RTSP_LOWER_TRANS_UDP_MCAST:
st->port = ct->port;
break;
}
- if (state->stream->session)
- g_object_get (state->stream->session, "internal-ssrc", &st->ssrc, NULL);
+ gst_rtsp_stream_get_ssrc (state->stream, &st->ssrc);
return st;
}
static gboolean
handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
{
+ GstRTSPClientPrivate *priv = client->priv;
GstRTSPResult res;
GstRTSPUrl *uri;
gchar *transport;
GstRTSPSessionMedia *sessmedia;
GstRTSPMedia *media;
GstRTSPStream *stream;
+ GstRTSPState rtspstate;
uri = state->uri;
/* we create the session after parsing stuff so that we don't make
* a session for malformed requests */
- if (client->session_pool == NULL)
+ if (priv->session_pool == NULL)
goto no_pool;
session = state->session;
} else {
/* create a session if this fails we probably reached our session limit or
* something. */
- if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
+ if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
goto service_unavailable;
state->session = session;
goto not_found;
state->sessmedia = sessmedia;
- state->media = media = sessmedia->media;
+ state->media = media = gst_rtsp_session_media_get_media (sessmedia);
/* now get the stream */
stream = gst_rtsp_media_get_stream (media, streamid);
send_response (client, session, state->response, FALSE);
/* update the state */
- switch (sessmedia->state) {
+ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
+ switch (rtspstate) {
case GST_RTSP_STATE_PLAYING:
case GST_RTSP_STATE_RECORDING:
case GST_RTSP_STATE_READY:
/* no state change */
break;
default:
- sessmedia->state = GST_RTSP_STATE_READY;
+ gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
break;
}
g_object_unref (session);
static GstSDPMessage *
create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
{
+ GstRTSPClientPrivate *priv = client->priv;
GstSDPMessage *sdp;
GstSDPInfo info;
const gchar *proto;
/* some standard things first */
gst_sdp_message_set_version (sdp, "0");
- if (client->is_ipv6)
+ if (priv->is_ipv6)
proto = "IP6";
else
proto = "IP4";
gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
- client->server_ip);
+ priv->server_ip);
gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
gst_sdp_message_set_information (sdp, "rtsp-server");
gst_sdp_message_add_attribute (sdp, "control", "*");
info.server_proto = proto;
- info.server_ip = g_strdup (client->server_ip);
+ info.server_ip = g_strdup (priv->server_ip);
/* create an SDP for the media object */
if (!gst_rtsp_sdp_from_media (sdp, &info, media))
static void
client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
{
+ GstRTSPClientPrivate *priv = client->priv;
+
GST_INFO ("client %p: session %p finished", client, session);
/* unlink all media managed in this session */
client_unlink_session (client, session);
/* remove the session */
- if (!(client->sessions = g_list_remove (client->sessions, session))) {
+ if (!(priv->sessions = g_list_remove (priv->sessions, session))) {
GST_INFO ("client %p: all sessions finalized, close the connection",
client);
close_connection (client);
static void
client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
{
+ GstRTSPClientPrivate *priv = client->priv;
GList *walk;
- for (walk = client->sessions; walk; walk = g_list_next (walk)) {
+ for (walk = priv->sessions; walk; walk = g_list_next (walk)) {
GstRTSPSession *msession = (GstRTSPSession *) walk->data;
/* we already know about this session */
g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
client);
- client->sessions = g_list_prepend (client->sessions, session);
+ priv->sessions = g_list_prepend (priv->sessions, session);
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
session);
static void
handle_request (GstRTSPClient * client, GstRTSPMessage * request)
{
+ GstRTSPClientPrivate *priv = client->priv;
GstRTSPMethod method;
const gchar *uristr;
GstRTSPUrl *uri = NULL;
/* get the session if there is any */
res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
if (res == GST_RTSP_OK) {
- if (client->session_pool == NULL)
+ if (priv->session_pool == NULL)
goto no_pool;
/* we had a session in the request, find it again */
- if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
+ if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
goto session_not_found;
/* we add the session to the client list of watched sessions. When a session
state.uri = uri;
state.session = session;
- if (client->auth) {
- if (!gst_rtsp_auth_check (client->auth, client, 0, &state))
+ if (priv->auth) {
+ if (!gst_rtsp_auth_check (priv->auth, client, 0, &state))
goto not_authorized;
}
not_authorized:
{
GST_ERROR ("client %p: not allowed", client);
- handle_unauthorized_request (client, client->auth, &state);
+ handle_unauthorized_request (client, priv->auth, &state);
goto done;
}
not_implemented:
static void
handle_data (GstRTSPClient * client, GstRTSPMessage * message)
{
+ GstRTSPClientPrivate *priv = client->priv;
GstRTSPResult res;
guint8 channel;
GList *walk;
buffer = gst_buffer_new_wrapped (data, size);
handled = FALSE;
- for (walk = client->transports; walk; walk = g_list_next (walk)) {
+ for (walk = priv->transports; walk; walk = g_list_next (walk)) {
GstRTSPStreamTransport *trans;
GstRTSPStream *stream;
- GstRTSPTransport *tr;
+ const GstRTSPTransport *tr;
trans = walk->data;
- /* we only add clients with a transport to the list */
- tr = trans->transport;
- stream = trans->stream;
+ tr = gst_rtsp_stream_transport_get_transport (trans);
+ stream = gst_rtsp_stream_transport_get_stream (trans);
/* check for TCP transport */
if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
GstRTSPSessionPool * pool)
{
GstRTSPSessionPool *old;
+ GstRTSPClientPrivate *priv;
g_return_if_fail (GST_IS_RTSP_CLIENT (client));
+ priv = client->priv;
+
if (pool)
g_object_ref (pool);
- g_mutex_lock (&client->lock);
- old = client->session_pool;
- client->session_pool = pool;
- g_mutex_unlock (&client->lock);
+ g_mutex_lock (&priv->lock);
+ old = priv->session_pool;
+ priv->session_pool = pool;
+ g_mutex_unlock (&priv->lock);
if (old)
g_object_unref (old);
GstRTSPSessionPool *
gst_rtsp_client_get_session_pool (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv;
GstRTSPSessionPool *result;
g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
- g_mutex_lock (&client->lock);
- if ((result = client->session_pool))
+ priv = client->priv;
+
+ g_mutex_lock (&priv->lock);
+ if ((result = priv->session_pool))
g_object_ref (result);
- g_mutex_unlock (&client->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
gst_rtsp_client_set_mount_points (GstRTSPClient * client,
GstRTSPMountPoints * mounts)
{
+ GstRTSPClientPrivate *priv;
GstRTSPMountPoints *old;
g_return_if_fail (GST_IS_RTSP_CLIENT (client));
+ priv = client->priv;
+
if (mounts)
g_object_ref (mounts);
- g_mutex_lock (&client->lock);
- old = client->mount_points;
- client->mount_points = mounts;
- g_mutex_unlock (&client->lock);
+ g_mutex_lock (&priv->lock);
+ old = priv->mount_points;
+ priv->mount_points = mounts;
+ g_mutex_unlock (&priv->lock);
if (old)
g_object_unref (old);
GstRTSPMountPoints *
gst_rtsp_client_get_mount_points (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv;
GstRTSPMountPoints *result;
g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
- g_mutex_lock (&client->lock);
- if ((result = client->mount_points))
+ priv = client->priv;
+
+ g_mutex_lock (&priv->lock);
+ if ((result = priv->mount_points))
g_object_ref (result);
- g_mutex_unlock (&client->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
gst_rtsp_client_set_use_client_settings (GstRTSPClient * client,
gboolean use_client_settings)
{
+ GstRTSPClientPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_CLIENT (client));
- g_mutex_lock (&client->lock);
- client->use_client_settings = use_client_settings;
- g_mutex_unlock (&client->lock);
+ priv = client->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->use_client_settings = use_client_settings;
+ g_mutex_unlock (&priv->lock);
}
/**
gboolean
gst_rtsp_client_get_use_client_settings (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv;
gboolean res;
g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
- g_mutex_lock (&client->lock);
- res = client->use_client_settings;
- g_mutex_unlock (&client->lock);
+ priv = client->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->use_client_settings;
+ g_mutex_unlock (&priv->lock);
return res;
}
void
gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
{
+ GstRTSPClientPrivate *priv;
GstRTSPAuth *old;
g_return_if_fail (GST_IS_RTSP_CLIENT (client));
+ priv = client->priv;
+
if (auth)
g_object_ref (auth);
- g_mutex_lock (&client->lock);
- old = client->auth;
- client->auth = auth;
- g_mutex_unlock (&client->lock);
+ g_mutex_lock (&priv->lock);
+ old = priv->auth;
+ priv->auth = auth;
+ g_mutex_unlock (&priv->lock);
if (old)
g_object_unref (old);
GstRTSPAuth *
gst_rtsp_client_get_auth (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv;
GstRTSPAuth *result;
g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
- g_mutex_lock (&client->lock);
- if ((result = client->auth))
+ priv = client->priv;
+
+ g_mutex_lock (&priv->lock);
+ if ((result = priv->auth))
g_object_ref (result);
- g_mutex_unlock (&client->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
gst_rtsp_client_set_send_func (GstRTSPClient * client,
GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
{
+ GstRTSPClientPrivate *priv;
GDestroyNotify old_notify;
gpointer old_data;
g_return_if_fail (GST_IS_RTSP_CLIENT (client));
- g_mutex_lock (&client->lock);
- client->send_func = func;
- old_notify = client->send_notify;
- old_data = client->send_data;
- client->send_notify = notify;
- client->send_data = user_data;
- g_mutex_unlock (&client->lock);
+ priv = client->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->send_func = func;
+ old_notify = priv->send_notify;
+ old_data = priv->send_data;
+ priv->send_notify = notify;
+ priv->send_data = user_data;
+ g_mutex_unlock (&priv->lock);
if (old_notify)
old_notify (old_data);
do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
gboolean close, gpointer user_data)
{
+ GstRTSPClientPrivate *priv = client->priv;
+
/* send the response and store the seq number so we can wait until it's
* written to the client to close the connection */
- return gst_rtsp_watch_send_message (client->watch, message, close ?
- &client->close_seq : NULL);
+ return gst_rtsp_watch_send_message (priv->watch, message, close ?
+ &priv->close_seq : NULL);
}
static GstRTSPResult
message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
{
GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
+ GstRTSPClientPrivate *priv = client->priv;
- if (client->close_seq && client->close_seq == cseq) {
- client->close_seq = 0;
+ if (priv->close_seq && priv->close_seq == cseq) {
+ priv->close_seq = 0;
close_connection (client);
}
closed (GstRTSPWatch * watch, gpointer user_data)
{
GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
+ GstRTSPClientPrivate *priv = client->priv;
const gchar *tunnelid;
GST_INFO ("client %p: connection closed", client);
- if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
+ if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
g_mutex_lock (&tunnels_lock);
/* remove from tunnelids */
g_hash_table_remove (tunnels, tunnelid);
static gboolean
remember_tunnel (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv = client->priv;
const gchar *tunnelid;
/* store client in the pending tunnels */
- tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
+ tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
if (tunnelid == NULL)
goto no_tunnelid;
static GstRTSPStatusCode
tunnel_start (GstRTSPWatch * watch, gpointer user_data)
{
- GstRTSPClient *client;
-
- client = GST_RTSP_CLIENT (user_data);
+ GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
+ GstRTSPClientPrivate *priv = client->priv;
GST_INFO ("client %p: tunnel start (connection %p)", client,
- client->connection);
+ priv->connection);
if (!remember_tunnel (client))
goto tunnel_error;
static GstRTSPResult
tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
{
- GstRTSPClient *client;
-
- client = GST_RTSP_CLIENT (user_data);
+ GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
+ GstRTSPClientPrivate *priv = client->priv;
GST_WARNING ("client %p: tunnel lost (connection %p)", client,
- client->connection);
+ priv->connection);
/* ignore error, it'll only be a problem when the client does a POST again */
remember_tunnel (client);
{
const gchar *tunnelid;
GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
+ GstRTSPClientPrivate *priv = client->priv;
GstRTSPClient *oclient;
+ GstRTSPClientPrivate *opriv;
GST_INFO ("client %p: tunnel complete", client);
/* find previous tunnel */
- tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
+ tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
if (tunnelid == NULL)
goto no_tunnelid;
g_object_ref (oclient);
g_hash_table_remove (tunnels, tunnelid);
- if (oclient->watch == NULL)
+ opriv = oclient->priv;
+
+ if (opriv->watch == NULL)
goto tunnel_closed;
g_mutex_unlock (&tunnels_lock);
GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
- oclient->connection, client->connection);
+ opriv->connection, priv->connection);
/* merge the tunnels into the first client */
- gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
- gst_rtsp_watch_reset (oclient->watch);
+ gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
+ gst_rtsp_watch_reset (opriv->watch);
g_object_unref (oclient);
return GST_RTSP_OK;
static void
client_watch_notify (GstRTSPClient * client)
{
+ GstRTSPClientPrivate *priv = client->priv;
+
GST_INFO ("client %p: watch destroyed", client);
- client->watch = NULL;
+ priv->watch = NULL;
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
g_object_unref (client);
}
setup_client (GstRTSPClient * client, GSocket * socket,
GstRTSPConnection * conn, GError ** error)
{
+ GstRTSPClientPrivate *priv = client->priv;
GSocket *read_socket;
GSocketAddress *address;
GstRTSPUrl *url;
read_socket = gst_rtsp_connection_get_read_socket (conn);
- client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6;
+ priv->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6;
if (!(address = g_socket_get_remote_address (read_socket, error)))
goto no_address;
- g_free (client->server_ip);
+ g_free (priv->server_ip);
/* keep the original ip that the client connected to */
if (G_IS_INET_SOCKET_ADDRESS (address)) {
GInetAddress *iaddr;
iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
- client->server_ip = g_inet_address_to_string (iaddr);
+ priv->server_ip = g_inet_address_to_string (iaddr);
g_object_unref (address);
} else {
- client->server_ip = g_strdup ("unknown");
+ priv->server_ip = g_strdup ("unknown");
}
GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
- client->server_ip, client->is_ipv6);
+ priv->server_ip, priv->is_ipv6);
url = gst_rtsp_connection_get_url (conn);
GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
- client->connection = conn;
+ priv->connection = conn;
return TRUE;
guint
gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
{
+ GstRTSPClientPrivate *priv;
guint res;
g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
- g_return_val_if_fail (client->watch == NULL, 0);
+ priv = client->priv;
+ g_return_val_if_fail (priv->watch == NULL, 0);
/* create watch for the connection and attach */
- client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
+ priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
g_object_ref (client), (GDestroyNotify) client_watch_notify);
gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL);
GST_INFO ("attaching to context %p", context);
- res = gst_rtsp_watch_attach (client->watch, context);
- gst_rtsp_watch_unref (client->watch);
+ res = gst_rtsp_watch_attach (priv->watch, context);
+ gst_rtsp_watch_unref (priv->watch);
return res;
}
typedef struct _GstRTSPClient GstRTSPClient;
typedef struct _GstRTSPClientClass GstRTSPClientClass;
typedef struct _GstRTSPClientState GstRTSPClientState;
+typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate;
#include "rtsp-media.h"
#include "rtsp-mount-points.h"
/**
* GstRTSPClient:
- * @lock: lock protecting the client object
- * @connection: the connection object handling the client request.
- * @watch: watch for the connection
- * @close_seq: sequence number of message with close header
- * @server_ip: ip address of the server
- * @is_ipv6: if we are IPv6
- * @use_client_settings: whether to allow client transport settings for multicast
- * @send_func: a #GstRTSPClientSendFunc called when an RTSP message needs to be
- * sent to the client.
- * @send_data: user data passed to @send_func
- * @send_notify: notify called when @send_data is no longer used.
- * @session_pool: handle to the session pool used by the client.
- * @mount_points: handle to the mount points used by the client.
- * @auth: authorization object
- * @uri: cached uri
- * @media: cached media
- * @transports: a list of #GstRTSPStreamTransport using @connection.
- * @sessions: a list of sessions managed by @connection.
*
* The client structure.
*/
struct _GstRTSPClient {
GObject parent;
- GMutex lock;
- GstRTSPConnection *connection;
- GstRTSPWatch *watch;
- guint close_seq;
- gchar *server_ip;
- gboolean is_ipv6;
- gboolean use_client_settings;
-
- GstRTSPClientSendFunc send_func;
- gpointer send_data;
- GDestroyNotify send_notify;
-
- GstRTSPSessionPool *session_pool;
- GstRTSPMountPoints *mount_points;
- GstRTSPAuth *auth;
-
- GstRTSPUrl *uri;
- GstRTSPMedia *media;
-
- GList *transports;
- GList *sessions;
+ GstRTSPClientPrivate *priv;
};
struct _GstRTSPClientClass {
#include "rtsp-media-factory-uri.h"
+#define GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_URI, GstRTSPMediaFactoryURIPrivate))
+
+struct _GstRTSPMediaFactoryURIPrivate
+{
+ GMutex lock;
+ gchar *uri;
+ gboolean use_gstpay;
+
+ GstCaps *raw_vcaps;
+ GstCaps *raw_acaps;
+ GList *demuxers;
+ GList *payloaders;
+ GList *decoders;
+};
+
#define DEFAULT_URI NULL
#define DEFAULT_USE_GSTPAY FALSE
static void
gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory)
{
+ GstRTSPMediaFactoryURIPrivate *priv =
+ GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE (factory);
FilterData data = { NULL, NULL, NULL };
GST_DEBUG_OBJECT (factory, "new");
- factory->uri = g_strdup (DEFAULT_URI);
- factory->use_gstpay = DEFAULT_USE_GSTPAY;
+ factory->priv = priv;
+
+ priv->uri = g_strdup (DEFAULT_URI);
+ priv->use_gstpay = DEFAULT_USE_GSTPAY;
+ g_mutex_init (&priv->lock);
/* get the feature list using the filter */
gst_registry_feature_filter (gst_registry_get (), (GstPluginFeatureFilter)
payloader_filter, FALSE, &data);
/* sort */
- factory->demuxers =
+ priv->demuxers =
g_list_sort (data.demux, gst_plugin_feature_rank_compare_func);
- factory->payloaders =
+ priv->payloaders =
g_list_sort (data.payload, gst_plugin_feature_rank_compare_func);
- factory->decoders =
+ priv->decoders =
g_list_sort (data.decode, gst_plugin_feature_rank_compare_func);
- factory->raw_vcaps = gst_static_caps_get (&raw_video_caps);
- factory->raw_acaps = gst_static_caps_get (&raw_audio_caps);
+ priv->raw_vcaps = gst_static_caps_get (&raw_video_caps);
+ priv->raw_acaps = gst_static_caps_get (&raw_audio_caps);
}
static void
gst_rtsp_media_factory_uri_finalize (GObject * obj)
{
GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj);
+ GstRTSPMediaFactoryURIPrivate *priv = factory->priv;
GST_DEBUG_OBJECT (factory, "finalize");
- g_free (factory->uri);
- gst_plugin_feature_list_free (factory->demuxers);
- gst_plugin_feature_list_free (factory->payloaders);
- gst_plugin_feature_list_free (factory->decoders);
- gst_caps_unref (factory->raw_vcaps);
- gst_caps_unref (factory->raw_acaps);
+ g_free (priv->uri);
+ gst_plugin_feature_list_free (priv->demuxers);
+ gst_plugin_feature_list_free (priv->payloaders);
+ gst_plugin_feature_list_free (priv->decoders);
+ gst_caps_unref (priv->raw_vcaps);
+ gst_caps_unref (priv->raw_acaps);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_media_factory_uri_parent_class)->finalize (obj);
}
GValue * value, GParamSpec * pspec)
{
GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object);
+ GstRTSPMediaFactoryURIPrivate *priv = factory->priv;
switch (propid) {
case PROP_URI:
g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory));
break;
case PROP_USE_GSTPAY:
- g_value_set_boolean (value, factory->use_gstpay);
+ g_value_set_boolean (value, priv->use_gstpay);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
const GValue * value, GParamSpec * pspec)
{
GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object);
+ GstRTSPMediaFactoryURIPrivate *priv = factory->priv;
switch (propid) {
case PROP_URI:
gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value));
break;
case PROP_USE_GSTPAY:
- factory->use_gstpay = g_value_get_boolean (value);
+ priv->use_gstpay = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI * factory,
const gchar * uri)
{
+ GstRTSPMediaFactoryURIPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory));
g_return_if_fail (uri != NULL);
- GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- g_free (factory->uri);
- factory->uri = g_strdup (uri);
- GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+ priv = factory->priv;
+
+ g_mutex_lock (&priv->lock);
+ g_free (priv->uri);
+ priv->uri = g_strdup (uri);
+ g_mutex_unlock (&priv->lock);
}
/**
gchar *
gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory)
{
+ GstRTSPMediaFactoryURIPrivate *priv;
gchar *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory), NULL);
- GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- result = g_strdup (factory->uri);
- GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+ priv = factory->priv;
+
+ g_mutex_lock (&priv->lock);
+ result = g_strdup (priv->uri);
+ g_mutex_unlock (&priv->lock);
return result;
}
static GstElementFactory *
find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps)
{
+ GstRTSPMediaFactoryURIPrivate *priv = urifact->priv;
GList *list;
GstElementFactory *factory = NULL;
gboolean autoplug_more = FALSE;
/* first find a demuxer that can link */
- list = gst_element_factory_list_filter (urifact->demuxers, caps,
+ list = gst_element_factory_list_filter (priv->demuxers, caps,
GST_PAD_SINK, FALSE);
if (list) {
return NULL;
/* no demuxer try a depayloader */
- list = gst_element_factory_list_filter (urifact->payloaders, caps,
+ list = gst_element_factory_list_filter (priv->payloaders, caps,
GST_PAD_SINK, FALSE);
if (list == NULL) {
- if (urifact->use_gstpay) {
+ if (priv->use_gstpay) {
/* no depayloader or parser/demuxer, use gstpay when allowed */
factory = gst_element_factory_find ("rtpgstpay");
} else {
/* no depayloader, try a decoder, we'll get to a payloader for a decoded
* video or audio format, worst case. */
- list = gst_element_factory_list_filter (urifact->decoders, caps,
+ list = gst_element_factory_list_filter (priv->decoders, caps,
GST_PAD_SINK, FALSE);
if (list != NULL) {
pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element)
{
GstRTSPMediaFactoryURI *urifact;
+ GstRTSPMediaFactoryURIPrivate *priv;
FactoryData *data;
GstElementFactory *factory;
GstElement *payloader;
/* link the element now and expose the pad */
data = g_object_get_data (G_OBJECT (element), factory_key);
urifact = data->factory;
+ priv = urifact->priv;
/* ref to make refcounting easier later */
gst_object_ref (pad);
goto no_caps;
/* check for raw caps */
- if (gst_caps_can_intersect (caps, urifact->raw_vcaps)) {
+ if (gst_caps_can_intersect (caps, priv->raw_vcaps)) {
/* we have raw video caps, insert converter */
convert = gst_element_factory_make ("videoconvert", NULL);
- } else if (gst_caps_can_intersect (caps, urifact->raw_acaps)) {
+ } else if (gst_caps_can_intersect (caps, priv->raw_acaps)) {
/* we have raw audio caps, insert converter */
convert = gst_element_factory_make ("audioconvert", NULL);
} else {
rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory,
const GstRTSPUrl * url)
{
+ GstRTSPMediaFactoryURIPrivate *priv;
GstElement *topbin, *element, *uribin;
GstRTSPMediaFactoryURI *urifact;
FactoryData *data;
urifact = GST_RTSP_MEDIA_FACTORY_URI_CAST (factory);
+ priv = urifact->priv;
GST_LOG ("creating element");
if (uribin == NULL)
goto no_uridecodebin;
- g_object_set (uribin, "uri", urifact->uri, NULL);
+ g_object_set (uribin, "uri", priv->uri, NULL);
/* keep factory data around */
data = g_new0 (FactoryData, 1);
typedef struct _GstRTSPMediaFactoryURI GstRTSPMediaFactoryURI;
typedef struct _GstRTSPMediaFactoryURIClass GstRTSPMediaFactoryURIClass;
+typedef struct _GstRTSPMediaFactoryURIPrivate GstRTSPMediaFactoryURIPrivate;
/**
* GstRTSPMediaFactoryURI:
- * @uri: the uri
*
* A media factory that creates a pipeline to play and uri.
*/
struct _GstRTSPMediaFactoryURI {
GstRTSPMediaFactory parent;
- gchar *uri;
- gboolean use_gstpay;
-
- GstCaps *raw_vcaps;
- GstCaps *raw_acaps;
- GList *demuxers;
- GList *payloaders;
- GList *decoders;
+ GstRTSPMediaFactoryURIPrivate *priv;
};
/**
#include "rtsp-media-factory.h"
+#define GST_RTSP_MEDIA_FACTORY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryPrivate))
+
+#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->priv->lock))
+#define GST_RTSP_MEDIA_FACTORY_LOCK(f) (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
+#define GST_RTSP_MEDIA_FACTORY_UNLOCK(f) (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
+
+struct _GstRTSPMediaFactoryPrivate
+{
+ GMutex lock;
+ gchar *launch;
+ gboolean shared;
+ gboolean eos_shutdown;
+ GstRTSPLowerTrans protocols;
+ GstRTSPAuth *auth;
+ guint buffer_size;
+ GstRTSPAddressPool *pool;
+
+ GMutex medias_lock;
+ GHashTable *medias;
+};
+
#define DEFAULT_LAUNCH NULL
#define DEFAULT_SHARED FALSE
#define DEFAULT_EOS_SHUTDOWN FALSE
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_media_factory_get_property;
static void
gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
{
- factory->launch = g_strdup (DEFAULT_LAUNCH);
- factory->shared = DEFAULT_SHARED;
- factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
- factory->protocols = DEFAULT_PROTOCOLS;
- factory->buffer_size = DEFAULT_BUFFER_SIZE;
-
- g_mutex_init (&factory->lock);
- g_mutex_init (&factory->medias_lock);
- factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
+ GstRTSPMediaFactoryPrivate *priv =
+ GST_RTSP_MEDIA_FACTORY_GET_PRIVATE (factory);
+ factory->priv = priv;
+
+ priv->launch = g_strdup (DEFAULT_LAUNCH);
+ priv->shared = DEFAULT_SHARED;
+ priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
+ priv->protocols = DEFAULT_PROTOCOLS;
+ priv->buffer_size = DEFAULT_BUFFER_SIZE;
+
+ g_mutex_init (&priv->lock);
+ g_mutex_init (&priv->medias_lock);
+ priv->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
}
gst_rtsp_media_factory_finalize (GObject * obj)
{
GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
+ GstRTSPMediaFactoryPrivate *priv = factory->priv;
- g_hash_table_unref (factory->medias);
- g_mutex_clear (&factory->medias_lock);
- g_free (factory->launch);
- g_mutex_clear (&factory->lock);
- if (factory->auth)
- g_object_unref (factory->auth);
- if (factory->pool)
- g_object_unref (factory->pool);
+ g_hash_table_unref (priv->medias);
+ g_mutex_clear (&priv->medias_lock);
+ g_free (priv->launch);
+ g_mutex_clear (&priv->lock);
+ if (priv->auth)
+ g_object_unref (priv->auth);
+ if (priv->pool)
+ g_object_unref (priv->pool);
G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
}
gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
const gchar * launch)
{
+ GstRTSPMediaFactoryPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
g_return_if_fail (launch != NULL);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- g_free (factory->launch);
- factory->launch = g_strdup (launch);
+ g_free (priv->launch);
+ priv->launch = g_strdup (launch);
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
gchar *
gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
{
+ GstRTSPMediaFactoryPrivate *priv;
gchar *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- result = g_strdup (factory->launch);
+ result = g_strdup (priv->launch);
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return result;
gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
gboolean shared)
{
+ GstRTSPMediaFactoryPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- factory->shared = shared;
+ priv->shared = shared;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
gboolean
gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
{
+ GstRTSPMediaFactoryPrivate *priv;
gboolean result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- result = factory->shared;
+ result = priv->shared;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return result;
gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
gboolean eos_shutdown)
{
+ GstRTSPMediaFactoryPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- factory->eos_shutdown = eos_shutdown;
+ priv->eos_shutdown = eos_shutdown;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
gboolean
gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
{
+ GstRTSPMediaFactoryPrivate *priv;
gboolean result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- result = factory->eos_shutdown;
+ result = priv->eos_shutdown;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return result;
gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
guint size)
{
+ GstRTSPMediaFactoryPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- factory->buffer_size = size;
+ priv->buffer_size = size;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
guint
gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
{
+ GstRTSPMediaFactoryPrivate *priv;
guint result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- result = factory->buffer_size;
+ result = priv->buffer_size;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return result;
gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory,
GstRTSPAddressPool * pool)
{
+ GstRTSPMediaFactoryPrivate *priv;
GstRTSPAddressPool *old;
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- if ((old = factory->pool) != pool)
- factory->pool = pool ? g_object_ref (pool) : NULL;
+ if ((old = priv->pool) != pool)
+ priv->pool = pool ? g_object_ref (pool) : NULL;
else
old = NULL;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
GstRTSPAddressPool *
gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory)
{
+ GstRTSPMediaFactoryPrivate *priv;
GstRTSPAddressPool *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- if ((result = factory->pool))
+ if ((result = priv->pool))
g_object_ref (result);
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
GstRTSPAuth * auth)
{
+ GstRTSPMediaFactoryPrivate *priv;
GstRTSPAuth *old;
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- if ((old = factory->auth) != auth)
- factory->auth = auth ? g_object_ref (auth) : NULL;
+ if ((old = priv->auth) != auth)
+ priv->auth = auth ? g_object_ref (auth) : NULL;
else
old = NULL;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
GstRTSPAuth *
gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
{
+ GstRTSPMediaFactoryPrivate *priv;
GstRTSPAuth *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- if ((result = factory->auth))
+ if ((result = priv->auth))
g_object_ref (result);
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory,
GstRTSPLowerTrans protocols)
{
+ GstRTSPMediaFactoryPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- factory->protocols = protocols;
+ priv->protocols = protocols;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
GstRTSPLowerTrans
gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory)
{
+ GstRTSPMediaFactoryPrivate *priv;
GstRTSPLowerTrans res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
GST_RTSP_LOWER_TRANS_UNKNOWN);
+ priv = factory->priv;
+
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- res = factory->protocols;
+ res = priv->protocols;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return res;
static void
media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
{
- g_mutex_lock (&factory->medias_lock);
- g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
- g_mutex_unlock (&factory->medias_lock);
+ GstRTSPMediaFactoryPrivate *priv = factory->priv;;
+
+ g_mutex_lock (&priv->medias_lock);
+ g_hash_table_foreach_remove (priv->medias, (GHRFunc) compare_media, media);
+ g_mutex_unlock (&priv->medias_lock);
}
/**
gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
const GstRTSPUrl * url)
{
+ GstRTSPMediaFactoryPrivate *priv;
gchar *key;
GstRTSPMedia *media;
GstRTSPMediaFactoryClass *klass;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
g_return_val_if_fail (url != NULL, NULL);
+ priv = factory->priv;;
klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
/* convert the url to a key for the hashtable. NULL return or a NULL function
else
key = NULL;
- g_mutex_lock (&factory->medias_lock);
+ g_mutex_lock (&priv->medias_lock);
if (key) {
/* we have a key, see if we find a cached media */
- media = g_hash_table_lookup (factory->medias, key);
+ media = g_hash_table_lookup (priv->medias, key);
if (media)
g_object_ref (media);
} else
if (gst_rtsp_media_is_shared (media)) {
/* insert in the hashtable, takes ownership of the key */
g_object_ref (media);
- g_hash_table_insert (factory->medias, key, media);
+ g_hash_table_insert (priv->medias, key, media);
key = NULL;
}
if (!gst_rtsp_media_is_reusable (media)) {
}
}
}
- g_mutex_unlock (&factory->medias_lock);
+ g_mutex_unlock (&priv->medias_lock);
if (key)
g_free (key);
static GstElement *
default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
{
+ GstRTSPMediaFactoryPrivate *priv = factory->priv;
GstElement *element;
GError *error = NULL;
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
/* we need a parse syntax */
- if (factory->launch == NULL)
+ if (priv->launch == NULL)
goto no_launch;
/* parse the user provided launch line */
- element = gst_parse_launch (factory->launch, &error);
+ element = gst_parse_launch (priv->launch, &error);
if (element == NULL)
goto parse_error;
parse_error:
{
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
- g_critical ("could not parse launch syntax (%s): %s", factory->launch,
+ g_critical ("could not parse launch syntax (%s): %s", priv->launch,
(error ? error->message : "unknown reason"));
if (error)
g_error_free (error);
default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
{
GstRTSPMedia *media;
- GstElement *element;
+ GstElement *element, *pipeline;
GstRTSPMediaFactoryClass *klass;
klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
goto no_element;
/* create a new empty media */
- media = gst_rtsp_media_new ();
- media->element = element;
+ media = gst_rtsp_media_new (element);
gst_rtsp_media_collect_streams (media);
- media->pipeline = klass->create_pipeline (factory, media);
- if (media->pipeline == NULL)
+ pipeline = klass->create_pipeline (factory, media);
+ if (pipeline == NULL)
goto no_pipeline;
return media;
{
GstElement *pipeline;
- if (media->element == NULL)
- goto no_element;
-
pipeline = gst_pipeline_new ("media-pipeline");
- gst_bin_add (GST_BIN_CAST (pipeline), media->element);
+ gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline));
return pipeline;
-
- /* ERRORS */
-no_element:
- {
- g_critical ("no element");
- return NULL;
- }
}
static void
default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
{
+ GstRTSPMediaFactoryPrivate *priv = factory->priv;
gboolean shared, eos_shutdown;
guint size;
GstRTSPAuth *auth;
/* configure the sharedness */
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
- shared = factory->shared;
- eos_shutdown = factory->eos_shutdown;
- size = factory->buffer_size;
- protocols = factory->protocols;
+ shared = priv->shared;
+ eos_shutdown = priv->eos_shutdown;
+ size = priv->buffer_size;
+ protocols = priv->protocols;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
gst_rtsp_media_set_shared (media, shared);
typedef struct _GstRTSPMediaFactory GstRTSPMediaFactory;
typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass;
-
-#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->lock))
-#define GST_RTSP_MEDIA_FACTORY_LOCK(f) (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
-#define GST_RTSP_MEDIA_FACTORY_UNLOCK(f) (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
+typedef struct _GstRTSPMediaFactoryPrivate GstRTSPMediaFactoryPrivate;
/**
* GstRTSPMediaFactory:
* @parent: the parent GObject
- * @lock: mutex protecting the datastructure.
- * @launch: the launch description
- * @shared: if media from this factory can be shared between clients
- * @eos_shutdown: if shutdown should first send EOS to the pipeline
- * @protocols: allowed transport protocols
- * @auth: the authentication manager
- * @buffer_size: the kernel udp buffer size
- * @pool: the multicast address pool to use
- * @medias_lock: mutex protecting the medias.
- * @medias: hashtable of shared media
*
* The definition and logic for constructing the pipeline for a media. The media
* can contain multiple streams like audio and video.
struct _GstRTSPMediaFactory {
GObject parent;
- GMutex lock;
- gchar *launch;
- gboolean shared;
- gboolean eos_shutdown;
- GstRTSPLowerTrans protocols;
- GstRTSPAuth *auth;
- guint buffer_size;
- GstRTSPAddressPool *pool;
-
- GMutex medias_lock;
- GHashTable *medias;
+ GstRTSPMediaFactoryPrivate *priv;
};
/**
#include "rtsp-media.h"
+#define GST_RTSP_MEDIA_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaPrivate))
+
+struct _GstRTSPMediaPrivate
+{
+ GMutex lock;
+ GCond cond;
+
+ gboolean shared;
+ gboolean reusable;
+ GstRTSPLowerTrans protocols;
+ gboolean reused;
+ gboolean eos_shutdown;
+ guint buffer_size;
+ GstRTSPAuth *auth;
+ GstRTSPAddressPool *pool;
+
+ GstElement *element;
+ GRecMutex state_lock;
+ GPtrArray *streams;
+ GList *dynamic;
+ GstRTSPMediaStatus status;
+ gint n_active;
+ gboolean adding;
+
+ /* the pipeline for the media */
+ GstElement *pipeline;
+ GstElement *fakesink;
+ GSource *source;
+ guint id;
+
+ gboolean is_live;
+ gboolean seekable;
+ gboolean buffering;
+ GstState target_state;
+
+ /* RTP session manager */
+ GstElement *rtpbin;
+
+ /* the range of media */
+ GstRTSPTimeRange range;
+ GstClockTime range_start;
+ GstClockTime range_stop;
+};
+
#define DEFAULT_SHARED FALSE
#define DEFAULT_REUSABLE FALSE
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPMediaPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_media_get_property;
static void
gst_rtsp_media_init (GstRTSPMedia * media)
{
- media->streams = g_ptr_array_new_with_free_func (g_object_unref);
- g_mutex_init (&media->lock);
- g_cond_init (&media->cond);
- g_rec_mutex_init (&media->state_lock);
-
- media->shared = DEFAULT_SHARED;
- media->reusable = DEFAULT_REUSABLE;
- media->protocols = DEFAULT_PROTOCOLS;
- media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
- media->buffer_size = DEFAULT_BUFFER_SIZE;
+ GstRTSPMediaPrivate *priv = GST_RTSP_MEDIA_GET_PRIVATE (media);
+
+ media->priv = priv;
+
+ priv->streams = g_ptr_array_new_with_free_func (g_object_unref);
+ g_mutex_init (&priv->lock);
+ g_cond_init (&priv->cond);
+ g_rec_mutex_init (&priv->state_lock);
+
+ priv->shared = DEFAULT_SHARED;
+ priv->reusable = DEFAULT_REUSABLE;
+ priv->protocols = DEFAULT_PROTOCOLS;
+ priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
+ priv->buffer_size = DEFAULT_BUFFER_SIZE;
}
static void
gst_rtsp_media_finalize (GObject * obj)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPMedia *media;
media = GST_RTSP_MEDIA (obj);
+ priv = media->priv;
GST_INFO ("finalize media %p", media);
gst_rtsp_media_unprepare (media);
- g_ptr_array_unref (media->streams);
+ g_ptr_array_unref (priv->streams);
- g_list_free_full (media->dynamic, gst_object_unref);
+ g_list_free_full (priv->dynamic, gst_object_unref);
- if (media->pipeline)
- gst_object_unref (media->pipeline);
- if (media->auth)
- g_object_unref (media->auth);
- if (media->pool)
- g_object_unref (media->pool);
- g_mutex_clear (&media->lock);
- g_cond_clear (&media->cond);
- g_rec_mutex_clear (&media->state_lock);
+ if (priv->pipeline)
+ gst_object_unref (priv->pipeline);
+ if (priv->auth)
+ g_object_unref (priv->auth);
+ if (priv->pool)
+ g_object_unref (priv->pool);
+ g_mutex_clear (&priv->lock);
+ g_cond_clear (&priv->cond);
+ g_rec_mutex_clear (&priv->state_lock);
G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
}
static void
collect_media_stats (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv = media->priv;
gint64 position, duration;
- media->range.unit = GST_RTSP_RANGE_NPT;
+ priv->range.unit = GST_RTSP_RANGE_NPT;
GST_INFO ("collect media stats");
- if (media->is_live) {
- media->range.min.type = GST_RTSP_TIME_NOW;
- media->range.min.seconds = -1;
- media->range_start = -1;
- media->range.max.type = GST_RTSP_TIME_END;
- media->range.max.seconds = -1;
- media->range_stop = -1;
+ if (priv->is_live) {
+ priv->range.min.type = GST_RTSP_TIME_NOW;
+ priv->range.min.seconds = -1;
+ priv->range_start = -1;
+ priv->range.max.type = GST_RTSP_TIME_END;
+ priv->range.max.seconds = -1;
+ priv->range_stop = -1;
} else {
/* get the position */
- if (!gst_element_query_position (media->pipeline, GST_FORMAT_TIME,
+ if (!gst_element_query_position (priv->pipeline, GST_FORMAT_TIME,
&position)) {
GST_INFO ("position query failed");
position = 0;
}
/* get the duration */
- if (!gst_element_query_duration (media->pipeline, GST_FORMAT_TIME,
+ if (!gst_element_query_duration (priv->pipeline, GST_FORMAT_TIME,
&duration)) {
GST_INFO ("duration query failed");
duration = -1;
GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
if (position == -1) {
- media->range.min.type = GST_RTSP_TIME_NOW;
- media->range.min.seconds = -1;
- media->range_start = -1;
+ priv->range.min.type = GST_RTSP_TIME_NOW;
+ priv->range.min.seconds = -1;
+ priv->range_start = -1;
} else {
- media->range.min.type = GST_RTSP_TIME_SECONDS;
- media->range.min.seconds = ((gdouble) position) / GST_SECOND;
- media->range_start = position;
+ priv->range.min.type = GST_RTSP_TIME_SECONDS;
+ priv->range.min.seconds = ((gdouble) position) / GST_SECOND;
+ priv->range_start = position;
}
if (duration == -1) {
- media->range.max.type = GST_RTSP_TIME_END;
- media->range.max.seconds = -1;
- media->range_stop = -1;
+ priv->range.max.type = GST_RTSP_TIME_END;
+ priv->range.max.seconds = -1;
+ priv->range_stop = -1;
} else {
- media->range.max.type = GST_RTSP_TIME_SECONDS;
- media->range.max.seconds = ((gdouble) duration) / GST_SECOND;
- media->range_stop = duration;
+ priv->range.max.type = GST_RTSP_TIME_SECONDS;
+ priv->range.max.seconds = ((gdouble) duration) / GST_SECOND;
+ priv->range_stop = duration;
}
}
}
/**
* gst_rtsp_media_new:
+ * @element: (transfer full): a #GstElement
*
- * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
+ * Create a new #GstRTSPMedia instance. @element is the bin element that
+ * provides the different streams. The #GstRTSPMedia object contains the
* element to produce RTP data for one or more related (audio/video/..)
* streams.
*
+ * Ownership is taken of @element.
+ *
* Returns: a new #GstRTSPMedia object.
*/
GstRTSPMedia *
-gst_rtsp_media_new (void)
+gst_rtsp_media_new (GstElement * element)
{
GstRTSPMedia *result;
result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
+ result->priv->element = element;
return result;
}
/**
+ * gst_rtsp_media_take_element:
+ * @media: a #GstRTSPMedia
+ * @pipeline: (transfer full): a #GstPipeline
+ *
+ * Set @pipeline as the #GstPipeline for @media. Ownership is
+ * taken of @pipeline.
+ */
+void
+gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline)
+{
+ GstRTSPMediaPrivate *priv;
+ GstElement *old;
+
+ g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+ g_return_if_fail (GST_IS_PIPELINE (pipeline));
+
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ old = priv->pipeline;
+ priv->pipeline = GST_ELEMENT_CAST (pipeline);
+ g_mutex_unlock (&priv->lock);
+
+ if (old)
+ gst_object_unref (old);
+
+ gst_bin_add (GST_BIN_CAST (pipeline), priv->element);
+}
+
+/**
* gst_rtsp_media_set_shared:
* @media: a #GstRTSPMedia
* @shared: the new value
void
gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
{
+ GstRTSPMediaPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
- g_mutex_lock (&media->lock);
- media->shared = shared;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->shared = shared;
+ g_mutex_unlock (&priv->lock);
}
/**
gboolean
gst_rtsp_media_is_shared (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
gboolean res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
- g_mutex_lock (&media->lock);
- res = media->shared;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->shared;
+ g_mutex_unlock (&priv->lock);
return res;
}
void
gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
{
+ GstRTSPMediaPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
- g_mutex_lock (&media->lock);
- media->reusable = reusable;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->reusable = reusable;
+ g_mutex_unlock (&priv->lock);
}
/**
gboolean
gst_rtsp_media_is_reusable (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
gboolean res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
- g_mutex_lock (&media->lock);
- res = media->reusable;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->reusable;
+ g_mutex_unlock (&priv->lock);
return res;
}
void
gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
{
+ GstRTSPMediaPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
- g_mutex_lock (&media->lock);
- media->protocols = protocols;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->protocols = protocols;
+ g_mutex_unlock (&priv->lock);
}
/**
GstRTSPLowerTrans
gst_rtsp_media_get_protocols (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPLowerTrans res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
GST_RTSP_LOWER_TRANS_UNKNOWN);
- g_mutex_lock (&media->lock);
- res = media->protocols;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->protocols;
+ g_mutex_unlock (&priv->lock);
return res;
}
void
gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
{
+ GstRTSPMediaPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
- g_mutex_lock (&media->lock);
- media->eos_shutdown = eos_shutdown;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->eos_shutdown = eos_shutdown;
+ g_mutex_unlock (&priv->lock);
}
/**
gboolean
gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
gboolean res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
- g_mutex_lock (&media->lock);
- res = media->eos_shutdown;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->eos_shutdown;
+ g_mutex_unlock (&priv->lock);
return res;
}
void
gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
{
+ GstRTSPMediaPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
GST_LOG_OBJECT (media, "set buffer size %u", size);
- g_mutex_lock (&media->lock);
- media->buffer_size = size;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->buffer_size = size;
+ g_mutex_unlock (&priv->lock);
}
/**
guint
gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
guint res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
- g_mutex_unlock (&media->lock);
- res = media->buffer_size;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_unlock (&priv->lock);
+ res = priv->buffer_size;
+ g_mutex_unlock (&priv->lock);
return res;
}
void
gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPAuth *old;
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+ priv = media->priv;
+
GST_LOG_OBJECT (media, "set auth %p", auth);
- g_mutex_lock (&media->lock);
- if ((old = media->auth) != auth)
- media->auth = auth ? g_object_ref (auth) : NULL;
+ g_mutex_lock (&priv->lock);
+ if ((old = priv->auth) != auth)
+ priv->auth = auth ? g_object_ref (auth) : NULL;
else
old = NULL;
- g_mutex_unlock (&media->lock);
+ g_mutex_unlock (&priv->lock);
if (old)
g_object_unref (old);
GstRTSPAuth *
gst_rtsp_media_get_auth (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPAuth *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
- g_mutex_lock (&media->lock);
- if ((result = media->auth))
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ if ((result = priv->auth))
g_object_ref (result);
- g_mutex_unlock (&media->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
gst_rtsp_media_set_address_pool (GstRTSPMedia * media,
GstRTSPAddressPool * pool)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPAddressPool *old;
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+ priv = media->priv;
+
GST_LOG_OBJECT (media, "set address pool %p", pool);
- g_mutex_lock (&media->lock);
- if ((old = media->pool) != pool)
- media->pool = pool ? g_object_ref (pool) : NULL;
+ g_mutex_lock (&priv->lock);
+ if ((old = priv->pool) != pool)
+ priv->pool = pool ? g_object_ref (pool) : NULL;
else
old = NULL;
- g_ptr_array_foreach (media->streams, (GFunc) gst_rtsp_stream_set_address_pool,
+ g_ptr_array_foreach (priv->streams, (GFunc) gst_rtsp_stream_set_address_pool,
pool);
- g_mutex_unlock (&media->lock);
+ g_mutex_unlock (&priv->lock);
if (old)
g_object_unref (old);
GstRTSPAddressPool *
gst_rtsp_media_get_address_pool (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPAddressPool *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
- g_mutex_lock (&media->lock);
- if ((result = media->pool))
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ if ((result = priv->pool))
g_object_ref (result);
- g_mutex_unlock (&media->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
void
gst_rtsp_media_collect_streams (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
GstElement *element, *elem;
GstPad *pad;
gint i;
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
- element = media->element;
+ priv = media->priv;
+ element = priv->element;
have_elem = TRUE;
for (i = 0; have_elem; i++) {
GST_INFO ("found dynamic element %d, %p", i, elem);
- g_mutex_lock (&media->lock);
- media->dynamic = g_list_prepend (media->dynamic, elem);
- g_mutex_unlock (&media->lock);
+ g_mutex_lock (&priv->lock);
+ priv->dynamic = g_list_prepend (priv->dynamic, elem);
+ g_mutex_unlock (&priv->lock);
have_elem = TRUE;
}
gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
GstPad * pad)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPStream *stream;
GstPad *srcpad;
gchar *name;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
- g_mutex_lock (&media->lock);
- idx = media->streams->len;
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ idx = priv->streams->len;
+
+ GST_DEBUG ("media %p: creating stream with index %d", media, idx);
name = g_strdup_printf ("src_%u", idx);
srcpad = gst_ghost_pad_new (name, pad);
gst_pad_set_active (srcpad, TRUE);
- gst_element_add_pad (media->element, srcpad);
+ gst_element_add_pad (priv->element, srcpad);
g_free (name);
stream = gst_rtsp_stream_new (idx, payloader, srcpad);
- if (media->pool)
- gst_rtsp_stream_set_address_pool (stream, media->pool);
+ if (priv->pool)
+ gst_rtsp_stream_set_address_pool (stream, priv->pool);
- g_ptr_array_add (media->streams, stream);
- g_mutex_unlock (&media->lock);
+ g_ptr_array_add (priv->streams, stream);
+ g_mutex_unlock (&priv->lock);
g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream,
NULL);
guint
gst_rtsp_media_n_streams (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
guint res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
- g_mutex_lock (&media->lock);
- res = media->streams->len;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->streams->len;
+ g_mutex_unlock (&priv->lock);
return res;
}
GstRTSPStream *
gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
{
+ GstRTSPMediaPrivate *priv;
GstRTSPStream *res;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
- g_mutex_lock (&media->lock);
- if (idx < media->streams->len)
- res = g_ptr_array_index (media->streams, idx);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (idx < priv->streams->len)
+ res = g_ptr_array_index (priv->streams, idx);
else
res = NULL;
- g_mutex_unlock (&media->lock);
+ g_mutex_unlock (&priv->lock);
return res;
}
gchar *
gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
{
+ GstRTSPMediaPrivate *priv;
gchar *result;
GstRTSPTimeRange range;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
- g_rec_mutex_lock (&media->state_lock);
- if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED)
+ priv = media->priv;
+
+ g_rec_mutex_lock (&priv->state_lock);
+ if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
goto not_prepared;
- g_mutex_lock (&media->lock);
+ g_mutex_lock (&priv->lock);
/* make copy */
- range = media->range;
+ range = priv->range;
- if (!play && media->n_active > 0) {
+ if (!play && priv->n_active > 0) {
range.min.type = GST_RTSP_TIME_NOW;
range.min.seconds = -1;
}
- g_mutex_unlock (&media->lock);
- g_rec_mutex_unlock (&media->state_lock);
+ g_mutex_unlock (&priv->lock);
+ g_rec_mutex_unlock (&priv->state_lock);
result = gst_rtsp_range_to_string (&range);
not_prepared:
{
GST_WARNING ("media %p was not prepared", media);
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return NULL;
}
}
gboolean
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
{
+ GstRTSPMediaPrivate *priv;
GstSeekFlags flags;
gboolean res;
GstClockTime start, stop;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
g_return_val_if_fail (range != NULL, FALSE);
- g_rec_mutex_lock (&media->state_lock);
- if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED)
+ priv = media->priv;
+
+ g_rec_mutex_lock (&priv->state_lock);
+ if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
goto not_prepared;
- if (!media->seekable)
+ if (!priv->seekable)
goto not_seekable;
/* depends on the current playing state of the pipeline. We might need to
GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
- GST_TIME_ARGS (media->range_start), GST_TIME_ARGS (media->range_stop));
+ GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
- if (media->range_start == start)
+ if (priv->range_start == start)
start = GST_CLOCK_TIME_NONE;
else if (start != GST_CLOCK_TIME_NONE)
start_type = GST_SEEK_TYPE_SET;
- if (media->range_stop == stop)
+ if (priv->range_stop == stop)
stop = GST_CLOCK_TIME_NONE;
else if (stop != GST_CLOCK_TIME_NONE)
stop_type = GST_SEEK_TYPE_SET;
GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
- res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME,
+ res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
flags, start_type, start, stop_type, stop);
/* and block for the seek to complete */
GST_INFO ("done seeking %d", res);
- gst_element_get_state (media->pipeline, NULL, NULL, -1);
+ gst_element_get_state (priv->pipeline, NULL, NULL, -1);
GST_INFO ("prerolled again");
collect_media_stats (media);
GST_INFO ("no seek needed");
res = TRUE;
}
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return res;
/* ERRORS */
not_prepared:
{
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
GST_INFO ("media %p is not prepared", media);
return FALSE;
}
not_seekable:
{
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
GST_INFO ("pipeline is not seekable");
return TRUE;
}
not_supported:
{
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
GST_WARNING ("seek unit %d not supported", range->unit);
return FALSE;
}
static void
gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
{
- g_mutex_lock (&media->lock);
+ GstRTSPMediaPrivate *priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
/* never overwrite the error status */
- if (media->status != GST_RTSP_MEDIA_STATUS_ERROR)
- media->status = status;
+ if (priv->status != GST_RTSP_MEDIA_STATUS_ERROR)
+ priv->status = status;
GST_DEBUG ("setting new status to %d", status);
- g_cond_broadcast (&media->cond);
- g_mutex_unlock (&media->lock);
+ g_cond_broadcast (&priv->cond);
+ g_mutex_unlock (&priv->lock);
}
-static GstRTSPMediaStatus
+/**
+ * gst_rtsp_media_get_status:
+ * @media: a #GstRTSPMedia
+ *
+ * Get the status of @media. When @media is busy preparing, this function waits
+ * until @media is prepared or in error.
+ *
+ * Returns: the status of @media.
+ */
+GstRTSPMediaStatus
gst_rtsp_media_get_status (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv = media->priv;
GstRTSPMediaStatus result;
gint64 end_time;
- g_mutex_lock (&media->lock);
+ g_mutex_lock (&priv->lock);
end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
/* while we are preparing, wait */
- while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
+ while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
GST_DEBUG ("waiting for status change");
- if (!g_cond_wait_until (&media->cond, &media->lock, end_time)) {
+ if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) {
GST_DEBUG ("timeout, assuming error status");
- media->status = GST_RTSP_MEDIA_STATUS_ERROR;
+ priv->status = GST_RTSP_MEDIA_STATUS_ERROR;
}
}
/* could be success or error */
- result = media->status;
+ result = priv->status;
GST_DEBUG ("got status %d", result);
- g_mutex_unlock (&media->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
static gboolean
default_handle_message (GstRTSPMedia * media, GstMessage * message)
{
+ GstRTSPMediaPrivate *priv = media->priv;
GstMessageType type;
type = GST_MESSAGE_TYPE (message);
gst_message_parse_buffering (message, &percent);
/* no state management needed for live pipelines */
- if (media->is_live)
+ if (priv->is_live)
break;
if (percent == 100) {
/* a 100% message means buffering is done */
- media->buffering = FALSE;
+ priv->buffering = FALSE;
/* if the desired state is playing, go back */
- if (media->target_state == GST_STATE_PLAYING) {
+ if (priv->target_state == GST_STATE_PLAYING) {
GST_INFO ("Buffering done, setting pipeline to PLAYING");
- gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
} else {
GST_INFO ("Buffering done");
}
} else {
/* buffering busy */
- if (media->buffering == FALSE) {
- if (media->target_state == GST_STATE_PLAYING) {
+ if (priv->buffering == FALSE) {
+ if (priv->target_state == GST_STATE_PLAYING) {
/* we were not buffering but PLAYING, PAUSE the pipeline. */
GST_INFO ("Buffering, setting pipeline to PAUSED ...");
- gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
+ gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
} else {
GST_INFO ("Buffering ...");
}
}
- media->buffering = TRUE;
+ priv->buffering = TRUE;
}
break;
}
case GST_MESSAGE_LATENCY:
{
- gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline));
+ gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline));
break;
}
case GST_MESSAGE_ERROR:
case GST_MESSAGE_STREAM_STATUS:
break;
case GST_MESSAGE_ASYNC_DONE:
- if (!media->adding) {
+ if (!priv->adding) {
/* when we are dynamically adding pads, the addition of the udpsrc will
* temporarily produce ASYNC_DONE messages. We have to ignore them and
* wait for the final ASYNC_DONE after everything prerolled */
case GST_MESSAGE_EOS:
GST_INFO ("%p: got EOS", media);
- if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
+ if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
GST_DEBUG ("shutting down after EOS");
finish_unprepare (media);
g_object_unref (media);
static gboolean
bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv = media->priv;
GstRTSPMediaClass *klass;
gboolean ret;
klass = GST_RTSP_MEDIA_GET_CLASS (media);
- g_rec_mutex_lock (&media->state_lock);
+ g_rec_mutex_lock (&priv->state_lock);
if (klass->handle_message)
ret = klass->handle_message (media, message);
else
ret = FALSE;
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return ret;
}
static void
pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv = media->priv;
GstRTSPStream *stream;
/* FIXME, element is likely not a payloader, find the payloader here */
stream = gst_rtsp_media_create_stream (media, element, pad);
- GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad),
- stream->idx);
+ GST_INFO ("pad added %s:%s, stream %s", GST_DEBUG_PAD_NAME (pad), stream);
- g_rec_mutex_lock (&media->state_lock);
+ g_rec_mutex_lock (&priv->state_lock);
/* we will be adding elements below that will cause ASYNC_DONE to be
* posted in the bus. We want to ignore those messages until the
* pipeline really prerolled. */
- media->adding = TRUE;
+ priv->adding = TRUE;
/* join the element in the PAUSED state because this callback is
* called from the streaming thread and it is PAUSED */
- gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline),
- media->rtpbin, GST_STATE_PAUSED);
+ gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
+ priv->rtpbin, GST_STATE_PAUSED);
- media->adding = FALSE;
- g_rec_mutex_unlock (&media->state_lock);
+ priv->adding = FALSE;
+ g_rec_mutex_unlock (&priv->state_lock);
}
static void
no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv = media->priv;
GstElement *fakesink;
- g_mutex_lock (&media->lock);
+ g_mutex_lock (&priv->lock);
GST_INFO ("no more pads");
- if ((fakesink = media->fakesink)) {
+ if ((fakesink = priv->fakesink)) {
gst_object_ref (fakesink);
- media->fakesink = NULL;
- g_mutex_unlock (&media->lock);
+ priv->fakesink = NULL;
+ g_mutex_unlock (&priv->lock);
- gst_bin_remove (GST_BIN (media->pipeline), fakesink);
+ gst_bin_remove (GST_BIN (priv->pipeline), fakesink);
gst_element_set_state (fakesink, GST_STATE_NULL);
gst_object_unref (fakesink);
GST_INFO ("removed fakesink");
gboolean
gst_rtsp_media_prepare (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
GstStateChangeReturn ret;
GstRTSPMediaStatus status;
guint i;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
- g_rec_mutex_lock (&media->state_lock);
- if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
+ priv = media->priv;
+
+ g_rec_mutex_lock (&priv->state_lock);
+ if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
goto was_prepared;
- if (media->status == GST_RTSP_MEDIA_STATUS_PREPARING)
+ if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
goto wait_status;
- if (media->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
+ if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
goto not_unprepared;
- if (!media->reusable && media->reused)
+ if (!priv->reusable && priv->reused)
goto is_reused;
- media->rtpbin = gst_element_factory_make ("rtpbin", NULL);
- if (media->rtpbin == NULL)
+ priv->rtpbin = gst_element_factory_make ("rtpbin", NULL);
+ if (priv->rtpbin == NULL)
goto no_rtpbin;
GST_INFO ("preparing media %p", media);
/* reset some variables */
- media->is_live = FALSE;
- media->seekable = FALSE;
- media->buffering = FALSE;
+ priv->is_live = FALSE;
+ priv->seekable = FALSE;
+ priv->buffering = FALSE;
/* we're preparing now */
- media->status = GST_RTSP_MEDIA_STATUS_PREPARING;
+ priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
- bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
+ bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
/* add the pipeline bus to our custom mainloop */
- media->source = gst_bus_create_watch (bus);
+ priv->source = gst_bus_create_watch (bus);
gst_object_unref (bus);
- g_source_set_callback (media->source, (GSourceFunc) bus_message,
+ g_source_set_callback (priv->source, (GSourceFunc) bus_message,
gst_object_ref (media), (GDestroyNotify) watch_destroyed);
klass = GST_RTSP_MEDIA_GET_CLASS (media);
- media->id = g_source_attach (media->source, klass->context);
+ priv->id = g_source_attach (priv->source, klass->context);
/* add stuff to the bin */
- gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
+ gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
/* link streams we already have, other streams might appear when we have
* dynamic elements */
- for (i = 0; i < media->streams->len; i++) {
+ for (i = 0; i < priv->streams->len; i++) {
GstRTSPStream *stream;
- stream = g_ptr_array_index (media->streams, i);
+ stream = g_ptr_array_index (priv->streams, i);
- gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline),
- media->rtpbin, GST_STATE_NULL);
+ gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
+ priv->rtpbin, GST_STATE_NULL);
}
- for (walk = media->dynamic; walk; walk = g_list_next (walk)) {
+ for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
GstElement *elem = walk->data;
GST_INFO ("adding callbacks for dynamic element %p", elem);
/* we add a fakesink here in order to make the state change async. We remove
* the fakesink again in the no-more-pads callback. */
- media->fakesink = gst_element_factory_make ("fakesink", "fakesink");
- gst_bin_add (GST_BIN (media->pipeline), media->fakesink);
+ priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
+ gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
}
GST_INFO ("setting pipeline to PAUSED for media %p", media);
/* first go to PAUSED */
- ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
- media->target_state = GST_STATE_PAUSED;
+ ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+ priv->target_state = GST_STATE_PAUSED;
switch (ret) {
case GST_STATE_CHANGE_SUCCESS:
GST_INFO ("SUCCESS state change for media %p", media);
- media->seekable = TRUE;
+ priv->seekable = TRUE;
break;
case GST_STATE_CHANGE_ASYNC:
GST_INFO ("ASYNC state change for media %p", media);
- media->seekable = TRUE;
+ priv->seekable = TRUE;
break;
case GST_STATE_CHANGE_NO_PREROLL:
/* we need to go to PLAYING */
GST_INFO ("NO_PREROLL state change: live media %p", media);
/* FIXME we disable seeking for live streams for now. We should perform a
* seeking query in preroll instead */
- media->seekable = FALSE;
- media->is_live = TRUE;
- ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
+ priv->seekable = FALSE;
+ priv->is_live = TRUE;
+ ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE)
goto state_failed;
break;
goto state_failed;
}
wait_status:
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
/* now wait for all pads to be prerolled, FIXME, we should somehow be
* able to do this async so that we don't block the server thread. */
was_prepared:
{
GST_LOG ("media %p was prepared", media);
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return TRUE;
}
/* ERRORS */
not_unprepared:
{
GST_WARNING ("media %p was not unprepared", media);
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return FALSE;
}
is_reused:
{
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
GST_WARNING ("can not reuse media %p", media);
return FALSE;
}
no_rtpbin:
{
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
GST_WARNING ("no rtpbin element");
g_warning ("failed to create element 'rtpbin', check your installation");
return FALSE;
{
GST_WARNING ("failed to preroll pipeline");
gst_rtsp_media_unprepare (media);
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return FALSE;
}
}
static void
finish_unprepare (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv = media->priv;
gint i;
GST_DEBUG ("shutting down");
- gst_element_set_state (media->pipeline, GST_STATE_NULL);
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
- for (i = 0; i < media->streams->len; i++) {
+ for (i = 0; i < priv->streams->len; i++) {
GstRTSPStream *stream;
GST_INFO ("Removing elements of stream %d from pipeline", i);
- stream = g_ptr_array_index (media->streams, i);
+ stream = g_ptr_array_index (priv->streams, i);
- gst_rtsp_stream_leave_bin (stream, GST_BIN (media->pipeline),
- media->rtpbin);
+ gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
}
- g_ptr_array_set_size (media->streams, 0);
+ g_ptr_array_set_size (priv->streams, 0);
- gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin);
- media->rtpbin = NULL;
+ gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
+ priv->rtpbin = NULL;
- gst_object_unref (media->pipeline);
- media->pipeline = NULL;
+ gst_object_unref (priv->pipeline);
+ priv->pipeline = NULL;
- media->reused = TRUE;
- media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
+ priv->reused = TRUE;
+ priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
- if (media->source) {
- g_source_destroy (media->source);
- g_source_unref (media->source);
- media->source = NULL;
+ if (priv->source) {
+ g_source_destroy (priv->source);
+ g_source_unref (priv->source);
+ priv->source = NULL;
}
/* when the media is not reusable, this will effectively unref the media and
static gboolean
default_unprepare (GstRTSPMedia * media)
{
- if (media->eos_shutdown) {
+ GstRTSPMediaPrivate *priv = media->priv;
+
+ if (priv->eos_shutdown) {
GST_DEBUG ("sending EOS for shutdown");
/* ref so that we don't disappear */
g_object_ref (media);
- gst_element_send_event (media->pipeline, gst_event_new_eos ());
+ gst_element_send_event (priv->pipeline, gst_event_new_eos ());
/* we need to go to playing again for the EOS to propagate, normally in this
* state, nothing is receiving data from us anymore so this is ok. */
- gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
- media->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+ priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
} else {
finish_unprepare (media);
}
gboolean
gst_rtsp_media_unprepare (GstRTSPMedia * media)
{
+ GstRTSPMediaPrivate *priv;
gboolean success;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
- g_rec_mutex_lock (&media->state_lock);
- if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
+ priv = media->priv;
+
+ g_rec_mutex_lock (&priv->state_lock);
+ if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
goto was_unprepared;
GST_INFO ("unprepare media %p", media);
- media->target_state = GST_STATE_NULL;
+ priv->target_state = GST_STATE_NULL;
success = TRUE;
- if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
+ if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
GstRTSPMediaClass *klass;
klass = GST_RTSP_MEDIA_GET_CLASS (media);
} else {
finish_unprepare (media);
}
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return success;
was_unprepared:
{
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
GST_INFO ("media %p was already unprepared", media);
return TRUE;
}
gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
GPtrArray * transports)
{
+ GstRTSPMediaPrivate *priv;
gint i;
- gboolean add, remove, do_state;
+ gboolean activate, deactivate, do_state;
gint old_active;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
g_return_val_if_fail (transports != NULL, FALSE);
- g_rec_mutex_lock (&media->state_lock);
- if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED)
+ priv = media->priv;
+
+ g_rec_mutex_lock (&priv->state_lock);
+ if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
goto not_prepared;
/* NULL and READY are the same */
if (state == GST_STATE_READY)
state = GST_STATE_NULL;
- add = remove = FALSE;
+ activate = deactivate = FALSE;
GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
media);
switch (state) {
case GST_STATE_NULL:
case GST_STATE_PAUSED:
- /* we're going from PLAYING to PAUSED, READY or NULL, remove */
- if (media->target_state == GST_STATE_PLAYING)
- remove = TRUE;
+ /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
+ if (priv->target_state == GST_STATE_PLAYING)
+ deactivate = TRUE;
break;
case GST_STATE_PLAYING:
- /* we're going to PLAYING, add */
- add = TRUE;
+ /* we're going to PLAYING, activate */
+ activate = TRUE;
break;
default:
break;
}
- old_active = media->n_active;
+ old_active = priv->n_active;
for (i = 0; i < transports->len; i++) {
GstRTSPStreamTransport *trans;
if (trans == NULL)
continue;
- /* we need a transport */
- if (!trans->transport)
- continue;
-
- if (add) {
- if (gst_rtsp_stream_add_transport (trans->stream, trans))
- media->n_active++;
- } else if (remove) {
- if (gst_rtsp_stream_remove_transport (trans->stream, trans))
- media->n_active--;
+ if (activate) {
+ if (gst_rtsp_stream_transport_set_active (trans, TRUE))
+ priv->n_active++;
+ } else if (deactivate) {
+ if (gst_rtsp_stream_transport_set_active (trans, FALSE))
+ priv->n_active--;
}
}
- /* we just added the first media, do the playing state change */
- if (old_active == 0 && add)
+ /* we just activated the first media, do the playing state change */
+ if (old_active == 0 && activate)
do_state = TRUE;
/* if we have no more active media, do the downward state changes */
- else if (media->n_active == 0)
+ else if (priv->n_active == 0)
do_state = TRUE;
else
do_state = FALSE;
- GST_INFO ("state %d active %d media %p do_state %d", state, media->n_active,
+ GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
media, do_state);
- if (media->target_state != state) {
+ if (priv->target_state != state) {
if (do_state) {
if (state == GST_STATE_NULL) {
gst_rtsp_media_unprepare (media);
} else {
GST_INFO ("state %s media %p", gst_element_state_get_name (state),
media);
- media->target_state = state;
- gst_element_set_state (media->pipeline, state);
+ priv->target_state = state;
+ gst_element_set_state (priv->pipeline, state);
}
}
g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
/* remember where we are */
if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
- old_active != media->n_active))
+ old_active != priv->n_active))
collect_media_stats (media);
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return TRUE;
not_prepared:
{
GST_WARNING ("media %p was not prepared", media);
- g_rec_mutex_unlock (&media->state_lock);
+ g_rec_mutex_unlock (&priv->state_lock);
return FALSE;
}
}
typedef struct _GstRTSPMedia GstRTSPMedia;
typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
+typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate;
#include "rtsp-stream.h"
#include "rtsp-auth.h"
/**
* GstRTSPMedia:
- * @parent: parent GObject
- * @lock: for protecting the object
- * @cond: for signaling the object
- * @shared: if this media can be shared between clients
- * @reusable: if this media can be reused after an unprepare
- * @protocols: the allowed lower transport for this stream
- * @reused: if this media has been reused
- * @is_ipv6: if this media is using ipv6
- * @eos_shutdown: if EOS should be sent on shutdown
- * @buffer_size: The UDP buffer size
- * @auth: the authentication service in use
- * @multicast_group: the multicast group to use
- * @element: the data providing element, owned by @pipeline
- * @streams: the different #GstRTSPStream provided by @element
- * @dynamic: list of dynamic elements managed by @element
- * @status: the status of the media pipeline
- * @n_active: the number of active connections
- * @adding: when elements are added to the pipeline
- * @pipeline: the toplevel pipeline
- * @fakesink: for making state changes async
- * @source: the bus watch for pipeline messages.
- * @id: the id of the watch
- * @is_live: if the pipeline is live
- * @seekable: if the pipeline can perform a seek
- * @buffering: if the pipeline is buffering
- * @target_state: the desired target state of the pipeline
- * @rtpbin: the rtpbin
- * @range: the range of the media being streamed
- * @range_start: range start in #GstClockTime
- * @range_stop: range stop in #GstClockTime
*
* A class that contains the GStreamer element along with a list of
* #GstRTSPStream objects that can produce data.
struct _GstRTSPMedia {
GObject parent;
- GMutex lock;
- GCond cond;
-
- gboolean shared;
- gboolean reusable;
- GstRTSPLowerTrans protocols;
- gboolean reused;
- gboolean is_ipv6;
- gboolean eos_shutdown;
- guint buffer_size;
- GstRTSPAuth *auth;
- GstRTSPAddressPool*pool;
-
- GstElement *element;
- GRecMutex state_lock;
- GPtrArray *streams;
- GList *dynamic;
- GstRTSPMediaStatus status;
- gint n_active;
- gboolean adding;
-
- /* the pipeline for the media */
- GstElement *pipeline;
- GstElement *fakesink;
- GSource *source;
- guint id;
-
- gboolean is_live;
- gboolean seekable;
- gboolean buffering;
- GstState target_state;
-
- /* RTP session manager */
- GstElement *rtpbin;
-
- /* the range of media */
- GstRTSPTimeRange range;
- GstClockTime range_start;
- GstClockTime range_stop;
+ GstRTSPMediaPrivate *priv;
};
/**
GType gst_rtsp_media_get_type (void);
/* creating the media */
-GstRTSPMedia * gst_rtsp_media_new (void);
+GstRTSPMedia * gst_rtsp_media_new (GstElement *element);
+
+void gst_rtsp_media_take_pipeline (GstRTSPMedia *media, GstPipeline *pipeline);
+
+GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia *media);
void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared);
gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media);
#include "rtsp-mount-points.h"
+#define GST_RTSP_MOUNT_POINTS_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPointsPrivate))
+
+struct _GstRTSPMountPointsPrivate
+{
+ GMutex lock;
+ GHashTable *mounts;
+};
+
G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT);
GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPMountPointsPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gst_rtsp_mount_points_finalize;
static void
gst_rtsp_mount_points_init (GstRTSPMountPoints * mounts)
{
+ GstRTSPMountPointsPrivate *priv = GST_RTSP_MOUNT_POINTS_GET_PRIVATE (mounts);
+
GST_DEBUG_OBJECT (mounts, "created");
- g_mutex_init (&mounts->lock);
- mounts->mounts = g_hash_table_new_full (g_str_hash, g_str_equal,
+ mounts->priv = priv;
+
+ g_mutex_init (&priv->lock);
+ priv->mounts = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
}
gst_rtsp_mount_points_finalize (GObject * obj)
{
GstRTSPMountPoints *mounts = GST_RTSP_MOUNT_POINTS (obj);
+ GstRTSPMountPointsPrivate *priv = mounts->priv;
GST_DEBUG_OBJECT (mounts, "finalized");
- g_hash_table_unref (mounts->mounts);
- g_mutex_clear (&mounts->lock);
+ g_hash_table_unref (priv->mounts);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_mount_points_parent_class)->finalize (obj);
}
static GstRTSPMediaFactory *
find_factory (GstRTSPMountPoints * mounts, const GstRTSPUrl * url)
{
+ GstRTSPMountPointsPrivate *priv = mounts->priv;
GstRTSPMediaFactory *result;
- g_mutex_lock (&mounts->lock);
+ g_mutex_lock (&priv->lock);
/* find the location of the media in the hashtable we only use the absolute
* path of the uri to find a media factory. If the factory depends on other
* properties found in the url, this method should be overridden. */
- result = g_hash_table_lookup (mounts->mounts, url->abspath);
+ result = g_hash_table_lookup (priv->mounts, url->abspath);
if (result)
g_object_ref (result);
- g_mutex_unlock (&mounts->lock);
+ g_mutex_unlock (&priv->lock);
GST_INFO ("found media factory %p for url abspath %s", result, url->abspath);
gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts,
const gchar * path, GstRTSPMediaFactory * factory)
{
+ GstRTSPMountPointsPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts));
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
g_return_if_fail (path != NULL);
- g_mutex_lock (&mounts->lock);
- g_hash_table_insert (mounts->mounts, g_strdup (path), factory);
- g_mutex_unlock (&mounts->lock);
+ priv = mounts->priv;
+
+ g_mutex_lock (&priv->lock);
+ g_hash_table_insert (priv->mounts, g_strdup (path), factory);
+ g_mutex_unlock (&priv->lock);
}
/**
gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts,
const gchar * path)
{
+ GstRTSPMountPointsPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts));
g_return_if_fail (path != NULL);
- g_mutex_lock (&mounts->lock);
- g_hash_table_remove (mounts->mounts, path);
- g_mutex_unlock (&mounts->lock);
+ priv = mounts->priv;
+
+ g_mutex_lock (&priv->lock);
+ g_hash_table_remove (priv->mounts, path);
+ g_mutex_unlock (&priv->lock);
}
typedef struct _GstRTSPMountPoints GstRTSPMountPoints;
typedef struct _GstRTSPMountPointsClass GstRTSPMountPointsClass;
+typedef struct _GstRTSPMountPointsPrivate GstRTSPMountPointsPrivate;
/**
* GstRTSPMountPoints:
struct _GstRTSPMountPoints {
GObject parent;
- GMutex lock;
- GHashTable *mounts;
+ GstRTSPMountPointsPrivate *priv;
};
/**
guint i, n_streams;
gchar *rangestr;
- if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED)
- goto not_prepared;
-
n_streams = gst_rtsp_media_n_streams (media);
rangestr = gst_rtsp_media_get_range_string (media, FALSE);
+ if (rangestr == NULL)
+ goto not_prepared;
+
gst_sdp_message_add_attribute (sdp, "range", rangestr);
g_free (rangestr);
guint n_fields, j;
gboolean first;
GString *fmtp;
+ GstCaps *caps;
stream = gst_rtsp_media_get_stream (media, i);
+ caps = gst_rtsp_stream_get_caps (stream);
- if (stream->caps == NULL) {
+ if (caps == NULL) {
g_warning ("ignoring stream %d without media type", i);
continue;
}
- s = gst_caps_get_structure (stream->caps, 0);
+ s = gst_caps_get_structure (caps, 0);
if (s == NULL) {
+ gst_caps_unref (caps);
g_warning ("ignoring stream %d without media type", i);
continue;
}
}
gst_sdp_message_add_media (sdp, smedia);
gst_sdp_media_free (smedia);
+ gst_caps_unref (caps);
}
return TRUE;
#include "rtsp-server.h"
#include "rtsp-client.h"
+#define GST_RTSP_SERVER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServerPrivate))
+
+#define GST_RTSP_SERVER_GET_LOCK(server) (&(GST_RTSP_SERVER_CAST(server)->priv->lock))
+#define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server)))
+#define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server)))
+
+struct _GstRTSPServerPrivate
+{
+ GMutex lock;
+
+ /* server information */
+ gchar *address;
+ gchar *service;
+ gint backlog;
+ gint max_threads;
+
+ GSocket *socket;
+
+ /* sessions on this server */
+ GstRTSPSessionPool *session_pool;
+
+ /* mount points for this server */
+ GstRTSPMountPoints *mount_points;
+
+ /* authentication manager */
+ GstRTSPAuth *auth;
+
+ /* the clients that are connected */
+ GList *clients;
+};
+
#define DEFAULT_ADDRESS "0.0.0.0"
#define DEFAULT_BOUND_PORT -1
/* #define DEFAULT_ADDRESS "::0" */
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPServerPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_server_get_property;
static void
gst_rtsp_server_init (GstRTSPServer * server)
{
- g_mutex_init (&server->lock);
- server->address = g_strdup (DEFAULT_ADDRESS);
- server->service = g_strdup (DEFAULT_SERVICE);
- server->socket = NULL;
- server->backlog = DEFAULT_BACKLOG;
- server->session_pool = gst_rtsp_session_pool_new ();
- server->mount_points = gst_rtsp_mount_points_new ();
- server->max_threads = DEFAULT_MAX_THREADS;
+ GstRTSPServerPrivate *priv = GST_RTSP_SERVER_GET_PRIVATE (server);
+
+ server->priv = priv;
+
+ g_mutex_init (&priv->lock);
+ priv->address = g_strdup (DEFAULT_ADDRESS);
+ priv->service = g_strdup (DEFAULT_SERVICE);
+ priv->socket = NULL;
+ priv->backlog = DEFAULT_BACKLOG;
+ priv->session_pool = gst_rtsp_session_pool_new ();
+ priv->mount_points = gst_rtsp_mount_points_new ();
+ priv->max_threads = DEFAULT_MAX_THREADS;
}
static void
gst_rtsp_server_finalize (GObject * object)
{
GstRTSPServer *server = GST_RTSP_SERVER (object);
+ GstRTSPServerPrivate *priv = server->priv;
GST_DEBUG_OBJECT (server, "finalize server");
- g_free (server->address);
- g_free (server->service);
+ g_free (priv->address);
+ g_free (priv->service);
- if (server->socket)
- g_object_unref (server->socket);
+ if (priv->socket)
+ g_object_unref (priv->socket);
- g_object_unref (server->session_pool);
- g_object_unref (server->mount_points);
+ g_object_unref (priv->session_pool);
+ g_object_unref (priv->mount_points);
- if (server->auth)
- g_object_unref (server->auth);
+ if (priv->auth)
+ g_object_unref (priv->auth);
- g_mutex_clear (&server->lock);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object);
}
void
gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address)
{
+ GstRTSPServerPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_SERVER (server));
g_return_if_fail (address != NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- g_free (server->address);
- server->address = g_strdup (address);
+ g_free (priv->address);
+ priv->address = g_strdup (address);
GST_RTSP_SERVER_UNLOCK (server);
}
gchar *
gst_rtsp_server_get_address (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
gchar *result;
+
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- result = g_strdup (server->address);
+ result = g_strdup (priv->address);
GST_RTSP_SERVER_UNLOCK (server);
return result;
int
gst_rtsp_server_get_bound_port (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
GSocketAddress *address;
int result = -1;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), result);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- if (server->socket == NULL)
+ if (priv->socket == NULL)
goto out;
- address = g_socket_get_local_address (server->socket, NULL);
+ address = g_socket_get_local_address (priv->socket, NULL);
result = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
g_object_unref (address);
void
gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service)
{
+ GstRTSPServerPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_SERVER (server));
g_return_if_fail (service != NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- g_free (server->service);
- server->service = g_strdup (service);
+ g_free (priv->service);
+ priv->service = g_strdup (service);
GST_RTSP_SERVER_UNLOCK (server);
}
gchar *
gst_rtsp_server_get_service (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
gchar *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- result = g_strdup (server->service);
+ result = g_strdup (priv->service);
GST_RTSP_SERVER_UNLOCK (server);
return result;
void
gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog)
{
+ GstRTSPServerPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_SERVER (server));
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- server->backlog = backlog;
+ priv->backlog = backlog;
GST_RTSP_SERVER_UNLOCK (server);
}
gint
gst_rtsp_server_get_backlog (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
gint result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- result = server->backlog;
+ result = priv->backlog;
GST_RTSP_SERVER_UNLOCK (server);
return result;
gst_rtsp_server_set_session_pool (GstRTSPServer * server,
GstRTSPSessionPool * pool)
{
+ GstRTSPServerPrivate *priv;
GstRTSPSessionPool *old;
g_return_if_fail (GST_IS_RTSP_SERVER (server));
+ priv = server->priv;
+
if (pool)
g_object_ref (pool);
GST_RTSP_SERVER_LOCK (server);
- old = server->session_pool;
- server->session_pool = pool;
+ old = priv->session_pool;
+ priv->session_pool = pool;
GST_RTSP_SERVER_UNLOCK (server);
if (old)
GstRTSPSessionPool *
gst_rtsp_server_get_session_pool (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
GstRTSPSessionPool *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- if ((result = server->session_pool))
+ if ((result = priv->session_pool))
g_object_ref (result);
GST_RTSP_SERVER_UNLOCK (server);
gst_rtsp_server_set_mount_points (GstRTSPServer * server,
GstRTSPMountPoints * mounts)
{
+ GstRTSPServerPrivate *priv;
GstRTSPMountPoints *old;
g_return_if_fail (GST_IS_RTSP_SERVER (server));
+ priv = server->priv;
+
if (mounts)
g_object_ref (mounts);
GST_RTSP_SERVER_LOCK (server);
- old = server->mount_points;
- server->mount_points = mounts;
+ old = priv->mount_points;
+ priv->mount_points = mounts;
GST_RTSP_SERVER_UNLOCK (server);
if (old)
GstRTSPMountPoints *
gst_rtsp_server_get_mount_points (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
GstRTSPMountPoints *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- if ((result = server->mount_points))
+ if ((result = priv->mount_points))
g_object_ref (result);
GST_RTSP_SERVER_UNLOCK (server);
void
gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth)
{
+ GstRTSPServerPrivate *priv;
GstRTSPAuth *old;
g_return_if_fail (GST_IS_RTSP_SERVER (server));
+ priv = server->priv;
+
if (auth)
g_object_ref (auth);
GST_RTSP_SERVER_LOCK (server);
- old = server->auth;
- server->auth = auth;
+ old = priv->auth;
+ priv->auth = auth;
GST_RTSP_SERVER_UNLOCK (server);
if (old)
GstRTSPAuth *
gst_rtsp_server_get_auth (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
GstRTSPAuth *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- if ((result = server->auth))
+ if ((result = priv->auth))
g_object_ref (result);
GST_RTSP_SERVER_UNLOCK (server);
void
gst_rtsp_server_set_max_threads (GstRTSPServer * server, gint max_threads)
{
+ GstRTSPServerPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_SERVER (server));
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- server->max_threads = max_threads;
+ priv->max_threads = max_threads;
GST_RTSP_SERVER_UNLOCK (server);
}
gint
gst_rtsp_server_get_max_threads (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv;
gint res;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- res = server->max_threads;
+ res = priv->max_threads;
GST_RTSP_SERVER_UNLOCK (server);
return res;
gst_rtsp_server_create_socket (GstRTSPServer * server,
GCancellable * cancellable, GError ** error)
{
+ GstRTSPServerPrivate *priv;
GSocketConnectable *conn;
GSocketAddressEnumerator *enumerator;
GSocket *socket = NULL;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+ priv = server->priv;
+
GST_RTSP_SERVER_LOCK (server);
- GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address,
- server->service);
+ GST_DEBUG_OBJECT (server, "getting address info of %s/%s", priv->address,
+ priv->service);
/* resolve the server IP address */
- port = atoi (server->service);
- if (port != 0 || !strcmp (server->service, "0"))
- conn = g_network_address_new (server->address, port);
+ port = atoi (priv->service);
+ if (port != 0 || !strcmp (priv->service, "0"))
+ conn = g_network_address_new (priv->address, port);
else
- conn = g_network_service_new (server->service, "tcp", server->address);
+ conn = g_network_service_new (priv->service, "tcp", priv->address);
enumerator = g_socket_connectable_enumerate (conn);
g_object_unref (conn);
g_socket_set_blocking (socket, FALSE);
/* set listen backlog */
- g_socket_set_listen_backlog (socket, server->backlog);
+ g_socket_set_listen_backlog (socket, priv->backlog);
if (!g_socket_listen (socket, error))
goto listen_failed;
GST_DEBUG_OBJECT (server, "listening on server socket %p with queue of %d",
- socket, server->backlog);
+ socket, priv->backlog);
GST_RTSP_SERVER_UNLOCK (server);
unmanage_client (GstRTSPClient * client, ClientContext * ctx)
{
GstRTSPServer *server = ctx->server;
+ GstRTSPServerPrivate *priv = server->priv;
GST_DEBUG_OBJECT (server, "unmanage client %p", client);
g_object_ref (server);
GST_RTSP_SERVER_LOCK (server);
- server->clients = g_list_remove (server->clients, ctx);
+ priv->clients = g_list_remove (priv->clients, ctx);
GST_RTSP_SERVER_UNLOCK (server);
if (ctx->loop)
manage_client (GstRTSPServer * server, GstRTSPClient * client)
{
ClientContext *ctx;
+ GstRTSPServerPrivate *priv = server->priv;
GST_DEBUG_OBJECT (server, "manage client %p", client);
ctx = g_slice_new0 (ClientContext);
ctx->server = server;
ctx->client = client;
- if (server->max_threads == 0) {
+ if (priv->max_threads == 0) {
GSource *source;
/* find the context to add the watch */
GST_RTSP_SERVER_LOCK (server);
g_signal_connect (client, "closed", (GCallback) unmanage_client, ctx);
- server->clients = g_list_prepend (server->clients, ctx);
+ priv->clients = g_list_prepend (priv->clients, ctx);
GST_RTSP_SERVER_UNLOCK (server);
if (ctx->loop) {
default_create_client (GstRTSPServer * server)
{
GstRTSPClient *client;
+ GstRTSPServerPrivate *priv = server->priv;
/* a new client connected, create a session to handle the client. */
client = gst_rtsp_client_new ();
/* set the session pool that this client should use */
GST_RTSP_SERVER_LOCK (server);
- gst_rtsp_client_set_session_pool (client, server->session_pool);
+ gst_rtsp_client_set_session_pool (client, priv->session_pool);
/* set the mount points that this client should use */
- gst_rtsp_client_set_mount_points (client, server->mount_points);
+ gst_rtsp_client_set_mount_points (client, priv->mount_points);
/* set authentication manager */
- gst_rtsp_client_set_auth (client, server->auth);
+ gst_rtsp_client_set_auth (client, priv->auth);
GST_RTSP_SERVER_UNLOCK (server);
return client;
static void
watch_destroyed (GstRTSPServer * server)
{
+ GstRTSPServerPrivate *priv = server->priv;
+
GST_DEBUG_OBJECT (server, "source destroyed");
- g_object_unref (server->socket);
- server->socket = NULL;
+
+ g_object_unref (priv->socket);
+ priv->socket = NULL;
g_object_unref (server);
}
gst_rtsp_server_create_source (GstRTSPServer * server,
GCancellable * cancellable, GError ** error)
{
+ GstRTSPServerPrivate *priv;
GSocket *socket, *old;
GSource *source;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+ priv = server->priv;
+
socket = gst_rtsp_server_create_socket (server, NULL, error);
if (socket == NULL)
goto no_socket;
GST_RTSP_SERVER_LOCK (server);
- old = server->socket;
- server->socket = g_object_ref (socket);
+ old = priv->socket;
+ priv->socket = g_object_ref (socket);
GST_RTSP_SERVER_UNLOCK (server);
if (old)
typedef struct _GstRTSPServer GstRTSPServer;
typedef struct _GstRTSPServerClass GstRTSPServerClass;
+typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate;
#include "rtsp-session-pool.h"
#include "rtsp-mount-points.h"
#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj))
#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass))
-#define GST_RTSP_SERVER_GET_LOCK(server) (&(GST_RTSP_SERVER_CAST(server)->lock))
-#define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server)))
-#define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server)))
-
/**
* GstRTSPServer:
*
struct _GstRTSPServer {
GObject parent;
- GMutex lock;
-
- /* server information */
- gchar *address;
- gchar *service;
- gint backlog;
- gint max_threads;
-
- GSocket *socket;
-
- /* sessions on this server */
- GstRTSPSessionPool *session_pool;
-
- /* mount points for this server */
- GstRTSPMountPoints *mount_points;
-
- /* authentication manager */
- GstRTSPAuth *auth;
-
- /* the clients that are connected */
- GList *clients;
+ GstRTSPServerPrivate *priv;
};
/**
#include "rtsp-session.h"
+#define GST_RTSP_SESSION_MEDIA_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMediaPrivate))
+
+struct _GstRTSPSessionMediaPrivate
+{
+ GMutex lock;
+ GstRTSPUrl *url;
+ GstRTSPMedia *media;
+ GstRTSPState state;
+ guint counter;
+
+ GPtrArray *transports;
+};
+
enum
{
PROP_0,
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPSessionMediaPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gst_rtsp_session_media_finalize;
static void
gst_rtsp_session_media_init (GstRTSPSessionMedia * media)
{
- g_mutex_init (&media->lock);
- media->state = GST_RTSP_STATE_INIT;
+ GstRTSPSessionMediaPrivate *priv = GST_RTSP_SESSION_MEDIA_GET_PRIVATE (media);
+
+ media->priv = priv;
+
+ g_mutex_init (&priv->lock);
+ priv->state = GST_RTSP_STATE_INIT;
}
static void
gst_rtsp_session_media_finalize (GObject * obj)
{
GstRTSPSessionMedia *media;
+ GstRTSPSessionMediaPrivate *priv;
media = GST_RTSP_SESSION_MEDIA (obj);
+ priv = media->priv;
GST_INFO ("free session media %p", media);
gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
- g_ptr_array_unref (media->transports);
+ g_ptr_array_unref (priv->transports);
- gst_rtsp_url_free (media->url);
- g_object_unref (media->media);
- g_mutex_clear (&media->lock);
+ gst_rtsp_url_free (priv->url);
+ g_object_unref (priv->media);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_session_media_parent_class)->finalize (obj);
}
GstRTSPSessionMedia *
gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
{
+ GstRTSPSessionMediaPrivate *priv;
GstRTSPSessionMedia *result;
guint n_streams;
g_return_val_if_fail (url != NULL, NULL);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
- g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
+ g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
+ GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL);
- result->url = gst_rtsp_url_copy ((GstRTSPUrl *) url);
- result->media = media;
+ priv = result->priv;
+
+ priv->url = gst_rtsp_url_copy ((GstRTSPUrl *) url);
+ priv->media = media;
/* prealloc the streams now, filled with NULL */
n_streams = gst_rtsp_media_n_streams (media);
- result->transports = g_ptr_array_new_full (n_streams, free_session_media);
- g_ptr_array_set_size (result->transports, n_streams);
+ priv->transports = g_ptr_array_new_full (n_streams, free_session_media);
+ g_ptr_array_set_size (priv->transports, n_streams);
return result;
}
/**
+ * gst_rtsp_session_media_matches_url:
+ * @media: a #GstRTSPSessionMedia
+ * @url: a #GstRTSPUrl
+ *
+ * Check if the url of @media matches @url.
+ *
+ * Returns: %TRUE when @url matches the url of @media.
+ */
+gboolean
+gst_rtsp_session_media_matches_url (GstRTSPSessionMedia * media,
+ const GstRTSPUrl * url)
+{
+ g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
+ g_return_val_if_fail (url != NULL, FALSE);
+
+ return g_str_equal (media->priv->url->abspath, url->abspath);
+}
+
+/**
+ * gst_rtsp_session_media_get_media:
+ * @media: a #GstRTSPSessionMedia
+ *
+ * Get the #GstRTSPMedia that was used when constructing @media
+ *
+ * Returns: (transfer none): the #GstRTSPMedia of @media. Remains valid as long
+ * as @media is valid.
+ */
+GstRTSPMedia *
+gst_rtsp_session_media_get_media (GstRTSPSessionMedia * media)
+{
+ g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
+
+ return media->priv->media;
+}
+
+/**
* gst_rtsp_session_media_set_transport:
* @media: a #GstRTSPSessionMedia
* @stream: a #GstRTSPStream
gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
GstRTSPStream * stream, GstRTSPTransport * tr)
{
+ GstRTSPSessionMediaPrivate *priv;
GstRTSPStreamTransport *result;
+ guint idx;
g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
- g_return_val_if_fail (stream->idx < media->transports->len, NULL);
+ g_return_val_if_fail (tr != NULL, NULL);
+ priv = media->priv;
+ idx = gst_rtsp_stream_get_index (stream);
+ g_return_val_if_fail (idx < priv->transports->len, NULL);
- g_mutex_lock (&media->lock);
- result = g_ptr_array_index (media->transports, stream->idx);
+ g_mutex_lock (&priv->lock);
+ result = g_ptr_array_index (priv->transports, idx);
if (result == NULL) {
result = gst_rtsp_stream_transport_new (stream, tr);
- g_ptr_array_index (media->transports, stream->idx) = result;
- g_mutex_unlock (&media->lock);
+ g_ptr_array_index (priv->transports, idx) = result;
+ g_mutex_unlock (&priv->lock);
} else {
gst_rtsp_stream_transport_set_transport (result, tr);
- g_mutex_unlock (&media->lock);
+ g_mutex_unlock (&priv->lock);
}
return result;
GstRTSPStreamTransport *
gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx)
{
+ GstRTSPSessionMediaPrivate *priv;
GstRTSPStreamTransport *result;
g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
- g_return_val_if_fail (idx < media->transports->len, NULL);
+ priv = media->priv;
+ g_return_val_if_fail (idx < priv->transports->len, NULL);
- g_mutex_lock (&media->lock);
- result = g_ptr_array_index (media->transports, idx);
- g_mutex_unlock (&media->lock);
+ g_mutex_lock (&priv->lock);
+ result = g_ptr_array_index (priv->transports, idx);
+ g_mutex_unlock (&priv->lock);
return result;
}
gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media,
GstRTSPRange * range)
{
+ GstRTSPSessionMediaPrivate *priv;
+
g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
- g_mutex_lock (&media->lock);
- range->min = media->counter++;
- range->max = media->counter++;
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ range->min = priv->counter++;
+ range->max = priv->counter++;
+ g_mutex_unlock (&priv->lock);
return TRUE;
}
gboolean
gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state)
{
+ GstRTSPSessionMediaPrivate *priv;
gboolean ret;
g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
- g_mutex_lock (&media->lock);
- ret = gst_rtsp_media_set_state (media->media, state, media->transports);
- g_mutex_unlock (&media->lock);
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ ret = gst_rtsp_media_set_state (priv->media, state, priv->transports);
+ g_mutex_unlock (&priv->lock);
+
+ return ret;
+}
+
+/**
+ * gst_rtsp_session_media_set_rtsp_state:
+ * @media: a #GstRTSPSessionMedia
+ * @state: a #GstRTSPState
+ *
+ * Set the RTSP state of @media to @state.
+ */
+void
+gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia * media,
+ GstRTSPState state)
+{
+ GstRTSPSessionMediaPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_SESSION_MEDIA (media));
+
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->state = state;
+ g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_session_media_set_rtsp_state:
+ * @media: a #GstRTSPSessionMedia
+ *
+ * Get the current RTSP state of @media.
+ *
+ * Returns: the current RTSP state of @media.
+ */
+GstRTSPState
+gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia * media)
+{
+ GstRTSPSessionMediaPrivate *priv;
+ GstRTSPState ret;
+
+ g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media),
+ GST_RTSP_STATE_INVALID);
+
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ ret = priv->state;
+ g_mutex_unlock (&priv->lock);
return ret;
}
typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia;
typedef struct _GstRTSPSessionMediaClass GstRTSPSessionMediaClass;
+typedef struct _GstRTSPSessionMediaPrivate GstRTSPSessionMediaPrivate;
/**
* GstRTSPSessionMedia:
{
GObject parent;
- GMutex lock;
- GstRTSPUrl *url;
- GstRTSPMedia *media;
- GstRTSPState state;
- guint counter;
-
- GPtrArray *transports;
+ GstRTSPSessionMediaPrivate *priv;
};
struct _GstRTSPSessionMediaClass
GstRTSPSessionMedia * gst_rtsp_session_media_new (const GstRTSPUrl *url,
GstRTSPMedia *media);
+
+gboolean gst_rtsp_session_media_matches_url (GstRTSPSessionMedia *media,
+ const GstRTSPUrl *url);
+GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia *media);
+
/* control media */
+
gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media,
GstState state);
+void gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia *media,
+ GstRTSPState state);
+GstRTSPState gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia *media);
+
/* get stream transport config */
GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media,
GstRTSPStream *stream,
#include "rtsp-session-pool.h"
+#define GST_RTSP_SESSION_POOL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_POOL, GstRTSPSessionPoolPrivate))
+
+struct _GstRTSPSessionPoolPrivate
+{
+ guint max_sessions;
+
+ GMutex lock;
+ GHashTable *sessions;
+};
+
#define DEFAULT_MAX_SESSIONS 0
enum
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPSessionPoolPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_session_pool_get_property;
static void
gst_rtsp_session_pool_init (GstRTSPSessionPool * pool)
{
- g_mutex_init (&pool->lock);
- pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal,
+ GstRTSPSessionPoolPrivate *priv = GST_RTSP_SESSION_POOL_GET_PRIVATE (pool);
+
+ pool->priv = priv;
+
+ g_mutex_init (&priv->lock);
+ priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, g_object_unref);
- pool->max_sessions = DEFAULT_MAX_SESSIONS;
+ priv->max_sessions = DEFAULT_MAX_SESSIONS;
}
static void
gst_rtsp_session_pool_finalize (GObject * object)
{
GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object);
+ GstRTSPSessionPoolPrivate *priv = pool->priv;
- g_mutex_clear (&pool->lock);
- g_hash_table_unref (pool->sessions);
+ g_mutex_clear (&priv->lock);
+ g_hash_table_unref (priv->sessions);
G_OBJECT_CLASS (gst_rtsp_session_pool_parent_class)->finalize (object);
}
void
gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool * pool, guint max)
{
+ GstRTSPSessionPoolPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_SESSION_POOL (pool));
- g_mutex_lock (&pool->lock);
- pool->max_sessions = max;
- g_mutex_unlock (&pool->lock);
+ priv = pool->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->max_sessions = max;
+ g_mutex_unlock (&priv->lock);
}
/**
guint
gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool * pool)
{
+ GstRTSPSessionPoolPrivate *priv;
guint result;
g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0);
- g_mutex_lock (&pool->lock);
- result = pool->max_sessions;
- g_mutex_unlock (&pool->lock);
+ priv = pool->priv;
+
+ g_mutex_lock (&priv->lock);
+ result = priv->max_sessions;
+ g_mutex_unlock (&priv->lock);
return result;
}
guint
gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool)
{
+ GstRTSPSessionPoolPrivate *priv;
guint result;
g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0);
- g_mutex_lock (&pool->lock);
- result = g_hash_table_size (pool->sessions);
- g_mutex_unlock (&pool->lock);
+ priv = pool->priv;
+
+ g_mutex_lock (&priv->lock);
+ result = g_hash_table_size (priv->sessions);
+ g_mutex_unlock (&priv->lock);
return result;
}
GstRTSPSession *
gst_rtsp_session_pool_find (GstRTSPSessionPool * pool, const gchar * sessionid)
{
+ GstRTSPSessionPoolPrivate *priv;
GstRTSPSession *result;
g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL);
g_return_val_if_fail (sessionid != NULL, NULL);
- g_mutex_lock (&pool->lock);
- result = g_hash_table_lookup (pool->sessions, sessionid);
+ priv = pool->priv;
+
+ g_mutex_lock (&priv->lock);
+ result = g_hash_table_lookup (priv->sessions, sessionid);
if (result) {
g_object_ref (result);
gst_rtsp_session_touch (result);
}
- g_mutex_unlock (&pool->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
GstRTSPSession *
gst_rtsp_session_pool_create (GstRTSPSessionPool * pool)
{
+ GstRTSPSessionPoolPrivate *priv;
GstRTSPSession *result = NULL;
GstRTSPSessionPoolClass *klass;
gchar *id = NULL;
g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL);
+ priv = pool->priv;
+
klass = GST_RTSP_SESSION_POOL_GET_CLASS (pool);
retry = 0;
if (id == NULL)
goto no_session;
- g_mutex_lock (&pool->lock);
+ g_mutex_lock (&priv->lock);
/* check session limit */
- if (pool->max_sessions > 0) {
- if (g_hash_table_size (pool->sessions) >= pool->max_sessions)
+ if (priv->max_sessions > 0) {
+ if (g_hash_table_size (priv->sessions) >= priv->max_sessions)
goto too_many_sessions;
}
/* check if the sessionid existed */
- result = g_hash_table_lookup (pool->sessions, id);
+ result = g_hash_table_lookup (priv->sessions, id);
if (result) {
/* found, retry with a different session id */
result = NULL;
result = gst_rtsp_session_new (id);
/* take additional ref for the pool */
g_object_ref (result);
- g_hash_table_insert (pool->sessions, result->sessionid, result);
+ g_hash_table_insert (priv->sessions,
+ (gchar *) gst_rtsp_session_get_sessionid (result), result);
}
- g_mutex_unlock (&pool->lock);
+ g_mutex_unlock (&priv->lock);
g_free (id);
} while (result == NULL);
collision:
{
GST_WARNING ("can't find unique sessionid for GstRTSPSessionPool %p", pool);
- g_mutex_unlock (&pool->lock);
+ g_mutex_unlock (&priv->lock);
g_free (id);
return NULL;
}
too_many_sessions:
{
- GST_WARNING ("session pool reached max sessions of %d", pool->max_sessions);
- g_mutex_unlock (&pool->lock);
+ GST_WARNING ("session pool reached max sessions of %d", priv->max_sessions);
+ g_mutex_unlock (&priv->lock);
g_free (id);
return NULL;
}
gboolean
gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess)
{
+ GstRTSPSessionPoolPrivate *priv;
gboolean found;
g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), FALSE);
g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE);
- g_mutex_lock (&pool->lock);
- found = g_hash_table_remove (pool->sessions, sess->sessionid);
- g_mutex_unlock (&pool->lock);
+ priv = pool->priv;
+
+ g_mutex_lock (&priv->lock);
+ found =
+ g_hash_table_remove (priv->sessions,
+ gst_rtsp_session_get_sessionid (sess));
+ g_mutex_unlock (&priv->lock);
return found;
}
guint
gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool)
{
+ GstRTSPSessionPoolPrivate *priv;
guint result;
GTimeVal now;
g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0);
+ priv = pool->priv;
+
g_get_current_time (&now);
- g_mutex_lock (&pool->lock);
+ g_mutex_lock (&priv->lock);
result =
- g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func,
+ g_hash_table_foreach_remove (priv->sessions, (GHRFunc) cleanup_func,
&now);
- g_mutex_unlock (&pool->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
typedef struct
{
GstRTSPSessionPool *pool;
- GstRTSPSessionFilterFunc func;
+ GstRTSPSessionPoolFilterFunc func;
gpointer user_data;
GList *list;
} FilterData;
*/
GList *
gst_rtsp_session_pool_filter (GstRTSPSessionPool * pool,
- GstRTSPSessionFilterFunc func, gpointer user_data)
+ GstRTSPSessionPoolFilterFunc func, gpointer user_data)
{
+ GstRTSPSessionPoolPrivate *priv;
FilterData data;
g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL);
g_return_val_if_fail (func != NULL, NULL);
+ priv = pool->priv;
+
data.pool = pool;
data.func = func;
data.user_data = user_data;
data.list = NULL;
- g_mutex_lock (&pool->lock);
- g_hash_table_foreach_remove (pool->sessions, (GHRFunc) filter_func, &data);
- g_mutex_unlock (&pool->lock);
+ g_mutex_lock (&priv->lock);
+ g_hash_table_foreach_remove (priv->sessions, (GHRFunc) filter_func, &data);
+ g_mutex_unlock (&priv->lock);
return data.list;
}
static gboolean
gst_pool_source_prepare (GSource * source, gint * timeout)
{
+ GstRTSPSessionPoolPrivate *priv;
GstPoolSource *psrc;
gboolean result;
psrc = (GstPoolSource *) source;
psrc->timeout = -1;
+ priv = psrc->pool->priv;
- g_mutex_lock (&psrc->pool->lock);
- g_hash_table_foreach (psrc->pool->sessions, (GHFunc) collect_timeout, psrc);
- g_mutex_unlock (&psrc->pool->lock);
+ g_mutex_lock (&priv->lock);
+ g_hash_table_foreach (priv->sessions, (GHFunc) collect_timeout, psrc);
+ g_mutex_unlock (&priv->lock);
if (timeout)
*timeout = psrc->timeout;
typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
+typedef struct _GstRTSPSessionPoolPrivate GstRTSPSessionPoolPrivate;
#include "rtsp-session.h"
struct _GstRTSPSessionPool {
GObject parent;
- guint max_sessions;
-
- GMutex lock;
- GHashTable *sessions;
+ GstRTSPSessionPoolPrivate *priv;
};
/**
typedef gboolean (*GstRTSPSessionPoolFunc) (GstRTSPSessionPool *pool, gpointer user_data);
/**
- * GstRTSPFilterResult:
- * @GST_RTSP_FILTER_REMOVE: Remove session
- * @GST_RTSP_FILTER_KEEP: Keep session in the pool
- * @GST_RTSP_FILTER_REF: Ref session in the result list
- *
- * Possible return values for gst_rtsp_session_pool_filter().
- */
-typedef enum
-{
- GST_RTSP_FILTER_REMOVE,
- GST_RTSP_FILTER_KEEP,
- GST_RTSP_FILTER_REF,
-} GstRTSPFilterResult;
-
-/**
- * GstRTSPSessionFilterFunc:
+ * GstRTSPSessionPoolFilterFunc:
* @pool: a #GstRTSPSessionPool object
* @session: a #GstRTSPSession in @pool
* @user_data: user data that has been given to gst_rtsp_session_pool_filter()
*
* Returns: a #GstRTSPFilterResult.
*/
-typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSessionPool *pool,
- GstRTSPSession *session,
- gpointer user_data);
+typedef GstRTSPFilterResult (*GstRTSPSessionPoolFilterFunc) (GstRTSPSessionPool *pool,
+ GstRTSPSession *session,
+ gpointer user_data);
GType gst_rtsp_session_pool_get_type (void);
/* perform session maintenance */
GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool,
- GstRTSPSessionFilterFunc func,
+ GstRTSPSessionPoolFilterFunc func,
gpointer user_data);
guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool);
GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool);
#include "rtsp-session.h"
+#define GST_RTSP_SESSION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION, GstRTSPSessionPrivate))
+
+struct _GstRTSPSessionPrivate
+{
+ GMutex lock;
+ gchar *sessionid;
+
+ guint timeout;
+ GTimeVal create_time;
+ GTimeVal last_access;
+ gint expire_count;
+
+ GList *medias;
+};
+
#undef DEBUG
#define DEFAULT_TIMEOUT 60
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPSessionPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_session_get_property;
static void
gst_rtsp_session_init (GstRTSPSession * session)
{
- g_mutex_init (&session->lock);
- session->timeout = DEFAULT_TIMEOUT;
- g_get_current_time (&session->create_time);
+ GstRTSPSessionPrivate *priv = GST_RTSP_SESSION_GET_PRIVATE (session);
+
+ session->priv = priv;
+
+ g_mutex_init (&priv->lock);
+ priv->timeout = DEFAULT_TIMEOUT;
+ g_get_current_time (&priv->create_time);
gst_rtsp_session_touch (session);
}
gst_rtsp_session_finalize (GObject * obj)
{
GstRTSPSession *session;
+ GstRTSPSessionPrivate *priv;
session = GST_RTSP_SESSION (obj);
+ priv = session->priv;
GST_INFO ("finalize session %p", session);
/* free all media */
- g_list_free_full (session->medias, g_object_unref);
+ g_list_free_full (priv->medias, g_object_unref);
/* free session id */
- g_free (session->sessionid);
- g_mutex_clear (&session->lock);
+ g_free (priv->sessionid);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj);
}
GValue * value, GParamSpec * pspec)
{
GstRTSPSession *session = GST_RTSP_SESSION (object);
+ GstRTSPSessionPrivate *priv = session->priv;
switch (propid) {
case PROP_SESSIONID:
- g_value_set_string (value, session->sessionid);
+ g_value_set_string (value, priv->sessionid);
break;
case PROP_TIMEOUT:
g_value_set_uint (value, gst_rtsp_session_get_timeout (session));
const GValue * value, GParamSpec * pspec)
{
GstRTSPSession *session = GST_RTSP_SESSION (object);
+ GstRTSPSessionPrivate *priv = session->priv;
switch (propid) {
case PROP_SESSIONID:
- g_free (session->sessionid);
- session->sessionid = g_value_dup_string (value);
+ g_free (priv->sessionid);
+ priv->sessionid = g_value_dup_string (value);
break;
case PROP_TIMEOUT:
gst_rtsp_session_set_timeout (session, g_value_get_uint (value));
gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri,
GstRTSPMedia * media)
{
+ GstRTSPSessionPrivate *priv;
GstRTSPSessionMedia *result;
g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
g_return_val_if_fail (uri != NULL, NULL);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
- g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
+ g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
+ GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
+
+ priv = sess->priv;
result = gst_rtsp_session_media_new (uri, media);
- g_mutex_lock (&sess->lock);
- sess->medias = g_list_prepend (sess->medias, result);
- g_mutex_unlock (&sess->lock);
+ g_mutex_lock (&priv->lock);
+ priv->medias = g_list_prepend (priv->medias, result);
+ g_mutex_unlock (&priv->lock);
GST_INFO ("manage new media %p in session %p", media, result);
gst_rtsp_session_release_media (GstRTSPSession * sess,
GstRTSPSessionMedia * media)
{
+ GstRTSPSessionPrivate *priv;
GList *find;
gboolean more;
g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE);
g_return_val_if_fail (media != NULL, FALSE);
- g_mutex_lock (&sess->lock);
- find = g_list_find (sess->medias, media);
+ priv = sess->priv;
+
+ g_mutex_lock (&priv->lock);
+ find = g_list_find (priv->medias, media);
if (find)
- sess->medias = g_list_delete_link (sess->medias, find);
- more = (sess->medias != NULL);
- g_mutex_unlock (&sess->lock);
+ priv->medias = g_list_delete_link (priv->medias, find);
+ more = (priv->medias != NULL);
+ g_mutex_unlock (&priv->lock);
if (find)
g_object_unref (media);
GstRTSPSessionMedia *
gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url)
{
+ GstRTSPSessionPrivate *priv;
GstRTSPSessionMedia *result;
GList *walk;
g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
g_return_val_if_fail (url != NULL, NULL);
+ priv = sess->priv;
result = NULL;
- g_mutex_lock (&sess->lock);
- for (walk = sess->medias; walk; walk = g_list_next (walk)) {
+ g_mutex_lock (&priv->lock);
+ for (walk = priv->medias; walk; walk = g_list_next (walk)) {
result = (GstRTSPSessionMedia *) walk->data;
- if (g_str_equal (result->url->abspath, url->abspath))
+ if (gst_rtsp_session_media_matches_url (result, url))
break;
result = NULL;
}
- g_mutex_unlock (&sess->lock);
+ g_mutex_unlock (&priv->lock);
+
+ return result;
+}
+
+/**
+ * gst_rtsp_session_filter:
+ * @sess: a #GstRTSPSession
+ * @func: (scope call): a callback
+ * @user_data: user data passed to @func
+ *
+ * Call @func for each media in @sess. The result value of @func determines
+ * what happens to the media. @func will be called with @sess
+ * locked so no further actions on @sess can be performed from @func.
+ *
+ * If @func returns #GST_RTSP_FILTER_REMOVE, the media will be removed from
+ * @sess.
+ *
+ * If @func returns #GST_RTSP_FILTER_KEEP, the media will remain in @sess.
+ *
+ * If @func returns #GST_RTSP_FILTER_REF, the media will remain in @sess but
+ * will also be added with an additional ref to the result #GList of this
+ * function..
+ *
+ * Returns: (element-type GstRTSPSessionMedia) (transfer full): a GList with all
+ * media for which @func returned #GST_RTSP_FILTER_REF. After usage, each
+ * element in the #GList should be unreffed before the list is freed.
+ */
+GList *
+gst_rtsp_session_filter (GstRTSPSession * sess,
+ GstRTSPSessionFilterFunc func, gpointer user_data)
+{
+ GstRTSPSessionPrivate *priv;
+ GList *result, *walk, *next;
+
+ g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
+ g_return_val_if_fail (func != NULL, NULL);
+
+ priv = sess->priv;
+
+ result = NULL;
+
+ g_mutex_lock (&priv->lock);
+ for (walk = priv->medias; walk; walk = next) {
+ GstRTSPSessionMedia *media = walk->data;
+
+ next = g_list_next (walk);
+
+ switch (func (sess, media, user_data)) {
+ case GST_RTSP_FILTER_REMOVE:
+ g_object_unref (media);
+ priv->medias = g_list_delete_link (priv->medias, walk);
+ break;
+ case GST_RTSP_FILTER_REF:
+ result = g_list_prepend (result, g_object_ref (media));
+ break;
+ case GST_RTSP_FILTER_KEEP:
+ default:
+ break;
+ }
+ }
+ g_mutex_unlock (&priv->lock);
return result;
}
{
g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL);
- return session->sessionid;
+ return session->priv->sessionid;
}
/**
gchar *
gst_rtsp_session_get_header (GstRTSPSession * session)
{
+ GstRTSPSessionPrivate *priv;
gchar *result;
g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL);
- g_mutex_lock (&session->lock);
- if (session->timeout != 60)
- result = g_strdup_printf ("%s; timeout=%d", session->sessionid,
- session->timeout);
+ priv = session->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (priv->timeout != 60)
+ result = g_strdup_printf ("%s; timeout=%d", priv->sessionid, priv->timeout);
else
- result = g_strdup (session->sessionid);
- g_mutex_unlock (&session->lock);
+ result = g_strdup (priv->sessionid);
+ g_mutex_unlock (&priv->lock);
return result;
}
void
gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout)
{
+ GstRTSPSessionPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_SESSION (session));
- g_mutex_lock (&session->lock);
- session->timeout = timeout;
- g_mutex_unlock (&session->lock);
+ priv = session->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->timeout = timeout;
+ g_mutex_unlock (&priv->lock);
}
/**
guint
gst_rtsp_session_get_timeout (GstRTSPSession * session)
{
+ GstRTSPSessionPrivate *priv;
guint res;
g_return_val_if_fail (GST_IS_RTSP_SESSION (session), 0);
- g_mutex_lock (&session->lock);
- res = session->timeout;
- g_mutex_unlock (&session->lock);
+ priv = session->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->timeout;
+ g_mutex_unlock (&priv->lock);
return res;
}
void
gst_rtsp_session_touch (GstRTSPSession * session)
{
+ GstRTSPSessionPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_SESSION (session));
- g_mutex_lock (&session->lock);
- g_get_current_time (&session->last_access);
- g_mutex_unlock (&session->lock);
+ priv = session->priv;
+
+ g_mutex_lock (&priv->lock);
+ g_get_current_time (&priv->last_access);
+ g_mutex_unlock (&priv->lock);
}
/**
{
g_return_if_fail (GST_IS_RTSP_SESSION (session));
- g_atomic_int_add (&session->expire_count, 1);
+ g_atomic_int_add (&session->priv->expire_count, 1);
}
/**
void
gst_rtsp_session_allow_expire (GstRTSPSession * session)
{
- g_atomic_int_add (&session->expire_count, -1);
+ g_atomic_int_add (&session->priv->expire_count, -1);
}
/**
gint
gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now)
{
+ GstRTSPSessionPrivate *priv;
gint res;
GstClockTime last_access, now_ns;
g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1);
g_return_val_if_fail (now != NULL, -1);
- g_mutex_lock (&session->lock);
- if (g_atomic_int_get (&session->expire_count) != 0) {
+ priv = session->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (g_atomic_int_get (&priv->expire_count) != 0) {
/* touch session when the expire count is not 0 */
- g_get_current_time (&session->last_access);
+ g_get_current_time (&priv->last_access);
}
- last_access = GST_TIMEVAL_TO_TIME (session->last_access);
+ last_access = GST_TIMEVAL_TO_TIME (priv->last_access);
/* add timeout allow for 5 seconds of extra time */
- last_access += session->timeout * GST_SECOND + (5 * GST_SECOND);
- g_mutex_unlock (&session->lock);
+ last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND);
+ g_mutex_unlock (&priv->lock);
now_ns = GST_TIMEVAL_TO_TIME (*now);
typedef struct _GstRTSPSession GstRTSPSession;
typedef struct _GstRTSPSessionClass GstRTSPSessionClass;
+typedef struct _GstRTSPSessionPrivate GstRTSPSessionPrivate;
+
+/**
+ * GstRTSPFilterResult:
+ * @GST_RTSP_FILTER_REMOVE: Remove session
+ * @GST_RTSP_FILTER_KEEP: Keep session in the pool
+ * @GST_RTSP_FILTER_REF: Ref session in the result list
+ *
+ * Possible return values for gst_rtsp_session_pool_filter().
+ */
+typedef enum
+{
+ GST_RTSP_FILTER_REMOVE,
+ GST_RTSP_FILTER_KEEP,
+ GST_RTSP_FILTER_REF,
+} GstRTSPFilterResult;
#include "rtsp-media.h"
#include "rtsp-session-media.h"
/**
* GstRTSPSession:
- * @parent: the parent GObject
- * @sessionid: the session id of the session
- * @timeout: the timeout of the session
- * @create_time: the time when the session was created
- * @last_access: the time the session was last accessed
- * @expire_count: the expire prevention counter
- * @medias: a list of #GstRTSPSessionMedia managed in this session
*
* Session information kept by the server for a specific client.
* One client session, identified with a session id, can handle multiple medias
struct _GstRTSPSession {
GObject parent;
- GMutex lock;
- gchar *sessionid;
-
- guint timeout;
- GTimeVal create_time;
- GTimeVal last_access;
- gint expire_count;
-
- GList *medias;
+ GstRTSPSessionPrivate *priv;
};
struct _GstRTSPSessionClass {
GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess,
const GstRTSPUrl *url);
+/**
+ * GstRTSPSessionFilterFunc:
+ * @sess: a #GstRTSPSession object
+ * @media: a #GstRTSPSessionMedia in @sess
+ * @user_data: user data that has been given to gst_rtsp_session_filter()
+ *
+ * This function will be called by the gst_rtsp_session_filter(). An
+ * implementation should return a value of #GstRTSPFilterResult.
+ *
+ * When this function returns #GST_RTSP_FILTER_REMOVE, @media will be removed
+ * from @sess.
+ *
+ * A return value of #GST_RTSP_FILTER_KEEP will leave @media untouched in
+ * @sess.
+ *
+ * A value of GST_RTSP_FILTER_REF will add @media to the result #GList of
+ * gst_rtsp_session_filter().
+ *
+ * Returns: a #GstRTSPFilterResult.
+ */
+typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSession *sess,
+ GstRTSPSessionMedia *media,
+ gpointer user_data);
+
+GList * gst_rtsp_session_filter (GstRTSPSession *sess,
+ GstRTSPSessionFilterFunc func,
+ gpointer user_data);
+
+
G_END_DECLS
#endif /* __GST_RTSP_SESSION_H__ */
#include <string.h>
#include <stdlib.h>
-#include <gst/app/gstappsrc.h>
-#include <gst/app/gstappsink.h>
-
#include "rtsp-stream-transport.h"
+#define GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransportPrivate))
+
+struct _GstRTSPStreamTransportPrivate
+{
+ GstRTSPStream *stream;
+
+ GstRTSPSendFunc send_rtp;
+ GstRTSPSendFunc send_rtcp;
+ gpointer user_data;
+ GDestroyNotify notify;
+
+ GstRTSPKeepAliveFunc keep_alive;
+ gpointer ka_user_data;
+ GDestroyNotify ka_notify;
+ gboolean active;
+ gboolean timed_out;
+
+ GstRTSPTransport *transport;
+
+ GObject *rtpsource;
+};
+
enum
{
PROP_0,
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPStreamTransportPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gst_rtsp_stream_transport_finalize;
static void
gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans)
{
+ GstRTSPStreamTransportPrivate *priv =
+ GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE (trans);
+
+ trans->priv = priv;
}
static void
gst_rtsp_stream_transport_finalize (GObject * obj)
{
+ GstRTSPStreamTransportPrivate *priv;
GstRTSPStreamTransport *trans;
trans = GST_RTSP_STREAM_TRANSPORT (obj);
+ priv = trans->priv;
/* remove callbacks now */
gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL);
gst_rtsp_stream_transport_set_keepalive (trans, NULL, NULL, NULL);
- if (trans->transport)
- gst_rtsp_transport_free (trans->transport);
+ if (priv->transport)
+ gst_rtsp_transport_free (priv->transport);
#if 0
- if (trans->rtpsource)
- g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL);
+ if (priv->rtpsource)
+ g_object_set_qdata (priv->rtpsource, ssrc_stream_map_key, NULL);
#endif
G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj);
GstRTSPStreamTransport *
gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr)
{
+ GstRTSPStreamTransportPrivate *priv;
GstRTSPStreamTransport *trans;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
g_return_val_if_fail (tr != NULL, NULL);
trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL);
- trans->stream = stream;
- trans->transport = tr;
+ priv = trans->priv;
+ priv->stream = stream;
+ priv->transport = tr;
return trans;
}
/**
+ * gst_rtsp_stream_transport_get_stream:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Get the #GstRTSPStream used when constructing @trans.
+ *
+ * Returns: (transfer none): the stream used when constructing @trans.
+ */
+GstRTSPStream *
+gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport * trans)
+{
+ g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
+
+ return trans->priv->stream;
+}
+
+/**
* gst_rtsp_stream_transport_set_callbacks:
* @trans: a #GstRTSPStreamTransport
* @send_rtp: (scope notified): a callback called when RTP should be sent
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp,
gpointer user_data, GDestroyNotify notify)
{
- trans->send_rtp = send_rtp;
- trans->send_rtcp = send_rtcp;
- if (trans->notify)
- trans->notify (trans->user_data);
- trans->user_data = user_data;
- trans->notify = notify;
+ GstRTSPStreamTransportPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
+
+ priv = trans->priv;
+
+ priv->send_rtp = send_rtp;
+ priv->send_rtcp = send_rtcp;
+ if (priv->notify)
+ priv->notify (priv->user_data);
+ priv->user_data = user_data;
+ priv->notify = notify;
}
/**
gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans,
GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify)
{
- trans->keep_alive = keep_alive;
- if (trans->ka_notify)
- trans->ka_notify (trans->ka_user_data);
- trans->ka_user_data = user_data;
- trans->ka_notify = notify;
+ GstRTSPStreamTransportPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
+
+ priv = trans->priv;
+
+ priv->keep_alive = keep_alive;
+ if (priv->ka_notify)
+ priv->ka_notify (priv->ka_user_data);
+ priv->ka_user_data = user_data;
+ priv->ka_notify = notify;
}
gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
GstRTSPTransport * tr)
{
+ GstRTSPStreamTransportPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
g_return_if_fail (tr != NULL);
+ priv = trans->priv;
+
/* keep track of the transports in the stream. */
- if (trans->transport)
- gst_rtsp_transport_free (trans->transport);
- trans->transport = tr;
+ if (priv->transport)
+ gst_rtsp_transport_free (priv->transport);
+ priv->transport = tr;
+}
+
+/**
+ * gst_rtsp_stream_transport_get_transport:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Get the transport configured in @trans.
+ *
+ * Returns: (transfer none): the transport configured in @trans. It remains
+ * valid for as long as @trans is valid.
+ */
+const GstRTSPTransport *
+gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport * trans)
+{
+ g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
+
+ return trans->priv->transport;
+}
+
+/**
+ * gst_rtsp_stream_transport_set_active:
+ * @trans: a #GstRTSPStreamTransport
+ * @active: new state of @trans
+ *
+ * Activate or deactivate datatransfer configured in @trans.
+ *
+ * Returns: %TRUE when the state was changed.
+ */
+gboolean
+gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport * trans,
+ gboolean active)
+{
+ GstRTSPStreamTransportPrivate *priv;
+ gboolean res;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
+
+ priv = trans->priv;
+
+ if (priv->active == active)
+ return FALSE;
+
+ if (active)
+ res = gst_rtsp_stream_add_transport (priv->stream, trans);
+ else
+ res = gst_rtsp_stream_remove_transport (priv->stream, trans);
+
+ if (res)
+ priv->active = active;
+
+ return res;
+}
+
+/**
+ * gst_rtsp_stream_transport_set_timed_out:
+ * @trans: a #GstRTSPStreamTransport
+ * @timedout: timed out value
+ *
+ * Set the timed out state of @trans to @timedout
+ */
+void
+gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport * trans,
+ gboolean timedout)
+{
+ g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
+
+ trans->priv->timed_out = timedout;
+}
+
+/**
+ * gst_rtsp_stream_transport_is_timed_out:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Check if @trans is timed out.
+ *
+ * Returns: %TRUE if @trans timed out.
+ */
+gboolean
+gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport * trans)
+{
+ g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
+
+ return trans->priv->timed_out;
}
/**
gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans,
GstBuffer * buffer)
{
+ GstRTSPStreamTransportPrivate *priv;
gboolean res = FALSE;
- if (trans->send_rtp)
+ priv = trans->priv;
+
+ if (priv->send_rtp)
res =
- trans->send_rtp (buffer, trans->transport->interleaved.min,
- trans->user_data);
+ priv->send_rtp (buffer, priv->transport->interleaved.min,
+ priv->user_data);
return res;
}
gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans,
GstBuffer * buffer)
{
+ GstRTSPStreamTransportPrivate *priv;
gboolean res = FALSE;
- if (trans->send_rtcp)
+ priv = trans->priv;
+
+ if (priv->send_rtcp)
res =
- trans->send_rtcp (buffer, trans->transport->interleaved.max,
- trans->user_data);
+ priv->send_rtcp (buffer, priv->transport->interleaved.max,
+ priv->user_data);
return res;
}
void
gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans)
{
- if (trans->keep_alive)
- trans->keep_alive (trans->ka_user_data);
+ GstRTSPStreamTransportPrivate *priv;
+
+ priv = trans->priv;
+
+ if (priv->keep_alive)
+ priv->keep_alive (priv->ka_user_data);
}
typedef struct _GstRTSPStreamTransport GstRTSPStreamTransport;
typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass;
+typedef struct _GstRTSPStreamTransportPrivate GstRTSPStreamTransportPrivate;
#include "rtsp-stream.h"
-#include "rtsp-address-pool.h"
typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data);
typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
/**
* GstRTSPStreamTransport:
* @parent: parent instance
- * @stream: the GstRTSPStream we manage
- * @send_rtp: callback for sending RTP messages
- * @send_rtcp: callback for sending RTCP messages
- * @user_data: user data passed in the callbacks
- * @notify: free function for the user_data.
- * @keep_alive: keep alive callback
- * @ka_user_data: data passed to @keep_alive
- * @ka_notify: called when @ka_user_data is freed
- * @active: if we are actively sending
- * @timeout: if we timed out
- * @transport: a transport description
- * @addr: an optional address
- * @rtpsource: the receiver rtp source object
*
- * A Transport description for stream @idx
+ * A Transport description for a stream
*/
struct _GstRTSPStreamTransport {
GObject parent;
- GstRTSPStream *stream;
-
- GstRTSPSendFunc send_rtp;
- GstRTSPSendFunc send_rtcp;
- gpointer user_data;
- GDestroyNotify notify;
-
- GstRTSPKeepAliveFunc keep_alive;
- gpointer ka_user_data;
- GDestroyNotify ka_notify;
- gboolean active;
- gboolean timeout;
-
- GstRTSPTransport *transport;
-
- GObject *rtpsource;
+ GstRTSPStreamTransportPrivate *priv;
};
struct _GstRTSPStreamTransportClass {
GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream,
GstRTSPTransport *tr);
+GstRTSPStream * gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport *trans);
+
void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans,
GstRTSPTransport * tr);
+const GstRTSPTransport * gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport *trans);
void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans,
GstRTSPSendFunc send_rtp,
gpointer user_data,
GDestroyNotify notify);
+gboolean gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport *trans,
+ gboolean active);
+
+void gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport *trans,
+ gboolean timedout);
+gboolean gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport *trans);
+
+
+
gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport *trans,
GstBuffer *buffer);
gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans,
#include "rtsp-stream.h"
+#define GST_RTSP_STREAM_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamPrivate))
+
+struct _GstRTSPStreamPrivate
+{
+ GMutex lock;
+ guint idx;
+ GstPad *srcpad;
+ GstElement *payloader;
+ gboolean is_ipv6;
+ guint buffer_size;
+ gboolean is_joined;
+
+ /* pads on the rtpbin */
+ GstPad *send_rtp_sink;
+ GstPad *recv_sink[2];
+ GstPad *send_src[2];
+
+ /* the RTPSession object */
+ GObject *session;
+
+ /* sinks used for sending and receiving RTP and RTCP, they share
+ * sockets */
+ GstElement *udpsrc[2];
+ GstElement *udpsink[2];
+ /* for TCP transport */
+ GstElement *appsrc[2];
+ GstElement *appqueue[2];
+ GstElement *appsink[2];
+
+ GstElement *tee[2];
+ GstElement *funnel[2];
+
+ /* server ports for sending/receiving */
+ GstRTSPRange server_port;
+
+ /* multicast addresses */
+ GstRTSPAddressPool *pool;
+ GstRTSPAddress *addr;
+
+ /* the caps of the stream */
+ gulong caps_sig;
+ GstCaps *caps;
+
+ /* transports we stream to */
+ guint n_active;
+ GList *transports;
+};
+
+
enum
{
PROP_0,
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (GstRTSPStreamPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gst_rtsp_stream_finalize;
static void
gst_rtsp_stream_init (GstRTSPStream * stream)
{
+ GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream);
+
GST_DEBUG ("new stream %p", stream);
- g_mutex_init (&stream->lock);
+ stream->priv = priv;
+
+ g_mutex_init (&priv->lock);
}
static void
gst_rtsp_stream_finalize (GObject * obj)
{
GstRTSPStream *stream;
+ GstRTSPStreamPrivate *priv;
stream = GST_RTSP_STREAM (obj);
+ priv = stream->priv;
GST_DEBUG ("finalize stream %p", stream);
/* we really need to be unjoined now */
- g_return_if_fail (!stream->is_joined);
+ g_return_if_fail (!priv->is_joined);
- if (stream->addr)
- gst_rtsp_address_free (stream->addr);
- if (stream->pool)
- g_object_unref (stream->pool);
- gst_object_unref (stream->payloader);
- gst_object_unref (stream->srcpad);
- g_mutex_clear (&stream->lock);
+ if (priv->addr)
+ gst_rtsp_address_free (priv->addr);
+ if (priv->pool)
+ g_object_unref (priv->pool);
+ gst_object_unref (priv->payloader);
+ gst_object_unref (priv->srcpad);
+ g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj);
}
GstRTSPStream *
gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad)
{
+ GstRTSPStreamPrivate *priv;
GstRTSPStream *stream;
g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
stream = g_object_new (GST_TYPE_RTSP_STREAM, NULL);
- stream->idx = idx;
- stream->payloader = gst_object_ref (payloader);
- stream->srcpad = gst_object_ref (srcpad);
+ priv = stream->priv;
+ priv->idx = idx;
+ priv->payloader = gst_object_ref (payloader);
+ priv->srcpad = gst_object_ref (srcpad);
return stream;
}
/**
+ * gst_rtsp_stream_get_index:
+ * @stream: a #GstRTSPStream
+ *
+ * Get the stream index.
+ *
+ * Return: the stream index.
+ */
+guint
+gst_rtsp_stream_get_index (GstRTSPStream * stream)
+{
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), -1);
+
+ return stream->priv->idx;
+}
+
+/**
* gst_rtsp_stream_set_mtu:
* @stream: a #GstRTSPStream
* @mtu: a new MTU
void
gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu)
{
+ GstRTSPStreamPrivate *priv;
+
g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+ priv = stream->priv;
+
GST_LOG_OBJECT (stream, "set MTU %u", mtu);
- g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL);
+ g_object_set (G_OBJECT (priv->payloader), "mtu", mtu, NULL);
}
/**
guint
gst_rtsp_stream_get_mtu (GstRTSPStream * stream)
{
+ GstRTSPStreamPrivate *priv;
guint mtu;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0);
- g_object_get (G_OBJECT (stream->payloader), "mtu", &mtu, NULL);
+ priv = stream->priv;
+
+ g_object_get (G_OBJECT (priv->payloader), "mtu", &mtu, NULL);
return mtu;
}
gst_rtsp_stream_set_address_pool (GstRTSPStream * stream,
GstRTSPAddressPool * pool)
{
+ GstRTSPStreamPrivate *priv;
GstRTSPAddressPool *old;
g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+ priv = stream->priv;
+
GST_LOG_OBJECT (stream, "set address pool %p", pool);
- g_mutex_lock (&stream->lock);
- if ((old = stream->pool) != pool)
- stream->pool = pool ? g_object_ref (pool) : NULL;
+ g_mutex_lock (&priv->lock);
+ if ((old = priv->pool) != pool)
+ priv->pool = pool ? g_object_ref (pool) : NULL;
else
old = NULL;
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
if (old)
g_object_unref (old);
GstRTSPAddressPool *
gst_rtsp_stream_get_address_pool (GstRTSPStream * stream)
{
+ GstRTSPStreamPrivate *priv;
GstRTSPAddressPool *result;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
- g_mutex_lock (&stream->lock);
- if ((result = stream->pool))
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ if ((result = priv->pool))
g_object_ref (result);
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
return result;
}
GstRTSPAddress *
gst_rtsp_stream_get_address (GstRTSPStream * stream)
{
+ GstRTSPStreamPrivate *priv;
GstRTSPAddress *result;
- g_mutex_lock (&stream->lock);
- if (stream->addr == NULL) {
- if (stream->pool == NULL)
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (priv->addr == NULL) {
+ if (priv->pool == NULL)
goto no_pool;
- stream->addr = gst_rtsp_address_pool_acquire_address (stream->pool,
+ priv->addr = gst_rtsp_address_pool_acquire_address (priv->pool,
GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2);
- if (stream->addr == NULL)
+ if (priv->addr == NULL)
goto no_address;
}
- result = gst_rtsp_address_copy (stream->addr);
- g_mutex_unlock (&stream->lock);
+ result = gst_rtsp_address_copy (priv->addr);
+ g_mutex_unlock (&priv->lock);
return result;
no_pool:
{
GST_ERROR_OBJECT (stream, "no address pool specified");
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
return NULL;
}
no_address:
{
GST_ERROR_OBJECT (stream, "failed to acquire address from pool");
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
return NULL;
}
}
static gboolean
alloc_ports (GstRTSPStream * stream)
{
+ GstRTSPStreamPrivate *priv = stream->priv;
GstStateChangeReturn ret;
GstElement *udpsrc0, *udpsrc1;
GstElement *udpsink0, *udpsink1;
GSocket *socket;
const gchar *host;
- g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
-
udpsrc0 = NULL;
udpsrc1 = NULL;
udpsink0 = NULL;
/* Start with random port */
tmp_rtp = 0;
- if (stream->is_ipv6)
+ if (priv->is_ipv6)
host = "udp://[::0]";
else
host = "udp://0.0.0.0";
if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
"buffer-size")) {
- g_object_set (G_OBJECT (udpsink0), "buffer-size", stream->buffer_size,
- NULL);
+ g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL);
} else {
GST_WARNING ("multiudpsink version found without buffer-size property");
}
/* we keep these elements, we will further configure them when the
* client told us to really use the UDP ports. */
- stream->udpsrc[0] = udpsrc0;
- stream->udpsrc[1] = udpsrc1;
- stream->udpsink[0] = udpsink0;
- stream->udpsink[1] = udpsink1;
- stream->server_port.min = rtpport;
- stream->server_port.max = rtcpport;
+ priv->udpsrc[0] = udpsrc0;
+ priv->udpsrc[1] = udpsrc1;
+ priv->udpsink[0] = udpsink0;
+ priv->udpsink[1] = udpsink1;
+ priv->server_port.min = rtpport;
+ priv->server_port.max = rtcpport;
return TRUE;
}
}
+/**
+ * gst_rtsp_stream_get_server_port:
+ * @stream: a #GstRTSPStream
+ * @server_port: (out): result server port
+ *
+ * Fill @server_port with the port pair used by the server. This function can
+ * only be called when @stream has been joined.
+ */
+void
+gst_rtsp_stream_get_server_port (GstRTSPStream * stream,
+ GstRTSPRange * server_port)
+{
+ GstRTSPStreamPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+ priv = stream->priv;
+ g_return_if_fail (priv->is_joined);
+
+ g_mutex_lock (&priv->lock);
+ if (server_port)
+ *server_port = priv->server_port;
+ g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_stream_get_ssrc:
+ * @stream: a #GstRTSPStream
+ * @ssrc: (out): result ssrc
+ *
+ * Get the SSRC used by the RTP session of this stream. This function can only
+ * be called when @stream has been joined.
+ */
+void
+gst_rtsp_stream_get_ssrc (GstRTSPStream * stream, guint * ssrc)
+{
+ GstRTSPStreamPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+ priv = stream->priv;
+ g_return_if_fail (priv->is_joined);
+
+ g_mutex_lock (&priv->lock);
+ if (ssrc && priv->session)
+ g_object_get (priv->session, "internal-ssrc", ssrc, NULL);
+ g_mutex_unlock (&priv->lock);
+}
+
/* executed from streaming thread */
static void
caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream)
{
+ GstRTSPStreamPrivate *priv = stream->priv;
GstCaps *newcaps, *oldcaps;
newcaps = gst_pad_get_current_caps (pad);
GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps,
newcaps);
- g_mutex_lock (&stream->lock);
- oldcaps = stream->caps;
- stream->caps = newcaps;
- g_mutex_unlock (&stream->lock);
+ g_mutex_lock (&priv->lock);
+ oldcaps = priv->caps;
+ priv->caps = newcaps;
+ g_mutex_unlock (&priv->lock);
if (oldcaps)
gst_caps_unref (oldcaps);
static GstRTSPStreamTransport *
find_transport (GstRTSPStream * stream, const gchar * rtcp_from)
{
+ GstRTSPStreamPrivate *priv = stream->priv;
GList *walk;
GstRTSPStreamTransport *result = NULL;
const gchar *tmp;
port = atoi (tmp + 1);
dest = g_strndup (rtcp_from, tmp - rtcp_from);
- g_mutex_lock (&stream->lock);
+ g_mutex_lock (&priv->lock);
GST_INFO ("finding %s:%d in %d transports", dest, port,
- g_list_length (stream->transports));
+ g_list_length (priv->transports));
- for (walk = stream->transports; walk; walk = g_list_next (walk)) {
+ for (walk = priv->transports; walk; walk = g_list_next (walk)) {
GstRTSPStreamTransport *trans = walk->data;
+ const GstRTSPTransport *tr;
gint min, max;
- min = trans->transport->client_port.min;
- max = trans->transport->client_port.max;
+ tr = gst_rtsp_stream_transport_get_transport (trans);
+
+ min = tr->client_port.min;
+ max = tr->client_port.max;
- if ((strcmp (trans->transport->destination, dest) == 0) && (min == port
- || max == port)) {
+ if ((strcmp (tr->destination, dest) == 0) && (min == port || max == port)) {
result = trans;
break;
}
}
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
g_free (dest);
if ((trans = find_transport (stream, rtcp_from))) {
GST_INFO ("%p: found transport %p for source %p", stream, trans,
source);
-
- /* keep ref to the source */
- trans->rtpsource = source;
-
g_object_set_qdata (source, ssrc_stream_map_key, trans);
}
gst_structure_free (stats);
}
}
-
return trans;
}
GST_INFO ("%p: source %p bye timeout", stream, source);
if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
- trans->rtpsource = NULL;
- trans->timeout = TRUE;
+ gst_rtsp_stream_transport_set_timed_out (trans, TRUE);
}
}
GST_INFO ("%p: source %p timeout", stream, source);
if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
- trans->rtpsource = NULL;
- trans->timeout = TRUE;
+ gst_rtsp_stream_transport_set_timed_out (trans, TRUE);
}
}
static GstFlowReturn
handle_new_sample (GstAppSink * sink, gpointer user_data)
{
+ GstRTSPStreamPrivate *priv;
GList *walk;
GstSample *sample;
GstBuffer *buffer;
return GST_FLOW_OK;
stream = (GstRTSPStream *) user_data;
+ priv = stream->priv;
buffer = gst_sample_get_buffer (sample);
- g_mutex_lock (&stream->lock);
- for (walk = stream->transports; walk; walk = g_list_next (walk)) {
+ g_mutex_lock (&priv->lock);
+ for (walk = priv->transports; walk; walk = g_list_next (walk)) {
GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data;
- if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
+ if (GST_ELEMENT_CAST (sink) == priv->appsink[0]) {
gst_rtsp_stream_transport_send_rtp (tr, buffer);
} else {
gst_rtsp_stream_transport_send_rtcp (tr, buffer);
}
}
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
gst_sample_unref (sample);
gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
GstElement * rtpbin, GstState state)
{
+ GstRTSPStreamPrivate *priv;
gint i, idx;
gchar *name;
GstPad *pad, *teepad, *queuepad, *selpad;
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
- g_mutex_lock (&stream->lock);
- if (stream->is_joined)
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (priv->is_joined)
goto was_joined;
/* create a session with the same index as the stream */
- idx = stream->idx;
+ idx = priv->idx;
GST_INFO ("stream %p joining bin as session %d", stream, idx);
/* get a pad for sending RTP */
name = g_strdup_printf ("send_rtp_sink_%u", idx);
- stream->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
+ priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
g_free (name);
/* link the RTP pad to the session manager, it should not really fail unless
* this is not really an RTP pad */
- ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink);
+ ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink);
if (ret != GST_PAD_LINK_OK)
goto link_failed;
/* get pads from the RTP session element for sending and receiving
* RTP/RTCP*/
name = g_strdup_printf ("send_rtp_src_%u", idx);
- stream->send_src[0] = gst_element_get_static_pad (rtpbin, name);
+ priv->send_src[0] = gst_element_get_static_pad (rtpbin, name);
g_free (name);
name = g_strdup_printf ("send_rtcp_src_%u", idx);
- stream->send_src[1] = gst_element_get_request_pad (rtpbin, name);
+ priv->send_src[1] = gst_element_get_request_pad (rtpbin, name);
g_free (name);
name = g_strdup_printf ("recv_rtp_sink_%u", idx);
- stream->recv_sink[0] = gst_element_get_request_pad (rtpbin, name);
+ priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name);
g_free (name);
name = g_strdup_printf ("recv_rtcp_sink_%u", idx);
- stream->recv_sink[1] = gst_element_get_request_pad (rtpbin, name);
+ priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name);
g_free (name);
/* get the session */
- g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &stream->session);
+ g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &priv->session);
- g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc,
+ g_signal_connect (priv->session, "on-new-ssrc", (GCallback) on_new_ssrc,
stream);
- g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
+ g_signal_connect (priv->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
stream);
- g_signal_connect (stream->session, "on-ssrc-active",
+ g_signal_connect (priv->session, "on-ssrc-active",
(GCallback) on_ssrc_active, stream);
- g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
+ g_signal_connect (priv->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
stream);
- g_signal_connect (stream->session, "on-bye-timeout",
+ g_signal_connect (priv->session, "on-bye-timeout",
(GCallback) on_bye_timeout, stream);
- g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout,
+ g_signal_connect (priv->session, "on-timeout", (GCallback) on_timeout,
stream);
for (i = 0; i < 2; i++) {
* '-----' '---------' '---------'
*/
/* make tee for RTP/RTCP */
- stream->tee[i] = gst_element_factory_make ("tee", NULL);
- gst_bin_add (bin, stream->tee[i]);
+ priv->tee[i] = gst_element_factory_make ("tee", NULL);
+ gst_bin_add (bin, priv->tee[i]);
/* and link to rtpbin send pad */
- pad = gst_element_get_static_pad (stream->tee[i], "sink");
- gst_pad_link (stream->send_src[i], pad);
+ pad = gst_element_get_static_pad (priv->tee[i], "sink");
+ gst_pad_link (priv->send_src[i], pad);
gst_object_unref (pad);
/* add udpsink */
- gst_bin_add (bin, stream->udpsink[i]);
+ gst_bin_add (bin, priv->udpsink[i]);
/* link tee to udpsink */
- teepad = gst_element_get_request_pad (stream->tee[i], "src_%u");
- pad = gst_element_get_static_pad (stream->udpsink[i], "sink");
+ teepad = gst_element_get_request_pad (priv->tee[i], "src_%u");
+ pad = gst_element_get_static_pad (priv->udpsink[i], "sink");
gst_pad_link (teepad, pad);
gst_object_unref (pad);
gst_object_unref (teepad);
/* make queue */
- stream->appqueue[i] = gst_element_factory_make ("queue", NULL);
- gst_bin_add (bin, stream->appqueue[i]);
+ priv->appqueue[i] = gst_element_factory_make ("queue", NULL);
+ gst_bin_add (bin, priv->appqueue[i]);
/* and link to tee */
- teepad = gst_element_get_request_pad (stream->tee[i], "src_%u");
- pad = gst_element_get_static_pad (stream->appqueue[i], "sink");
+ teepad = gst_element_get_request_pad (priv->tee[i], "src_%u");
+ pad = gst_element_get_static_pad (priv->appqueue[i], "sink");
gst_pad_link (teepad, pad);
gst_object_unref (pad);
gst_object_unref (teepad);
/* make appsink */
- stream->appsink[i] = gst_element_factory_make ("appsink", NULL);
- g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL);
- g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL);
- gst_bin_add (bin, stream->appsink[i]);
- gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]),
+ priv->appsink[i] = gst_element_factory_make ("appsink", NULL);
+ g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL);
+ g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL);
+ gst_bin_add (bin, priv->appsink[i]);
+ gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]),
&sink_cb, stream, NULL);
/* and link to queue */
- queuepad = gst_element_get_static_pad (stream->appqueue[i], "src");
- pad = gst_element_get_static_pad (stream->appsink[i], "sink");
+ queuepad = gst_element_get_static_pad (priv->appqueue[i], "src");
+ pad = gst_element_get_static_pad (priv->appsink[i], "sink");
gst_pad_link (queuepad, pad);
gst_object_unref (pad);
gst_object_unref (queuepad);
* '--------' '--------'
*/
/* make funnel for the RTP/RTCP receivers */
- stream->funnel[i] = gst_element_factory_make ("funnel", NULL);
- gst_bin_add (bin, stream->funnel[i]);
+ priv->funnel[i] = gst_element_factory_make ("funnel", NULL);
+ gst_bin_add (bin, priv->funnel[i]);
- pad = gst_element_get_static_pad (stream->funnel[i], "src");
- gst_pad_link (pad, stream->recv_sink[i]);
+ pad = gst_element_get_static_pad (priv->funnel[i], "src");
+ gst_pad_link (pad, priv->recv_sink[i]);
gst_object_unref (pad);
/* we set and keep these to playing so that they don't cause NO_PREROLL return
* values */
- gst_element_set_state (stream->udpsrc[i], GST_STATE_PLAYING);
- gst_element_set_locked_state (stream->udpsrc[i], TRUE);
+ gst_element_set_state (priv->udpsrc[i], GST_STATE_PLAYING);
+ gst_element_set_locked_state (priv->udpsrc[i], TRUE);
/* add udpsrc */
- gst_bin_add (bin, stream->udpsrc[i]);
+ gst_bin_add (bin, priv->udpsrc[i]);
/* and link to the funnel */
- selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u");
- pad = gst_element_get_static_pad (stream->udpsrc[i], "src");
+ selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
+ pad = gst_element_get_static_pad (priv->udpsrc[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
/* make and add appsrc */
- stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
- gst_bin_add (bin, stream->appsrc[i]);
+ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
+ gst_bin_add (bin, priv->appsrc[i]);
/* and link to the funnel */
- selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u");
- pad = gst_element_get_static_pad (stream->appsrc[i], "src");
+ selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
+ pad = gst_element_get_static_pad (priv->appsrc[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
/* check if we need to set to a special state */
if (state != GST_STATE_NULL) {
- gst_element_set_state (stream->udpsink[i], state);
- gst_element_set_state (stream->appsink[i], state);
- gst_element_set_state (stream->appqueue[i], state);
- gst_element_set_state (stream->tee[i], state);
- gst_element_set_state (stream->funnel[i], state);
- gst_element_set_state (stream->appsrc[i], state);
+ gst_element_set_state (priv->udpsink[i], state);
+ gst_element_set_state (priv->appsink[i], state);
+ gst_element_set_state (priv->appqueue[i], state);
+ gst_element_set_state (priv->tee[i], state);
+ gst_element_set_state (priv->funnel[i], state);
+ gst_element_set_state (priv->appsrc[i], state);
}
}
/* be notified of caps changes */
- stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
+ priv->caps_sig = g_signal_connect (priv->send_rtp_sink, "notify::caps",
(GCallback) caps_notify, stream);
- stream->is_joined = TRUE;
- g_mutex_unlock (&stream->lock);
+ priv->is_joined = TRUE;
+ g_mutex_unlock (&priv->lock);
return TRUE;
/* ERRORS */
was_joined:
{
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
return TRUE;
}
no_ports:
{
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
GST_WARNING ("failed to allocate ports %d", idx);
return FALSE;
}
link_failed:
{
GST_WARNING ("failed to link stream %d", idx);
- gst_object_unref (stream->send_rtp_sink);
- stream->send_rtp_sink = NULL;
- g_mutex_unlock (&stream->lock);
+ gst_object_unref (priv->send_rtp_sink);
+ priv->send_rtp_sink = NULL;
+ g_mutex_unlock (&priv->lock);
return FALSE;
}
}
gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
GstElement * rtpbin)
{
+ GstRTSPStreamPrivate *priv;
gint i;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
- g_mutex_lock (&stream->lock);
- if (!stream->is_joined)
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (!priv->is_joined)
goto was_not_joined;
/* all transports must be removed by now */
- g_return_val_if_fail (stream->transports == NULL, FALSE);
+ g_return_val_if_fail (priv->transports == NULL, FALSE);
GST_INFO ("stream %p leaving bin", stream);
- gst_pad_unlink (stream->srcpad, stream->send_rtp_sink);
- g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig);
- gst_element_release_request_pad (rtpbin, stream->send_rtp_sink);
- gst_object_unref (stream->send_rtp_sink);
- stream->send_rtp_sink = NULL;
+ gst_pad_unlink (priv->srcpad, priv->send_rtp_sink);
+ g_signal_handler_disconnect (priv->send_rtp_sink, priv->caps_sig);
+ gst_element_release_request_pad (rtpbin, priv->send_rtp_sink);
+ gst_object_unref (priv->send_rtp_sink);
+ priv->send_rtp_sink = NULL;
for (i = 0; i < 2; i++) {
/* and set udpsrc to NULL now before removing */
- gst_element_set_locked_state (stream->udpsrc[i], FALSE);
- gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL);
+ gst_element_set_locked_state (priv->udpsrc[i], FALSE);
+ gst_element_set_state (priv->udpsrc[i], GST_STATE_NULL);
/* removing them should also nicely release the request
* pads when they finalize */
- gst_bin_remove (bin, stream->udpsrc[i]);
- gst_bin_remove (bin, stream->udpsink[i]);
- gst_bin_remove (bin, stream->appsrc[i]);
- gst_bin_remove (bin, stream->appsink[i]);
- gst_bin_remove (bin, stream->appqueue[i]);
- gst_bin_remove (bin, stream->tee[i]);
- gst_bin_remove (bin, stream->funnel[i]);
-
- gst_element_release_request_pad (rtpbin, stream->recv_sink[i]);
- gst_object_unref (stream->recv_sink[i]);
- stream->recv_sink[i] = NULL;
-
- stream->udpsrc[i] = NULL;
- stream->udpsink[i] = NULL;
- stream->appsrc[i] = NULL;
- stream->appsink[i] = NULL;
- stream->appqueue[i] = NULL;
- stream->tee[i] = NULL;
- stream->funnel[i] = NULL;
+ gst_bin_remove (bin, priv->udpsrc[i]);
+ gst_bin_remove (bin, priv->udpsink[i]);
+ gst_bin_remove (bin, priv->appsrc[i]);
+ gst_bin_remove (bin, priv->appsink[i]);
+ gst_bin_remove (bin, priv->appqueue[i]);
+ gst_bin_remove (bin, priv->tee[i]);
+ gst_bin_remove (bin, priv->funnel[i]);
+
+ gst_element_release_request_pad (rtpbin, priv->recv_sink[i]);
+ gst_object_unref (priv->recv_sink[i]);
+ priv->recv_sink[i] = NULL;
+
+ priv->udpsrc[i] = NULL;
+ priv->udpsink[i] = NULL;
+ priv->appsrc[i] = NULL;
+ priv->appsink[i] = NULL;
+ priv->appqueue[i] = NULL;
+ priv->tee[i] = NULL;
+ priv->funnel[i] = NULL;
}
- gst_object_unref (stream->send_src[0]);
- stream->send_src[0] = NULL;
+ gst_object_unref (priv->send_src[0]);
+ priv->send_src[0] = NULL;
- gst_element_release_request_pad (rtpbin, stream->send_src[1]);
- gst_object_unref (stream->send_src[1]);
- stream->send_src[1] = NULL;
+ gst_element_release_request_pad (rtpbin, priv->send_src[1]);
+ gst_object_unref (priv->send_src[1]);
+ priv->send_src[1] = NULL;
- g_object_unref (stream->session);
- if (stream->caps)
- gst_caps_unref (stream->caps);
+ g_object_unref (priv->session);
+ if (priv->caps)
+ gst_caps_unref (priv->caps);
- stream->is_joined = FALSE;
- g_mutex_unlock (&stream->lock);
+ priv->is_joined = FALSE;
+ g_mutex_unlock (&priv->lock);
return TRUE;
gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
guint * rtptime, guint * seq)
{
+ GstRTSPStreamPrivate *priv;
GObjectClass *payobjclass;
- payobjclass = G_OBJECT_GET_CLASS (stream->payloader);
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+ g_return_val_if_fail (rtptime != NULL, FALSE);
+ g_return_val_if_fail (seq != NULL, FALSE);
+
+ priv = stream->priv;
+
+ payobjclass = G_OBJECT_GET_CLASS (priv->payloader);
if (!g_object_class_find_property (payobjclass, "seqnum") ||
!g_object_class_find_property (payobjclass, "timestamp"))
return FALSE;
- g_object_get (stream->payloader, "seqnum", seq, "timestamp", rtptime, NULL);
+ g_object_get (priv->payloader, "seqnum", seq, "timestamp", rtptime, NULL);
return TRUE;
}
/**
+ * gst_rtsp_stream_get_caps:
+ * @stream: a #GstRTSPStream
+ *
+ * Retrieve the current caps of @stream.
+ *
+ * Returns: (transfer full): the #GstCaps of @stream. use gst_caps_unref()
+ * after usage.
+ */
+GstCaps *
+gst_rtsp_stream_get_caps (GstRTSPStream * stream)
+{
+ GstRTSPStreamPrivate *priv;
+ GstCaps *result;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ if ((result = priv->caps))
+ gst_caps_ref (result);
+ g_mutex_unlock (&priv->lock);
+
+ return result;
+}
+
+/**
* gst_rtsp_stream_recv_rtp:
* @stream: a #GstRTSPStream
* @buffer: (transfer full): a #GstBuffer
GstFlowReturn
gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer)
{
+ GstRTSPStreamPrivate *priv;
GstFlowReturn ret;
GstElement *element;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR);
+ priv = stream->priv;
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
- g_return_val_if_fail (stream->is_joined, FALSE);
+ g_return_val_if_fail (priv->is_joined, FALSE);
- g_mutex_lock (&stream->lock);
- element = gst_object_ref (stream->appsrc[0]);
- g_mutex_unlock (&stream->lock);
+ g_mutex_lock (&priv->lock);
+ element = gst_object_ref (priv->appsrc[0]);
+ g_mutex_unlock (&priv->lock);
ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer);
GstFlowReturn
gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer)
{
+ GstRTSPStreamPrivate *priv;
GstFlowReturn ret;
GstElement *element;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR);
+ priv = stream->priv;
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
- g_return_val_if_fail (stream->is_joined, FALSE);
+ g_return_val_if_fail (priv->is_joined, FALSE);
- g_mutex_lock (&stream->lock);
- element = gst_object_ref (stream->appsrc[1]);
- g_mutex_unlock (&stream->lock);
+ g_mutex_lock (&priv->lock);
+ element = gst_object_ref (priv->appsrc[1]);
+ g_mutex_unlock (&priv->lock);
ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer);
update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
gboolean add)
{
- GstRTSPTransport *tr;
- gboolean updated;
+ GstRTSPStreamPrivate *priv = stream->priv;
+ const GstRTSPTransport *tr;
- updated = FALSE;
-
- tr = trans->transport;
+ tr = gst_rtsp_stream_transport_get_transport (trans);
switch (tr->lower_transport) {
case GST_RTSP_LOWER_TRANS_UDP:
max = tr->client_port.max;
}
- if (add && !trans->active) {
+ if (add) {
GST_INFO ("adding %s:%d-%d", dest, min, max);
- g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
- g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
+ g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL);
+ g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL);
if (ttl > 0) {
GST_INFO ("setting ttl-mc %d", ttl);
- g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL);
- g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL);
+ g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", ttl, NULL);
+ g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", ttl, NULL);
}
- stream->transports = g_list_prepend (stream->transports, trans);
- trans->active = TRUE;
- updated = TRUE;
- } else if (trans->active) {
+ priv->transports = g_list_prepend (priv->transports, trans);
+ } else {
GST_INFO ("removing %s:%d-%d", dest, min, max);
- g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
- g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
- stream->transports = g_list_remove (stream->transports, trans);
- trans->active = FALSE;
- updated = TRUE;
+ g_signal_emit_by_name (priv->udpsink[0], "remove", dest, min, NULL);
+ g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL);
+ priv->transports = g_list_remove (priv->transports, trans);
}
break;
}
case GST_RTSP_LOWER_TRANS_TCP:
- if (add && !trans->active) {
+ if (add) {
GST_INFO ("adding TCP %s", tr->destination);
- stream->transports = g_list_prepend (stream->transports, trans);
- trans->active = TRUE;
- updated = TRUE;
- } else if (trans->active) {
+ priv->transports = g_list_prepend (priv->transports, trans);
+ } else {
GST_INFO ("removing TCP %s", tr->destination);
- stream->transports = g_list_remove (stream->transports, trans);
- trans->active = FALSE;
- updated = TRUE;
+ priv->transports = g_list_remove (priv->transports, trans);
}
break;
default:
- GST_INFO ("Unknown transport %d", tr->lower_transport);
- break;
+ goto unknown_transport;
+ }
+ return TRUE;
+
+ /* ERRORS */
+unknown_transport:
+ {
+ GST_INFO ("Unknown transport %d", tr->lower_transport);
+ return FALSE;
}
- return updated;
}
gst_rtsp_stream_add_transport (GstRTSPStream * stream,
GstRTSPStreamTransport * trans)
{
+ GstRTSPStreamPrivate *priv;
gboolean res;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+ priv = stream->priv;
g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
- g_return_val_if_fail (stream->is_joined, FALSE);
- g_return_val_if_fail (trans->transport != NULL, FALSE);
+ g_return_val_if_fail (priv->is_joined, FALSE);
- g_mutex_lock (&stream->lock);
+ g_mutex_lock (&priv->lock);
res = update_transport (stream, trans, TRUE);
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
return res;
}
gst_rtsp_stream_remove_transport (GstRTSPStream * stream,
GstRTSPStreamTransport * trans)
{
+ GstRTSPStreamPrivate *priv;
gboolean res;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+ priv = stream->priv;
g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
- g_return_val_if_fail (stream->is_joined, FALSE);
- g_return_val_if_fail (trans->transport != NULL, FALSE);
+ g_return_val_if_fail (priv->is_joined, FALSE);
- g_mutex_lock (&stream->lock);
+ g_mutex_lock (&priv->lock);
res = update_transport (stream, trans, FALSE);
- g_mutex_unlock (&stream->lock);
+ g_mutex_unlock (&priv->lock);
return res;
}
typedef struct _GstRTSPStream GstRTSPStream;
typedef struct _GstRTSPStreamClass GstRTSPStreamClass;
+typedef struct _GstRTSPStreamPrivate GstRTSPStreamPrivate;
#include "rtsp-stream-transport.h"
#include "rtsp-address-pool.h"
/**
* GstRTSPStream:
* @parent: the parent instance
- * @lock: mutex protecting the stream
- * @idx: the stream index
- * @srcpad: the srcpad of the stream
- * @payloader: the payloader of the format
- * @is_ipv6: should this stream be IPv6
- * @buffer_size: the UDP buffer size
- * @is_joined: if the stream is joined in a bin
- * @send_rtp_sink: sinkpad for sending RTP buffers
- * @recv_sink: sinkpad for receiving RTP/RTCP buffers
- * @send_src: srcpad for sending RTP/RTCP buffers
- * @session: the RTP session object
- * @udpsrc: the udp source elements for RTP/RTCP
- * @udpsink: the udp sink elements for RTP/RTCP
- * @appsrc: the app source elements for RTP/RTCP
- * @appqueue: the app queue elements for RTP/RTCP
- * @appsink: the app sink elements for RTP/RTCP
- * @tee: tee for the sending to udpsink and appsink
- * @funnel: tee for the receiving from udpsrc and appsrc
- * @server_port: the server ports for this stream
- * @pool: the address pool for this stream
- * @addr: the address for this stream
- * @caps_sig: the signal id for detecting caps
- * @caps: the caps of the stream
- * @n_active: the number of active transports in @transports
- * @transports: list of #GstStreamTransport being streamed to
*
- * The definition of a media stream. The streams are identified by @idx.
+ * The definition of a media stream.
*/
struct _GstRTSPStream {
GObject parent;
- GMutex lock;
- guint idx;
- GstPad *srcpad;
- GstElement *payloader;
- gboolean is_ipv6;
- guint buffer_size;
- gboolean is_joined;
-
- /* pads on the rtpbin */
- GstPad *send_rtp_sink;
- GstPad *recv_sink[2];
- GstPad *send_src[2];
-
- /* the RTPSession object */
- GObject *session;
-
- /* sinks used for sending and receiving RTP and RTCP, they share
- * sockets */
- GstElement *udpsrc[2];
- GstElement *udpsink[2];
- /* for TCP transport */
- GstElement *appsrc[2];
- GstElement *appqueue[2];
- GstElement *appsink[2];
-
- GstElement *tee[2];
- GstElement *funnel[2];
-
- /* server ports for sending/receiving */
- GstRTSPRange server_port;
-
- /* multicast addresses */
- GstRTSPAddressPool *pool;
- GstRTSPAddress *addr;
-
- /* the caps of the stream */
- gulong caps_sig;
- GstCaps *caps;
-
- /* transports we stream to */
- guint n_active;
- GList *transports;
+ GstRTSPStreamPrivate *priv;
};
struct _GstRTSPStreamClass {
GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader,
GstPad *srcpad);
+guint gst_rtsp_stream_get_index (GstRTSPStream *stream);
-void gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu);
-guint gst_rtsp_stream_get_mtu (GstRTSPStream * stream);
+void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu);
+guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream);
void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRTSPAddressPool *pool);
GstRTSPAddressPool *
GstRTSPAddress * gst_rtsp_stream_get_address (GstRTSPStream *stream);
-gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream,
+gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream,
GstBin *bin, GstElement *rtpbin,
GstState state);
-gboolean gst_rtsp_stream_leave_bin (GstRTSPStream * stream,
+gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream,
GstBin *bin, GstElement *rtpbin);
-gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
- guint *rtptime, guint * seq);
+void gst_rtsp_stream_get_server_port (GstRTSPStream *stream,
+ GstRTSPRange *server_port);
+void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream,
+ guint *ssrc);
+
+gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream,
+ guint *rtptime, guint *seq);
+GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream);
GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream *stream,
GstBuffer *buffer);
{
GstRTSPMedia *media;
- media = gst_rtsp_media_new ();
+ media = gst_rtsp_media_new (NULL);
fail_unless (GST_IS_RTSP_MEDIA (media));
g_object_unref (media);
}