#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "gmyth-stream-client.h" #define BUFFER_SIZE 1024 #define GMYTH_STREAM_CLIENT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_TYPE_STREAM_CLIENT,\ GMythStreamClientPrivate)) typedef struct _sock _socket; struct _sock { gint fd; struct sockaddr_in addr; }; typedef struct _GMythStreamClientPrivate GMythStreamClientPrivate; struct _GMythStreamClientPrivate { const gchar *host; _socket* sock; _socket* sock_stream; gboolean connected; }; static void gmyth_stream_client_class_init (GMythStreamClientClass *klass); static void gmyth_stream_client_init (GMythStreamClient *object); static void gmyth_stream_client_dispose (GObject *object); static void gmyth_stream_client_finalize (GObject *object); G_DEFINE_TYPE(GMythStreamClient, gmyth_stream_client, G_TYPE_OBJECT) static _socket* create_socket (const gchar* hostname, gint port) { _socket* sock = (_socket*)g_malloc(sizeof(_socket)); sock->fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock->fd == -1) { g_debug ("Fail to create sock"); g_free(sock); return NULL; } sock->addr.sin_family = AF_INET; sock->addr.sin_addr.s_addr = inet_addr(hostname); sock->addr.sin_port = htons(port); if (connect (sock->fd, (struct sockaddr *) &(sock->addr), \ sizeof (sock->addr)) == -1) { g_debug ("Fail to connect with server"); g_free(sock); return NULL; } return sock; } static gint read_message (int socket) { gint64 total_read = 0; gint result = -1; gchar buffer[BUFFER_SIZE]; gchar** response; total_read = recv(socket, buffer, BUFFER_SIZE, 0); if (total_read > 0) { response = g_strsplit_set(buffer, " +\n", 8); if ( g_ascii_strcasecmp(response[0], "OK") == 0 ) { int payload = atoi(response[1]); if (payload == 0) result = 0; else if (payload == 1) { total_read = recv(socket, buffer, BUFFER_SIZE, 0); response = g_strsplit_set(buffer, "+\n", 8); result = atoi(response[1]); } } g_strfreev(response); } return result; } static void gmyth_stream_client_class_init (GMythStreamClientClass *klass) { GObjectClass *gobject_class; gobject_class = (GObjectClass *) klass; g_type_class_add_private (klass, sizeof (GMythStreamClientPrivate)); gobject_class->dispose = gmyth_stream_client_dispose; gobject_class->finalize = gmyth_stream_client_finalize; } static void gmyth_stream_client_init (GMythStreamClient *self) { GMythStreamClientPrivate *priv = GMYTH_STREAM_CLIENT_GET_PRIVATE (self); priv->sock = NULL; priv->sock_stream = NULL; } static void gmyth_stream_client_dispose (GObject *object) { gmyth_stream_client_disconnect (GMYTH_STREAM_CLIENT (object)); } static void gmyth_stream_client_finalize (GObject *object) { } GMythStreamClient* gmyth_stream_client_new () { return GMYTH_STREAM_CLIENT (g_object_new (GMYTH_TYPE_STREAM_CLIENT, NULL)); } gboolean gmyth_stream_client_connect (GMythStreamClient *self, const gchar *server, guint port) { GMythStreamClientPrivate *priv = GMYTH_STREAM_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->connected == FALSE, TRUE); priv->host = server; priv->sock = create_socket (server, port); if (priv->sock == NULL) return FALSE; priv->connected = TRUE; return TRUE; } void gmyth_stream_client_disconnect (GMythStreamClient *self) { GMythStreamClientPrivate *priv = GMYTH_STREAM_CLIENT_GET_PRIVATE (self); g_return_if_fail (priv->connected == TRUE); close (priv->sock->fd); //shutdown (priv->sock->fd, SHUT_RDWR); g_free(priv->sock); priv->sock = NULL; priv->connected = FALSE; } gint gmyth_stream_client_open_stream (GMythStreamClient *self, const gchar* file_name, const gchar* mux, const gchar* vcodec, guint vbitrate, gdouble fps, const gchar* acodec, guint abitrate, guint width, guint height, const gchar* opt) { gchar *cmd; GMythStreamClientPrivate *priv = GMYTH_STREAM_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->connected == TRUE, FALSE); g_return_val_if_fail (file_name != NULL, FALSE); cmd = g_strdup_printf ("SETUP %s %s %s %d %f %s %d %d %d %s\n", file_name, (mux == NULL ? "X" : mux), (vcodec == NULL ? "X" : vcodec), vbitrate, fps, (acodec == NULL ? "X" : acodec), abitrate, width, height, (opt == NULL ? "X" : opt) ); if (send (priv->sock->fd, cmd, strlen (cmd), MSG_CONFIRM) == -1) { g_free (cmd); return -1; } g_free (cmd); read_message(priv->sock->fd); return 0; } gint gmyth_stream_client_play_stream (GMythStreamClient *self) { GMythStreamClientPrivate *priv = GMYTH_STREAM_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->connected == TRUE, FALSE); if (send (priv->sock->fd, "PLAY\n", 5, 0) == -1) { return -1; } gint port = read_message(priv->sock->fd); priv->sock_stream = create_socket(priv->host, port); return priv->sock_stream->fd; } void gmyth_stream_client_close_stream (GMythStreamClient *self) { GMythStreamClientPrivate *priv = GMYTH_STREAM_CLIENT_GET_PRIVATE (self); g_return_if_fail (priv->connected == TRUE); if (send (priv->sock->fd, "STOP\n", 5, 0) == -1) { return; } read_message(priv->sock->fd); close(priv->sock_stream->fd); g_free(priv->sock_stream); priv->sock_stream = NULL; }