gmyth/src/gmyth_monitor_handler.c
author rosfran
Tue Dec 05 21:57:35 2006 +0000 (2006-12-05)
branchtrunk
changeset 198 109630cf20ef
parent 192 b13b1e81f5af
child 199 4bed4ce6b681
permissions -rw-r--r--
[svn r199] Fixed problem with COxa.
     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 GMainContext *io_watcher_context = NULL;
    74 
    75 GThreadPool *monitor_th = NULL;
    76 
    77 enum myth_sock_types {
    78   GMYTH_PLAYBACK_TYPE = 0,
    79   GMYTH_MONITOR_TYPE,
    80   GMYTH_FILETRANSFER_TYPE,
    81   GMYTH_RINGBUFFER_TYPE
    82 };
    83 
    84 //static gboolean* myth_control_sock_listener( GIOChannel *io_channel );
    85 //static gboolean myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition, 
    86 //				gpointer data );
    87 
    88 static void myth_control_sock_listener( GIOChannel *io_channel, gboolean* ret );
    89 
    90 static GMutex*				mutex 					 = NULL;
    91 
    92 static GCond*					io_watcher_cond  = NULL;
    93 
    94 static void gmyth_monitor_handler_class_init          (GMythMonitorHandlerClass *klass);
    95 static void gmyth_monitor_handler_init                (GMythMonitorHandler *object);
    96 
    97 static void gmyth_monitor_handler_dispose  (GObject *object);
    98 static void gmyth_monitor_handler_finalize (GObject *object);
    99 
   100 static gboolean gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor);
   101 
   102 void gmyth_monitor_handler_close( GMythMonitorHandler *monitor );
   103 
   104 G_DEFINE_TYPE(GMythMonitorHandler, gmyth_monitor_handler, G_TYPE_OBJECT)
   105 
   106 static void
   107 gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass)
   108 {
   109   GObjectClass *gobject_class;
   110 
   111   gobject_class = (GObjectClass *) klass;
   112 
   113   gobject_class->dispose  = gmyth_monitor_handler_dispose;
   114   gobject_class->finalize = gmyth_monitor_handler_finalize;
   115 }
   116 
   117 static void
   118 gmyth_monitor_handler_init (GMythMonitorHandler *monitor)
   119 { 
   120   g_return_if_fail( monitor != NULL );
   121 
   122   monitor->event_sock = NULL;
   123   monitor->hostname = NULL;
   124   monitor->port = 0;
   125   monitor->actual_index = 0;
   126   
   127   monitor->backend_msgs = g_hash_table_new( g_int_hash, g_int_equal );
   128     
   129   /* it is used for signalizing the event socket consumer thread */
   130   io_watcher_cond = g_cond_new();
   131   
   132   /* mutex to control access to the event socket consumer thread */
   133   mutex = g_mutex_new();
   134 }
   135 
   136 static void
   137 gmyth_monitor_handler_dispose  (GObject *object)
   138 {
   139 	
   140 	GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER (object);
   141 	
   142   if ( monitor->event_sock != NULL )  
   143   {
   144   	g_object_unref( monitor->event_sock );
   145   	monitor->event_sock = NULL;
   146   }
   147   
   148   if ( monitor->hostname != NULL )  
   149   {
   150   	g_free( monitor->hostname );
   151   	monitor->hostname = NULL;
   152   }
   153 
   154   if ( monitor->backend_msgs != NULL )  
   155   {
   156   	g_hash_table_unref( monitor->backend_msgs );
   157   	monitor->backend_msgs = NULL;
   158   }
   159   
   160   if ( mutex != NULL )  
   161   {
   162   	g_mutex_free( mutex );
   163   	mutex = NULL;
   164   }
   165   
   166   if ( io_watcher_cond != NULL )  
   167   {
   168   	g_cond_free( io_watcher_cond );
   169   	io_watcher_cond = NULL;
   170   }
   171   
   172   if ( monitor_th != NULL )  
   173   {
   174   	g_thread_pool_free( monitor_th, TRUE, FALSE );
   175   	//g_object_unref( monitor_th );
   176   	monitor_th = NULL;
   177   }
   178 
   179   G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->dispose (object);
   180 }
   181 
   182 static void
   183 gmyth_monitor_handler_finalize (GObject *object)
   184 {
   185   g_signal_handlers_destroy (object);
   186 
   187   G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->finalize (object);
   188 }
   189 
   190 // fixme: do we need the card_id????
   191 GMythMonitorHandler*
   192 gmyth_monitor_handler_new (void)
   193 {
   194   GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER ( g_object_new (
   195 				GMYTH_MONITOR_HANDLER_TYPE, FALSE ));
   196 
   197   return monitor;
   198 }
   199 
   200 gboolean
   201 gmyth_monitor_handler_open (GMythMonitorHandler *monitor, gchar *hostname, gint port)
   202 {
   203   gboolean ret = TRUE;
   204 
   205   if (monitor->hostname != NULL) {
   206     g_free (monitor->hostname);
   207     monitor->hostname = NULL;
   208   }
   209 
   210   monitor->hostname = g_strdup( hostname );
   211   monitor->port = port;
   212 
   213   gmyth_debug ("Monitor event socket --- hostname: %s, port %d\n", monitor->hostname, monitor->port);
   214   
   215   /* configure the event socket */
   216   if (monitor->event_sock == NULL) { 
   217     if (!gmyth_connect_to_backend_monitor (monitor)) {
   218       g_printerr( "Connection to backend failed (Event Socket).\n" );
   219       ret = FALSE;
   220     }
   221   } else {
   222     g_warning("Remote monitor event socket already created.\n");
   223   }
   224 
   225   return ret;
   226 
   227 }
   228 
   229 static void
   230 //myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition, gpointer data )
   231 myth_control_sock_listener( GIOChannel *io_channel, gboolean* ret )
   232 {
   233 
   234   GIOStatus io_status;
   235   GError *error = NULL;
   236   GIOCondition io_cond;
   237   GIOCondition condition;
   238   gchar *trash = NULL;
   239   GByteArray *byte_array = NULL;
   240   guint recv = 0;
   241   ret = g_new0( gboolean, 1 );
   242   *ret = TRUE;
   243   //gboolean ret = TRUE;
   244   gsize len = 0;
   245   
   246   static guint count = 0;  
   247   
   248   
   249   //GMythMonitorHandler *monitor = (GMythMonitorHandler*)data;
   250   
   251   //myth_control_acquire_context (TRUE);
   252   
   253   if ( io_channel == NULL ) {
   254   	g_debug ("Monitor socket is NULL!\n");
   255   	*ret = FALSE;
   256   	goto clean_up;
   257   }
   258     
   259   while (TRUE) {
   260   	++count;
   261   	
   262   	gmyth_debug ("%d - Listening on Monitor socket...!\n", count);
   263 	  	
   264 	  condition = g_io_channel_get_buffer_condition( io_channel );	  
   265 	  //while ( !has_io_access ) 
   266 	  //	g_cond_wait( io_watcher_cond, mutex );
   267 	  	
   268 	  //myth_control_acquire_context (TRUE);  
   269 	  
   270 	  if (condition & G_IO_HUP) {
   271 	    gmyth_debug ("Read end of pipe died!\n");
   272 	    ret = FALSE;
   273 	    //goto clean_up;
   274 	  }
   275 	    
   276 	  //if ( ( condition & G_IO_IN ) != 0 ) {
   277 	  	byte_array = g_byte_array_new();
   278 	  	io_status = g_io_channel_set_encoding( io_channel, NULL, &error );
   279 	  	guint buffer_size = GMYTHTV_BUFFER_SIZE;
   280 	    do 
   281 	    {
   282 	      trash = g_new0( gchar, buffer_size );
   283 	
   284 	      io_status = g_io_channel_read_chars( io_channel, trash, 
   285 	      		buffer_size, &len, &error);
   286 	
   287 	      gmyth_debug ( "[%s] Received data buffer from IO binary channel... %d bytes gone!\n", 
   288 	      		__FUNCTION__, len );
   289 	      		
   290 	      recv += len;
   291 	      
   292 	      byte_array = g_byte_array_append( byte_array, (const guint8*)trash, len );
   293 	      
   294 	      if ( trash != NULL )
   295 	      	g_free( trash );
   296 	      	
   297 	      io_cond = g_io_channel_get_buffer_condition( io_channel );
   298 	
   299 	    } while ( ( io_cond & G_IO_IN ) != 0 );
   300 	    
   301 	    gmyth_debug ("\n\n\n[%s]\tEVENT: Read %d bytes: %s\n\n\n", __FUNCTION__, recv, byte_array != NULL && byte_array->data != NULL ? (gchar*)byte_array->data : "[no event data]" );
   302 	    
   303 	  //}	  
   304 	  
   305 	  if ( byte_array != NULL ) {
   306 	  	g_byte_array_free( byte_array, TRUE );
   307 	  	byte_array = NULL;
   308 	  }
   309 	  
   310 	  g_usleep( 300 );
   311 	  
   312   }
   313   
   314   if ( io_status == G_IO_STATUS_ERROR || error != NULL ) {
   315     gmyth_debug ("[%s] Error reading: %s\n", __FUNCTION__, error != NULL ? error->message : "" );
   316    	*ret = FALSE;
   317    	goto clean_up;   	
   318   }
   319   
   320   //g_hash_table_insert( monitor->backend_msgs, (gpointer)monitor->actual_index,
   321   //				  byte_array->data );
   322   
   323   //monitor->actual_index += recv;
   324 
   325 clean_up:
   326 
   327   if ( byte_array != NULL ) {
   328   	g_byte_array_free( byte_array, TRUE );
   329   	byte_array = NULL;
   330   }
   331   
   332   //return ret;
   333 
   334 }
   335 
   336 static gboolean
   337 gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor)
   338 {
   339   gboolean ret = TRUE;
   340 
   341   /* Creates the event socket */
   342   if (monitor->event_sock != NULL) {
   343     g_object_unref (monitor->event_sock);
   344     monitor->event_sock = NULL;
   345   }
   346 
   347   monitor->event_sock = gmyth_socket_new();
   348 
   349   /* Connects the socket, send Mythtv ANN Monitor and verify Mythtv protocol version */ 
   350   if (!gmyth_socket_connect_to_backend_events ( monitor->event_sock,
   351           monitor->hostname, monitor->port, FALSE ) ) 
   352   {
   353     g_object_unref (monitor->event_sock);
   354     monitor->event_sock = NULL;
   355     ret = FALSE;
   356   }
   357   
   358   return ret;
   359 }    
   360 
   361 static gboolean*
   362 myth_control_sock_setup( GIOChannel *channel )
   363 {
   364 	gboolean *ret = g_new0( gboolean, 1 );
   365 	//guint src_id = 0;
   366 	
   367 	*ret = TRUE;
   368 	
   369   io_watcher_context = g_main_context_default();
   370   GMainLoop *loop = g_main_loop_new( io_watcher_context, TRUE );
   371 
   372   GSource *source;
   373 
   374   if ( channel != NULL ) {
   375     source = g_io_create_watch( channel, G_IO_IN | G_IO_HUP );
   376     //src_id = g_io_add_watch( channel, G_IO_IN | G_IO_HUP, 
   377     //					(GSourceFunc)myth_control_sock_listener, NULL );
   378   } else {
   379   	*ret = FALSE;
   380   	goto cleanup;
   381   }
   382 
   383   g_source_set_callback ( source, (GSourceFunc)myth_control_sock_listener, NULL, NULL );
   384 
   385   g_source_attach( source, io_watcher_context );
   386   
   387   if (NULL == source){
   388     gmyth_debug( "[%s] Error adding watch listener function to the IO control channel!\n", __FUNCTION__ );
   389     *ret = FALSE;
   390     goto cleanup;
   391   }
   392   
   393   g_main_loop_run( loop );
   394   
   395 cleanup:
   396   if ( source != NULL )
   397     g_source_unref( source );
   398     
   399   //if ( io_watcher_context != NULL )
   400   //  g_main_context_unref( io_watcher_context );
   401 
   402   //if ( loop != NULL )
   403   //  g_main_loop_unref( loop );
   404     
   405   return ret;
   406   
   407 }
   408 
   409 gboolean 
   410 gmyth_monitor_handler_start (GMythMonitorHandler *monitor)
   411 {
   412 	gboolean *ret = g_new0( gboolean, 1 ); 
   413 	*ret = TRUE;	
   414 	
   415 	if (!g_thread_supported () ) 	g_thread_init (NULL);
   416 	
   417   monitor_th = g_thread_pool_new( (GFunc)myth_control_sock_listener, 
   418   					monitor->event_sock->sd_io_ch, 3, FALSE, NULL );
   419   					
   420   //if ( ( ret = g_thread_join( monitor_th ) ) == FALSE )
   421   if ( monitor_th != NULL )
   422   {
   423   	gmyth_debug ( "\n[%s]\tOK! Starting listener on the MONITOR event socket...[thread location = %p]\n", 
   424   				__FUNCTION__, g_thread_self( ) );
   425   	*ret = TRUE;  	  	
   426   } else {
   427   	gmyth_debug ( "\n[%s]\tERROR! Coudn't start listener on the MONITOR event socket...[thread location = %p]\n", 
   428   				__FUNCTION__, g_thread_self( ) );
   429   	*ret = FALSE;
   430   }
   431 
   432 //cleanup:
   433     
   434   gmyth_debug( "[%s] Watch listener function over the IO control channel? %s!!!\n", 
   435   			__FUNCTION__, ( *ret == TRUE ? "YES" : "NO" ) );
   436     
   437     return *ret;
   438 }
   439 
   440 void
   441 gmyth_monitor_handler_close( GMythMonitorHandler *monitor )
   442 {
   443 	
   444   if (monitor->event_sock) {
   445     g_object_unref( monitor->event_sock );
   446     monitor->event_sock = NULL;
   447   }
   448 
   449   if (monitor->hostname) {
   450     g_free( monitor->hostname );
   451     monitor->hostname = NULL;
   452   }
   453   
   454 }
   455