branches/gmyth-0.1b/src/gmyth_tvchain.c
author rosfran
Fri Feb 09 20:28:36 2007 +0000 (2007-02-09)
branchtrunk
changeset 344 21a15c29957b
permissions -rw-r--r--
[svn r346] Fixes to the socket closing and memory cleanup.
     1 /**
     2  * GMyth Library
     3  *
     4  * @file gmyth/gmyth_tvchain.c
     5  * 
     6  * @brief <p> This component contains functions for creating and accessing
     7  * the tvchain functions for live tv playback.
     8  * 
     9  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
    10  * @author Hallyson Luiz de Morais Melo <hallyson.melo@indt.org.br>
    11  *
    12  *//*
    13  * 
    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.
    18  *
    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.
    23  *
    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
    27  */
    28  
    29 #ifdef HAVE_CONFIG_H
    30 #include "config.h"
    31 #endif
    32 
    33 #include "gmyth_tvchain.h"
    34 
    35 #include <glib.h>
    36 #include <time.h>
    37 #include <stdio.h>
    38 #include <stdlib.h>
    39 #include <assert.h>
    40 
    41 #include "gmyth_epg.h"
    42 #include "gmyth_util.h"
    43 #include "gmyth_query.h"
    44 #include "gmyth_scheduler.h"
    45 #include "gmyth_debug.h"
    46 
    47 static void gmyth_tvchain_class_init          (GMythTVChainClass *klass);
    48 static void gmyth_tvchain_init                (GMythTVChain *object);
    49 
    50 static void gmyth_tvchain_dispose  (GObject *object);
    51 static void gmyth_tvchain_finalize (GObject *object);
    52 
    53 G_DEFINE_TYPE(GMythTVChain, gmyth_tvchain, G_TYPE_OBJECT)
    54 
    55 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
    56 
    57 static void
    58 gmyth_tvchain_class_init (GMythTVChainClass *klass)
    59 {
    60 	GObjectClass *gobject_class;
    61 
    62 	gobject_class = (GObjectClass *) klass;
    63 
    64 	gobject_class->dispose  = gmyth_tvchain_dispose;
    65 	gobject_class->finalize = gmyth_tvchain_finalize;	
    66 }
    67 
    68 static void
    69 gmyth_tvchain_init (GMythTVChain *tvchain)
    70 {
    71 	tvchain->tvchain_id = NULL;
    72 
    73 	tvchain->cur_chanid = g_string_new ("");
    74 	tvchain->cur_startts = NULL;
    75 }
    76 
    77 static void
    78 gmyth_tvchain_dispose  (GObject *object)
    79 {
    80     GMythTVChain *tvchain = GMYTH_TVCHAIN(object);
    81 
    82     if ( tvchain->tvchain_id != NULL ) {
    83 	g_string_free( tvchain->tvchain_id, TRUE );
    84 	tvchain->tvchain_id = NULL;
    85     }
    86 
    87     if ( tvchain->tvchain_list != NULL ) {
    88 	g_list_free( tvchain->tvchain_list );
    89 	tvchain->tvchain_list = NULL;
    90     }
    91 
    92     if ( tvchain->cur_chanid != NULL ) {
    93 	g_string_free( tvchain->cur_chanid, TRUE );
    94 	tvchain->cur_chanid = NULL;
    95     }
    96 
    97     if ( tvchain->backend_info) {
    98         g_object_unref (tvchain->backend_info);
    99         tvchain->backend_info = NULL;
   100     }
   101 
   102 
   103     G_OBJECT_CLASS (gmyth_tvchain_parent_class)->dispose (object);
   104 }
   105 
   106 static void
   107 gmyth_tvchain_finalize (GObject *object)
   108 {
   109     g_signal_handlers_destroy (object);
   110 
   111     G_OBJECT_CLASS (gmyth_tvchain_parent_class)->finalize (object);
   112 }
   113 
   114 /** Initializes the tvchain and generates the tvchain id.
   115  * 
   116  * @param tvchain The GMythTVChain instance.
   117  * @param hostname The local hostname used to generate the tvchain id.
   118  */
   119 gboolean
   120 gmyth_tvchain_initialize (GMythTVChain *tvchain, GMythBackendInfo *backend_info)
   121 {
   122     const char *hostname;
   123 
   124     assert (tvchain);
   125     g_return_val_if_fail (backend_info != NULL, FALSE);
   126 
   127     g_object_ref (backend_info);
   128     tvchain->backend_info = backend_info;
   129 
   130     hostname = gmyth_backend_info_get_hostname (backend_info);
   131     
   132     if (tvchain->tvchain_id == NULL) {
   133 	    gchar *isodate = NULL;
   134     	GTimeVal *cur_time = g_new0( GTimeVal, 1 );
   135     	//struct tm* gmyth_util_time_val_to_date ( const GTimeVal* time )
   136 
   137 	    g_get_current_time(cur_time);
   138     	isodate = gmyth_util_time_to_isoformat_from_time_val_fmt ( "%Y-%m-%dT%H:%M:%S", cur_time );
   139 
   140 	    tvchain->tvchain_id = g_string_sized_new (7 + strlen (hostname) + strlen(isodate));
   141     	g_string_printf(tvchain->tvchain_id, 
   142 	    	"live-%s-%s", hostname, isodate);
   143 
   144     	gmyth_debug ("[%s] tv_chain_id: %s", __FUNCTION__, tvchain->tvchain_id->str);
   145 
   146 			if (isodate)
   147 	    	g_free(isodate);
   148 	    
   149 	    if ( cur_time )
   150 	    	g_free( cur_time );
   151     } else {
   152     	g_warning ("[%s] TVchain already initialized", __FUNCTION__);
   153     }
   154 
   155     return TRUE;
   156 }
   157 
   158 /** Gets the tvchain id.
   159  * 
   160  * @param tvchain The GMythTVChain instance.
   161  * @return The tvchain id.
   162  */
   163 GString*
   164 gmyth_tvchain_get_id (GMythTVChain *tvchain)
   165 {
   166 	g_return_val_if_fail( tvchain != NULL && tvchain->tvchain_id != NULL, NULL );
   167 
   168 	return g_string_new (tvchain->tvchain_id->str);
   169 }
   170 
   171 /** Reloads all tvchain entries in the database.
   172  * 
   173  * @param tvchain The GMythTVChain instance.
   174  * @return  TRUE if success, or FALSE if error.
   175  */
   176 gboolean
   177 gmyth_tvchain_reload_all (GMythTVChain *tvchain)
   178 {
   179 	MYSQL_ROW msql_row;
   180 	MYSQL_RES *msql_res = NULL;
   181 	GMythQuery *gmyth_query = NULL;
   182 	gboolean ret = TRUE;
   183 	GString *stmt_str = NULL;
   184 
   185 	g_static_mutex_lock( &mutex );
   186 	
   187 	/* gets the initial size of the TVChain entries list */
   188 	guint prev_size = g_list_length (tvchain->tvchain_list);
   189 
   190 	gmyth_debug ("[%s] chainid: %s", __FUNCTION__, tvchain->tvchain_id->str);
   191 
   192 	if ( tvchain != NULL && tvchain->tvchain_list != NULL ) {
   193 		g_list_free (tvchain->tvchain_list);
   194 		tvchain->tvchain_list = NULL;
   195 	}
   196 
   197 	// TODO: Reuse gmyth_query already connected from context
   198 	gmyth_query = gmyth_query_new ();
   199 	if (!gmyth_query_connect (gmyth_query, tvchain->backend_info)) {
   200 		g_warning ("[%s] Could not connect to db", __FUNCTION__);
   201 		g_static_mutex_unlock( &mutex );
   202 		ret = FALSE;
   203 		goto done;
   204 	}
   205 
   206 	stmt_str = g_string_new ("");
   207 	g_string_printf (stmt_str, 
   208 			"SELECT chanid, starttime, endtime, discontinuity, "
   209 			"chainpos, hostprefix, cardtype, channame, input "
   210 			"FROM tvchain "
   211 			"WHERE chainid = \"%s\" ORDER BY chainpos;",
   212 			tvchain->tvchain_id->str);
   213 
   214 	msql_res = gmyth_query_process_statement(gmyth_query, stmt_str->str);
   215 	if (msql_res != NULL) {
   216 
   217 		while ((msql_row = mysql_fetch_row (msql_res)) != NULL) {
   218 			struct LiveTVChainEntry *entry = g_new0 (struct LiveTVChainEntry, 1);
   219 			entry->chanid = g_string_new (msql_row[0]);
   220 			entry->starttime = gmyth_util_string_to_time_val ((const gchar*) msql_row[1]);
   221 			entry->endtime = gmyth_util_string_to_time_val ((const gchar*) msql_row[2]);
   222 			entry->discontinuity = g_ascii_strtoull (msql_row[3], NULL, 10 ) != 0;
   223 			entry->hostprefix = g_string_new (msql_row[5]);
   224 			entry->cardtype = g_string_new (msql_row[6]);
   225 			entry->channum = g_string_new (msql_row[7]);
   226 			entry->inputname = g_string_new (msql_row[8]);
   227 
   228 			//m_maxpos = query.value(4).toInt() + 1;
   229 			g_print( "[%s] Reading TV chain entry (channel %s): [%s, %s, %s]\n", __FUNCTION__, entry->channum->str, entry->chanid->str, 
   230 					(gchar*)msql_row[1], (gchar*)msql_row[2] );
   231 			
   232 			/* add this to get the actual start timestamp of the last recording */
   233 			if ( tvchain->cur_startts < entry->starttime )
   234 				tvchain->cur_startts = entry->starttime;
   235 
   236 			tvchain->tvchain_list = g_list_append (tvchain->tvchain_list, entry);			
   237 		}
   238 	} else {
   239 		g_warning ("gmyth_tvchain_reload_all query error!\n");
   240 		g_static_mutex_unlock( &mutex );
   241 
   242 		ret = FALSE;
   243 		goto done;
   244 	}
   245 
   246 	g_static_mutex_unlock( &mutex );
   247 	
   248 	tvchain->cur_pos = gmyth_tvchain_program_is_at (tvchain, tvchain->cur_chanid, tvchain->cur_startts);
   249 	g_print( "[%s] TVChain current position = %d.\n", __FUNCTION__, tvchain->cur_pos );
   250 
   251 	if (tvchain->cur_pos < 0)
   252 		tvchain->cur_pos = 0;
   253 
   254 	//    if (m_switchid >= 0)
   255 	//        m_switchid = ProgramIsAt(m_switchentry.chanid,m_switchentry.starttime);
   256 
   257 	if (prev_size != g_list_length (tvchain->tvchain_list)) {
   258 		gmyth_debug ("[%s] Added new recording", __FUNCTION__);
   259 	}	
   260 
   261 done:
   262 	if ( stmt_str != NULL )
   263 		g_string_free (stmt_str, TRUE);
   264 
   265 	if ( msql_res != NULL )
   266 		mysql_free_result (msql_res);
   267 
   268 	if ( gmyth_query != NULL )
   269 		g_object_unref (gmyth_query);
   270 
   271 	return ret;
   272 }
   273 
   274 /** Returns the internal index for the TV chain related to the given
   275  * channel and start time.
   276  * 
   277  * @param tvchain The GMythTVChain instance.
   278  * @param chanid The channel id.
   279  * @param startts The program start time.
   280  */
   281 gint
   282 gmyth_tvchain_program_is_at (GMythTVChain *tvchain, GString *chanid, GTimeVal* startts)
   283 {
   284 	gint count = 0;
   285 	struct LiveTVChainEntry *entry;
   286 	GList *tmp_list = tvchain->tvchain_list;
   287 	guint list_size = g_list_length (tvchain->tvchain_list);
   288 
   289 	g_static_mutex_lock( &mutex );
   290 	
   291 	for (; tmp_list && ( count < list_size ); tmp_list = tvchain->tvchain_list->next, count++)
   292 	{
   293 		entry = (struct LiveTVChainEntry*) tmp_list->data;
   294 		if ( !g_strncasecmp (entry->chanid->str, chanid->str, chanid->len)
   295 				&& entry->starttime == startts )
   296 		{
   297 			g_static_mutex_unlock( &mutex );
   298 			return count;
   299 		}
   300 	}
   301 	g_static_mutex_unlock( &mutex );
   302 
   303 	return -1;	
   304 }
   305 
   306 /** Get the program info associated to the tvchain.
   307  * 
   308  * @param tvchain The GMythTVChain instance.
   309  * @param index The tvchain index.
   310  * @return The program info structure.
   311  */
   312 GMythProgramInfo*
   313 gmyth_tvchain_get_program_at (GMythTVChain *tvchain, gint index)
   314 {
   315 	struct LiveTVChainEntry *entry;
   316 
   317 	entry = gmyth_tvchain_get_entry_at (tvchain, index);
   318 
   319 	if (entry)
   320 		return gmyth_tvchain_entry_to_program (tvchain, entry);	
   321 
   322 	return NULL;
   323 }
   324 
   325 /** Gets a LiveTVChainEntry associated to the tvchain by its index.
   326  * 
   327  * @param tvchain The GMythTVChain instance.
   328  * @param index The tvchain entry index
   329  * @return The LiveTVchainEntry structure.
   330  */
   331 struct LiveTVChainEntry*
   332 gmyth_tvchain_get_entry_at (GMythTVChain *tvchain, gint index)
   333 {
   334 	struct LiveTVChainEntry* chain_entry = NULL;
   335 
   336 	g_return_val_if_fail( tvchain != NULL && tvchain->tvchain_list != NULL, NULL );
   337 	
   338 	g_static_mutex_lock( &mutex );
   339 	
   340 	gint size = g_list_length (tvchain->tvchain_list);
   341 	gint new_index = (index < 0 || index >= size) ? size - 1 : index;
   342 
   343 	if (new_index >= 0) 
   344 		chain_entry = (struct LiveTVChainEntry*) g_list_nth_data (tvchain->tvchain_list, new_index);
   345 
   346 	g_static_mutex_unlock( &mutex );
   347 	
   348 	if ( chain_entry != NULL ) {
   349 		gmyth_debug ("[%s] Got TV Chain entry at %d.\n", __FUNCTION__, new_index );
   350 
   351 	} else {
   352 		g_warning ("[%s] failed to get entry at index %d", __FUNCTION__, index);
   353 	}
   354 
   355 	return chain_entry;
   356 }
   357 
   358 /** Gets the program info from backend database associated to the tv chain entry.
   359  * 
   360  * @param tvchain The GMythTVChain instance.
   361  * @param entry the LiveTVChainEntry to be converted.
   362  * @return The progrma info.
   363  */
   364 GMythProgramInfo*
   365 gmyth_tvchain_entry_to_program (GMythTVChain *tvchain, struct LiveTVChainEntry *entry)
   366 {
   367 	GMythProgramInfo *proginfo = NULL;
   368 
   369 	g_return_val_if_fail( tvchain != NULL, NULL );
   370 
   371 	if ( !entry || !tvchain ) {
   372 		g_warning ("gmyth_tvchain_entry_to_program() received NULL argument");
   373 		return NULL;
   374 	}
   375 
   376 	GMythScheduler *scheduler = gmyth_scheduler_new ();
   377 
   378 	gmyth_scheduler_connect( scheduler, tvchain->backend_info );
   379 	proginfo = gmyth_scheduler_get_recorded (scheduler, 
   380 			entry->chanid, entry->starttime);
   381 	gmyth_scheduler_disconnect( scheduler );
   382 
   383 	if (proginfo) {
   384 		proginfo->pathname = g_string_prepend (proginfo->pathname, entry->hostprefix->str);
   385 	} else {
   386 		g_warning ("tvchain_entry_to_program( chan id = %s, starttime = %ld) failed!", entry->chanid->str, entry->starttime->tv_sec);
   387 	}
   388 
   389 	return proginfo;
   390 }