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>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * GStreamer MythTV plug-in properties:
28 * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
29 * - path (qurl - remote file to be opened)
39 #include <arpa/inet.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
47 #include "gmyth_marshal.h"
49 #include "gmyth_monitor_handler.h"
50 #include "gmyth_debug.h"
52 #define GMYTHTV_QUERY_HEADER "QUERY_FILETRANSFER "
54 #define GMYTHTV_VERSION 30
56 #define GMYTHTV_TRANSFER_MAX_WAITS 700
58 #define GMYTHTV_BUFFER_SIZE 8*1024
60 #ifdef GMYTHTV_ENABLE_DEBUG
61 #define GMYTHTV_ENABLE_DEBUG 1
63 #undef GMYTHTV_ENABLE_DEBUG
66 /* this NDEBUG is to maintain compatibility with GMyth library */
68 #define GMYTHTV_ENABLE_DEBUG 1
71 gpointer gmyth_monitor_handler_listener(gpointer data);
73 static void gmyth_monitor_handler_default_listener(GMythMonitorHandler *
74 monitor, gint msg_code,
77 static void gmyth_monitor_handler_class_init(GMythMonitorHandlerClass *
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 *
87 static gboolean gmyth_monitor_handler_setup(GMythMonitorHandler * monitor,
88 GIOChannel * channel);
90 void gmyth_monitor_handler_close(GMythMonitorHandler * monitor);
92 G_DEFINE_TYPE(GMythMonitorHandler, gmyth_monitor_handler, G_TYPE_OBJECT)
94 gmyth_monitor_handler_class_init(GMythMonitorHandlerClass * klass)
96 GObjectClass *gobject_class;
97 GMythMonitorHandlerClass *gmonitor_class;
99 gobject_class = (GObjectClass *) klass;
100 gmonitor_class = (GMythMonitorHandlerClass *) gobject_class;
102 gobject_class->dispose = gmyth_monitor_handler_dispose;
103 gobject_class->finalize = gmyth_monitor_handler_finalize;
105 gmonitor_class->backend_events_handler_signal_id =
106 g_signal_new("backend-events-handler",
107 G_TYPE_FROM_CLASS(gmonitor_class),
108 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE |
109 G_SIGNAL_NO_HOOKS, 0, NULL, NULL,
110 gmyth_marshal_VOID__INT_STRING, G_TYPE_NONE, 2,
111 G_TYPE_INT, G_TYPE_STRING);
113 gmonitor_class->backend_events_handler =
114 gmyth_monitor_handler_default_listener;
119 gmyth_monitor_handler_init(GMythMonitorHandler * monitor)
121 g_return_if_fail(monitor != NULL);
123 monitor->event_sock = NULL;
124 monitor->hostname = NULL;
126 monitor->actual_index = 0;
128 monitor->allow_msgs_listener = FALSE;
130 /* monitor->backend_msgs = g_hash_table_new( g_int_hash, g_int_equal ); */
132 /* it is used for signalizing the event socket consumer thread */
133 monitor->mutex = g_mutex_new();
137 monitor->gmyth_monitor_handler_listener = gmyth_monitor_handler_listener;
141 gmyth_monitor_handler_dispose(GObject * object)
143 GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER(object);
145 gmyth_monitor_handler_close(monitor);
147 monitor->allow_msgs_listener = FALSE;
149 if (monitor->th != NULL)
151 gboolean *ret = (gboolean *) g_thread_join(monitor->th);
154 gmyth_debug("Error closing GThread listener socket!");
156 gmyth_debug("Closed GThread listener socket.");
157 //g_object_unref( monitor->th );
160 /* mutex to control access to the event socket consumer thread */
161 if (monitor->mutex != NULL)
163 //g_mutex_unlock( monitor->mutex );
164 g_mutex_free(monitor->mutex);
165 monitor->mutex = NULL;
168 if (monitor->event_sock != NULL)
170 g_object_unref(monitor->event_sock);
171 monitor->event_sock = NULL;
174 if (monitor->hostname != NULL)
176 g_free(monitor->hostname);
177 monitor->hostname = NULL;
180 if (monitor->backend_msgs != NULL)
182 g_hash_table_destroy(monitor->backend_msgs);
183 monitor->backend_msgs = NULL;
187 if ( io_watcher_cond != NULL )
189 g_cond_free( io_watcher_cond );
190 io_watcher_cond = NULL;
194 G_OBJECT_CLASS(gmyth_monitor_handler_parent_class)->dispose(object);
198 gmyth_monitor_handler_finalize(GObject * object)
200 g_signal_handlers_destroy(object);
202 G_OBJECT_CLASS(gmyth_monitor_handler_parent_class)->finalize(object);
206 * Creates a new instance of GMyth Monitor Handler.
208 * @return a new instance of the Monitor Handler.
210 GMythMonitorHandler *
211 gmyth_monitor_handler_new(void)
213 GMythMonitorHandler *monitor =
214 GMYTH_MONITOR_HANDLER(g_object_new(GMYTH_MONITOR_HANDLER_TYPE, FALSE));
220 * Acquire the mutex to have access to the IO Watcher listener.
222 * @param monitor The GMythMonitorHandler instance.
223 * @param do_wait Tells the IO Watcher to wait on the GCond. (obsolete)
225 * @return <code>true</code>, if the access to IO Watcher was acquired.
228 myth_control_acquire_context(GMythMonitorHandler * monitor, gboolean do_wait)
233 g_mutex_lock(monitor->mutex);
240 * Release the mutex to have access to the IO Watcher listener.
242 * @param monitor The GMythMonitorHandler instance.
244 * @return <code>true</code>, if the access to IO Watcher was released.
247 myth_control_release_context(GMythMonitorHandler * monitor)
252 g_mutex_unlock(monitor->mutex);
258 gmyth_monitor_handler_close(GMythMonitorHandler * monitor)
260 monitor->allow_msgs_listener = FALSE;
263 if (monitor->monitor_th != NULL)
265 g_thread_pool_free(monitor->monitor_th, TRUE, FALSE);
266 //g_thread_exit( monitor->monitor_th );
267 /*if ( monitor->monitor_th != NULL )
268 g_object_unref( monitor->monitor_th ); */
269 monitor->monitor_th = NULL;
272 if (monitor->event_sock != NULL)
274 gmyth_socket_close_connection(monitor->event_sock);
281 * Opens connection the the Monitor socket on MythTV backend server,
282 * where all status messages are notified to the client.
284 * @param monitor The GMythMonitorHandler instance.
285 * @param hostname The remote host name of the MythTV backend server.
286 * @param port The remote port number of the MythTV backend server.
288 * @return <code>true</code>, if the connection was successfully opened.
291 gmyth_monitor_handler_open(GMythMonitorHandler * monitor,
292 const gchar * hostname, gint port)
296 g_return_val_if_fail(hostname != NULL, FALSE);
298 if (monitor->hostname != NULL)
300 g_free(monitor->hostname);
301 monitor->hostname = NULL;
304 monitor->hostname = g_strdup(hostname);
305 monitor->port = port;
307 gmyth_debug("Monitor event socket --- hostname: %s, port %d\n",
308 monitor->hostname, monitor->port);
310 if (NULL != monitor->event_sock)
312 g_object_unref(monitor->event_sock);
313 monitor->event_sock = NULL;
316 /* configure the event socket */
317 if (NULL == monitor->event_sock)
319 if (!gmyth_connect_to_backend_monitor(monitor))
321 gmyth_debug("Connection to backend failed (Event Socket)!");
327 ("Remote monitor event socket had been succesfully created. (io_fd == %d)\n",
328 g_io_channel_unix_get_fd(monitor->event_sock->sd_io_ch));
334 ("ASSERT ERROR: Remote monitor event socket is not NULL at the setup...\n");
342 * Reads the data got from the connection to the Monitor socket,
343 * and looks for some important status messages.
345 * @param monitor The GMythMonitorHandler instance.
346 * @param strlist The GMythStringList instance got from the Monitor remote socket.
347 * @param back_msg_action A string pointer to the status message detailed description.
349 * @return The backend status message code ID.
352 gmyth_monitor_handler_is_backend_message(GMythMonitorHandler * monitor,
353 GMythStringList * strlist,
354 gchar ** back_msg_action)
356 gint msg_type = GMYTH_BACKEND_NO_MESSAGE;
357 GString *back_msg = NULL;
359 if (gmyth_string_list_length(strlist) > 0)
362 back_msg = gmyth_string_list_get_string(strlist, 0);
363 if (back_msg != NULL && back_msg->str != NULL &&
364 strstr(back_msg->str, "BACKEND") != NULL)
366 gmyth_debug("MONITOR HANDLER - Received backend message = %s",
368 *back_msg_action = gmyth_string_list_get_char_array(strlist, 1);
370 if (back_msg_action != NULL)
374 (*back_msg_action, strlen(*back_msg_action),
376 || g_strstr_len(*back_msg_action,
377 strlen(*back_msg_action),
378 "RECORDING_LIST_CHANGE")
379 || g_strstr_len(*back_msg_action,
380 strlen(*back_msg_action),
382 || g_strstr_len(*back_msg_action,
383 strlen(*back_msg_action), "LIVETV_WATCH"))
386 ("MONITOR: message type == GMYTH_BACKEND_PROGRAM_INFO_CHANGED, msg = %s",
388 msg_type = GMYTH_BACKEND_PROGRAM_INFO_CHANGED;
390 else if (g_strstr_len
391 (*back_msg_action, strlen(*back_msg_action),
395 ("MONITOR: message type == GMYTH_BACKEND_DONE_RECORDING, msg = %s",
397 msg_type = GMYTH_BACKEND_DONE_RECORDING;
399 else if (g_strstr_len
400 (*back_msg_action, strlen(*back_msg_action), "QUIT"))
403 ("MONITOR: message type == GMYTH_BACKEND_STOP_LIVETV, msg = %s",
405 msg_type = GMYTH_BACKEND_STOP_LIVETV;
408 /* g_hash_table_insert ( monitor->backend_msgs,
409 &(monitor->actual_index), *back_msg_action ); */
415 if (back_msg != NULL)
417 g_string_free(back_msg, TRUE);
421 } /* if - Does Monitor got any message from backend? */
424 *back_msg_action = g_strdup("");
432 gmyth_monitor_handler_default_listener(GMythMonitorHandler * monitor,
433 gint msg_code, gchar * message)
435 //assert( message!= NULL );
436 gmyth_debug("DEFAULT Signal handler ( msg = %s, code = %d )\n",
441 gmyth_monitor_handler_print(GString * str, gpointer ptr)
443 gmyth_debug("Backend message event: %s --- ", str->str);
447 * Opens connection the the Monitor socket on MythTV backend server,
448 * where all status messages are notified to the client.
450 * @param data Pointer to the GMythMonitorHandler.
452 * @return Pointer to a gboolean <code>true</code> value, if the data was
456 gmyth_monitor_handler_listener(gpointer data)
458 GMythMonitorHandler *monitor = (GMythMonitorHandler *) data;
460 gboolean *ret = g_new0(gboolean, 1);
462 GIOChannel *io_channel = monitor->event_sock->sd_io_ch;
463 GIOCondition io_cond = g_io_channel_get_buffer_condition(io_channel);
464 static guint count = 0;
468 gmyth_debug("Entering MONITOR handler listener...");
470 myth_control_acquire_context(monitor, TRUE);
472 if ((io_cond & G_IO_HUP) != 0)
478 GMythStringList *strlist = NULL;
480 if (NULL == io_channel)
482 gmyth_debug("Monitor socket is NULL! (GIOChannel)");
487 while (monitor->allow_msgs_listener)
491 gmyth_debug("%d - Listening on Monitor socket...!\n", count);
498 strlist = gmyth_string_list_new();
500 if (monitor->event_sock != NULL)
504 gmyth_socket_read_stringlist(monitor->event_sock, strlist);
506 if ((len > 0) && strlist != NULL
507 && gmyth_string_list_length(strlist) > 0)
509 bytes_sent = gmyth_string_list_get_int(strlist, 0); // -1 on backend error
512 ("[%s] MONITOR: received data buffer from IO event channel... %d strings gone!\n",
517 /* debug purpose: prints out all the string list elements */
518 g_list_foreach(strlist->glist,
519 (GFunc) gmyth_monitor_handler_print, NULL);
521 gchar *back_msg_action = g_new0(gchar, 1);
523 gmyth_monitor_handler_is_backend_message(monitor,
527 if (monitor != NULL && msg_type != GMYTH_BACKEND_NO_MESSAGE)
528 g_signal_emit(monitor, GMYTH_MONITOR_HANDLER_GET_CLASS(monitor)->backend_events_handler_signal_id, 0, /* details */
529 msg_type, back_msg_action);
531 if (back_msg_action != NULL)
532 g_free(back_msg_action);
540 g_object_unref(strlist);
544 io_cond = g_io_channel_get_buffer_condition(io_channel);
549 while (recv <= 0 && ((io_cond & G_IO_HUP) == 0));
551 gmyth_debug("\tMONITOR EVENT: Read %d bytes\n", recv);
553 } /* main GThread while */
556 myth_control_release_context(monitor);
560 return (gpointer) ret;
565 * Opens connection events' socket the the Monitor socket on
566 * MythTV backend server.
568 * @param monitor The GMythMonitorHandler instance.
570 * @return <code>true</code>, if the socket was successfully opened.
573 gmyth_connect_to_backend_monitor(GMythMonitorHandler * monitor)
577 monitor->event_sock = gmyth_socket_new();
579 /* Connects the socket, send Mythtv ANN Monitor and verify Mythtv protocol version */
580 if (!gmyth_socket_connect_to_backend_events(monitor->event_sock,
582 monitor->port, FALSE))
584 g_object_unref(monitor->event_sock);
585 monitor->event_sock = NULL;
593 * Opens connection the the Monitor socket on MythTV backend server,
594 * where all status messages are notified to the client.
596 * @param monitor The GMythMonitorHandler instance.
597 * @param channel The GIOChannel instance to the Monitor socket.
599 * @return Pointer to the boolean value, and it is <code>true</code> only if the
600 * GMythMonitorHandler could be configured.
603 gmyth_monitor_handler_setup(GMythMonitorHandler * monitor,
604 GIOChannel * channel)
610 monitor->allow_msgs_listener = TRUE;
613 g_thread_create((GThreadFunc) gmyth_monitor_handler_listener,
614 monitor, TRUE, NULL);
615 gmyth_debug("MONITOR GThread created!");
623 if (NULL == monitor->th)
626 ("[%s] Error adding GThread listener function to the IO control channel!\n",
638 * Starts the MonitorHandler thread to the GIOWatcher.
640 * @param monitor The GMythMonitorHandler instance.
642 * @return <code>true</code>, if the MonitorHandler was started.
645 gmyth_monitor_handler_start(GMythMonitorHandler * monitor)
649 if (!(ret = g_thread_supported()))
651 gmyth_debug("Thread system wasn't initialized, starting NOW!!!");
655 ret = gmyth_monitor_handler_setup(monitor, monitor->event_sock->sd_io_ch);
659 ("\n[%s]\tOK! Starting listener on the MONITOR event socket...[thread location = %p]\n",
660 __FUNCTION__, g_thread_self());
665 ("\n[%s]\tERROR! Coudn't start listener on the MONITOR event socket...[thread location = %p]\n",
666 __FUNCTION__, g_thread_self());
671 ("[%s] Watch listener function over the IO control channel? %s!!!\n",
672 __FUNCTION__, (ret == TRUE ? "YES" : "NO"));