gmyth/src/gmyth_file_transfer.c
author rosfran
Thu Mar 01 20:03:52 2007 +0000 (2007-03-01)
branchtrunk
changeset 381 8ce480699085
parent 356 5486e606498b
child 384 060c3ceb43a0
permissions -rwxr-xr-x
[svn r386] Put a mutex on the GMythFileTransfer send/receive transfer methods. Added timeout message to the LiveTV.
rosfran@41
     1
/**
rosfran@68
     2
 * GMyth Library
rosfran@68
     3
 *
rosfran@68
     4
 * @file gmyth/gmyth_file_transfer.c
rosfran@68
     5
 * 
rosfran@68
     6
 * @brief <p> GMythFileTransfer deals with the file streaming media remote/local
rosfran@68
     7
 * transfering to the MythTV frontend.
rosfran@68
     8
 *
rosfran@68
     9
 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
rosfran@68
    10
 * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
rosfran@68
    11
 *
rosfran@68
    12
 *//*
rosfran@68
    13
 * 
rosfran@68
    14
 * This program is free software; you can redistribute it and/or modify
rosfran@68
    15
 * it under the terms of the GNU Lesser General Public License as published by
rosfran@68
    16
 * the Free Software Foundation; either version 2 of the License, or
rosfran@68
    17
 * (at your option) any later version.
rosfran@68
    18
 *
rosfran@68
    19
 * This program is distributed in the hope that it will be useful,
rosfran@68
    20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rosfran@68
    21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rosfran@68
    22
 * GNU General Public License for more details.
rosfran@68
    23
 *
rosfran@68
    24
 * You should have received a copy of the GNU Lesser General Public License
rosfran@68
    25
 * along with this program; if not, write to the Free Software
rosfran@68
    26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
rosfran@68
    27
 *
rosfran@68
    28
 * GStreamer MythTV plug-in properties:
rosfran@41
    29
 * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
rosfran@41
    30
 * - path (qurl - remote file to be opened)
rosfran@68
    31
 * - port number *   
rosfran@41
    32
 */
leo_sobral@213
    33
 
leo_sobral@213
    34
#ifdef HAVE_CONFIG_H
leo_sobral@213
    35
#include "config.h"
leo_sobral@213
    36
#endif
rosfran@41
    37
rosfran@42
    38
#include "gmyth_file_transfer.h"
rosfran@216
    39
#include "gmyth_livetv.h"
rosfran@216
    40
#include "gmyth_util.h"
rosfran@216
    41
#include "gmyth_socket.h"
rosfran@216
    42
#include "gmyth_stringlist.h"
rosfran@216
    43
#include "gmyth_debug.h"
rosfran@216
    44
#include "gmyth_uri.h"
rosfran@216
    45
#include "gmyth_marshal.h"
rosfran@216
    46
rosfran@41
    47
#include <unistd.h>
rosfran@41
    48
#include <glib.h>
rosfran@41
    49
rosfran@41
    50
#include <arpa/inet.h>
rosfran@41
    51
#include <sys/types.h>
rosfran@41
    52
#include <sys/socket.h>
rosfran@41
    53
#include <netdb.h>
rosfran@41
    54
#include <errno.h>
rosfran@41
    55
#include <stdlib.h>
melunko@117
    56
#include <assert.h>
rosfran@41
    57
melunko@112
    58
#define GMYTHTV_QUERY_HEADER		"QUERY_FILETRANSFER "
rosfran@41
    59
rosfran@41
    60
/* default values to the file transfer parameters */
rosfran@97
    61
#define GMYTHTV_USER_READ_AHEAD			TRUE
rosfran@97
    62
#define GMYTHTV_RETRIES							-1
rosfran@54
    63
#define GMYTHTV_FILE_SIZE						0
rosfran@41
    64
melunko@313
    65
#define GMYTHTV_BUFFER_SIZE					64*1024
rosfran@41
    66
rosfran@54
    67
#define GMYTHTV_VERSION							30
rosfran@41
    68
rosfran@41
    69
#define GMYTHTV_TRANSFER_MAX_WAITS	700
rosfran@41
    70
rosfran@41
    71
#ifdef GMYTHTV_ENABLE_DEBUG
rosfran@54
    72
#define GMYTHTV_ENABLE_DEBUG				1
rosfran@41
    73
#else
rosfran@41
    74
#undef GMYTHTV_ENABLE_DEBUG
rosfran@41
    75
#endif
rosfran@41
    76
rosfran@41
    77
/* this NDEBUG is to maintain compatibility with GMyth library */
rosfran@41
    78
#ifndef NDEBUG
rosfran@54
    79
#define GMYTHTV_ENABLE_DEBUG				1
rosfran@41
    80
#endif
rosfran@41
    81
rosfran@41
    82
enum myth_sock_types {
rosfran@41
    83
  GMYTH_PLAYBACK_TYPE = 0,
rosfran@41
    84
  GMYTH_MONITOR_TYPE,
rosfran@41
    85
  GMYTH_FILETRANSFER_TYPE,
rosfran@41
    86
  GMYTH_RINGBUFFER_TYPE
rosfran@41
    87
};
rosfran@41
    88
rosfran@216
    89
#define GMYTH_FILE_TRANSFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_FILE_TRANSFER_TYPE, GMythFileTransferPrivate))
rosfran@216
    90
rosfran@216
    91
struct _GMythFileTransferPrivate {
rosfran@216
    92
	
rosfran@216
    93
	GMythLiveTV *livetv;
rosfran@216
    94
	
rosfran@216
    95
	gboolean do_next_program_chain;
rosfran@216
    96
	
rosfran@216
    97
};
rosfran@115
    98
rosfran@41
    99
static void gmyth_file_transfer_class_init          (GMythFileTransferClass *klass);
rosfran@41
   100
static void gmyth_file_transfer_init                (GMythFileTransfer *object);
rosfran@41
   101
rosfran@41
   102
static void gmyth_file_transfer_dispose  (GObject *object);
rosfran@41
   103
static void gmyth_file_transfer_finalize (GObject *object);
rosfran@41
   104
rosfran@216
   105
static void gmyth_file_transfer_program_info_changed( GMythFileTransfer *transfer, 
rosfran@232
   106
										gint msg_code, gpointer livetv_transfer );
rosfran@216
   107
melunko@112
   108
static gboolean gmyth_connect_to_backend (GMythFileTransfer *transfer);
rosfran@41
   109
rosfran@41
   110
void gmyth_file_transfer_close( GMythFileTransfer *transfer );
rosfran@41
   111
rosfran@381
   112
static gboolean myth_control_acquire_context( GMythFileTransfer *transfer, gboolean do_wait );
rosfran@97
   113
rosfran@381
   114
static gboolean myth_control_release_context( GMythFileTransfer *transfer );
rosfran@97
   115
rosfran@41
   116
G_DEFINE_TYPE(GMythFileTransfer, gmyth_file_transfer, G_TYPE_OBJECT)
rosfran@41
   117
rosfran@41
   118
static void
rosfran@41
   119
gmyth_file_transfer_class_init (GMythFileTransferClass *klass)
rosfran@41
   120
{
rosfran@41
   121
  GObjectClass *gobject_class;
rosfran@216
   122
  GMythFileTransferClass *gtransfer_class;
rosfran@41
   123
rosfran@41
   124
  gobject_class = (GObjectClass *) klass;
rosfran@216
   125
  gtransfer_class = (GMythFileTransferClass *) gobject_class;
rosfran@41
   126
rosfran@41
   127
  gobject_class->dispose  = gmyth_file_transfer_dispose;
rosfran@41
   128
  gobject_class->finalize = gmyth_file_transfer_finalize;
rosfran@216
   129
  
rosfran@216
   130
  g_type_class_add_private (gobject_class, sizeof (GMythFileTransferPrivate));
rosfran@216
   131
  
rosfran@233
   132
	gtransfer_class->program_info_changed_handler = gmyth_file_transfer_program_info_changed;
rosfran@233
   133
  
rosfran@216
   134
	gtransfer_class->program_info_changed_handler_signal_id = 
rosfran@233
   135
		  g_signal_new ( "program-info-changed",
rosfran@216
   136
		                 G_TYPE_FROM_CLASS (gtransfer_class),
rosfran@216
   137
		                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
rosfran@216
   138
		                 0,
rosfran@216
   139
										 NULL,
rosfran@216
   140
										 NULL,
rosfran@216
   141
										 gmyth_marshal_VOID__INT_POINTER,
rosfran@216
   142
										 G_TYPE_NONE,
rosfran@216
   143
										 2,
rosfran@216
   144
										 G_TYPE_INT,
rosfran@233
   145
										 G_TYPE_POINTER );
rosfran@216
   146
rosfran@41
   147
}
rosfran@41
   148
melunko@112
   149
static void
melunko@112
   150
gmyth_file_transfer_init (GMythFileTransfer *transfer)
rosfran@41
   151
{ 
melunko@112
   152
  g_return_if_fail( transfer != NULL );
melunko@112
   153
melunko@112
   154
  transfer->readposition = 0;
melunko@112
   155
  transfer->filesize = GMYTHTV_FILE_SIZE;
rosfran@216
   156
  
rosfran@216
   157
  transfer->priv = GMYTH_FILE_TRANSFER_GET_PRIVATE(transfer);	
rosfran@216
   158
  
rosfran@216
   159
  transfer->priv->do_next_program_chain = FALSE;
rosfran@216
   160
  transfer->priv->livetv = NULL;
melunko@112
   161
melunko@112
   162
  transfer->control_sock = NULL;
melunko@112
   163
  transfer->sock = NULL;
rosfran@177
   164
  
rosfran@220
   165
  transfer->mutex = g_mutex_new();
rosfran@220
   166
  
rosfran@233
   167
	g_signal_connect ( G_OBJECT (transfer), "program-info-changed",
rosfran@233
   168
              (GCallback)(GMYTH_FILE_TRANSFER_GET_CLASS(transfer)->program_info_changed_handler),
rosfran@233
   169
              NULL );
rosfran@233
   170
rosfran@41
   171
}
rosfran@41
   172
rosfran@41
   173
static void
rosfran@41
   174
gmyth_file_transfer_dispose  (GObject *object)
rosfran@336
   175
{	
rosfran@192
   176
	GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (object);
rosfran@192
   177
	
rosfran@220
   178
  if ( transfer->mutex != NULL )  
rosfran@220
   179
  {
rosfran@220
   180
  	g_mutex_free( transfer->mutex );
rosfran@220
   181
  	transfer->mutex = NULL;
rosfran@220
   182
  }
rosfran@220
   183
  
rosfran@192
   184
  if ( transfer->control_sock != NULL )  
rosfran@192
   185
  {
rosfran@192
   186
  	g_object_unref( transfer->control_sock );
rosfran@192
   187
  	transfer->control_sock = NULL;
rosfran@192
   188
  }  
rosfran@192
   189
  
rosfran@192
   190
  if ( transfer->sock != NULL )  
rosfran@192
   191
  {
rosfran@192
   192
  	g_object_unref( transfer->sock );
rosfran@192
   193
  	transfer->sock = NULL;
renatofilho@187
   194
  }
rosfran@336
   195
  
rosfran@336
   196
  if ( transfer->priv->livetv != NULL )  
rosfran@336
   197
  {
rosfran@336
   198
  	g_object_unref( transfer->priv->livetv );
rosfran@336
   199
  	transfer->priv->livetv = NULL;
rosfran@336
   200
  }
rosfran@336
   201
rosfran@336
   202
	/*  
rosfran@336
   203
  if ( transfer->priv != NULL )  
rosfran@336
   204
  {
rosfran@336
   205
  	g_object_unref( transfer->priv );
rosfran@336
   206
  	transfer->priv = NULL;
rosfran@336
   207
  }
rosfran@336
   208
  */
rosfran@203
   209
    
rosfran@336
   210
  if ( transfer->filename != NULL )
rosfran@192
   211
  {
rosfran@192
   212
  	g_free( transfer->filename );
rosfran@192
   213
  	transfer->filename = NULL;
renatofilho@187
   214
  }
renatofilho@187
   215
rosfran@41
   216
  G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->dispose (object);
rosfran@41
   217
}
rosfran@41
   218
rosfran@101
   219
static void
rosfran@41
   220
gmyth_file_transfer_finalize (GObject *object)
rosfran@41
   221
{
rosfran@41
   222
  g_signal_handlers_destroy (object);
rosfran@41
   223
rosfran@41
   224
  G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->finalize (object);
rosfran@41
   225
}
rosfran@41
   226
melunko@112
   227
// fixme: do we need the card_id????
melunko@112
   228
GMythFileTransfer*
rosfran@177
   229
gmyth_file_transfer_new ( const GMythBackendInfo *backend_info)
rosfran@41
   230
{
renatofilho@166
   231
  GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (g_object_new (GMYTH_FILE_TRANSFER_TYPE, NULL));
rosfran@177
   232
  
rosfran@177
   233
  transfer->backend_info = (GMythBackendInfo *)backend_info;
renatofilho@187
   234
  g_object_ref (transfer->backend_info);
rosfran@41
   235
rosfran@177
   236
  return transfer;
rosfran@177
   237
}
rosfran@177
   238
rosfran@177
   239
GMythFileTransfer* 
renatofilho@187
   240
gmyth_file_transfer_new_with_uri (const gchar* uri_str)
rosfran@177
   241
{
rosfran@177
   242
  GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (g_object_new (GMYTH_FILE_TRANSFER_TYPE, NULL));
melunko@158
   243
melunko@201
   244
  transfer->backend_info = gmyth_backend_info_new_with_uri (uri_str);
renatofilho@187
   245
rosfran@41
   246
  return transfer;
rosfran@41
   247
}
rosfran@41
   248
rosfran@41
   249
gboolean
renatofilho@187
   250
gmyth_file_transfer_open (GMythFileTransfer *transfer, const gchar* filename)
rosfran@41
   251
{
rosfran@41
   252
  gboolean ret = TRUE;
rosfran@177
   253
  
renatofilho@202
   254
  g_return_val_if_fail (transfer != NULL, FALSE);
rosfran@343
   255
  g_return_val_if_fail (filename != NULL && strlen(filename) > 0, FALSE);
rosfran@356
   256
  /*
rosfran@177
   257
  
renatofilho@202
   258
  if (transfer->filename != NULL)
rosfran@184
   259
  {
renatofilho@202
   260
    g_free (transfer->filename);
renatofilho@202
   261
    transfer->filename = NULL;
rosfran@184
   262
  }
rosfran@356
   263
  */
renatofilho@202
   264
rosfran@343
   265
  transfer->filename = g_strdup( filename );
rosfran@184
   266
  
rosfran@41
   267
  /* configure the control socket */
melunko@112
   268
  if (transfer->control_sock == NULL) { 
renatofilho@143
   269
    if (!gmyth_connect_to_backend (transfer)) {
renatofilho@187
   270
      gmyth_debug ("Connection to backend failed (Control Socket).\n");
rosfran@41
   271
      ret = FALSE;
rosfran@41
   272
    }
rosfran@356
   273
  
rosfran@41
   274
  } else {
rosfran@41
   275
    g_warning("Remote transfer control socket already created.\n");
rosfran@41
   276
  }
rosfran@177
   277
  
rosfran@205
   278
  gmyth_debug ("Got file with size = %lld.\n", transfer->filesize);
rosfran@205
   279
  
rosfran@41
   280
  return ret;
rosfran@41
   281
rosfran@41
   282
}
rosfran@41
   283
rosfran@115
   284
static gboolean
melunko@112
   285
gmyth_connect_to_backend (GMythFileTransfer *transfer)
rosfran@41
   286
{
renatofilho@143
   287
  GString *base_str = NULL;
rosfran@177
   288
  GString *hostname = NULL;
melunko@158
   289
  GMythStringList *strlist = NULL; 
renatofilho@143
   290
  gboolean ret = TRUE;
rosfran@41
   291
melunko@112
   292
  g_return_val_if_fail (transfer != NULL, FALSE );
rosfran@381
   293
  
rosfran@381
   294
  myth_control_acquire_context( transfer, TRUE );
rosfran@41
   295
renatofilho@143
   296
  base_str = g_string_new ("");
rosfran@41
   297
melunko@112
   298
  /* Creates the control socket */
rosfran@356
   299
  
renatofilho@143
   300
  if (transfer->control_sock != NULL) {
renatofilho@143
   301
    g_object_unref (transfer->control_sock);
renatofilho@143
   302
    transfer->control_sock = NULL;
renatofilho@143
   303
  }
rosfran@356
   304
  
rosfran@356
   305
  //if ( NULL == transfer->control_sock )
rosfran@356
   306
  //{
rosfran@356
   307
  	transfer->control_sock = gmyth_socket_new();
renatofilho@143
   308
rosfran@356
   309
	  // Connects the socket, send Mythtv ANN command and verify Mythtv protocol version 
rosfran@356
   310
	  if (!gmyth_socket_connect_to_backend (transfer->control_sock,
rosfran@356
   311
	        transfer->backend_info->hostname, transfer->backend_info->port, TRUE)) {
rosfran@356
   312
	
rosfran@356
   313
	    g_object_unref (transfer->control_sock);
rosfran@356
   314
	    transfer->control_sock = NULL;
rosfran@356
   315
	    return FALSE;
rosfran@356
   316
	  }
rosfran@356
   317
	  
rosfran@356
   318
  //}
melunko@112
   319
    
melunko@112
   320
  /* Creates the data socket */
renatofilho@143
   321
  if (transfer->sock != NULL) {
renatofilho@143
   322
    g_object_unref (transfer->sock);
renatofilho@143
   323
    transfer->sock = NULL;
rosfran@356
   324
  }  
rosfran@356
   325
  
rosfran@356
   326
  //if ( NULL == transfer->sock ) {	
rosfran@356
   327
	  transfer->sock = gmyth_socket_new ();
rosfran@356
   328
	  gmyth_socket_connect (transfer->sock, transfer->backend_info->hostname, transfer->backend_info->port);
rosfran@356
   329
	  gmyth_debug("Connecting file transfer... (%s, %d)", transfer->backend_info->hostname, transfer->backend_info->port);	  
rosfran@356
   330
  //}
rosfran@356
   331
  
rosfran@356
   332
  if ( transfer->control_sock != NULL )
rosfran@356
   333
  {
rosfran@356
   334
	
rosfran@356
   335
	  strlist = gmyth_string_list_new();
rosfran@356
   336
	  hostname = gmyth_socket_get_local_hostname();
rosfran@356
   337
	  gmyth_debug( "[%s] MythTV version (from backend) = %d.\n", __FUNCTION__, transfer->control_sock->mythtv_version );
rosfran@356
   338
	  if ( transfer->control_sock->mythtv_version > 26 )
rosfran@356
   339
	  	g_string_printf( base_str, "ANN FileTransfer %s 1 -1", hostname->str);
rosfran@356
   340
	  else
rosfran@356
   341
	  	g_string_printf( base_str, "ANN FileTransfer %s", hostname->str);
rosfran@356
   342
	
rosfran@356
   343
	  gmyth_string_list_append_string (strlist, base_str );
rosfran@356
   344
	  gmyth_string_list_append_char_array (strlist, transfer->filename);
rosfran@356
   345
	
rosfran@356
   346
	  gmyth_socket_write_stringlist (transfer->sock, strlist );
rosfran@356
   347
	  gmyth_socket_read_stringlist (transfer->sock, strlist );
rosfran@356
   348
	    
rosfran@356
   349
	  /* file identification used in future file transfer requests to backend */
rosfran@356
   350
	  transfer->file_id = gmyth_string_list_get_int( strlist, 1 );
rosfran@356
   351
	
rosfran@356
   352
	  /* Myth URI stream file size - decoded using two 8-bytes sequences (64 bits/long long types) */
rosfran@356
   353
	  transfer->filesize = gmyth_util_decode_long_long( strlist, 2 );
rosfran@356
   354
	
rosfran@356
   355
	  gmyth_debug ( "[%s] ***** Received: recordernum = %d, filesize = %" G_GUINT64_FORMAT "\n", __FUNCTION__,
rosfran@356
   356
	          transfer->file_id, transfer->filesize );
rosfran@356
   357
	
rosfran@356
   358
	  if (transfer->filesize < 0 ) {
rosfran@356
   359
	      gmyth_debug ( "[%s] Got filesize equals to %llu is lesser than 0 [invalid stream file]\n", __FUNCTION__, transfer->filesize );
rosfran@356
   360
	      g_object_unref (transfer->sock);
rosfran@356
   361
	      transfer->sock = NULL;
rosfran@356
   362
	      ret = FALSE;
rosfran@356
   363
	      goto cleanup;
rosfran@356
   364
	  }
rosfran@356
   365
	  
rosfran@356
   366
  } /* if - Control Socket is not equals to NULL? */
melunko@112
   367
  
renatofilho@143
   368
cleanup:
rosfran@41
   369
rosfran@381
   370
	myth_control_release_context( transfer );
rosfran@381
   371
rosfran@41
   372
  if ( strlist != NULL )
rosfran@41
   373
    g_object_unref( strlist );
rosfran@356
   374
  
rosfran@356
   375
  if ( base_str != NULL )
rosfran@356
   376
  	g_string_free (base_str, TRUE);
rosfran@356
   377
  	
rosfran@356
   378
  if ( hostname != NULL )
rosfran@356
   379
  	g_string_free (hostname, TRUE);
rosfran@41
   380
renatofilho@143
   381
  return ret;
rosfran@41
   382
}    
rosfran@41
   383
rosfran@233
   384
void
rosfran@233
   385
gmyth_file_transfer_emit_program_info_changed_signal ( GMythFileTransfer *transfer, gint msg_code,
rosfran@233
   386
			gpointer live_tv ) 
rosfran@233
   387
{
rosfran@233
   388
				/*
rosfran@233
   389
	g_signal_emit_by_name ( G_OBJECT(transfer),
rosfran@233
   390
         "program-info-changed",
rosfran@233
   391
         msg_code, live_tv );
rosfran@233
   392
         */
rosfran@233
   393
         
rosfran@233
   394
  gmyth_debug( "Calling signal handler... [FILE_TRANSFER]" );
rosfran@233
   395
rosfran@233
   396
  g_signal_emit ( transfer,
rosfran@233
   397
         GMYTH_FILE_TRANSFER_GET_CLASS (transfer)->program_info_changed_handler_signal_id,
rosfran@233
   398
         0, /* details */
rosfran@233
   399
         msg_code, live_tv );
rosfran@233
   400
rosfran@233
   401
}
rosfran@233
   402
melunko@112
   403
gboolean
melunko@112
   404
gmyth_file_transfer_is_open (GMythFileTransfer *transfer)
rosfran@41
   405
{
melunko@112
   406
    GMythStringList *strlist;
melunko@112
   407
    GString *query;
rosfran@41
   408
melunko@112
   409
    g_return_val_if_fail (transfer->control_sock != NULL, FALSE);
melunko@112
   410
    g_return_val_if_fail (transfer->sock != NULL, FALSE);
rosfran@381
   411
    
rosfran@381
   412
    myth_control_acquire_context( transfer, TRUE );
rosfran@41
   413
melunko@112
   414
    strlist = gmyth_string_list_new();
melunko@112
   415
    query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   416
    g_string_append_printf (query, "%d", transfer->file_id );
rosfran@41
   417
melunko@112
   418
    gmyth_string_list_append_string (strlist, query );
melunko@112
   419
    gmyth_string_list_append_char_array( strlist, "IS_OPEN" );
rosfran@41
   420
melunko@112
   421
    gmyth_socket_write_stringlist( transfer->control_sock, strlist );
melunko@112
   422
    gmyth_socket_read_stringlist( transfer->control_sock, strlist );
rosfran@381
   423
    
rosfran@381
   424
    myth_control_release_context( transfer );
rosfran@41
   425
melunko@112
   426
    g_string_free (query, TRUE);
melunko@112
   427
    g_object_unref (strlist);
rosfran@41
   428
melunko@112
   429
    return ( strlist != NULL && gmyth_string_list_get_int( strlist, 0 ) == 1 );
rosfran@41
   430
}
rosfran@41
   431
melunko@112
   432
void
rosfran@41
   433
gmyth_file_transfer_close( GMythFileTransfer *transfer )
rosfran@41
   434
{
rosfran@41
   435
  GMythStringList *strlist;
melunko@112
   436
  GString *query;
rosfran@41
   437
melunko@112
   438
  g_return_if_fail (transfer->control_sock != NULL);
rosfran@381
   439
  
rosfran@381
   440
  myth_control_acquire_context( transfer, TRUE );
rosfran@41
   441
rosfran@41
   442
  strlist = gmyth_string_list_new( );
melunko@112
   443
  query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   444
  g_string_append_printf( query, "%d", transfer->file_id);
rosfran@41
   445
melunko@112
   446
  gmyth_string_list_append_string( strlist, query );
rosfran@41
   447
  gmyth_string_list_append_char_array( strlist, "DONE" );
rosfran@41
   448
melunko@112
   449
  if ( gmyth_socket_sendreceive_stringlist(transfer->control_sock, strlist) <= 0 ) {
melunko@112
   450
    // fixme: time out???
rosfran@381
   451
    gmyth_debug ( "Remote file timeout.\n" );
rosfran@41
   452
  }
rosfran@41
   453
melunko@112
   454
  g_string_free (query, TRUE);
melunko@112
   455
  g_object_unref (strlist);
melunko@112
   456
melunko@112
   457
  if (transfer->sock) {
rosfran@41
   458
    g_object_unref( transfer->sock );
rosfran@41
   459
    transfer->sock = NULL;
rosfran@41
   460
  }
rosfran@41
   461
melunko@112
   462
  if (transfer->control_sock) {
rosfran@41
   463
    g_object_unref( transfer->control_sock );
rosfran@41
   464
    transfer->control_sock = NULL;
rosfran@41
   465
  } 
rosfran@381
   466
rosfran@381
   467
  myth_control_release_context( transfer );
rosfran@381
   468
rosfran@41
   469
}
rosfran@41
   470
rosfran@41
   471
gint64
rosfran@41
   472
gmyth_file_transfer_seek(GMythFileTransfer *transfer, guint64 pos, gint whence)
rosfran@41
   473
{
melunko@112
   474
  GMythStringList *strlist = gmyth_string_list_new();
melunko@112
   475
  GString *query;
rosfran@41
   476
melunko@112
   477
  g_return_val_if_fail (transfer->sock != NULL, -1);
melunko@112
   478
  g_return_val_if_fail (transfer->control_sock != NULL, -1);
rosfran@41
   479
melunko@112
   480
  strlist = gmyth_string_list_new();
melunko@112
   481
  query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   482
  g_string_append_printf (query, "%d", transfer->file_id);
rosfran@97
   483
  
rosfran@381
   484
  myth_control_acquire_context( transfer, TRUE );
rosfran@41
   485
melunko@112
   486
  gmyth_string_list_append_string( strlist, query );
rosfran@41
   487
  gmyth_string_list_append_char_array( strlist, "SEEK" );
rosfran@41
   488
  gmyth_string_list_append_uint64( strlist, pos );
rosfran@41
   489
  
rosfran@41
   490
  gmyth_string_list_append_int( strlist, whence );  
rosfran@41
   491
rosfran@41
   492
  if (pos > 0 )
rosfran@41
   493
    gmyth_string_list_append_uint64( strlist, pos );
rosfran@41
   494
  else
rosfran@41
   495
    gmyth_string_list_append_uint64( strlist, transfer->readposition );
rosfran@41
   496
  
rosfran@41
   497
  gmyth_socket_sendreceive_stringlist( transfer->control_sock, strlist );
rosfran@41
   498
rosfran@41
   499
  gint64 retval = gmyth_string_list_get_int64(strlist, 0);
rosfran@41
   500
  transfer->readposition = retval;
renatofilho@131
   501
  gmyth_debug ( "[%s] got reading position pointer from the streaming = %lld\n", 
rosfran@41
   502
      __FUNCTION__, retval );
rosfran@41
   503
rosfran@381
   504
  myth_control_release_context( transfer );
rosfran@41
   505
rosfran@41
   506
  return retval;
rosfran@41
   507
}
rosfran@41
   508
rosfran@97
   509
static gboolean 
rosfran@381
   510
myth_control_acquire_context( GMythFileTransfer *transfer, gboolean do_wait )
rosfran@97
   511
{
rosfran@97
   512
	gboolean ret = TRUE;	
rosfran@140
   513
	//guint max_iter = 50;
rosfran@97
   514
	
rosfran@381
   515
	g_mutex_lock( transfer->mutex );
rosfran@97
   516
	
rosfran@97
   517
  //while ( !has_io_access ) 
rosfran@97
   518
  //	g_cond_wait( io_watcher_cond, mutex );
rosfran@97
   519
  	
rosfran@97
   520
  //has_io_access = FALSE;
rosfran@97
   521
  
rosfran@97
   522
  //myth_control_acquire_context (FALSE);
rosfran@140
   523
   
rosfran@140
   524
  /* 
rosfran@97
   525
  if ( do_wait ) {
rosfran@120
   526
  	while ( --max_iter > 0 && !g_main_context_wait( io_watcher_context, io_watcher_cond, mutex ) )
rosfran@97
   527
  		ret = FALSE;
rosfran@97
   528
  } else if ( !g_main_context_acquire( io_watcher_context ) )
rosfran@97
   529
  	ret = FALSE;
rosfran@140
   530
  */
rosfran@140
   531
  	
rosfran@140
   532
  //g_static_mutex_lock( &st_mutex );
rosfran@97
   533
  
rosfran@97
   534
  return ret;
rosfran@97
   535
}
rosfran@97
   536
rosfran@97
   537
static gboolean 
rosfran@381
   538
myth_control_release_context( GMythFileTransfer *transfer ) 
rosfran@97
   539
{
rosfran@97
   540
	gboolean ret = TRUE;
rosfran@140
   541
    
rosfran@140
   542
  //g_static_mutex_unlock( &st_mutex );
rosfran@97
   543
  
rosfran@140
   544
	//g_main_context_release( io_watcher_context );
rosfran@140
   545
  
rosfran@140
   546
  //g_main_context_wakeup( io_watcher_context );
rosfran@97
   547
  
rosfran@97
   548
  //has_io_access = TRUE;
rosfran@97
   549
rosfran@97
   550
  //g_cond_broadcast( io_watcher_cond );
rosfran@97
   551
  
rosfran@381
   552
  g_mutex_unlock( transfer->mutex );  
rosfran@97
   553
 
rosfran@97
   554
  return ret;
rosfran@97
   555
}
rosfran@97
   556
rosfran@41
   557
gint 
rosfran@115
   558
gmyth_file_transfer_read(GMythFileTransfer *transfer, GByteArray *data, gint size, gboolean read_unlimited)
rosfran@41
   559
{
rosfran@177
   560
  gint bytes_sent = 0;
rosfran@41
   561
  gsize bytes_read = 0;
melunko@112
   562
  gsize total_read = 0;
melunko@112
   563
  
melunko@112
   564
  GError *error = NULL;
melunko@112
   565
  
rosfran@41
   566
  GIOChannel *io_channel;
rosfran@41
   567
  GIOChannel *io_channel_control;
rosfran@41
   568
rosfran@41
   569
  GIOCondition io_cond;
rosfran@41
   570
  GIOCondition io_cond_control;
rosfran@220
   571
  GIOStatus io_status = G_IO_STATUS_NORMAL, io_status_control = G_IO_STATUS_NORMAL;
rosfran@220
   572
  
rosfran@220
   573
  gboolean ret = TRUE;   
rosfran@41
   574
melunko@112
   575
  GString *query;
rosfran@115
   576
  
rosfran@41
   577
  g_return_val_if_fail ( data != NULL, -2 );
rosfran@101
   578
rosfran@41
   579
  io_channel = transfer->sock->sd_io_ch;
rosfran@41
   580
  io_channel_control = transfer->control_sock->sd_io_ch;
rosfran@41
   581
rosfran@41
   582
  io_status = g_io_channel_set_encoding( io_channel, NULL, &error );
rosfran@41
   583
  if ( io_status == G_IO_STATUS_NORMAL )
renatofilho@131
   584
    gmyth_debug ( "[%s] Setting encoding to binary data socket).\n", __FUNCTION__ );
rosfran@41
   585
rosfran@41
   586
  io_cond = g_io_channel_get_buffer_condition( io_channel );  
rosfran@41
   587
rosfran@41
   588
  io_cond_control = g_io_channel_get_buffer_condition( io_channel );
melunko@112
   589
  if ( transfer->sock == NULL || ( io_status == G_IO_STATUS_ERROR ) ) {
rosfran@41
   590
    g_printerr( "gmyth_file_transfer_read(): Called with no raw socket.\n" );
melunko@112
   591
    return -1;
rosfran@41
   592
  }
rosfran@41
   593
melunko@112
   594
  if ( transfer->control_sock == NULL || ( io_status_control == G_IO_STATUS_ERROR ) ) {
rosfran@41
   595
    g_printerr( "gmyth_file_transfer_read(): Called with no control socket.\n" );
melunko@112
   596
    return -1;
rosfran@41
   597
  }
rosfran@41
   598
melunko@112
   599
  query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   600
  g_string_append_printf ( query, "%d", transfer->file_id );
renatofilho@131
   601
  gmyth_debug ("[%s] Transfer_query = %s\n", __FUNCTION__, query->str );
rosfran@41
   602
  
rosfran@177
   603
  /* send requests to the maximum number of REQUEST_BLOCK messages */
rosfran@197
   604
  guint max_tries = 5;
rosfran@177
   605
  
rosfran@381
   606
  myth_control_acquire_context( transfer, TRUE );
rosfran@140
   607
  
rosfran@177
   608
  while (total_read == 0 && --max_tries > 0) {
renatofilho@143
   609
    GMythStringList *strlist = gmyth_string_list_new();
melunko@112
   610
melunko@112
   611
    gmyth_string_list_append_char_array( strlist, query->str );
rosfran@101
   612
    gmyth_string_list_append_char_array( strlist, "REQUEST_BLOCK" );
melunko@112
   613
    gmyth_string_list_append_int( strlist, size );
melunko@112
   614
melunko@112
   615
    // Request the block to the backend
melunko@112
   616
    gmyth_socket_write_stringlist( transfer->control_sock, strlist );
melunko@112
   617
melunko@112
   618
    // Receives the backand answer    
rosfran@101
   619
    gmyth_socket_read_stringlist( transfer->control_sock, strlist );
rosfran@101
   620
rosfran@220
   621
    if ( strlist != NULL && gmyth_string_list_length( strlist ) > 0 ) 
rosfran@220
   622
    { 
renatofilho@143
   623
	    bytes_sent = gmyth_string_list_get_int( strlist,  0 ); // -1 on backend error
renatofilho@143
   624
	    gmyth_debug ( "[%s] got SENT buffer message = %d\n", __FUNCTION__, bytes_sent );
rosfran@89
   625
rosfran@342
   626
    	if ( bytes_sent >= 0 )
rosfran@220
   627
    	{
rosfran@220
   628
        gchar *data_buffer = g_new0 ( gchar, bytes_sent );    
rosfran@220
   629
   	    while ( 0 != bytes_sent ) 
rosfran@220
   630
   	    { 
rosfran@220
   631
          io_status = g_io_channel_read_chars( io_channel, data_buffer + total_read, 
rosfran@220
   632
	    				(gsize) bytes_sent,	&bytes_read, &error );
rosfran@220
   633
rosfran@220
   634
	        total_read += bytes_read;
rosfran@220
   635
          bytes_sent -= bytes_read;
rosfran@342
   636
rosfran@220
   637
            /* append new data to the increasing byte array */
rosfran@220
   638
	    		data = g_byte_array_append (data, (const guint8*)data_buffer, bytes_read);
rosfran@220
   639
	        gmyth_debug ("Total transfer data read: %d\n", total_read);
rosfran@220
   640
        }
rosfran@220
   641
        g_free (data_buffer);
rosfran@220
   642
      } /* if */
rosfran@302
   643
    } else if ( !(transfer->priv != NULL && transfer->priv->livetv != NULL &&
rosfran@302
   644
					transfer->priv->do_next_program_chain) ) {
rosfran@177
   645
    	total_read = GMYTHTV_FILE_TRANSFER_READ_ERROR;
rosfran@177
   646
    	g_object_unref (strlist);
rosfran@302
   647
    	strlist = NULL;
rosfran@177
   648
    	break;
melunko@112
   649
    }
rosfran@353
   650
    if ( strlist!=NULL )
rosfran@353
   651
    {
rosfran@353
   652
	    g_object_unref (strlist);
rosfran@353
   653
	    strlist = NULL;
rosfran@353
   654
    }
rosfran@353
   655
  } /* while - iterates through bytes until reaches the end of stream */
rosfran@342
   656
rosfran@348
   657
  if ( bytes_sent == 0 && max_tries == 0 )
rosfran@234
   658
	{
rosfran@234
   659
		gmyth_debug( "Trying to move to the next program chain..." );
rosfran@234
   660
		transfer->priv = GMYTH_FILE_TRANSFER_GET_PRIVATE(transfer);
rosfran@234
   661
		
rosfran@234
   662
		if ( transfer->priv != NULL && transfer->priv->livetv != NULL &&
rosfran@234
   663
					transfer->priv->do_next_program_chain )
rosfran@234
   664
		{
rosfran@234
   665
		
rosfran@356
   666
			  total_read = GMYTHTV_FILE_TRANSFER_NEXT_PROG_CHAIN;	
rosfran@234
   667
		
rosfran@356
   668
	  		//g_mutex_lock( transfer->mutex );
rosfran@234
   669
	  		
rosfran@356
   670
	  		//ret = gmyth_livetv_next_program_chain( transfer->priv->livetv );
rosfran@356
   671
	  		GMythProgramInfo *prog_info = gmyth_recorder_get_current_program_info( transfer->priv->livetv->recorder );
rosfran@234
   672
	  		
rosfran@356
   673
	  		if ( prog_info != NULL && prog_info->pathname != NULL && strlen( prog_info->pathname->str ) > 0 &&
rosfran@356
   674
	  						g_ascii_strcasecmp( prog_info->pathname->str, transfer->filename ) != 0 )
rosfran@356
   675
	  			ret = gmyth_file_transfer_open ( transfer, g_strrstr( prog_info->pathname->str, "/" ) );
rosfran@342
   676
	  		
rosfran@356
   677
	  		if ( prog_info != NULL )
rosfran@356
   678
	  			g_object_unref( prog_info );
rosfran@356
   679
	  			
rosfran@356
   680
	  		//g_mutex_unlock( transfer->mutex );
rosfran@234
   681
  		
rosfran@234
   682
			if ( !ret )
rosfran@356
   683
				gmyth_debug( "Cannot change to the next program info!" );
rosfran@234
   684
			else
rosfran@356
   685
				gmyth_debug( "OK!!! MOVED to the next program info [%s]!", 
rosfran@356
   686
										transfer->filename );						
rosfran@234
   687
		}
rosfran@234
   688
rosfran@234
   689
	} /* if */
rosfran@234
   690
  
rosfran@381
   691
  myth_control_release_context( transfer );
renatofilho@143
   692
  g_string_free (query, TRUE);
rosfran@41
   693
renatofilho@143
   694
  if ( error != NULL ) {
renatofilho@143
   695
    gmyth_debug ("Cleaning-up ERROR: %s [msg = %s, code = %d]\n", __FUNCTION__, error->message, 
renatofilho@143
   696
	    error->code);
renatofilho@143
   697
    g_error_free (error);
renatofilho@143
   698
  }
melunko@112
   699
  
rosfran@216
   700
  if ( total_read > 0 )
rosfran@220
   701
  	transfer->readposition += total_read;  	
rosfran@177
   702
  	
melunko@112
   703
  return total_read;
rosfran@41
   704
}
rosfran@41
   705
rosfran@216
   706
static void 
rosfran@216
   707
gmyth_file_transfer_program_info_changed( GMythFileTransfer *transfer, 
rosfran@232
   708
										gint msg_code, gpointer livetv_transfer )
rosfran@216
   709
{
rosfran@233
   710
	GMythLiveTV *livetv = GMYTH_LIVETV( livetv_transfer );
rosfran@216
   711
	
rosfran@220
   712
	gmyth_debug( "Program info changed! ( file transfer orig. = %p, ptr. = [%s], user data = [%s] )", transfer, 
rosfran@220
   713
		livetv_transfer != NULL ? "[NOT NULL]" : "[NULL]", livetv != NULL ? "[NOT NULL]" : "[NULL]" );
rosfran@216
   714
	
rosfran@220
   715
	if ( livetv != NULL && transfer == livetv->file_transfer )
rosfran@216
   716
	{
rosfran@216
   717
		gmyth_debug( "YES, the requested program info movement on the LiveTV transfer is authentical!" );
rosfran@216
   718
	}
rosfran@216
   719
	
rosfran@216
   720
	transfer->priv = GMYTH_FILE_TRANSFER_GET_PRIVATE(transfer);	
rosfran@216
   721
	
rosfran@342
   722
	transfer->priv->livetv = livetv;
rosfran@216
   723
	transfer->priv->do_next_program_chain = TRUE;
rosfran@216
   724
	
rosfran@216
   725
}
rosfran@216
   726
melunko@112
   727
gboolean 
rosfran@41
   728
gmyth_file_transfer_settimeout( GMythFileTransfer *transfer, gboolean fast )
rosfran@41
   729
{
rosfran@41
   730
rosfran@41
   731
  GMythStringList *strlist = NULL;
rosfran@41
   732
melunko@112
   733
  g_return_val_if_fail (transfer->sock != NULL, FALSE);
melunko@112
   734
  g_return_val_if_fail (transfer->control_sock != NULL, FALSE);
rosfran@381
   735
  
rosfran@381
   736
  myth_control_acquire_context( transfer, TRUE );
rosfran@41
   737
rosfran@41
   738
  strlist = gmyth_string_list_new(); 
melunko@112
   739
  gmyth_string_list_append_char_array( strlist, GMYTHTV_QUERY_HEADER );
rosfran@41
   740
  gmyth_string_list_append_char_array( strlist, "SET_TIMEOUT" );
rosfran@41
   741
  gmyth_string_list_append_int( strlist, fast ); 
rosfran@41
   742
rosfran@381
   743
  gint strlist_len = gmyth_socket_sendreceive_stringlist( transfer->control_sock, 
rosfran@381
   744
  				strlist );
rosfran@381
   745
  
rosfran@381
   746
  if ( strlist_len > 0 )
rosfran@381
   747
  	gmyth_debug( "Yes, timeout was changed: %s.", gmyth_string_list_get_char_array( strlist, 0 ) );
rosfran@381
   748
  else
rosfran@381
   749
  	gmyth_debug( "Timeout cannot be changed!" );
rosfran@381
   750
  	
rosfran@381
   751
 	myth_control_release_context( transfer );
rosfran@41
   752
rosfran@381
   753
  gmyth_debug ( "%s setting timeout flag of this file transfer = %s\n", 
rosfran@381
   754
  		strlist_len > 0 ? "Yes," : "NOT", fast ? "FAST" : "NOT FAST" );
rosfran@41
   755
melunko@112
   756
  return TRUE;
rosfran@41
   757
}
rosfran@41
   758
melunko@117
   759
guint64
melunko@117
   760
gmyth_file_transfer_get_filesize (GMythFileTransfer *transfer)
melunko@117
   761
{
renatofilho@206
   762
    g_return_val_if_fail (transfer != NULL, 0);
melunko@117
   763
    return transfer->filesize;
melunko@117
   764
}