[svn r328] Some fixes on program info, and some memory clean ups.
4 * @file gmyth/gmyth_tvchain.c
6 * @brief <p> This component contains functions for creating and accessing
7 * the tvchain functions for live tv playback.
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Hallyson Luiz de Morais Melo <hallyson.melo@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
33 #include "gmyth_tvchain.h"
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"
47 static void gmyth_tvchain_class_init (GMythTVChainClass *klass);
48 static void gmyth_tvchain_init (GMythTVChain *object);
50 static void gmyth_tvchain_dispose (GObject *object);
51 static void gmyth_tvchain_finalize (GObject *object);
53 G_DEFINE_TYPE(GMythTVChain, gmyth_tvchain, G_TYPE_OBJECT)
55 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
58 gmyth_tvchain_class_init (GMythTVChainClass *klass)
60 GObjectClass *gobject_class;
62 gobject_class = (GObjectClass *) klass;
64 gobject_class->dispose = gmyth_tvchain_dispose;
65 gobject_class->finalize = gmyth_tvchain_finalize;
69 gmyth_tvchain_init (GMythTVChain *tvchain)
71 tvchain->tvchain_id = NULL;
73 tvchain->cur_chanid = g_string_new ("");
74 tvchain->cur_startts = NULL;
78 gmyth_tvchain_dispose (GObject *object)
80 GMythTVChain *tvchain = GMYTH_TVCHAIN(object);
82 if ( tvchain->tvchain_id != NULL ) {
83 g_string_free( tvchain->tvchain_id, TRUE );
84 tvchain->tvchain_id = NULL;
87 if ( tvchain->tvchain_list != NULL ) {
88 g_list_free( tvchain->tvchain_list );
89 tvchain->tvchain_list = NULL;
92 if ( tvchain->cur_chanid != NULL ) {
93 g_string_free( tvchain->cur_chanid, TRUE );
94 tvchain->cur_chanid = NULL;
97 if ( tvchain->backend_info) {
98 g_object_unref (tvchain->backend_info);
99 tvchain->backend_info = NULL;
103 G_OBJECT_CLASS (gmyth_tvchain_parent_class)->dispose (object);
107 gmyth_tvchain_finalize (GObject *object)
109 g_signal_handlers_destroy (object);
111 G_OBJECT_CLASS (gmyth_tvchain_parent_class)->finalize (object);
114 /** Initializes the tvchain and generates the tvchain id.
116 * @param tvchain The GMythTVChain instance.
117 * @param hostname The local hostname used to generate the tvchain id.
120 gmyth_tvchain_initialize (GMythTVChain *tvchain, GMythBackendInfo *backend_info)
122 const char *hostname;
125 g_return_val_if_fail (backend_info != NULL, FALSE);
127 g_object_ref (backend_info);
128 tvchain->backend_info = backend_info;
130 hostname = gmyth_backend_info_get_hostname (backend_info);
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 )
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 );
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);
144 gmyth_debug ("[%s] tv_chain_id: %s", __FUNCTION__, tvchain->tvchain_id->str);
152 g_warning ("[%s] TVchain already initialized", __FUNCTION__);
158 /** Gets the tvchain id.
160 * @param tvchain The GMythTVChain instance.
161 * @return The tvchain id.
164 gmyth_tvchain_get_id (GMythTVChain *tvchain)
166 g_return_val_if_fail( tvchain != NULL && tvchain->tvchain_id != NULL, NULL );
168 return g_string_new (tvchain->tvchain_id->str);
171 /** Reloads all tvchain entries in the database.
173 * @param tvchain The GMythTVChain instance.
174 * @return TRUE if success, or FALSE if error.
177 gmyth_tvchain_reload_all (GMythTVChain *tvchain)
180 MYSQL_RES *msql_res = NULL;
181 GMythQuery *gmyth_query = NULL;
183 GString *stmt_str = NULL;
185 g_static_mutex_lock( &mutex );
187 /* gets the initial size of the TVChain entries list */
188 guint prev_size = g_list_length (tvchain->tvchain_list);
190 gmyth_debug ("[%s] chainid: %s", __FUNCTION__, tvchain->tvchain_id->str);
192 if ( tvchain != NULL && tvchain->tvchain_list != NULL ) {
193 g_list_free (tvchain->tvchain_list);
194 tvchain->tvchain_list = NULL;
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 );
206 stmt_str = g_string_new ("");
207 g_string_printf (stmt_str,
208 "SELECT chanid, starttime, endtime, discontinuity, "
209 "chainpos, hostprefix, cardtype, channame, input "
211 "WHERE chainid = \"%s\" ORDER BY chainpos;",
212 tvchain->tvchain_id->str);
214 msql_res = gmyth_query_process_statement(gmyth_query, stmt_str->str);
215 if (msql_res != NULL) {
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]);
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] );
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;
236 tvchain->tvchain_list = g_list_append (tvchain->tvchain_list, entry);
239 g_warning ("gmyth_tvchain_reload_all query error!\n");
240 g_static_mutex_unlock( &mutex );
246 g_static_mutex_unlock( &mutex );
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 );
251 if (tvchain->cur_pos < 0)
252 tvchain->cur_pos = 0;
254 // if (m_switchid >= 0)
255 // m_switchid = ProgramIsAt(m_switchentry.chanid,m_switchentry.starttime);
257 if (prev_size != g_list_length (tvchain->tvchain_list)) {
258 gmyth_debug ("[%s] Added new recording", __FUNCTION__);
262 if ( stmt_str != NULL )
263 g_string_free (stmt_str, TRUE);
265 if ( msql_res != NULL )
266 mysql_free_result (msql_res);
268 if ( gmyth_query != NULL )
269 g_object_unref (gmyth_query);
274 /** Returns the internal index for the TV chain related to the given
275 * channel and start time.
277 * @param tvchain The GMythTVChain instance.
278 * @param chanid The channel id.
279 * @param startts The program start time.
282 gmyth_tvchain_program_is_at (GMythTVChain *tvchain, GString *chanid, GTimeVal* startts)
285 struct LiveTVChainEntry *entry;
286 GList *tmp_list = tvchain->tvchain_list;
287 guint list_size = g_list_length (tvchain->tvchain_list);
289 g_static_mutex_lock( &mutex );
291 for (; tmp_list && ( count < list_size ); tmp_list = tvchain->tvchain_list->next, count++)
293 entry = (struct LiveTVChainEntry*) tmp_list->data;
294 if ( !g_strncasecmp (entry->chanid->str, chanid->str, chanid->len)
295 && entry->starttime == startts )
297 g_static_mutex_unlock( &mutex );
301 g_static_mutex_unlock( &mutex );
306 /** Get the program info associated to the tvchain.
308 * @param tvchain The GMythTVChain instance.
309 * @param index The tvchain index.
310 * @return The program info structure.
313 gmyth_tvchain_get_program_at (GMythTVChain *tvchain, gint index)
315 struct LiveTVChainEntry *entry;
317 entry = gmyth_tvchain_get_entry_at (tvchain, index);
320 return gmyth_tvchain_entry_to_program (tvchain, entry);
325 /** Gets a LiveTVChainEntry associated to the tvchain by its index.
327 * @param tvchain The GMythTVChain instance.
328 * @param index The tvchain entry index
329 * @return The LiveTVchainEntry structure.
331 struct LiveTVChainEntry*
332 gmyth_tvchain_get_entry_at (GMythTVChain *tvchain, gint index)
334 struct LiveTVChainEntry* chain_entry = NULL;
336 g_return_val_if_fail( tvchain != NULL && tvchain->tvchain_list != NULL, NULL );
338 g_static_mutex_lock( &mutex );
340 gint size = g_list_length (tvchain->tvchain_list);
341 gint new_index = (index < 0 || index >= size) ? size - 1 : index;
344 chain_entry = (struct LiveTVChainEntry*) g_list_nth_data (tvchain->tvchain_list, new_index);
346 g_static_mutex_unlock( &mutex );
348 if ( chain_entry != NULL ) {
349 gmyth_debug ("[%s] Got TV Chain entry at %d.\n", __FUNCTION__, new_index );
352 g_warning ("[%s] failed to get entry at index %d", __FUNCTION__, index);
358 /** Gets the program info from backend database associated to the tv chain entry.
360 * @param tvchain The GMythTVChain instance.
361 * @param entry the LiveTVChainEntry to be converted.
362 * @return The progrma info.
365 gmyth_tvchain_entry_to_program (GMythTVChain *tvchain, struct LiveTVChainEntry *entry)
367 GMythProgramInfo *proginfo = NULL;
369 g_return_val_if_fail( tvchain != NULL, NULL );
371 if ( !entry || !tvchain ) {
372 g_warning ("gmyth_tvchain_entry_to_program() received NULL argument");
376 GMythScheduler *scheduler = gmyth_scheduler_new ();
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 );
384 proginfo->pathname = g_string_prepend (proginfo->pathname, entry->hostprefix->str);
386 g_warning ("tvchain_entry_to_program( chan id = %s, starttime = %ld) failed!", entry->chanid->str, entry->starttime->tv_sec);