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