gmyth/src/gmyth_monitor_handler.c
author renatofilho
Mon Dec 04 22:00:41 2006 +0000 (2006-12-04)
branchtrunk
changeset 187 653d06bca826
parent 186 08b70ec67aa4
child 192 b13b1e81f5af
permissions -rw-r--r--
[svn r188] bug fix
     1 /* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */
     2 /**
     3  * GMyth Library
     4  *
     5  * @file gmyth/gmyth_monitor_handler.c
     6  * 
     7  * @brief <p> GMythMonitorHandler deals with the streaming media events remote/local
     8  * that are sent to the MythTV frontend.
     9  *
    10  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
    11  * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
    12  *
    13  *//*
    14  * 
    15  * This program is free software; you can redistribute it and/or modify
    16  * it under the terms of the GNU Lesser General Public License as published by
    17  * the Free Software Foundation; either version 2 of the License, or
    18  * (at your option) any later version.
    19  *
    20  * This program is distributed in the hope that it will be useful,
    21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    23  * GNU General Public License for more details.
    24  *
    25  * You should have received a copy of the GNU Lesser General Public License
    26  * along with this program; if not, write to the Free Software
    27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    28  *
    29  * GStreamer MythTV plug-in properties:
    30  * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
    31  * - path (qurl - remote file to be opened)
    32  * - port number *   
    33  */
    34 
    35 #include "gmyth_uri.h"
    36 #include "gmyth_livetv.h"
    37 #include "gmyth_util.h"
    38 #include "gmyth_socket.h"
    39 #include "gmyth_stringlist.h"
    40 #include "gmyth_monitor_handler.h"
    41 #include "gmyth_debug.h"
    42 
    43 #include <unistd.h>
    44 #include <glib.h>
    45 
    46 #include <arpa/inet.h>
    47 #include <sys/types.h>
    48 #include <sys/socket.h>
    49 #include <netdb.h>
    50 #include <errno.h>
    51 #include <stdlib.h>
    52 #include <assert.h>
    53 
    54 #define GMYTHTV_QUERY_HEADER		"QUERY_FILETRANSFER "
    55 
    56 #define GMYTHTV_VERSION							30
    57 
    58 #define GMYTHTV_TRANSFER_MAX_WAITS	700
    59 
    60 #define GMYTHTV_BUFFER_SIZE					8*1024
    61 
    62 #ifdef GMYTHTV_ENABLE_DEBUG
    63 #define GMYTHTV_ENABLE_DEBUG				1
    64 #else
    65 #undef GMYTHTV_ENABLE_DEBUG
    66 #endif
    67 
    68 /* this NDEBUG is to maintain compatibility with GMyth library */
    69 #ifndef NDEBUG
    70 #define GMYTHTV_ENABLE_DEBUG				1
    71 #endif
    72 
    73 GThread *monitor_th = NULL;
    74 
    75 enum myth_sock_types {
    76   GMYTH_PLAYBACK_TYPE = 0,
    77   GMYTH_MONITOR_TYPE,
    78   GMYTH_FILETRANSFER_TYPE,
    79   GMYTH_RINGBUFFER_TYPE
    80 };
    81 
    82 static gboolean* myth_control_sock_listener( GIOChannel *io_channel );
    83 //static gboolean myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition, 
    84 //				gpointer data );
    85 
    86 static GMutex*				mutex 					 = NULL;
    87 
    88 static GCond*					io_watcher_cond  = NULL;
    89 
    90 static void gmyth_monitor_handler_class_init          (GMythMonitorHandlerClass *klass);
    91 static void gmyth_monitor_handler_init                (GMythMonitorHandler *object);
    92 
    93 static void gmyth_monitor_handler_dispose  (GObject *object);
    94 static void gmyth_monitor_handler_finalize (GObject *object);
    95 
    96 static gboolean gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor);
    97 
    98 void gmyth_monitor_handler_close( GMythMonitorHandler *monitor );
    99 
   100 G_DEFINE_TYPE(GMythMonitorHandler, gmyth_monitor_handler, G_TYPE_OBJECT)
   101 
   102 static void
   103 gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass)
   104 {
   105   GObjectClass *gobject_class;
   106 
   107   gobject_class = (GObjectClass *) klass;
   108 
   109   gobject_class->dispose  = gmyth_monitor_handler_dispose;
   110   gobject_class->finalize = gmyth_monitor_handler_finalize;
   111 }
   112 
   113 static void
   114 gmyth_monitor_handler_init (GMythMonitorHandler *monitor)
   115 { 
   116   g_return_if_fail( monitor != NULL );
   117 
   118   monitor->event_sock = NULL;
   119   monitor->hostname = NULL;
   120   monitor->port = 0;
   121   monitor->actual_index = 0;
   122   
   123   monitor->backend_msgs = g_hash_table_new( g_int_hash, g_int_equal );
   124     
   125   /* it is used for signalizing the event socket consumer thread */
   126   io_watcher_cond = g_cond_new();
   127   
   128   /* mutex to control access to the event socket consumer thread */
   129   mutex = g_mutex_new();
   130 }
   131 
   132 static void
   133 gmyth_monitor_handler_dispose  (GObject *object)
   134 {
   135   G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->dispose (object);
   136 }
   137 
   138 static void
   139 gmyth_monitor_handler_finalize (GObject *object)
   140 {
   141   g_signal_handlers_destroy (object);
   142 
   143   G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->finalize (object);
   144 }
   145 
   146 // fixme: do we need the card_id????
   147 GMythMonitorHandler*
   148 gmyth_monitor_handler_new (void)
   149 {
   150   GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER ( g_object_new (
   151 				GMYTH_MONITOR_HANDLER_TYPE, FALSE ));
   152 
   153   return monitor;
   154 }
   155 
   156 gboolean
   157 gmyth_monitor_handler_open (GMythMonitorHandler *monitor, gchar *hostname, gint port)
   158 {
   159   gboolean ret = TRUE;
   160 
   161   if (monitor->hostname != NULL) {
   162     g_free (monitor->hostname);
   163     monitor->hostname = NULL;
   164   }
   165 
   166   monitor->hostname = g_strdup( hostname );
   167   monitor->port = port;
   168 
   169   gmyth_debug ("Monitor event socket --- hostname: %s, port %d\n", monitor->hostname, monitor->port);
   170   
   171   /* configure the event socket */
   172   if (monitor->event_sock == NULL) { 
   173     if (!gmyth_connect_to_backend_monitor (monitor)) {
   174       g_printerr( "Connection to backend failed (Event Socket).\n" );
   175       ret = FALSE;
   176     }
   177   } else {
   178     g_warning("Remote monitor event socket already created.\n");
   179   }
   180 
   181   return ret;
   182 
   183 }
   184 
   185 static gboolean*
   186 //myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition, gpointer data )
   187 myth_control_sock_listener( GIOChannel *io_channel )
   188 {
   189 
   190   GIOStatus io_status;
   191   GError *error = NULL;
   192   GIOCondition io_cond;
   193   GIOCondition condition;
   194   gchar *trash = NULL;
   195   GByteArray *byte_array = NULL;
   196   guint recv = 0;
   197   gboolean* ret = g_new0( gboolean, 1 );
   198   //gboolean ret = TRUE;
   199   gsize len = 0;
   200   
   201   //GMythMonitorHandler *monitor = (GMythMonitorHandler*)data;
   202   
   203   *ret = TRUE;
   204   //myth_control_acquire_context (TRUE);
   205   
   206   if ( io_channel == NULL ) {
   207   	g_debug ("Monitor socket is NULL!\n");
   208   	*ret = FALSE;
   209   	goto clean_up;
   210   }
   211   gmyth_debug ("Listening on Monitor socket...!\n");
   212   
   213   while (TRUE) {
   214 	  	
   215 	  condition = g_io_channel_get_buffer_condition( io_channel );
   216 	  
   217 	  //myth_control_acquire_context (TRUE);
   218 	  
   219 	  //while ( !has_io_access ) 
   220 	  //	g_cond_wait( io_watcher_cond, mutex );
   221 	  	
   222 	  //myth_control_acquire_context (TRUE);  
   223 	  
   224 	  if (condition & G_IO_HUP) {
   225 	    gmyth_debug ("Read end of pipe died!\n");
   226 	    *ret = FALSE;
   227 	    //goto clean_up;
   228 	  }
   229 	    
   230 	  if ( ( condition & G_IO_IN ) != 0 ) {
   231 	  	byte_array = g_byte_array_new();
   232 	  	io_status = g_io_channel_set_encoding( io_channel, NULL, &error );
   233 	  	guint buffer_size = GMYTHTV_BUFFER_SIZE;
   234 	    do 
   235 	    {
   236 	      trash = g_new0( gchar, buffer_size );
   237 	
   238 	      io_status = g_io_channel_read_chars( io_channel, trash, 
   239 	      		buffer_size, &len, &error);
   240 	
   241 	      gmyth_debug ( "[%s] Received data buffer from IO binary channel... %d bytes gone!\n", 
   242 	      		__FUNCTION__, len );
   243 	      		
   244 	      recv += len;
   245 	      
   246 	      byte_array = g_byte_array_append( byte_array, (const guint8*)trash, len );
   247 	      
   248 	      if ( trash != NULL )
   249 	      	g_free( trash );
   250 	      	
   251 	      io_cond = g_io_channel_get_buffer_condition( io_channel );
   252 	
   253 	    } while ( ( io_cond & G_IO_IN ) != 0 );
   254 	    gmyth_debug ("\n[%s]\tEVENT: Read %d bytes: %s\n\n", __FUNCTION__, recv, byte_array != NULL && byte_array->data != NULL ? (gchar*)byte_array->data : "[no event data]" );
   255 	  }	  
   256 	  
   257 	  if ( byte_array != NULL ) {
   258 	  	g_byte_array_free( byte_array, TRUE );
   259 	  	byte_array = NULL;
   260 	  }
   261 	  
   262 	  g_usleep( 300 );
   263 	  
   264   }
   265   //ret = g_io_channel_read_chars ( source, &msg, &len, NULL, &err);
   266   if ( io_status == G_IO_STATUS_ERROR ) {
   267     gmyth_debug ("[%s] Error reading: %s\n", __FUNCTION__, error != NULL ? error->message : "" );
   268    	*ret = FALSE;
   269    	goto clean_up;   	
   270   }
   271   
   272   //g_hash_table_insert( monitor->backend_msgs, (gpointer)monitor->actual_index,
   273   //				  byte_array->data );
   274   
   275   //monitor->actual_index += recv;
   276 
   277 clean_up:
   278   
   279   return ret;
   280 
   281 }
   282 
   283 static gboolean
   284 gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor)
   285 {
   286   gboolean ret = TRUE;
   287 
   288   /* Creates the event socket */
   289   if (monitor->event_sock != NULL) {
   290     g_object_unref (monitor->event_sock);
   291     monitor->event_sock = NULL;
   292   }
   293 
   294   monitor->event_sock = gmyth_socket_new();
   295 
   296   /* Connects the socket, send Mythtv ANN Monitor and verify Mythtv protocol version */ 
   297   if (!gmyth_socket_connect_to_backend_events ( monitor->event_sock,
   298           monitor->hostname, monitor->port, FALSE ) ) 
   299   {
   300     g_object_unref (monitor->event_sock);
   301     monitor->event_sock = NULL;
   302     ret = FALSE;
   303   }
   304   
   305   return ret;
   306 }    
   307 
   308 gboolean 
   309 gmyth_monitor_handler_start (GMythMonitorHandler *monitor)
   310 {
   311     monitor_th = g_thread_create( (GThreadFunc)myth_control_sock_listener, 
   312   					monitor->event_sock->sd_io_ch, TRUE, NULL );
   313 
   314     gmyth_debug( "[%s] Watch listener function over the IO control channel? %s!!!\n", 
   315   			__FUNCTION__, ( ret == TRUE ? "YES" : "NO" ) );
   316     
   317     return TRUE;
   318 }
   319 
   320 void
   321 gmyth_monitor_handler_close( GMythMonitorHandler *monitor )
   322 {
   323 	
   324   if (monitor->event_sock) {
   325     g_object_unref( monitor->event_sock );
   326     monitor->event_sock = NULL;
   327   }
   328 
   329   if (monitor->hostname) {
   330     g_free( monitor->hostname );
   331     monitor->hostname = NULL;
   332   }
   333   
   334 }
   335