gmyth/src/gmyth_livetv.c
author rosfran
Tue Dec 05 21:56:57 2006 +0000 (2006-12-05)
branchtrunk
changeset 197 c57ba96bda15
parent 117 b90cf50ca3dc
child 203 a43fed947ec8
permissions -rwxr-xr-x
[svn r198] Fixed problem with Coxinha.
rosfran@68
     1
/**
rosfran@68
     2
 * GMyth Library
rosfran@68
     3
 *
rosfran@68
     4
 * @file gmyth/gmyth_livetv.c
rosfran@68
     5
 * 
rosfran@68
     6
 * @brief <p> GMythLiveTV starts a remote TV session with the MythTV backend.
rosfran@68
     7
 *
rosfran@68
     8
 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
rosfran@68
     9
 * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
rosfran@68
    10
 *
rosfran@68
    11
 *//*
rosfran@68
    12
 * 
rosfran@68
    13
 * This program is free software; you can redistribute it and/or modify
rosfran@68
    14
 * it under the terms of the GNU Lesser General Public License as published by
rosfran@68
    15
 * the Free Software Foundation; either version 2 of the License, or
rosfran@68
    16
 * (at your option) any later version.
rosfran@68
    17
 *
rosfran@68
    18
 * This program is distributed in the hope that it will be useful,
rosfran@68
    19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rosfran@68
    20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rosfran@68
    21
 * GNU General Public License for more details.
rosfran@68
    22
 *
rosfran@68
    23
 * You should have received a copy of the GNU Lesser General Public License
rosfran@68
    24
 * along with this program; if not, write to the Free Software
rosfran@68
    25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
rosfran@68
    26
 */
rosfran@68
    27
 
rosfran@42
    28
#include "gmyth_remote_util.h"
rosfran@42
    29
#include "gmyth_tvchain.h"
melunko@117
    30
#include "gmyth_socket.h"
renatofilho@131
    31
#include "gmyth_debug.h"
rosfran@41
    32
rosfran@42
    33
#include "gmyth_livetv.h"
rosfran@42
    34
#include "gmyth_file_transfer.h"
rosfran@41
    35
rosfran@41
    36
static void gmyth_livetv_class_init          (GMythLiveTVClass *klass);
rosfran@41
    37
static void gmyth_livetv_init                (GMythLiveTV *object);
rosfran@41
    38
rosfran@41
    39
static void gmyth_livetv_dispose  (GObject *object);
rosfran@41
    40
static void gmyth_livetv_finalize (GObject *object);
rosfran@41
    41
rosfran@41
    42
static gint tvchain_curr_index = -1; 
rosfran@41
    43
melunko@107
    44
#define GMYTHTV_RECORDER_HEADER         "QUERY_RECORDER"
melunko@107
    45
melunko@107
    46
rosfran@41
    47
G_DEFINE_TYPE(GMythLiveTV, gmyth_livetv, G_TYPE_OBJECT)
rosfran@41
    48
rosfran@41
    49
static void
rosfran@41
    50
gmyth_livetv_class_init (GMythLiveTVClass *klass)
rosfran@41
    51
{
rosfran@41
    52
	GObjectClass *gobject_class;
rosfran@41
    53
rosfran@41
    54
	gobject_class = (GObjectClass *) klass;
rosfran@41
    55
rosfran@41
    56
	gobject_class->dispose  = gmyth_livetv_dispose;
rosfran@41
    57
	gobject_class->finalize = gmyth_livetv_finalize;	
rosfran@41
    58
}
rosfran@41
    59
rosfran@41
    60
static void
rosfran@41
    61
gmyth_livetv_init (GMythLiveTV *livetv)
rosfran@41
    62
{
rosfran@41
    63
	livetv->backend_hostname = NULL;
rosfran@41
    64
	livetv->backend_port = 0;
rosfran@41
    65
	livetv->local_hostname = NULL;
rosfran@41
    66
rosfran@65
    67
	livetv->recorder = NULL;
rosfran@41
    68
	livetv->tvchain = NULL;
rosfran@41
    69
	livetv->proginfo = NULL;
rosfran@41
    70
}
rosfran@41
    71
rosfran@41
    72
static void
rosfran@41
    73
gmyth_livetv_dispose  (GObject *object)
rosfran@41
    74
{
rosfran@41
    75
rosfran@41
    76
	G_OBJECT_CLASS (gmyth_livetv_parent_class)->dispose (object);
rosfran@41
    77
}
rosfran@41
    78
rosfran@41
    79
static void
rosfran@41
    80
gmyth_livetv_finalize (GObject *object)
rosfran@41
    81
{
rosfran@41
    82
	g_signal_handlers_destroy (object);
rosfran@41
    83
rosfran@41
    84
	GMythLiveTV *livetv = GMYTH_LIVETV (object);
rosfran@41
    85
renatofilho@131
    86
	gmyth_debug ("[%s] Finalizing livetv", __FUNCTION__);
rosfran@41
    87
rosfran@65
    88
	if ( livetv->recorder != NULL ) {
rosfran@65
    89
		g_object_unref (livetv->recorder);
rosfran@65
    90
		livetv->recorder = NULL;
rosfran@41
    91
	}
rosfran@41
    92
rosfran@41
    93
	if ( livetv->tvchain != NULL ) {
rosfran@41
    94
		g_object_unref (livetv->tvchain);
rosfran@41
    95
		livetv->tvchain = NULL;
rosfran@41
    96
	}
rosfran@41
    97
rosfran@41
    98
	if ( livetv->proginfo != NULL ) {
rosfran@41
    99
		g_object_unref (livetv->proginfo);
rosfran@41
   100
		livetv->proginfo = NULL;
rosfran@41
   101
	}
rosfran@41
   102
rosfran@41
   103
	G_OBJECT_CLASS ( gmyth_livetv_parent_class )->finalize ( object );
rosfran@41
   104
}
rosfran@41
   105
rosfran@41
   106
GMythLiveTV*
rosfran@41
   107
gmyth_livetv_new ()
rosfran@41
   108
{
rosfran@41
   109
	GMythLiveTV *livetv = GMYTH_LIVETV ( g_object_new( GMYTH_LIVETV_TYPE, NULL ) );
rosfran@41
   110
rosfran@41
   111
	return livetv;
rosfran@41
   112
}
rosfran@41
   113
rosfran@41
   114
gboolean
melunko@117
   115
gmyth_livetv_setup ( GMythLiveTV *livetv, GMythBackendInfo *backend_info )
rosfran@41
   116
{
rosfran@41
   117
	gboolean res = TRUE;
melunko@117
   118
	char *hostname;
rosfran@41
   119
melunko@117
   120
	GMythSocket *socket = gmyth_socket_new ();
rosfran@41
   121
melunko@117
   122
	// FIME: Implement this at gmyth_socket
melunko@117
   123
	res = gmyth_socket_connect_to_backend (socket, backend_info->hostname,
melunko@117
   124
			backend_info->port, TRUE);
rosfran@41
   125
	if (!res) {
rosfran@41
   126
		g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__);	
rosfran@41
   127
		res = FALSE;
rosfran@41
   128
		goto error;
rosfran@41
   129
	}
rosfran@41
   130
melunko@117
   131
	livetv->is_livetv = TRUE;
rosfran@41
   132
melunko@117
   133
	hostname = gmyth_backend_info_get_hostname(backend_info);
melunko@117
   134
	livetv->backend_hostname = g_string_new (hostname);
melunko@117
   135
	livetv->backend_port = gmyth_backend_info_get_port (backend_info);
melunko@117
   136
melunko@117
   137
	livetv->local_hostname  = gmyth_socket_get_local_hostname ( );
rosfran@41
   138
rosfran@41
   139
	if ( livetv->local_hostname == NULL ) {
rosfran@41
   140
		res = FALSE;
rosfran@41
   141
		goto error;
rosfran@41
   142
	}
rosfran@41
   143
rosfran@65
   144
	// Gets the recorder num
melunko@117
   145
	livetv->recorder = remote_request_next_free_recorder (socket, -1);
melunko@117
   146
	gmyth_socket_close_connection (socket);
rosfran@41
   147
rosfran@65
   148
	if ( livetv->recorder == NULL ) {
rosfran@41
   149
		g_warning ("[%s] None remote encoder available", __FUNCTION__);
rosfran@41
   150
		res = FALSE;
rosfran@41
   151
		goto error;
rosfran@41
   152
	}
rosfran@41
   153
rosfran@41
   154
	// Creates livetv chain handler
rosfran@41
   155
	livetv->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) );
melunko@117
   156
	gmyth_tvchain_initialize ( livetv->tvchain, backend_info );
rosfran@41
   157
rosfran@41
   158
	if ( livetv->tvchain == NULL || livetv->tvchain->tvchain_id == NULL ) {
rosfran@41
   159
		res = FALSE;
rosfran@41
   160
		goto error;
rosfran@41
   161
	}
rosfran@41
   162
rosfran@41
   163
	// Init remote encoder. Opens its control socket.
rosfran@65
   164
	res = gmyth_recorder_setup(livetv->recorder);
rosfran@41
   165
	if ( !res ) {
rosfran@41
   166
		g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
rosfran@41
   167
		res = FALSE;
rosfran@41
   168
		goto error;
rosfran@41
   169
	}
rosfran@67
   170
rosfran@67
   171
#if 0
rosfran@67
   172
  gint ch = 1011;
rosfran@67
   173
  gint idx = 0;  
rosfran@67
   174
  for ( ; idx < 5; idx++ ) {
rosfran@67
   175
  	if ( gmyth_recorder_check_channel( livetv->recorder, ch ) ) {
rosfran@67
   176
	  	if ( gmyth_recorder_set_channel( livetv->recorder, ch ) ) {
rosfran@67
   177
	  		g_print( "[%s] Channel changed!!! [%d].\n", __FUNCTION__, ch );
rosfran@67
   178
	  		break;
rosfran@67
   179
	  	}
rosfran@67
   180
  	}
rosfran@67
   181
  	++ch;
rosfran@67
   182
  }
rosfran@67
   183
#endif
rosfran@67
   184
rosfran@41
   185
	// Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly)
rosfran@65
   186
	res = gmyth_recorder_spawntv ( livetv->recorder,
rosfran@41
   187
			gmyth_tvchain_get_id(livetv->tvchain) );
rosfran@41
   188
	if (!res) {
rosfran@41
   189
		g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__);
rosfran@41
   190
		res = FALSE;
rosfran@41
   191
		goto error;
rosfran@41
   192
	}
rosfran@41
   193
rosfran@41
   194
	// Reload all TV chain from Mysql database.
rosfran@41
   195
	gmyth_tvchain_reload_all (livetv->tvchain);
rosfran@41
   196
rosfran@41
   197
	if ( livetv->tvchain == NULL ) {
rosfran@41
   198
		res = FALSE;
rosfran@41
   199
		goto error;
rosfran@41
   200
	}
rosfran@41
   201
rosfran@41
   202
	// Get program info from database using chanid and starttime
rosfran@41
   203
	livetv->proginfo = gmyth_tvchain_get_program_at (livetv->tvchain, tvchain_curr_index++ );
rosfran@41
   204
	if ( livetv->proginfo == NULL ) {
rosfran@41
   205
		g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ );
rosfran@41
   206
		res = FALSE;
rosfran@41
   207
		goto error;
rosfran@41
   208
	} else {
renatofilho@131
   209
		gmyth_debug ("[%s] GMythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ );
rosfran@41
   210
	}
rosfran@41
   211
rosfran@41
   212
	return res;
rosfran@41
   213
rosfran@41
   214
error:
rosfran@54
   215
	g_print( "[%s] ERROR running LiveTV setup.\n", __FUNCTION__ );
rosfran@54
   216
	if ( livetv->backend_hostname != NULL ) {
rosfran@54
   217
		g_string_free( livetv->backend_hostname, TRUE );
rosfran@54
   218
		res = FALSE;
rosfran@54
   219
	}
rosfran@54
   220
rosfran@54
   221
	if ( livetv->local_hostname != NULL ) {
rosfran@54
   222
		g_string_free( livetv->local_hostname, TRUE );
rosfran@54
   223
		res = FALSE;
rosfran@54
   224
	}
rosfran@54
   225
rosfran@65
   226
	if ( livetv->recorder != NULL ) {
rosfran@65
   227
		g_object_unref (livetv->recorder);
rosfran@65
   228
		livetv->recorder = NULL;
rosfran@54
   229
	}
rosfran@54
   230
rosfran@54
   231
	if ( livetv->tvchain != NULL ) {
rosfran@54
   232
		g_object_unref (livetv->tvchain);
rosfran@54
   233
		livetv->tvchain = NULL;
rosfran@54
   234
	}
rosfran@54
   235
rosfran@54
   236
	if ( livetv->proginfo != NULL ) {
rosfran@54
   237
		g_object_unref (livetv->proginfo);
rosfran@54
   238
		livetv->proginfo = NULL;
rosfran@54
   239
	}
rosfran@54
   240
rosfran@54
   241
	return res;
rosfran@54
   242
rosfran@54
   243
}
rosfran@54
   244
rosfran@54
   245
gboolean
rosfran@54
   246
gmyth_livetv_next_program_chain ( GMythLiveTV *livetv )
rosfran@54
   247
{
rosfran@54
   248
	gboolean res = TRUE;
rosfran@54
   249
	
rosfran@54
   250
	// Reload all TV chain from Mysql database.
rosfran@54
   251
	gmyth_tvchain_reload_all (livetv->tvchain);
rosfran@54
   252
rosfran@54
   253
	if ( livetv->tvchain == NULL ) {
rosfran@54
   254
		res = FALSE;
rosfran@54
   255
		goto error;
rosfran@54
   256
	}
rosfran@54
   257
rosfran@54
   258
	// Get program info from database using chanid and starttime
rosfran@54
   259
	livetv->proginfo = gmyth_tvchain_get_program_at (livetv->tvchain, -1 );
rosfran@54
   260
	if ( livetv->proginfo == NULL ) {
rosfran@54
   261
		g_warning ("[%s] LiveTV not successfully started on the next program chain.\n", __FUNCTION__ );
rosfran@54
   262
		res = FALSE;
rosfran@54
   263
		goto error;
rosfran@54
   264
	} else {
renatofilho@131
   265
		gmyth_debug ("[%s] GMythLiveTV: All requests to backend to start TV were OK, TV chain changed.\n", __FUNCTION__ );
rosfran@54
   266
	}
rosfran@54
   267
rosfran@54
   268
	return res;
rosfran@54
   269
rosfran@54
   270
error:
rosfran@54
   271
	g_print( "[%s] ERROR running LiveTV setup.\n", __FUNCTION__ );
rosfran@41
   272
	if ( livetv->backend_hostname != NULL ) {
rosfran@41
   273
		g_string_free( livetv->backend_hostname, TRUE );
rosfran@41
   274
		res = FALSE;
rosfran@41
   275
	}
rosfran@41
   276
rosfran@41
   277
	if ( livetv->local_hostname != NULL ) {
rosfran@41
   278
		g_string_free( livetv->local_hostname, TRUE );
rosfran@41
   279
		res = FALSE;
rosfran@41
   280
	}
rosfran@41
   281
rosfran@65
   282
	if ( livetv->recorder != NULL ) {
rosfran@65
   283
		g_object_unref (livetv->recorder);
rosfran@65
   284
		livetv->recorder = NULL;
rosfran@41
   285
	}
rosfran@41
   286
rosfran@41
   287
	if ( livetv->tvchain != NULL ) {
rosfran@41
   288
		g_object_unref (livetv->tvchain);
rosfran@41
   289
		livetv->tvchain = NULL;
rosfran@41
   290
	}
rosfran@41
   291
rosfran@41
   292
	if ( livetv->proginfo != NULL ) {
rosfran@41
   293
		g_object_unref (livetv->proginfo);
rosfran@41
   294
		livetv->proginfo = NULL;
rosfran@41
   295
	}
rosfran@41
   296
rosfran@41
   297
	return res;
rosfran@41
   298
rosfran@41
   299
}
rosfran@41
   300
rosfran@41
   301
// FIXME: How to proceed differently between livetv and recorded content
rosfran@41
   302
void
rosfran@41
   303
gmyth_livetv_stop_playing (GMythLiveTV *livetv) 
rosfran@41
   304
{
renatofilho@131
   305
	gmyth_debug ("[%s] Stopping the LiveTV...\n", __FUNCTION__);
rosfran@41
   306
rosfran@41
   307
	if (livetv->is_livetv) {
rosfran@65
   308
		if (!gmyth_recorder_stop_livetv (livetv->recorder)) {
rosfran@41
   309
			g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__);	
rosfran@41
   310
		}
rosfran@41
   311
	}
rosfran@41
   312
}
rosfran@41
   313
melunko@117
   314
// FIXME: put here just a wrapper function to call gmyth_recorder_is_recording()...
rosfran@41
   315
gboolean
melunko@107
   316
gmyth_livetv_is_recording ( GMythLiveTV *livetv )
melunko@107
   317
{
melunko@107
   318
  gboolean ret = TRUE;
melunko@107
   319
melunko@107
   320
  GMythStringList *str_list = gmyth_string_list_new ();
melunko@107
   321
  GString *message = g_string_new ("");
melunko@107
   322
renatofilho@131
   323
  gmyth_debug ( "[%s]\n", __FUNCTION__ );
melunko@107
   324
  //g_static_mutex_lock (&mutex);
melunko@107
   325
  //
melunko@107
   326
  g_string_printf( message, "%s %d", GMYTHTV_RECORDER_HEADER,
melunko@107
   327
      /* FIXME file_transfer->rec_id >= 0 ? file_transfer->rec_id : file_transfer->card_id );*/
melunko@107
   328
        livetv->recorder->recorder_num);
melunko@107
   329
  gmyth_string_list_append_string (str_list, message);
melunko@107
   330
  gmyth_string_list_append_string (str_list, g_string_new ("IS_RECORDING"));
melunko@107
   331
melunko@107
   332
  gmyth_socket_sendreceive_stringlist ( livetv->recorder->myth_socket, str_list );
melunko@107
   333
melunko@107
   334
  if ( str_list != NULL && gmyth_string_list_length(str_list) > 0 )
melunko@107
   335
  {
melunko@107
   336
    GString *str = NULL;
melunko@107
   337
    if ( ( str = gmyth_string_list_get_string( str_list, 0 ) ) != NULL && strcmp( str->str, "bad" )!= 0 ) {
melunko@107
   338
      gint is_rec = gmyth_string_list_get_int( str_list, 0 );
melunko@107
   339
      if ( is_rec != 0 )
melunko@107
   340
        ret = TRUE;
melunko@107
   341
      else
melunko@107
   342
        ret = FALSE;
melunko@107
   343
    }
melunko@107
   344
  }
melunko@107
   345
  g_print( "[%s] %s, stream is %s being recorded!\n", __FUNCTION__, ret ? "YES" : "NO", ret ? "" : "NOT" );
melunko@107
   346
  //g_static_mutex_unlock (&mutex);
melunko@107
   347
melunko@107
   348
  if ( str_list != NULL )
melunko@107
   349
    g_object_unref (str_list);
melunko@107
   350
melunko@107
   351
  return ret;
melunko@107
   352
melunko@107
   353
}
melunko@107
   354
melunko@107
   355
melunko@107
   356
gboolean
rosfran@41
   357
gmyth_livetv_is_playing (GMythLiveTV *livetv)
rosfran@41
   358
{
rosfran@41
   359
	return TRUE;
rosfran@41
   360
}
rosfran@41
   361
rosfran@41
   362
void
rosfran@41
   363
gmyth_livetv_start_playing (GMythLiveTV *livetv)
rosfran@41
   364
{
rosfran@41
   365
rosfran@41
   366
	// TODO
rosfran@41
   367
rosfran@41
   368
}
rosfran@41
   369