From ad00c5e79278593174217d40f8f45740731d3bf1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Nov 2012 11:11:05 +0100 Subject: [PATCH] rtsp: make object details private Make all object details private Add methods to access private bits --- docs/libs/gst-rtsp-server-sections.txt | 1 + examples/test-auth.c | 4 +- gst/rtsp-server/rtsp-auth.c | 44 +- gst/rtsp-server/rtsp-auth.h | 6 +- gst/rtsp-server/rtsp-client.c | 436 +++++++++++-------- gst/rtsp-server/rtsp-client.h | 41 +- gst/rtsp-server/rtsp-media-factory-uri.c | 95 +++-- gst/rtsp-server/rtsp-media-factory-uri.h | 11 +- gst/rtsp-server/rtsp-media-factory.c | 199 ++++++--- gst/rtsp-server/rtsp-media-factory.h | 27 +- gst/rtsp-server/rtsp-media.c | 693 +++++++++++++++++++------------ gst/rtsp-server/rtsp-media.h | 77 +--- gst/rtsp-server/rtsp-mount-points.c | 51 ++- gst/rtsp-server/rtsp-mount-points.h | 4 +- gst/rtsp-server/rtsp-sdp.c | 14 +- gst/rtsp-server/rtsp-server.c | 213 +++++++--- gst/rtsp-server/rtsp-server.h | 27 +- gst/rtsp-server/rtsp-session-media.c | 180 ++++++-- gst/rtsp-server/rtsp-session-media.h | 19 +- gst/rtsp-server/rtsp-session-pool.c | 128 ++++-- gst/rtsp-server/rtsp-session-pool.h | 31 +- gst/rtsp-server/rtsp-session.c | 204 +++++++-- gst/rtsp-server/rtsp-session.h | 62 ++- gst/rtsp-server/rtsp-stream-transport.c | 217 ++++++++-- gst/rtsp-server/rtsp-stream-transport.h | 46 +- gst/rtsp-server/rtsp-stream.c | 608 +++++++++++++++++---------- gst/rtsp-server/rtsp-stream.h | 90 +--- tests/check/gst/media.c | 2 +- 28 files changed, 2242 insertions(+), 1288 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index a94dea9..0122798 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -313,6 +313,7 @@ gst_rtsp_stream_set_mtu 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 diff --git a/examples/test-auth.c b/examples/test-auth.c index a505743..a810b4d 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -35,8 +35,8 @@ remove_sessions (GstRTSPServer * server) 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; diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 398bc28..5a156fb 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -21,6 +21,16 @@ #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, @@ -48,6 +58,8 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) { 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; @@ -63,9 +75,11 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) 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 | @@ -77,10 +91,11 @@ static void 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); } @@ -132,12 +147,16 @@ gst_rtsp_auth_new (void) 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 @@ -190,10 +209,11 @@ 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; @@ -207,10 +227,10 @@ default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, /* 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 */ diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index a71388c..6fd1a2f 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -24,6 +24,7 @@ typedef struct _GstRTSPAuth GstRTSPAuth; typedef struct _GstRTSPAuthClass GstRTSPAuthClass; +typedef struct _GstRTSPAuthPrivate GstRTSPAuthPrivate; #include "rtsp-client.h" @@ -46,10 +47,7 @@ G_BEGIN_DECLS struct _GstRTSPAuth { GObject parent; - /*< private >*/ - GMutex lock; - gchar *basic; - GstRTSPMethod methods; + GstRTSPAuthPrivate *priv; }; struct _GstRTSPAuthClass { diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 15d3696..e8f3957 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -24,6 +24,34 @@ #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; @@ -79,6 +107,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) { 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; @@ -173,39 +203,50 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) 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 */ @@ -213,35 +254,36 @@ static void 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); } @@ -311,6 +353,8 @@ static void 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"); @@ -330,8 +374,8 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, 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); } @@ -380,28 +424,29 @@ compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2) 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; @@ -423,19 +468,17 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) 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); } @@ -486,6 +529,7 @@ no_prepare: static gboolean do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPMessage message = { 0 }; GstMapInfo map_info; guint8 *data; @@ -499,8 +543,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) 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); @@ -514,12 +558,15 @@ static void 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); @@ -529,10 +576,13 @@ static void 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); @@ -544,17 +594,18 @@ unlink_session_transports (GstRTSPClient * client, GstRTSPSession * 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 */ @@ -566,23 +617,25 @@ unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, 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; @@ -605,7 +658,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) /* 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); @@ -613,7 +666,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) * 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; @@ -723,6 +776,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSession *session; GstRTSPSessionMedia *media; GstRTSPStatusCode code; + GstRTSPState rtspstate; if (!(session = state->session)) goto no_session; @@ -734,9 +788,10 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) 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 */ @@ -753,7 +808,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) 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); @@ -793,6 +848,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) gchar *str; GstRTSPTimeRange *range; GstRTSPResult res; + GstRTSPState rtspstate; if (!(session = state->session)) goto no_session; @@ -805,8 +861,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) 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 */ @@ -815,7 +871,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) 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); } } @@ -823,10 +879,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* 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; @@ -836,14 +894,15 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) 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, ", "); @@ -872,7 +931,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) } /* 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); @@ -880,7 +941,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* 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); @@ -1001,9 +1062,11 @@ static gboolean 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); @@ -1019,7 +1082,7 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, } 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); @@ -1057,7 +1120,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, 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; @@ -1070,8 +1133,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, 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; } @@ -1079,6 +1141,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, static gboolean handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; GstRTSPUrl *uri; gchar *transport; @@ -1092,6 +1155,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; GstRTSPStream *stream; + GstRTSPState rtspstate; uri = state->uri; @@ -1130,7 +1194,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* 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; @@ -1143,7 +1207,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) } 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; @@ -1166,7 +1230,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) 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); @@ -1207,14 +1271,15 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) 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); @@ -1287,6 +1352,7 @@ service_unavailable: static GstSDPMessage * create_sdp (GstRTSPClient * client, GstRTSPMedia * media) { + GstRTSPClientPrivate *priv = client->priv; GstSDPMessage *sdp; GstSDPInfo info; const gchar *proto; @@ -1296,13 +1362,13 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) /* 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"); @@ -1312,7 +1378,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) 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)) @@ -1484,13 +1550,15 @@ sanitize_uri (GstRTSPUrl * uri) 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); @@ -1500,9 +1568,10 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) 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 */ @@ -1514,7 +1583,7 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * 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); @@ -1523,6 +1592,7 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) static void handle_request (GstRTSPClient * client, GstRTSPMessage * request) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPMethod method; const gchar *uristr; GstRTSPUrl *uri = NULL; @@ -1557,11 +1627,11 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* 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 @@ -1575,8 +1645,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) 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; } @@ -1651,7 +1721,7 @@ session_not_found: 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: @@ -1665,6 +1735,7 @@ not_implemented: static void handle_data (GstRTSPClient * client, GstRTSPMessage * message) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; guint8 channel; GList *walk; @@ -1683,16 +1754,15 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) 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) { @@ -1726,16 +1796,19 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, 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); @@ -1752,14 +1825,17 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, 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; } @@ -1777,17 +1853,20 @@ void 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); @@ -1804,14 +1883,17 @@ gst_rtsp_client_set_mount_points (GstRTSPClient * client, 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; } @@ -1829,11 +1911,15 @@ void 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); } /** @@ -1846,13 +1932,16 @@ gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, 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; } @@ -1867,17 +1956,20 @@ gst_rtsp_client_get_use_client_settings (GstRTSPClient * client) 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); @@ -1896,14 +1988,17 @@ gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth) 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; } @@ -1923,18 +2018,21 @@ void 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); @@ -1975,10 +2073,12 @@ static GstRTSPResult 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 @@ -1992,9 +2092,10 @@ 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); } @@ -2005,11 +2106,12 @@ static GstRTSPResult 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); @@ -2051,10 +2153,11 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result, 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; @@ -2088,12 +2191,11 @@ tunnel_existed: 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; @@ -2111,12 +2213,11 @@ 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); @@ -2129,12 +2230,14 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) { 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; @@ -2147,16 +2250,18 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) 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; @@ -2196,8 +2301,10 @@ static GstRTSPWatchFuncs watch_funcs = { 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); } @@ -2206,36 +2313,37 @@ static gboolean 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; @@ -2343,19 +2451,21 @@ accept_failed: 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; } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 6ec1f86..a718cc7 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS 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" @@ -90,51 +91,13 @@ typedef gboolean (*GstRTSPClientSendFunc) (GstRTSPClient *client, /** * 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 { diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index cd262b3..84022a3 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -21,6 +21,22 @@ #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 @@ -156,41 +172,48 @@ payloader_filter (GstPluginFeature * feature, FilterData * data) 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); } @@ -200,13 +223,14 @@ gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid, 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); @@ -218,13 +242,14 @@ gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid, 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); @@ -259,13 +284,17 @@ void 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); } /** @@ -279,13 +308,16 @@ gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI * factory, 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; } @@ -293,12 +325,13 @@ gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory) 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) { @@ -340,17 +373,17 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) 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) { @@ -405,6 +438,7 @@ static void pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) { GstRTSPMediaFactoryURI *urifact; + GstRTSPMediaFactoryURIPrivate *priv; FactoryData *data; GstElementFactory *factory; GstElement *payloader; @@ -418,6 +452,7 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) /* 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); @@ -429,10 +464,10 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) 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 { @@ -536,11 +571,13 @@ static GstElement * 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"); @@ -555,7 +592,7 @@ rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, 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); diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index da71aa7..fd1eb98 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -38,24 +38,17 @@ G_BEGIN_DECLS 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; }; /** diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 0861c97..cd4b1a7 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -19,6 +19,28 @@ #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 @@ -72,6 +94,8 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) { 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; @@ -144,15 +168,19 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) 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); } @@ -160,15 +188,16 @@ static void 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); } @@ -268,12 +297,16 @@ void 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); } @@ -289,12 +322,15 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * 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; @@ -311,10 +347,14 @@ void 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); } @@ -329,12 +369,15 @@ gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * 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; @@ -352,10 +395,14 @@ void 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); } @@ -371,12 +418,15 @@ gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * 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; @@ -393,10 +443,14 @@ void 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); } @@ -411,12 +465,15 @@ gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * 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; @@ -433,13 +490,16 @@ void 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); @@ -460,12 +520,15 @@ gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * 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); @@ -483,13 +546,16 @@ void 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); @@ -510,12 +576,15 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * 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); @@ -533,10 +602,14 @@ void 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); } @@ -551,13 +624,16 @@ gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * 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; @@ -572,9 +648,11 @@ compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) 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); } /** @@ -598,6 +676,7 @@ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { + GstRTSPMediaFactoryPrivate *priv; gchar *key; GstRTSPMedia *media; GstRTSPMediaFactoryClass *klass; @@ -605,6 +684,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, 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 @@ -614,10 +694,10 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, 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 @@ -647,7 +727,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, 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)) { @@ -658,7 +738,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, } } } - g_mutex_unlock (&factory->medias_lock); + g_mutex_unlock (&priv->medias_lock); if (key) g_free (key); @@ -687,16 +767,17 @@ default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) 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; @@ -719,7 +800,7 @@ no_launch: 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); @@ -731,7 +812,7 @@ static GstRTSPMedia * default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { GstRTSPMedia *media; - GstElement *element; + GstElement *element, *pipeline; GstRTSPMediaFactoryClass *klass; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); @@ -744,13 +825,12 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) 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; @@ -779,25 +859,16 @@ default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * 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; @@ -806,10 +877,10 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) /* 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); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 2a4745a..dce19e5 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -41,24 +41,11 @@ G_BEGIN_DECLS 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. @@ -66,17 +53,7 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; 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; }; /** diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 766f670..0165769 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -25,6 +25,51 @@ #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 @@ -79,6 +124,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) { 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; @@ -144,42 +191,48 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) 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); } @@ -252,29 +305,30 @@ do_loop (GstRTSPMediaClass * klass) 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; @@ -284,46 +338,81 @@ collect_media_stats (GstRTSPMedia * media) 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 @@ -335,11 +424,15 @@ gst_rtsp_media_new (void) 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); } /** @@ -353,13 +446,16 @@ gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared) 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; } @@ -375,11 +471,15 @@ gst_rtsp_media_is_shared (GstRTSPMedia * media) 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); } /** @@ -393,13 +493,16 @@ gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable) 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; } @@ -414,11 +517,15 @@ gst_rtsp_media_is_reusable (GstRTSPMedia * media) 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); } /** @@ -432,14 +539,17 @@ gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) 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; } @@ -455,11 +565,15 @@ gst_rtsp_media_get_protocols (GstRTSPMedia * media) 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); } /** @@ -474,13 +588,16 @@ gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown) 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; } @@ -495,13 +612,17 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) 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); } /** @@ -515,13 +636,16 @@ gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) 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; } @@ -536,18 +660,21 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) 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); @@ -565,14 +692,17 @@ gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) 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; } @@ -588,20 +718,23 @@ void 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); @@ -619,14 +752,17 @@ gst_rtsp_media_set_address_pool (GstRTSPMedia * media, 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; } @@ -644,6 +780,7 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) void gst_rtsp_media_collect_streams (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; GstElement *element, *elem; GstPad *pad; gint i; @@ -651,7 +788,8 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) 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++) { @@ -680,9 +818,9 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) 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; } @@ -706,6 +844,7 @@ GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, GstPad * pad) { + GstRTSPMediaPrivate *priv; GstRTSPStream *stream; GstPad *srcpad; gchar *name; @@ -716,21 +855,25 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, 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); @@ -749,13 +892,16 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, 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; } @@ -773,16 +919,19 @@ gst_rtsp_media_n_streams (GstRTSPMedia * media) 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; } @@ -800,25 +949,28 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) 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); @@ -828,7 +980,7 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) 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; } } @@ -846,6 +998,7 @@ not_prepared: gboolean gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { + GstRTSPMediaPrivate *priv; GstSeekFlags flags; gboolean res; GstClockTime start, stop; @@ -854,11 +1007,13 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) 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 @@ -873,14 +1028,14 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) 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; @@ -889,12 +1044,12 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) 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); @@ -902,26 +1057,26 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) 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; } @@ -930,35 +1085,47 @@ not_supported: 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; } @@ -967,6 +1134,7 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message) { + GstRTSPMediaPrivate *priv = media->priv; GstMessageType type; type = GST_MESSAGE_TYPE (message); @@ -981,37 +1149,37 @@ default_handle_message (GstRTSPMedia * media, GstMessage * 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: @@ -1043,7 +1211,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) 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 */ @@ -1058,7 +1226,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) 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); @@ -1075,17 +1243,18 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) 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; } @@ -1101,42 +1270,43 @@ watch_destroyed (GstRTSPMedia * media) 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"); @@ -1158,6 +1328,7 @@ no_more_pads_cb (GstElement * element, GstRTSPMedia * media) gboolean gst_rtsp_media_prepare (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; GstStateChangeReturn ret; GstRTSPMediaStatus status; guint i; @@ -1167,59 +1338,61 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) 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); @@ -1229,32 +1402,32 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* 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; @@ -1262,7 +1435,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) 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. */ @@ -1280,25 +1453,25 @@ wait_status: 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; @@ -1307,7 +1480,7 @@ state_failed: { 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; } } @@ -1316,37 +1489,37 @@ state_failed: 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 @@ -1358,15 +1531,17 @@ finish_unprepare (GstRTSPMedia * media) 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); } @@ -1386,19 +1561,22 @@ default_unprepare (GstRTSPMedia * 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); @@ -1407,13 +1585,13 @@ gst_rtsp_media_unprepare (GstRTSPMedia * 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; } @@ -1435,22 +1613,25 @@ gboolean 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); @@ -1458,18 +1639,18 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, 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; @@ -1479,40 +1660,36 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, 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, @@ -1521,10 +1698,10 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState 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; @@ -1532,7 +1709,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, 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; } } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 64cda5e..230806b 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -38,6 +38,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; +typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate; #include "rtsp-stream.h" #include "rtsp-auth.h" @@ -64,36 +65,6 @@ typedef enum { /** * 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. @@ -103,45 +74,7 @@ typedef enum { 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; }; /** @@ -179,7 +112,11 @@ struct _GstRTSPMediaClass { 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); diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 3a92d55..c18cb63 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -19,6 +19,15 @@ #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); @@ -34,6 +43,8 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) { 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; @@ -47,10 +58,14 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) 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); } @@ -58,11 +73,12 @@ static void 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); } @@ -87,16 +103,17 @@ gst_rtsp_mount_points_new (void) 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); @@ -150,13 +167,17 @@ void 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); } /** @@ -170,10 +191,14 @@ void 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); } diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index 3ab6016..d8dd1b8 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -39,6 +39,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPMountPoints GstRTSPMountPoints; typedef struct _GstRTSPMountPointsClass GstRTSPMountPointsClass; +typedef struct _GstRTSPMountPointsPrivate GstRTSPMountPointsPrivate; /** * GstRTSPMountPoints: @@ -50,8 +51,7 @@ typedef struct _GstRTSPMountPointsClass GstRTSPMountPointsClass; struct _GstRTSPMountPoints { GObject parent; - GMutex lock; - GHashTable *mounts; + GstRTSPMountPointsPrivate *priv; }; /** diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 14ba38e..847b487 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -38,12 +38,12 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, 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); @@ -57,16 +57,19 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, 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; } @@ -152,6 +155,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, } gst_sdp_message_add_media (sdp, smedia); gst_sdp_media_free (smedia); + gst_caps_unref (caps); } return TRUE; diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index dfd4de8..f66b23a 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -23,6 +23,38 @@ #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" */ @@ -80,6 +112,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) { 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; @@ -185,36 +219,41 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) 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); } @@ -246,12 +285,16 @@ gst_rtsp_server_new (void) 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); } @@ -266,11 +309,15 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) 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; @@ -287,16 +334,19 @@ gst_rtsp_server_get_address (GstRTSPServer * server) 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); @@ -320,12 +370,16 @@ out: 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); } @@ -340,12 +394,15 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) 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; @@ -364,10 +421,14 @@ gst_rtsp_server_get_service (GstRTSPServer * server) 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); } @@ -382,12 +443,15 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog) 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; @@ -404,16 +468,19 @@ void 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) @@ -432,12 +499,15 @@ gst_rtsp_server_set_session_pool (GstRTSPServer * server, 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); @@ -455,16 +525,19 @@ void 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) @@ -484,12 +557,15 @@ gst_rtsp_server_set_mount_points (GstRTSPServer * server, 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); @@ -506,16 +582,19 @@ gst_rtsp_server_get_mount_points (GstRTSPServer * 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) @@ -535,12 +614,15 @@ gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth) 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); @@ -559,10 +641,14 @@ gst_rtsp_server_get_auth (GstRTSPServer * 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); } @@ -578,12 +664,15 @@ gst_rtsp_server_set_max_threads (GstRTSPServer * server, gint max_threads) 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; @@ -668,6 +757,7 @@ GSocket * gst_rtsp_server_create_socket (GstRTSPServer * server, GCancellable * cancellable, GError ** error) { + GstRTSPServerPrivate *priv; GSocketConnectable *conn; GSocketAddressEnumerator *enumerator; GSocket *socket = NULL; @@ -680,16 +770,18 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, 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); @@ -764,13 +856,13 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, 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); @@ -854,13 +946,14 @@ static void 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) @@ -877,13 +970,14 @@ static void 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 */ @@ -899,7 +993,7 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) 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) { @@ -913,17 +1007,18 @@ static GstRTSPClient * 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; @@ -1073,9 +1168,12 @@ accept_failed: 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); } @@ -1100,18 +1198,21 @@ GSource * 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) diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 3d56376..6df3a6d 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPServer GstRTSPServer; typedef struct _GstRTSPServerClass GstRTSPServerClass; +typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; #include "rtsp-session-pool.h" #include "rtsp-mount-points.h" @@ -41,10 +42,6 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; #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: * @@ -54,27 +51,7 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; 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; }; /** diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 31caca7..fb4d71c 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -20,6 +20,20 @@ #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, @@ -38,6 +52,8 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) { 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; @@ -49,26 +65,32 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) 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); } @@ -95,26 +117,66 @@ free_session_media (gpointer data) 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 @@ -128,21 +190,26 @@ GstRTSPStreamTransport * 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; @@ -161,14 +228,16 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, 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; } @@ -187,12 +256,16 @@ gboolean 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; } @@ -209,13 +282,64 @@ gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media, 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; } diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 2156f30..ed5284d 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -37,6 +37,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; typedef struct _GstRTSPSessionMediaClass GstRTSPSessionMediaClass; +typedef struct _GstRTSPSessionMediaPrivate GstRTSPSessionMediaPrivate; /** * GstRTSPSessionMedia: @@ -53,13 +54,7 @@ struct _GstRTSPSessionMedia { GObject parent; - GMutex lock; - GstRTSPUrl *url; - GstRTSPMedia *media; - GstRTSPState state; - guint counter; - - GPtrArray *transports; + GstRTSPSessionMediaPrivate *priv; }; struct _GstRTSPSessionMediaClass @@ -71,10 +66,20 @@ GType gst_rtsp_session_media_get_type (void); 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, diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 7a3231d..2fe209f 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -19,6 +19,17 @@ #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 @@ -54,6 +65,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) { 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; @@ -75,19 +88,24 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) 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); } @@ -152,11 +170,15 @@ gst_rtsp_session_pool_new (void) 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); } /** @@ -171,13 +193,16 @@ gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool * pool, guint max) 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; } @@ -193,13 +218,16 @@ gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool * pool) 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; } @@ -218,18 +246,21 @@ gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool) 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; } @@ -260,6 +291,7 @@ create_session_id (GstRTSPSessionPool * pool) GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) { + GstRTSPSessionPoolPrivate *priv; GstRTSPSession *result = NULL; GstRTSPSessionPoolClass *klass; gchar *id = NULL; @@ -267,6 +299,8 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) 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; @@ -281,14 +315,14 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) 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; @@ -300,9 +334,10 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) 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); @@ -323,14 +358,14 @@ no_session: 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; } @@ -348,14 +383,19 @@ too_many_sessions: 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; } @@ -378,18 +418,21 @@ cleanup_func (gchar * sessionid, GstRTSPSession * sess, GTimeVal * now) 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; } @@ -397,7 +440,7 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) typedef struct { GstRTSPSessionPool *pool; - GstRTSPSessionFilterFunc func; + GstRTSPSessionPoolFilterFunc func; gpointer user_data; GList *list; } FilterData; @@ -443,21 +486,24 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) */ 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; } @@ -489,15 +535,17 @@ collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc) 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; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index ede06ce..ca490de 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPSessionPool GstRTSPSessionPool; typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; +typedef struct _GstRTSPSessionPoolPrivate GstRTSPSessionPoolPrivate; #include "rtsp-session.h" @@ -51,10 +52,7 @@ typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; struct _GstRTSPSessionPool { GObject parent; - guint max_sessions; - - GMutex lock; - GHashTable *sessions; + GstRTSPSessionPoolPrivate *priv; }; /** @@ -83,22 +81,7 @@ struct _GstRTSPSessionPoolClass { 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() @@ -117,9 +100,9 @@ typedef enum * * 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); @@ -142,7 +125,7 @@ gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPoo /* 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); diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 7f22026..f50a476 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -20,6 +20,22 @@ #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 @@ -48,6 +64,8 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) { 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; @@ -71,9 +89,13 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) 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); } @@ -81,17 +103,19 @@ static void 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); } @@ -101,10 +125,11 @@ gst_rtsp_session_get_property (GObject * object, guint propid, 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)); @@ -119,11 +144,12 @@ gst_rtsp_session_set_property (GObject * object, guint propid, 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)); @@ -150,18 +176,22 @@ GstRTSPSessionMedia * 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); @@ -181,18 +211,21 @@ gboolean 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); @@ -212,24 +245,87 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, 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; } @@ -266,7 +362,7 @@ gst_rtsp_session_get_sessionid (GstRTSPSession * session) { g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL); - return session->sessionid; + return session->priv->sessionid; } /** @@ -280,17 +376,19 @@ gst_rtsp_session_get_sessionid (GstRTSPSession * session) 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; } @@ -306,11 +404,15 @@ gst_rtsp_session_get_header (GstRTSPSession * session) 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); } /** @@ -324,13 +426,16 @@ gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout) 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; } @@ -344,11 +449,15 @@ gst_rtsp_session_get_timeout (GstRTSPSession * session) 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); } /** @@ -362,7 +471,7 @@ gst_rtsp_session_prevent_expire (GstRTSPSession * session) { 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); } /** @@ -375,7 +484,7 @@ gst_rtsp_session_prevent_expire (GstRTSPSession * session) 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); } /** @@ -390,22 +499,25 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session) 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); diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index f5c4fcd..844795d 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -37,19 +37,28 @@ G_BEGIN_DECLS 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 @@ -58,15 +67,7 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass; 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 { @@ -102,6 +103,35 @@ gboolean gst_rtsp_session_release_media (GstRTSPSession *se 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__ */ diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 6df8d4d..0859573 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -20,11 +20,31 @@ #include #include -#include -#include - #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, @@ -44,6 +64,8 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) { 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; @@ -55,25 +77,31 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) 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); @@ -92,19 +120,37 @@ gst_rtsp_stream_transport_finalize (GObject * 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 @@ -120,12 +166,18 @@ gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport * trans, 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; } /** @@ -142,11 +194,17 @@ void 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; } @@ -162,13 +220,100 @@ void 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; } /** @@ -184,12 +329,15 @@ gboolean 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; } @@ -207,12 +355,15 @@ gboolean 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; } @@ -226,6 +377,10 @@ gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, 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); } diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 8839267..ed69faa 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -38,9 +38,9 @@ G_BEGIN_DECLS 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); @@ -48,41 +48,13 @@ 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 { @@ -94,8 +66,11 @@ GType gst_rtsp_stream_transport_get_type (void); 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, @@ -107,6 +82,15 @@ void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamT 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, diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6e35d8f..d1776e8 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -27,6 +27,56 @@ #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, @@ -47,6 +97,8 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPStreamPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_stream_finalize; @@ -59,30 +111,36 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) 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); } @@ -101,6 +159,7 @@ gst_rtsp_stream_finalize (GObject * 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); @@ -108,14 +167,31 @@ gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) 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 @@ -125,11 +201,15 @@ gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) 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); } /** @@ -143,11 +223,14 @@ gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu) 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; } @@ -163,18 +246,21 @@ void 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); @@ -192,14 +278,17 @@ gst_rtsp_stream_set_address_pool (GstRTSPStream * stream, 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; } @@ -216,20 +305,25 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) 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; @@ -237,13 +331,13 @@ gst_rtsp_stream_get_address (GstRTSPStream * stream) 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; } } @@ -252,6 +346,7 @@ no_address: static gboolean alloc_ports (GstRTSPStream * stream) { + GstRTSPStreamPrivate *priv = stream->priv; GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; GstElement *udpsink0, *udpsink1; @@ -261,8 +356,6 @@ alloc_ports (GstRTSPStream * stream) GSocket *socket; const gchar *host; - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - udpsrc0 = NULL; udpsrc1 = NULL; udpsink0 = NULL; @@ -272,7 +365,7 @@ alloc_ports (GstRTSPStream * stream) /* 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"; @@ -372,8 +465,7 @@ again: 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"); } @@ -391,12 +483,12 @@ again: /* 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; @@ -439,10 +531,58 @@ cleanup: } } +/** + * 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); @@ -450,10 +590,10 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) 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); @@ -472,6 +612,7 @@ dump_structure (const GstStructure * s) static GstRTSPStreamTransport * find_transport (GstRTSPStream * stream, const gchar * rtcp_from) { + GstRTSPStreamPrivate *priv = stream->priv; GList *walk; GstRTSPStreamTransport *result = NULL; const gchar *tmp; @@ -488,24 +629,26 @@ find_transport (GstRTSPStream * stream, const gchar * rtcp_from) 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); @@ -531,16 +674,11 @@ check_transport (GObject * source, GstRTSPStream * stream) 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; } @@ -601,8 +739,7 @@ on_bye_timeout (GObject * session, GObject * source, GstRTSPStream * stream) 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); } } @@ -614,14 +751,14 @@ on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) 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; @@ -632,19 +769,20 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) 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); @@ -675,6 +813,7 @@ gboolean 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; @@ -684,12 +823,14 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, 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); @@ -698,43 +839,43 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* 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++) { @@ -754,44 +895,44 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * '-----' '---------' '---------' */ /* 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); @@ -810,74 +951,74 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * '--------' '--------' */ /* 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; } } @@ -897,67 +1038,70 @@ gboolean 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; @@ -982,20 +1126,54 @@ gboolean 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 @@ -1010,16 +1188,18 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, 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); @@ -1043,16 +1223,18 @@ gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * 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); @@ -1066,12 +1248,10 @@ static gboolean 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: @@ -1091,46 +1271,44 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, 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; } @@ -1152,16 +1330,17 @@ gboolean 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; } @@ -1184,16 +1363,17 @@ gboolean 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; } diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index bdb50c2..3367fe2 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -38,6 +38,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPStream GstRTSPStream; typedef struct _GstRTSPStreamClass GstRTSPStreamClass; +typedef struct _GstRTSPStreamPrivate GstRTSPStreamPrivate; #include "rtsp-stream-transport.h" #include "rtsp-address-pool.h" @@ -45,79 +46,13 @@ typedef struct _GstRTSPStreamClass GstRTSPStreamClass; /** * 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 { @@ -128,9 +63,10 @@ GType gst_rtsp_stream_get_type (void); 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 * @@ -138,14 +74,20 @@ 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); diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index f7bff01..c1115de 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -93,7 +93,7 @@ GST_START_TEST (test_media) { GstRTSPMedia *media; - media = gst_rtsp_media_new (); + media = gst_rtsp_media_new (NULL); fail_unless (GST_IS_RTSP_MEDIA (media)); g_object_unref (media); } -- 2.7.4