1 /* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */
5 * @file gmyth/gmyth_monitor_handler.c
7 * @brief <p> GMythMonitorHandler deals with the streaming media events remote/local
8 * that are sent to the MythTV frontend.
10 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
11 * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
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.
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.
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
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)
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"
46 #include <arpa/inet.h>
47 #include <sys/types.h>
48 #include <sys/socket.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 GThread *monitor_th = NULL;
75 enum myth_sock_types {
76 GMYTH_PLAYBACK_TYPE = 0,
78 GMYTH_FILETRANSFER_TYPE,
82 static gboolean* myth_control_sock_listener( GIOChannel *io_channel );
83 //static gboolean myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition,
86 static GMutex* mutex = NULL;
88 static GCond* io_watcher_cond = NULL;
90 static void gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass);
91 static void gmyth_monitor_handler_init (GMythMonitorHandler *object);
93 static void gmyth_monitor_handler_dispose (GObject *object);
94 static void gmyth_monitor_handler_finalize (GObject *object);
96 static gboolean gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor);
98 void gmyth_monitor_handler_close( GMythMonitorHandler *monitor );
100 G_DEFINE_TYPE(GMythMonitorHandler, gmyth_monitor_handler, G_TYPE_OBJECT)
103 gmyth_monitor_handler_class_init (GMythMonitorHandlerClass *klass)
105 GObjectClass *gobject_class;
107 gobject_class = (GObjectClass *) klass;
109 gobject_class->dispose = gmyth_monitor_handler_dispose;
110 gobject_class->finalize = gmyth_monitor_handler_finalize;
114 gmyth_monitor_handler_init (GMythMonitorHandler *monitor)
116 g_return_if_fail( monitor != NULL );
118 monitor->event_sock = NULL;
119 monitor->hostname = NULL;
121 monitor->actual_index = 0;
123 monitor->backend_msgs = g_hash_table_new( g_int_hash, g_int_equal );
125 /* it is used for signalizing the event socket consumer thread */
126 io_watcher_cond = g_cond_new();
128 /* mutex to control access to the event socket consumer thread */
129 mutex = g_mutex_new();
133 gmyth_monitor_handler_dispose (GObject *object)
135 G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->dispose (object);
139 gmyth_monitor_handler_finalize (GObject *object)
141 g_signal_handlers_destroy (object);
143 G_OBJECT_CLASS (gmyth_monitor_handler_parent_class)->finalize (object);
146 // fixme: do we need the card_id????
148 gmyth_monitor_handler_new (void)
150 GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER ( g_object_new (
151 GMYTH_MONITOR_HANDLER_TYPE, FALSE ));
157 gmyth_monitor_handler_open (GMythMonitorHandler *monitor, gchar *hostname, gint port)
161 if (monitor->hostname != NULL) {
162 g_free (monitor->hostname);
163 monitor->hostname = NULL;
166 monitor->hostname = g_strdup( hostname );
167 monitor->port = port;
169 gmyth_debug ("Monitor event socket --- hostname: %s, port %d\n", monitor->hostname, monitor->port);
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" );
178 g_warning("Remote monitor event socket already created.\n");
186 //myth_control_sock_listener( GIOChannel *io_channel, GIOCondition condition, gpointer data )
187 myth_control_sock_listener( GIOChannel *io_channel )
191 GError *error = NULL;
192 GIOCondition io_cond;
193 GIOCondition condition;
195 GByteArray *byte_array = NULL;
197 gboolean* ret = g_new0( gboolean, 1 );
198 //gboolean ret = TRUE;
201 //GMythMonitorHandler *monitor = (GMythMonitorHandler*)data;
204 //myth_control_acquire_context (TRUE);
206 if ( io_channel == NULL ) {
207 g_debug ("Monitor socket is NULL!\n");
211 gmyth_debug ("Listening on Monitor socket...!\n");
215 condition = g_io_channel_get_buffer_condition( io_channel );
217 //myth_control_acquire_context (TRUE);
219 //while ( !has_io_access )
220 // g_cond_wait( io_watcher_cond, mutex );
222 //myth_control_acquire_context (TRUE);
224 if (condition & G_IO_HUP) {
225 gmyth_debug ("Read end of pipe died!\n");
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;
236 trash = g_new0( gchar, buffer_size );
238 io_status = g_io_channel_read_chars( io_channel, trash,
239 buffer_size, &len, &error);
241 gmyth_debug ( "[%s] Received data buffer from IO binary channel... %d bytes gone!\n",
246 byte_array = g_byte_array_append( byte_array, (const guint8*)trash, len );
251 io_cond = g_io_channel_get_buffer_condition( io_channel );
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]" );
257 if ( byte_array != NULL ) {
258 g_byte_array_free( byte_array, TRUE );
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 : "" );
272 //g_hash_table_insert( monitor->backend_msgs, (gpointer)monitor->actual_index,
273 // byte_array->data );
275 //monitor->actual_index += recv;
284 gmyth_connect_to_backend_monitor (GMythMonitorHandler *monitor)
288 /* Creates the event socket */
289 if (monitor->event_sock != NULL) {
290 g_object_unref (monitor->event_sock);
291 monitor->event_sock = NULL;
294 monitor->event_sock = gmyth_socket_new();
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 ) )
300 g_object_unref (monitor->event_sock);
301 monitor->event_sock = NULL;
309 gmyth_monitor_handler_start (GMythMonitorHandler *monitor)
311 monitor_th = g_thread_create( (GThreadFunc)myth_control_sock_listener,
312 monitor->event_sock->sd_io_ch, TRUE, NULL );
314 gmyth_debug( "[%s] Watch listener function over the IO control channel? %s!!!\n",
315 __FUNCTION__, ( ret == TRUE ? "YES" : "NO" ) );
321 gmyth_monitor_handler_close( GMythMonitorHandler *monitor )
324 if (monitor->event_sock) {
325 g_object_unref( monitor->event_sock );
326 monitor->event_sock = NULL;
329 if (monitor->hostname) {
330 g_free( monitor->hostname );
331 monitor->hostname = NULL;