[svn r424] Added documention.
4 * @file gmyth/gmyth_monitor_handler.c
6 * @brief <p> GMythMonitorHandler deals with the streaming media events remote/local
7 * that are sent to the MythTV frontend.
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * GStreamer MythTV plug-in properties:
29 * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
30 * - path (qurl - remote file to be opened)
40 #include <arpa/inet.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
48 #include "gmyth_marshal.h"
50 #include "gmyth_monitor_handler.h"
54 #define GMYTHTV_QUERY_HEADER "QUERY_FILETRANSFER "
56 #define GMYTHTV_VERSION 30
58 #define GMYTHTV_TRANSFER_MAX_WAITS 700
60 #define GMYTHTV_BUFFER_SIZE 8*1024
62 #ifdef GMYTHTV_ENABLE_DEBUG
63 #define GMYTHTV_ENABLE_DEBUG 1
65 #undef GMYTHTV_ENABLE_DEBUG
68 /* this NDEBUG is to maintain compatibility with GMyth library */
70 #define GMYTHTV_ENABLE_DEBUG 1
73 gboolean gmyth_monitor_handler_listener( GIOChannel *io_channel,
74 GIOCondition io_cond, gpointer data );
76 static void gmyth_monitor_handler_default_listener( GMythMonitorHandler *monitor, gint msg_code, gchar* message );
78 static void gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass);
79 static void gmyth_monitor_handler_init (GMythMonitorHandler *object);
81 static void gmyth_monitor_handler_dispose (GObject *object);
82 static void gmyth_monitor_handler_finalize (GObject *object);
84 static gboolean gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor);
86 void gmyth_monitor_handler_close( GMythMonitorHandler *monitor );
88 G_DEFINE_TYPE(GMythMonitorHandler, gmyth_monitor_handler, G_TYPE_OBJECT)
91 gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass)
93 GObjectClass *gobject_class;
94 GMythMonitorHandlerClass *gmonitor_class;
96 gobject_class = (GObjectClass *) klass;
97 gmonitor_class = (GMythMonitorHandlerClass *) gobject_class;
99 gobject_class->dispose = gmyth_monitor_handler_dispose;
100 gobject_class->finalize = gmyth_monitor_handler_finalize;
102 gmonitor_class->backend_events_handler_signal_id =
103 g_signal_new ("backend-events-handler",
104 G_TYPE_FROM_CLASS (gmonitor_class),
105 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
109 gmyth_marshal_VOID__INT_STRING,
115 gmonitor_class->backend_events_handler = gmyth_monitor_handler_default_listener;
120 gmyth_monitor_handler_init (GMythMonitorHandler *monitor)
122 g_return_if_fail( monitor != NULL );
124 monitor->event_sock = NULL;
125 monitor->hostname = NULL;
127 monitor->actual_index = 0;
129 monitor->allow_msgs_listener = FALSE;
131 /* monitor->backend_msgs = g_hash_table_new( g_int_hash, g_int_equal ); */
133 /* it is used for signalizing the event socket consumer thread */
134 monitor->mutex = g_mutex_new();
136 monitor->sid_io_watch = -1;
138 monitor->gmyth_monitor_handler_listener = gmyth_monitor_handler_listener;
142 gmyth_monitor_handler_dispose (GObject *object)
144 GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER (object);
145 GSource* source = NULL;
146 GMainContext* context = g_main_context_default();
148 gmyth_monitor_handler_close(monitor);
150 monitor->allow_msgs_listener = FALSE;
152 if ( context != NULL && monitor->sid_io_watch != -1 )
154 g_main_context_acquire( context );
156 source = g_main_context_find_source_by_id( context,
157 monitor->sid_io_watch );
159 if ( source != NULL )
161 g_source_destroy( source );
164 g_main_context_release( context );
168 /* mutex to control access to the event socket consumer thread */
169 if ( monitor->mutex != NULL )
171 g_mutex_free( monitor->mutex );
172 monitor->mutex = NULL;
175 if ( monitor->event_sock != NULL )
177 g_object_unref( monitor->event_sock );
178 /*gmyth_socket_close_connection( monitor->event_sock );*/
179 monitor->event_sock = NULL;
182 if ( monitor->hostname != NULL )
184 g_free( monitor->hostname );
185 monitor->hostname = NULL;
188 if ( monitor->backend_msgs != NULL )
190 g_hash_table_destroy ( monitor->backend_msgs );
191 monitor->backend_msgs = NULL;
195 if ( io_watcher_cond != NULL )
197 g_cond_free( io_watcher_cond );
198 io_watcher_cond = NULL;
202 G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->dispose (object);
206 gmyth_monitor_handler_finalize (GObject *object)
208 g_signal_handlers_destroy (object);
210 G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->finalize (object);
214 * Creates a new instance of GMyth Monitor Handler.
216 * @return a new instance of the Monitor Handler.
219 gmyth_monitor_handler_new ( void )
221 GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER (
222 g_object_new ( GMYTH_MONITOR_HANDLER_TYPE, FALSE ) );
228 * Acquire the mutex to have access to the IO Watcher listener.
230 * @param monitor The GMythMonitorHandler instance.
231 * @param do_wait Tells the IO Watcher to wait on the GCond. (obsolete)
233 * @return <code>true</code>, if the access to IO Watcher was acquired.
236 myth_control_acquire_context( GMythMonitorHandler *monitor, gboolean do_wait )
241 g_mutex_lock( monitor->mutex );
248 * Release the mutex to have access to the IO Watcher listener.
250 * @param monitor The GMythMonitorHandler instance.
252 * @return <code>true</code>, if the access to IO Watcher was released.
255 myth_control_release_context( GMythMonitorHandler *monitor )
260 g_mutex_unlock( monitor->mutex );
267 gmyth_monitor_handler_close (GMythMonitorHandler *monitor)
269 monitor->allow_msgs_listener = FALSE;
272 if ( monitor->monitor_th != NULL )
274 g_thread_pool_free( monitor->monitor_th, TRUE, FALSE );
275 //g_thread_exit( monitor->monitor_th );
276 /*if ( monitor->monitor_th != NULL )
277 g_object_unref( monitor->monitor_th );*/
278 monitor->monitor_th = NULL;
281 if ( monitor->event_sock != NULL )
283 gmyth_socket_close_connection( monitor->event_sock );
290 * Opens connection the the Monitor socket on MythTV backend server,
291 * where all status messages are notified to the client.
293 * @param monitor The GMythMonitorHandler instance.
294 * @param hostname The remote host name of the MythTV backend server.
295 * @param port The remote port number of the MythTV backend server.
297 * @return <code>true</code>, if the connection was successfully opened.
300 gmyth_monitor_handler_open (GMythMonitorHandler *monitor, const gchar *hostname, gint port)
304 g_return_val_if_fail( hostname != NULL, FALSE );
306 if (monitor->hostname != NULL) {
307 g_free (monitor->hostname);
308 monitor->hostname = NULL;
311 monitor->hostname = g_strdup( hostname );
312 monitor->port = port;
314 gmyth_debug ("Monitor event socket --- hostname: %s, port %d\n", monitor->hostname, monitor->port);
316 /* configure the event socket */
317 //if ( NULL == monitor->event_sock ) {
318 if (!gmyth_connect_to_backend_monitor (monitor)) {
319 gmyth_debug( "Connection to backend failed (Event Socket)." );
323 g_warning("Remote monitor event socket already created.\n");
331 * Reads the data got from the connection to the Monitor socket,
332 * and looks for some important status messages.
334 * @param monitor The GMythMonitorHandler instance.
335 * @param strlist The GMythStringList instance got from the Monitor remote socket.
336 * @param back_msg_action A string pointer to the status message detailed description.
338 * @return The backend status message code ID.
341 gmyth_monitor_handler_is_backend_message( GMythMonitorHandler *monitor,
342 GMythStringList* strlist, gchar **back_msg_action )
344 gint msg_type = GMYTH_BACKEND_NO_MESSAGE;
345 GString *back_msg = NULL;
347 if ( gmyth_string_list_length(strlist) > 0 )
350 back_msg = gmyth_string_list_get_string( strlist, 0 );
351 if ( back_msg != NULL && back_msg->str != NULL &&
352 strstr( back_msg->str, "BACKEND" ) != NULL )
354 gmyth_debug( "MONITOR HANDLER - Received backend message = %s", back_msg->str );
355 *back_msg_action = gmyth_string_list_get_char_array( strlist, 1 );
357 if ( back_msg_action != NULL )
360 if ( g_strstr_len( *back_msg_action, strlen( *back_msg_action ), "LIVETV_CHAIN" ) ||
361 g_strstr_len( *back_msg_action, strlen( *back_msg_action ), "RECORDING_LIST_CHANGE" ) ||
362 g_strstr_len( *back_msg_action, strlen( *back_msg_action ), "SCHEDULE_CHANGE" ) ||
363 g_strstr_len( *back_msg_action, strlen( *back_msg_action ), "LIVETV_WATCH" ) )
365 gmyth_debug( "MONITOR: message type == GMYTH_BACKEND_PROGRAM_INFO_CHANGED, msg = %s", *back_msg_action );
366 msg_type = GMYTH_BACKEND_PROGRAM_INFO_CHANGED;
367 } else if ( g_strstr_len( *back_msg_action, strlen( *back_msg_action ), "DONE_RECORDING" ) ) {
368 gmyth_debug( "MONITOR: message type == GMYTH_BACKEND_DONE_RECORDING, msg = %s", *back_msg_action );
369 msg_type = GMYTH_BACKEND_DONE_RECORDING;
370 } else if ( g_strstr_len( *back_msg_action, strlen( *back_msg_action ), "QUIT" ) ) {
371 gmyth_debug( "MONITOR: message type == GMYTH_BACKEND_STOP_LIVETV, msg = %s", *back_msg_action );
372 msg_type = GMYTH_BACKEND_STOP_LIVETV;
375 /* g_hash_table_insert ( monitor->backend_msgs,
376 &(monitor->actual_index), *back_msg_action ); */
382 if ( back_msg != NULL )
384 g_string_free( back_msg, TRUE );
388 } /* if - Does Monitor got any message from backend? */
390 *back_msg_action = g_strdup("");
398 gmyth_monitor_handler_default_listener( GMythMonitorHandler *monitor, gint msg_code, gchar* message )
400 //assert( message!= NULL );
401 gmyth_debug( "DEFAULT Signal handler ( msg = %s, code = %d )\n",
406 gmyth_monitor_handler_print( GString *str, gpointer ptr )
408 gmyth_debug( "Backend message event: %s --- ", str->str );
412 * Opens connection the the Monitor socket on MythTV backend server,
413 * where all status messages are notified to the client.
415 * @param io_channel The GIOChannel instance to the Monitor connection.
416 * @param io_cond The GIOCondition describing the actual status of the IO Channel.
417 * @param data Pointer to the GMythMonitorHandler.
419 * @return <code>true</code>, if the data was successfully read.
422 gmyth_monitor_handler_listener( GIOChannel *io_channel, GIOCondition io_cond, gpointer data )
424 GMythMonitorHandler *monitor = (GMythMonitorHandler*)data;
426 //GIOCondition io_cond;
428 gboolean *ret = g_new0( gboolean, 1 );
430 //gboolean ret = TRUE;
433 static guint count = 0;
435 myth_control_acquire_context ( monitor, TRUE );
437 if ( ( io_cond & G_IO_HUP ) != 0 )
443 //GIOChannel *io_channel = monitor->event_sock->sd_io_ch;
444 //GIOCondition condition = g_io_channel_get_buffer_condition( io_channel );
446 GMythStringList *strlist = NULL;
448 if ( NULL == io_channel ) {
449 gmyth_debug ("Monitor socket is NULL! (GIOChannel)");
454 if (monitor->allow_msgs_listener) {
457 gmyth_debug ("%d - Listening on Monitor socket...!\n", count);
464 strlist = gmyth_string_list_new();
466 if ( monitor->event_sock != NULL )
469 len = gmyth_socket_read_stringlist( monitor->event_sock, strlist );
471 if ( ( len > 0 ) && strlist != NULL && gmyth_string_list_length( strlist ) > 0 )
473 bytes_sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error
475 gmyth_debug ( "[%s] MONITOR: received data buffer from IO event channel... %d strings gone!\n",
480 /* debug purpose: prints out all the string list elements */
481 g_list_foreach( strlist->glist, (GFunc)gmyth_monitor_handler_print, NULL );
483 gchar *back_msg_action = g_new0( gchar, 1 );
484 gint msg_type = gmyth_monitor_handler_is_backend_message( monitor, strlist,
488 g_signal_emit ( monitor,
489 GMYTH_MONITOR_HANDLER_GET_CLASS (monitor)->backend_events_handler_signal_id,
491 msg_type, back_msg_action );
493 if (back_msg_action!= NULL)
494 g_free( back_msg_action );
502 g_object_unref( strlist );
506 io_cond = g_io_channel_get_buffer_condition( io_channel );
508 } while ( recv <= 0 && ( ( io_cond & G_IO_HUP ) == 0 ) );
510 gmyth_debug ("\tMONITOR EVENT: Read %d bytes\n", recv );
512 } /* main GThread while */
514 if ( io_status == G_IO_STATUS_ERROR ) {
515 gmyth_debug ("Error reading MONITOR event socket.\n");
521 myth_control_release_context (monitor);
528 * Opens connection events' socket the the Monitor socket on
529 * MythTV backend server.
531 * @param monitor The GMythMonitorHandler instance.
533 * @return <code>true</code>, if the socket was successfully opened.
536 gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor)
540 monitor->event_sock = gmyth_socket_new();
542 /* Connects the socket, send Mythtv ANN Monitor and verify Mythtv protocol version */
543 if (!gmyth_socket_connect_to_backend_events ( monitor->event_sock,
544 monitor->hostname, monitor->port, FALSE ) )
546 g_object_unref (monitor->event_sock);
547 monitor->event_sock = NULL;
555 * Opens connection the the Monitor socket on MythTV backend server,
556 * where all status messages are notified to the client.
558 * @param monitor The GMythMonitorHandler instance.
559 * @param channel The GIOChannel instance to the Monitor socket.
561 * @return Pointer to the boolean value, and it is <code>true</code> only if the
562 * GMythMonitorHandler could be configured.
565 gmyth_monitor_handler_setup( GMythMonitorHandler *monitor, GIOChannel *channel )
567 gboolean *ret = g_new0( gboolean, 1 );
571 if ( channel != NULL ) {
573 monitor->allow_msgs_listener = TRUE;
575 monitor->sid_io_watch = g_io_add_watch( channel, G_IO_IN | G_IO_HUP,
576 (GIOFunc)gmyth_monitor_handler_listener, monitor );
582 if (monitor->sid_io_watch < 0){
583 gmyth_debug( "[%s] Error adding watch listener function to the IO control channel!\n", __FUNCTION__ );
595 * Starts the MonitorHandler thread to the GIOWatcher.
597 * @param monitor The GMythMonitorHandler instance.
599 * @return <code>true</code>, if the MonitorHandler was started.
602 gmyth_monitor_handler_start (GMythMonitorHandler *monitor)
604 gboolean *ret = g_new0( gboolean, 1 );
607 ret = gmyth_monitor_handler_setup( monitor, monitor->event_sock->sd_io_ch );
610 gmyth_debug ( "\n[%s]\tOK! Starting listener on the MONITOR event socket...[thread location = %p]\n",
611 __FUNCTION__, g_thread_self( ) );
614 gmyth_debug ( "\n[%s]\tERROR! Coudn't start listener on the MONITOR event socket...[thread location = %p]\n",
615 __FUNCTION__, g_thread_self( ) );
619 gmyth_debug( "[%s] Watch listener function over the IO control channel? %s!!!\n",
620 __FUNCTION__, ( *ret == TRUE ? "YES" : "NO" ) );