# HG changeset patch
# User rosfran
# Date 1165030820 0
# Node ID d021c43d190ce01331f28706c748f2c3742623ae
# Parent 49f0333ad361d0b7c31c8c8232857aba9f0a6664
[svn r176] Added the Monitor socket handler to receive backend event messages.
diff -r 49f0333ad361 -r d021c43d190c gmyth/src/gmyth_monitor_handler.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gmyth/src/gmyth_monitor_handler.c Sat Dec 02 03:40:20 2006 +0000
@@ -0,0 +1,429 @@
+/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */
+/**
+ * GMyth Library
+ *
+ * @file gmyth/gmyth_monitor_handler.c
+ *
+ * @brief
GMythMonitorHandler deals with the streaming media events remote/local
+ * that are sent to the MythTV frontend.
+ *
+ * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
+ * @author Rosfran Lins Borges
+ *
+ *//*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * GStreamer MythTV plug-in properties:
+ * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
+ * - path (qurl - remote file to be opened)
+ * - port number *
+ */
+
+#include "gmyth_uri.h"
+#include "gmyth_livetv.h"
+#include "gmyth_util.h"
+#include "gmyth_socket.h"
+#include "gmyth_stringlist.h"
+#include "gmyth_monitor_handler.h"
+#include "gmyth_debug.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define GMYTHTV_QUERY_HEADER "QUERY_FILETRANSFER "
+
+#define GMYTHTV_VERSION 30
+
+#define GMYTHTV_TRANSFER_MAX_WAITS 700
+
+#define GMYTHTV_BUFFER_SIZE 8*1024
+
+#ifdef GMYTHTV_ENABLE_DEBUG
+#define GMYTHTV_ENABLE_DEBUG 1
+#else
+#undef GMYTHTV_ENABLE_DEBUG
+#endif
+
+/* this NDEBUG is to maintain compatibility with GMyth library */
+#ifndef NDEBUG
+#define GMYTHTV_ENABLE_DEBUG 1
+#endif
+
+GThread *monitor_th = NULL;
+
+enum myth_sock_types {
+ GMYTH_PLAYBACK_TYPE = 0,
+ GMYTH_MONITOR_TYPE,
+ GMYTH_FILETRANSFER_TYPE,
+ GMYTH_RINGBUFFER_TYPE
+};
+
+static GStaticMutex st_mutex = G_STATIC_MUTEX_INIT;
+
+static gboolean* myth_control_sock_listener( GIOChannel *io_channel );
+//static gboolean myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition,
+// gpointer data );
+
+static GMutex* mutex = NULL;
+
+static GCond* io_watcher_cond = NULL;
+
+static GMainContext* io_watcher_context = NULL;
+
+static void gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass);
+static void gmyth_monitor_handler_init (GMythMonitorHandler *object);
+
+static void gmyth_monitor_handler_dispose (GObject *object);
+static void gmyth_monitor_handler_finalize (GObject *object);
+
+static gboolean gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor);
+
+void gmyth_monitor_handler_close( GMythMonitorHandler *monitor );
+
+static gboolean myth_control_acquire_context( gboolean do_wait );
+
+static gboolean myth_control_release_context( );
+
+G_DEFINE_TYPE(GMythMonitorHandler, gmyth_monitor_handler, G_TYPE_OBJECT)
+
+static void
+gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ gobject_class->dispose = gmyth_monitor_handler_dispose;
+ gobject_class->finalize = gmyth_monitor_handler_finalize;
+}
+
+static void
+gmyth_monitor_handler_init (GMythMonitorHandler *monitor)
+{
+ g_return_if_fail( monitor != NULL );
+
+ monitor->event_sock = NULL;
+ monitor->hostname = NULL;
+ monitor->port = 0;
+ monitor->actual_index = 0;
+
+ monitor->backend_msgs = g_hash_table_new( g_int_hash, g_int_equal );
+
+ /* it is used for signalizing the event socket consumer thread */
+ io_watcher_cond = g_cond_new();
+
+ /* mutex to control access to the event socket consumer thread */
+ mutex = g_mutex_new();
+}
+
+static void
+gmyth_monitor_handler_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->dispose (object);
+}
+
+static void
+gmyth_monitor_handler_finalize (GObject *object)
+{
+ g_signal_handlers_destroy (object);
+
+ G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->finalize (object);
+}
+
+// fixme: do we need the card_id????
+GMythMonitorHandler*
+gmyth_monitor_handler_new (void)
+{
+ GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER ( g_object_new (
+ GMYTH_MONITOR_HANDLER_TYPE, FALSE ));
+
+ return monitor;
+}
+
+gboolean
+gmyth_monitor_handler_open (GMythMonitorHandler *monitor, gchar *hostname, gint port)
+{
+ gboolean ret = TRUE;
+
+ if (monitor->hostname != NULL) {
+ g_free (monitor->hostname);
+ monitor->hostname = NULL;
+ }
+
+ monitor->hostname = g_strdup( hostname );
+ monitor->port = port;
+
+ gmyth_debug ("Monitor event socket --- hostname: %s, port %d\n", monitor->hostname, monitor->port);
+
+ /* configure the event socket */
+ if (monitor->event_sock == NULL) {
+ if (!gmyth_connect_to_backend_monitor (monitor)) {
+ g_printerr( "Connection to backend failed (Event Socket).\n" );
+ ret = FALSE;
+ }
+ } else {
+ g_warning("Remote monitor event socket already created.\n");
+ }
+
+ return ret;
+
+}
+
+static gboolean*
+//myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition, gpointer data )
+myth_control_sock_listener( GIOChannel *io_channel )
+{
+
+ GIOStatus io_status;
+ GError *error = NULL;
+ GIOCondition io_cond;
+ GIOCondition condition;
+ gchar *trash = NULL;
+ GByteArray *byte_array = NULL;
+ guint recv = 0;
+ gboolean* ret = g_new0( gboolean, 1 );
+ //gboolean ret = TRUE;
+ gsize len = 0;
+
+ //GMythMonitorHandler *monitor = (GMythMonitorHandler*)data;
+
+ //*ret = TRUE;
+ //myth_control_acquire_context (TRUE);
+
+ if ( io_channel == NULL ) {
+ g_debug ("Monitor socket is NULL!\n");
+ *ret = FALSE;
+ goto clean_up;
+ }
+ gmyth_debug ("Listening on Monitor socket...!\n");
+
+ while (TRUE) {
+
+ //condition = g_io_channel_get_buffer_condition( io_channel );
+
+ //myth_control_acquire_context (TRUE);
+
+ //while ( !has_io_access )
+ // g_cond_wait( io_watcher_cond, mutex );
+
+ //myth_control_acquire_context (TRUE);
+
+ if (condition & G_IO_HUP) {
+ gmyth_debug ("Read end of pipe died!\n");
+ *ret = FALSE;
+ goto clean_up;
+ }
+
+ if ( ( condition & G_IO_IN ) != 0 ) {
+ byte_array = g_byte_array_new();
+ io_status = g_io_channel_set_encoding( io_channel, NULL, &error );
+ guint buffer_size = GMYTHTV_BUFFER_SIZE;
+ do
+ {
+ trash = g_new0( gchar, buffer_size );
+
+ io_status = g_io_channel_read_chars( io_channel, trash,
+ buffer_size, &len, &error);
+
+ gmyth_debug ( "[%s] Received data buffer from IO binary channel... %d bytes gone!\n",
+ __FUNCTION__, len );
+
+ recv += len;
+
+ byte_array = g_byte_array_append( byte_array, (const guint8*)trash, len );
+
+ if ( trash != NULL )
+ g_free( trash );
+
+ io_cond = g_io_channel_get_buffer_condition( io_channel );
+
+ } while ( ( io_cond & G_IO_IN ) != 0 );
+ }
+
+ g_usleep( 300 );
+
+ }
+ //ret = g_io_channel_read_chars ( source, &msg, &len, NULL, &err);
+ if ( io_status == G_IO_STATUS_ERROR ) {
+ gmyth_debug ("[%s] Error reading: %s\n", __FUNCTION__, error != NULL ? error->message : "" );
+ *ret = FALSE;
+ goto clean_up;
+ }
+ gmyth_debug ("\n[%s]\tEVENT: Read %d bytes: %s\n\n", __FUNCTION__, recv, byte_array->data != NULL ? (gchar*)byte_array->data : "[no event data]" );
+
+ //g_hash_table_insert( monitor->backend_msgs, (gpointer)monitor->actual_index,
+ // byte_array->data );
+
+ //monitor->actual_index += recv;
+
+ if ( byte_array != NULL ) {
+ g_byte_array_free( byte_array, TRUE );
+ byte_array = NULL;
+ }
+
+clean_up:
+
+ return ret;
+
+}
+
+static gboolean
+gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor)
+{
+ gboolean ret = TRUE;
+
+ /* Creates the event socket */
+ if (monitor->event_sock != NULL) {
+ g_object_unref (monitor->event_sock);
+ monitor->event_sock = NULL;
+ }
+
+ monitor->event_sock = gmyth_socket_new();
+
+ /* Connects the socket, send Mythtv ANN Monitor and verify Mythtv protocol version */
+ if (!gmyth_socket_connect_to_backend_events ( monitor->event_sock,
+ monitor->hostname, monitor->port, FALSE ) )
+ {
+ g_object_unref (monitor->event_sock);
+ monitor->event_sock = NULL;
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+gboolean
+gmyth_monitor_handler_start (GMythMonitorHandler *monitor)
+{
+ gboolean ret = TRUE;
+
+ monitor_th = g_thread_create( (GThreadFunc)myth_control_sock_listener,
+ monitor->event_sock->sd_io_ch, TRUE, NULL );
+
+/*
+ io_watcher_context = g_main_context_default();
+ //GMainLoop *loop = g_main_loop_new( NULL, TRUE );
+
+ GSource *source;
+
+ if ( monitor->event_sock->sd_io_ch != NULL ) {
+ source = g_io_create_watch( monitor->event_sock->sd_io_ch, G_IO_IN );
+ //monitor->event_sock->sd_io_ch
+ } else {
+ ret = FALSE;
+ goto cleanup;
+ }
+
+ g_source_set_callback ( source, (GSourceFunc)myth_control_sock_listener, NULL, NULL );
+
+ g_source_attach( source, io_watcher_context );
+
+ if (source==NULL) {
+ gmyth_debug( "[%s] Error adding watch listener function to the IO control channel!\n", __FUNCTION__ );
+ goto cleanup;
+ }
+ */
+
+ gmyth_debug ( "[%s]\tOK! Starting listener on the MONITOR event socket...\n", __FUNCTION__ );
+
+ //g_main_loop_run( loop );
+
+cleanup:
+ //if ( source != NULL )
+ // g_source_unref( source );
+
+ gmyth_debug( "[%s] Watch listener function over the IO control channel? %s!!!\n",
+ __FUNCTION__, ( ret == TRUE ? "YES" : "NO" ) );
+
+ return ret;
+}
+
+void
+gmyth_monitor_handler_close( GMythMonitorHandler *monitor )
+{
+
+ if (monitor->event_sock) {
+ g_object_unref( monitor->event_sock );
+ monitor->event_sock = NULL;
+ }
+
+ if (monitor->hostname) {
+ g_free( monitor->hostname );
+ monitor->hostname = NULL;
+ }
+
+}
+
+static gboolean
+myth_control_acquire_context( gboolean do_wait )
+{
+
+ gboolean ret = TRUE;
+ //guint max_iter = 50;
+
+ //g_mutex_lock( mutex );
+
+ //while ( !has_io_access )
+ // g_cond_wait( io_watcher_cond, mutex );
+
+ //has_io_access = FALSE;
+
+ //myth_control_acquire_context (FALSE);
+
+ /*
+ if ( do_wait ) {
+ while ( --max_iter > 0 && !g_main_context_wait( io_watcher_context, io_watcher_cond, mutex ) )
+ ret = FALSE;
+ } else if ( !g_main_context_acquire( io_watcher_context ) )
+ ret = FALSE;
+ */
+
+ //g_static_mutex_lock( &st_mutex );
+
+ return ret;
+
+}
+
+static gboolean
+myth_control_release_context( )
+{
+
+ gboolean ret = TRUE;
+
+ //g_static_mutex_unlock( &st_mutex );
+
+ //g_main_context_release( io_watcher_context );
+
+ //g_main_context_wakeup( io_watcher_context );
+
+ //has_io_access = TRUE;
+
+ //g_cond_broadcast( io_watcher_cond );
+
+ //g_mutex_unlock( mutex );
+
+ return ret;
+
+}
+
diff -r 49f0333ad361 -r d021c43d190c gmyth/src/gmyth_monitor_handler.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gmyth/src/gmyth_monitor_handler.h Sat Dec 02 03:40:20 2006 +0000
@@ -0,0 +1,100 @@
+/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */
+/**
+ * GMyth Library
+ *
+ * @file gmyth/gmyth_monitor_handler.h
+ *
+ * @brief GMythMonitorHandler deals with the streaming media events remote/local
+ * that are sent to the MythTV frontend.
+ *
+ * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
+ * @author Rosfran Lins Borges
+ *
+ *//*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __GMYTH_MONITOR_HANDLER_H__
+#define __GMYTH_MONITOR_HANDLER_H__
+
+#include
+#include
+
+#include "gmyth_socket.h"
+#include "gmyth_uri.h"
+#include "gmyth_livetv.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define G_BEGIN_DECLS
+
+#define GMYTH_MONITOR_HANDLER_TYPE (gmyth_monitor_handler_get_type ())
+#define GMYTH_MONITOR_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_MONITOR_HANDLER_TYPE, GMythMonitorHandler))
+#define GMYTH_MONITOR_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_MONITOR_HANDLER_TYPE, GMythMonitorHandlerClass))
+#define IS_GMYTH_MONITOR_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_MONITOR_HANDLER_TYPE))
+#define IS_GMYTH_MONITOR_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_MONITOR_HANDLER_TYPE))
+#define GMYTH_MONITOR_HANDLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_MONITOR_HANDLER_TYPE, GMythMonitorHandlerClass))
+
+#define GMYTHTV_MONITOR_HANDLER_READ_ERROR -314
+
+typedef struct _GMythMonitorHandler GMythMonitorHandler;
+typedef struct _GMythMonitorHandlerClass GMythMonitorHandlerClass;
+
+struct _GMythMonitorHandlerClass
+{
+ GObjectClass parent_class;
+
+ /* callbacks */
+ /* no one for now */
+};
+
+struct _GMythMonitorHandler
+{
+ GObject parent;
+
+ /* MythTV version number */
+ gint mythtv_version;
+
+ /* socket descriptors */
+ GMythSocket *event_sock;
+
+ gchar *hostname;
+ gint port;
+
+ gint64 actual_index;
+
+ /* stores the messages coming from the backend */
+ GHashTable *backend_msgs;
+};
+
+GType gmyth_monitor_handler_get_type (void);
+
+GMythMonitorHandler* gmyth_monitor_handler_new (void);
+
+gboolean gmyth_monitor_handler_open (GMythMonitorHandler *monitor, gchar *hostname, gint port);
+
+gboolean gmyth_monitor_handler_start (GMythMonitorHandler *monitor);
+
+void gmyth_monitor_handler_close (GMythMonitorHandler *monitor);
+
+#define G_END_DECLS
+
+#endif /* __GMYTH_MONITOR_HANDLER_H__ */