4 * @file gmyth/gmyth_file_transfer.c
6 * @brief <p> GMythFileTransfer deals with the file streaming media remote/local
7 * transfering to the MythTV frontend.
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Rosfran Lins Borges <rosfran.borges@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
28 * GStreamer MythTV plug-in properties:
29 * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
30 * - path (qurl - remote file to be opened)
38 #include "gmyth_file_transfer.h"
39 #include "gmyth_recorder.h"
40 #include "gmyth_util.h"
41 #include "gmyth_socket.h"
42 #include "gmyth_stringlist.h"
43 #include "gmyth_debug.h"
44 #include "gmyth_uri.h"
45 #include "gmyth_marshal.h"
50 #include <arpa/inet.h>
51 #include <sys/types.h>
52 #include <sys/socket.h>
58 #define GMYTHTV_QUERY_HEADER "QUERY_FILETRANSFER "
60 /* default values to the file transfer parameters */
61 #define GMYTHTV_USER_READ_AHEAD TRUE
62 #define GMYTHTV_RETRIES -1
63 #define GMYTHTV_FILE_SIZE 0
65 #define GMYTHTV_BUFFER_SIZE 64*1024
67 #define GMYTHTV_VERSION 30
69 #define GMYTHTV_TRANSFER_MAX_WAITS 700
71 #ifdef GMYTHTV_ENABLE_DEBUG
72 #define GMYTHTV_ENABLE_DEBUG 1
74 #undef GMYTHTV_ENABLE_DEBUG
77 /* this NDEBUG is to maintain compatibility with GMyth library */
79 #define GMYTHTV_ENABLE_DEBUG 1
82 enum myth_sock_types {
83 GMYTH_PLAYBACK_TYPE = 0,
85 GMYTH_FILETRANSFER_TYPE,
89 #define GMYTH_FILE_TRANSFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_FILE_TRANSFER_TYPE, GMythFileTransferPrivate))
91 struct _GMythFileTransferPrivate {
92 GMythRecorder *recorder;
94 gboolean do_next_program_chain;
98 static void gmyth_file_transfer_class_init (GMythFileTransferClass *klass);
99 static void gmyth_file_transfer_init (GMythFileTransfer *object);
101 static void gmyth_file_transfer_dispose (GObject *object);
102 static void gmyth_file_transfer_finalize (GObject *object);
104 static void gmyth_file_transfer_program_info_changed( GMythFileTransfer *transfer,
105 gint msg_code, gpointer livetv_recorder );
107 static gboolean gmyth_connect_to_backend (GMythFileTransfer *transfer);
109 void gmyth_file_transfer_close( GMythFileTransfer *transfer );
111 static gboolean myth_control_acquire_context( GMythFileTransfer *transfer, gboolean do_wait );
113 static gboolean myth_control_release_context( GMythFileTransfer *transfer );
115 G_DEFINE_TYPE(GMythFileTransfer, gmyth_file_transfer, G_TYPE_OBJECT)
118 gmyth_file_transfer_class_init (GMythFileTransferClass *klass)
120 GObjectClass *gobject_class;
121 GMythFileTransferClass *gtransfer_class;
123 gobject_class = (GObjectClass *) klass;
124 gtransfer_class = (GMythFileTransferClass *) gobject_class;
126 gobject_class->dispose = gmyth_file_transfer_dispose;
127 gobject_class->finalize = gmyth_file_transfer_finalize;
129 g_type_class_add_private (gobject_class, sizeof (GMythFileTransferPrivate));
131 gtransfer_class->program_info_changed_handler = gmyth_file_transfer_program_info_changed;
133 gtransfer_class->program_info_changed_handler_signal_id =
134 g_signal_new ( "program-info-changed",
135 G_TYPE_FROM_CLASS (gtransfer_class),
136 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
140 gmyth_marshal_VOID__INT_POINTER,
149 gmyth_file_transfer_init (GMythFileTransfer *transfer)
151 g_return_if_fail( transfer != NULL );
153 transfer->readposition = 0;
154 transfer->filesize = GMYTHTV_FILE_SIZE;
156 transfer->priv = GMYTH_FILE_TRANSFER_GET_PRIVATE(transfer);
158 transfer->priv->do_next_program_chain = FALSE;
159 transfer->priv->recorder = NULL;
161 transfer->control_sock = NULL;
162 transfer->sock = NULL;
164 transfer->mutex = g_mutex_new();
166 g_signal_connect ( G_OBJECT (transfer), "program-info-changed",
167 (GCallback)(GMYTH_FILE_TRANSFER_GET_CLASS(transfer)->program_info_changed_handler),
173 gmyth_file_transfer_dispose (GObject *object)
175 GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (object);
177 if (transfer->priv->disposed) {
178 /* If dispose did already run, return. */
182 /* Make sure dispose does not run twice. */
183 transfer->priv->disposed = TRUE;
185 if ( transfer->mutex != NULL ) {
186 g_mutex_free( transfer->mutex );
187 transfer->mutex = NULL;
190 if ( transfer->control_sock != NULL ) {
191 g_object_unref( transfer->control_sock );
192 transfer->control_sock = NULL;
195 if ( transfer->sock != NULL ) {
196 g_object_unref( transfer->sock );
197 transfer->sock = NULL;
200 if ( transfer->backend_info != NULL ) {
201 g_object_unref( transfer->backend_info );
202 transfer->backend_info = NULL;
205 if ( transfer->priv->recorder != NULL ) {
206 g_object_unref( transfer->priv->recorder );
207 transfer->priv->recorder = NULL;
210 if ( transfer->filename != NULL ) {
211 g_free( transfer->filename );
212 transfer->filename = NULL;
215 G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->dispose (object);
219 gmyth_file_transfer_finalize (GObject *object)
221 g_signal_handlers_destroy (object);
223 G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->finalize (object);
227 * Creates a new instance of GMythFileTransfer.
229 * @param backend_info The BackendInfo instance, with all the MythTV network
230 * configuration data.
232 * @return a new instance of the File Transfer.
235 gmyth_file_transfer_new (GMythBackendInfo *backend_info)
237 GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (g_object_new (GMYTH_FILE_TRANSFER_TYPE, NULL));
239 transfer->backend_info = backend_info;
240 g_object_ref (transfer->backend_info);
246 * Creates a new instance of GMythFileTransfer.
248 * @param uri_str The URI poiting to the MythTV backend server.
250 * @return a new instance of the File Transfer.
253 gmyth_file_transfer_new_with_uri (const gchar* uri_str)
255 GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (g_object_new (GMYTH_FILE_TRANSFER_TYPE, NULL));
257 transfer->backend_info = gmyth_backend_info_new_with_uri (uri_str);
263 * Open a File Transfer connection in order to get a remote file.
265 * @param transfer The actual File Transfer instance.
266 * @param filename The file name of the remote file to be transfered to the client.
268 * @return <code>true</code>, if the connection opening had been done successfully.
271 gmyth_file_transfer_open (GMythFileTransfer *transfer, const gchar* filename)
275 g_return_val_if_fail (transfer != NULL, FALSE);
276 g_return_val_if_fail (filename != NULL && strlen(filename) > 0, FALSE);
278 if (transfer->filename != NULL)
280 g_free (transfer->filename);
281 transfer->filename = NULL;
284 transfer->filename = g_strdup( filename );
286 /* configure the control socket */
287 if (transfer->control_sock == NULL) {
288 if (!gmyth_connect_to_backend (transfer)) {
289 gmyth_debug ("Connection to backend failed (Control Socket).\n");
293 g_warning("Remote transfer control socket already created.\n");
296 gmyth_debug ("Got file with size = %lld.\n", transfer->filesize);
302 * Connect a File Transfer binary client socket to a remote file.
304 * @param transfer The actual File Transfer instance.
306 * @return <code>true</code>, if the connection had been configured successfully.
309 gmyth_connect_to_backend (GMythFileTransfer *transfer)
311 GString *base_str = NULL;
312 GString *hostname = NULL;
313 GMythStringList *strlist = NULL;
316 g_return_val_if_fail (transfer != NULL, FALSE );
318 myth_control_acquire_context( transfer, TRUE );
320 base_str = g_string_new ("");
322 /* Creates the control socket */
324 if (transfer->control_sock != NULL) {
325 g_object_unref (transfer->control_sock);
326 transfer->control_sock = NULL;
329 if ( NULL == transfer->control_sock )
331 transfer->control_sock = gmyth_socket_new();
333 // Connects the socket, send Mythtv ANN command and verify Mythtv protocol version
334 if (!gmyth_socket_connect_to_backend (transfer->control_sock,
335 transfer->backend_info->hostname, transfer->backend_info->port, TRUE)) {
337 g_object_unref (transfer->control_sock);
338 transfer->control_sock = NULL;
344 /* Creates the data socket */
345 if (transfer->sock != NULL) {
346 g_object_unref (transfer->sock);
347 transfer->sock = NULL;
350 //if ( NULL == transfer->sock ) {
351 transfer->sock = gmyth_socket_new ();
352 gmyth_socket_connect (transfer->sock, transfer->backend_info->hostname, transfer->backend_info->port);
353 gmyth_debug("Connecting file transfer... (%s, %d)", transfer->backend_info->hostname, transfer->backend_info->port);
356 if ( transfer->control_sock != NULL )
359 strlist = gmyth_string_list_new();
360 hostname = gmyth_socket_get_local_hostname();
361 gmyth_debug( "[%s] MythTV version (from backend) = %d.\n", __FUNCTION__, transfer->control_sock->mythtv_version );
362 if ( transfer->control_sock->mythtv_version > 26 )
363 g_string_printf( base_str, "ANN FileTransfer %s 1 -1", hostname->str);
365 g_string_printf( base_str, "ANN FileTransfer %s", hostname->str);
367 gmyth_string_list_append_string (strlist, base_str );
368 gmyth_string_list_append_char_array (strlist, transfer->filename);
370 gmyth_socket_write_stringlist (transfer->sock, strlist );
371 gmyth_socket_read_stringlist (transfer->sock, strlist );
373 /* file identification used in future file transfer requests to backend */
374 transfer->file_id = gmyth_string_list_get_int( strlist, 1 );
376 /* Myth URI stream file size - decoded using two 8-bytes sequences (64 bits/long long types) */
377 transfer->filesize = gmyth_util_decode_long_long( strlist, 2 );
379 gmyth_debug ( "[%s] ***** Received: recordernum = %d, filesize = %" G_GUINT64_FORMAT "\n", __FUNCTION__,
380 transfer->file_id, transfer->filesize );
382 if (transfer->filesize < 0 ) {
383 gmyth_debug ( "[%s] Got filesize equals to %llu is lesser than 0 [invalid stream file]\n", __FUNCTION__, transfer->filesize );
384 g_object_unref (transfer->sock);
385 transfer->sock = NULL;
390 } /* if - Control Socket is not equals to NULL? */
394 myth_control_release_context( transfer );
396 if ( strlist != NULL )
397 g_object_unref( strlist );
399 if ( base_str != NULL )
400 g_string_free (base_str, TRUE);
402 if ( hostname != NULL )
403 g_string_free (hostname, TRUE);
409 * Receives a GObject signal coming from a LiveTV instance, all the time a
410 * program info changes.
412 * @param transfer The actual File Transfer instance.
413 * @param msg_code The MythTV backend message status code.
414 * @param live_tv A pointer to the LiveTV instance. *
417 gmyth_file_transfer_emit_program_info_changed_signal ( GMythFileTransfer *transfer, gint msg_code,
418 gpointer live_tv_recorder )
421 g_signal_emit_by_name ( G_OBJECT(transfer),
422 "program-info-changed",
426 gmyth_debug( "Calling signal handler... [FILE_TRANSFER]" );
428 g_signal_emit ( transfer,
429 GMYTH_FILE_TRANSFER_GET_CLASS (transfer)->program_info_changed_handler_signal_id,
431 msg_code, live_tv_recorder );
436 * Checks if the actual File Transfer connection is open.
438 * @param transfer The actual File Transfer instance.
440 * @return <code>true</code>, if the File Transfer connection is opened.
443 gmyth_file_transfer_is_open (GMythFileTransfer *transfer)
445 GMythStringList *strlist;
448 g_return_val_if_fail (transfer->control_sock != NULL, FALSE);
449 g_return_val_if_fail (transfer->sock != NULL, FALSE);
451 myth_control_acquire_context( transfer, TRUE );
453 strlist = gmyth_string_list_new();
454 query = g_string_new (GMYTHTV_QUERY_HEADER);
455 g_string_append_printf (query, "%d", transfer->file_id );
457 gmyth_string_list_append_string (strlist, query );
458 gmyth_string_list_append_char_array( strlist, "IS_OPEN" );
460 gmyth_socket_write_stringlist( transfer->control_sock, strlist );
461 gmyth_socket_read_stringlist( transfer->control_sock, strlist );
463 myth_control_release_context( transfer );
465 g_string_free (query, TRUE);
466 g_object_unref (strlist);
468 return ( strlist != NULL && gmyth_string_list_get_int( strlist, 0 ) == 1 );
472 * Closes a remote File Transfer connection.
474 * @param transfer The actual File Transfer instance.
477 gmyth_file_transfer_close( GMythFileTransfer *transfer )
479 GMythStringList *strlist;
482 g_return_if_fail (transfer->control_sock != NULL);
484 myth_control_acquire_context( transfer, TRUE );
486 strlist = gmyth_string_list_new( );
487 query = g_string_new (GMYTHTV_QUERY_HEADER);
488 g_string_append_printf( query, "%d", transfer->file_id);
490 gmyth_string_list_append_string( strlist, query );
491 gmyth_string_list_append_char_array( strlist, "DONE" );
493 if ( gmyth_socket_sendreceive_stringlist(transfer->control_sock, strlist) <= 0 ) {
494 // fixme: time out???
495 gmyth_debug ( "Remote file timeout.\n" );
498 g_string_free (query, TRUE);
499 g_object_unref (strlist);
501 if (transfer->sock) {
502 g_object_unref( transfer->sock );
503 transfer->sock = NULL;
506 if (transfer->control_sock) {
507 g_object_unref( transfer->control_sock );
508 transfer->control_sock = NULL;
511 myth_control_release_context( transfer );
516 * Do a seek operation (moves the read/write file pointer) on a remote file.
518 * @param transfer The actual File Transfer instance.
519 * @param pos The position to be moved in the remote file.
520 * @param whence Tells to what direction seek movement should be done.
522 * @return The actual position on the remote file (after seek has been done).
525 gmyth_file_transfer_seek(GMythFileTransfer *transfer, guint64 pos, gint whence)
527 GMythStringList *strlist = gmyth_string_list_new();
530 g_return_val_if_fail (transfer->sock != NULL, -1);
531 g_return_val_if_fail (transfer->control_sock != NULL, -1);
533 strlist = gmyth_string_list_new();
534 query = g_string_new (GMYTHTV_QUERY_HEADER);
535 g_string_append_printf (query, "%d", transfer->file_id);
537 /* myth_control_acquire_context( transfer, TRUE ); */
539 gmyth_string_list_append_string( strlist, query );
540 gmyth_string_list_append_char_array( strlist, "SEEK" );
541 gmyth_string_list_append_uint64( strlist, pos );
543 gmyth_string_list_append_int( strlist, whence );
546 gmyth_string_list_append_uint64( strlist, pos );
548 gmyth_string_list_append_uint64( strlist, transfer->readposition );
550 gmyth_socket_sendreceive_stringlist( transfer->control_sock, strlist );
552 gint64 retval = gmyth_string_list_get_int64(strlist, 0);
553 transfer->readposition = retval;
554 gmyth_debug ( "[%s] got reading position pointer from the streaming = %lld\n",
555 __FUNCTION__, retval );
557 g_object_unref (strlist);
558 g_string_free (query, TRUE);
560 /* myth_control_release_context( transfer ); */
566 * Acquire access to a remote file socket read/write pointer.
568 * @param transfer The actual File Transfer instance.
569 * @param do_wait Waits or not on a GCond, when trying to read from the remote socket.
571 * @return <code>true</code>, if the acquire had been got.
574 myth_control_acquire_context( GMythFileTransfer *transfer, gboolean do_wait )
577 //guint max_iter = 50;
579 g_mutex_lock( transfer->mutex );
581 //while ( !has_io_access )
582 // g_cond_wait( io_watcher_cond, mutex );
584 //has_io_access = FALSE;
586 //myth_control_acquire_context (FALSE);
590 while ( --max_iter > 0 && !g_main_context_wait( io_watcher_context, io_watcher_cond, mutex ) )
592 } else if ( !g_main_context_acquire( io_watcher_context ) )
596 //g_static_mutex_lock( &st_mutex );
602 * Release access to a remote file socket read/write pointer.
604 * @param transfer The actual File Transfer instance.
606 * @return <code>true</code>, if the socket read/write permissions had been releaseds.
609 myth_control_release_context( GMythFileTransfer *transfer )
613 //g_static_mutex_unlock( &st_mutex );
615 //g_main_context_release( io_watcher_context );
617 //g_main_context_wakeup( io_watcher_context );
619 //has_io_access = TRUE;
621 //g_cond_broadcast( io_watcher_cond );
623 g_mutex_unlock( transfer->mutex );
629 * Reads a block from a remote file.
631 * @param transfer The actual File Transfer instance.
632 * @param data A GByteArray instance, where all the binary data representing
633 * the remote file will be stored.
634 * @param size The block size, in bytes, to be requested from a remote file.
635 * @param read_unlimited Tells the backend to read indefinitely (LiveTV), or only
636 * gets the actual size
638 * @return The actual block size (in bytes) returned by REQUEST_BLOCK message,
642 gmyth_file_transfer_read(GMythFileTransfer *transfer, GByteArray *data, gint size, gboolean read_unlimited)
645 gsize bytes_read = 0;
646 gsize total_read = 0;
648 GError *error = NULL;
650 GIOChannel *io_channel;
651 GIOChannel *io_channel_control;
653 GIOCondition io_cond;
654 GIOCondition io_cond_control;
655 GIOStatus io_status = G_IO_STATUS_NORMAL, io_status_control = G_IO_STATUS_NORMAL;
661 g_return_val_if_fail ( data != NULL, -2 );
663 io_channel = transfer->sock->sd_io_ch;
664 io_channel_control = transfer->control_sock->sd_io_ch;
666 io_status = g_io_channel_set_encoding( io_channel, NULL, &error );
667 if ( io_status == G_IO_STATUS_NORMAL )
668 gmyth_debug ( "[%s] Setting encoding to binary data socket).\n", __FUNCTION__ );
670 io_cond = g_io_channel_get_buffer_condition( io_channel );
672 io_cond_control = g_io_channel_get_buffer_condition( io_channel );
673 if ( transfer->sock == NULL || ( io_status == G_IO_STATUS_ERROR ) ) {
674 g_printerr( "gmyth_file_transfer_read(): Called with no raw socket.\n" );
678 if ( transfer->control_sock == NULL || ( io_status_control == G_IO_STATUS_ERROR ) ) {
679 g_printerr( "gmyth_file_transfer_read(): Called with no control socket.\n" );
683 query = g_string_new (GMYTHTV_QUERY_HEADER);
684 g_string_append_printf ( query, "%d", transfer->file_id );
685 gmyth_debug ("[%s] Transfer_query = %s\n", __FUNCTION__, query->str );
687 /* send requests to the maximum number of REQUEST_BLOCK messages */
690 myth_control_acquire_context( transfer, TRUE );
692 while (total_read == 0 && --max_tries > 0) {
693 GMythStringList *strlist = gmyth_string_list_new();
695 gmyth_string_list_append_char_array( strlist, query->str );
696 gmyth_string_list_append_char_array( strlist, "REQUEST_BLOCK" );
697 gmyth_string_list_append_int( strlist, size );
699 // Request the block to the backend
700 gmyth_socket_write_stringlist( transfer->control_sock, strlist );
702 // Receives the backand answer
703 gmyth_socket_read_stringlist( transfer->control_sock, strlist );
705 if ( strlist != NULL && gmyth_string_list_length( strlist ) > 0 )
707 bytes_sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error
708 gmyth_debug ( "[%s] got SENT buffer message = %d\n", __FUNCTION__, bytes_sent );
710 if ( bytes_sent > 0 )
712 gchar *data_buffer = g_new0 ( gchar, bytes_sent );
713 while ( 0 != bytes_sent )
715 io_status = g_io_channel_read_chars( io_channel, data_buffer + total_read,
716 (gsize) bytes_sent, &bytes_read, &error );
718 total_read += bytes_read;
719 bytes_sent -= bytes_read;
721 /* append new data to the increasing byte array */
722 data = g_byte_array_append (data, (const guint8*)data_buffer, bytes_read);
723 gmyth_debug ("Total transfer data read: %d\n", total_read);
725 g_free (data_buffer);
726 } else if ( bytes_sent <= 0 && !read_unlimited ) {
727 total_read = GMYTHTV_FILE_TRANSFER_READ_ERROR;
728 g_object_unref (strlist);
732 } else if ( !read_unlimited || !(transfer->priv != NULL && transfer->priv->recorder != NULL &&
733 transfer->priv->do_next_program_chain) ) {
734 total_read = GMYTHTV_FILE_TRANSFER_READ_ERROR;
735 g_object_unref (strlist);
741 g_object_unref (strlist);
744 } /* while - iterates through bytes until reaches the end of stream */
746 if ( read_unlimited && ( bytes_sent == 0 ) && ( max_tries == 0 ) )
748 gmyth_debug( "Trying to move to the next program chain..." );
749 transfer->priv = GMYTH_FILE_TRANSFER_GET_PRIVATE(transfer);
751 if ( transfer->priv != NULL && transfer->priv->recorder != NULL &&
752 transfer->priv->do_next_program_chain )
755 total_read = GMYTHTV_FILE_TRANSFER_NEXT_PROG_CHAIN;
757 //g_mutex_lock( transfer->mutex );
759 //ret = gmyth_livetv_next_program_chain( transfer->priv->recorder );
760 GMythProgramInfo *prog_info = gmyth_recorder_get_current_program_info( transfer->priv->recorder );
762 if ( prog_info != NULL && prog_info->pathname != NULL && strlen( prog_info->pathname->str ) > 0 &&
763 g_ascii_strcasecmp( prog_info->pathname->str, transfer->filename ) != 0 )
764 ret = gmyth_file_transfer_open ( transfer, g_strrstr( prog_info->pathname->str, "/" ) );
766 if ( prog_info != NULL )
767 g_object_unref( prog_info );
769 //g_mutex_unlock( transfer->mutex );
772 gmyth_debug( "Cannot change to the next program info!" );
774 gmyth_debug( "OK!!! MOVED to the next program info [%s]!",
775 transfer->filename );
780 myth_control_release_context( transfer );
781 g_string_free (query, TRUE);
783 if ( error != NULL ) {
784 gmyth_debug ("Cleaning-up ERROR: %s [msg = %s, code = %d]\n", __FUNCTION__, error->message,
786 g_error_free (error);
789 if ( total_read > 0 )
790 transfer->readposition += total_read;
797 gmyth_file_transfer_program_info_changed( GMythFileTransfer *transfer,
798 gint msg_code, gpointer livetv_recorder )
800 GMythRecorder *recorder = GMYTH_RECORDER( livetv_recorder );
802 gmyth_debug( "Program info changed! ( file transfer orig. = %p, ptr. = [%s], user data = [%s] )", transfer,
803 livetv_recorder != NULL ? "[NOT NULL]" : "[NULL]", livetv != NULL ? "[NOT NULL]" : "[NULL]" );
805 if ( NULL != recorder )
807 gmyth_debug( "YES, the requested program info movement on the LiveTV transfer is authentical!" );
810 transfer->priv = GMYTH_FILE_TRANSFER_GET_PRIVATE(transfer);
812 g_object_ref(recorder);
814 transfer->priv->recorder = recorder;
816 transfer->priv->do_next_program_chain = TRUE;
820 * Sets the timeout flag of a file being transfered.
822 * @param transfer The actual File Transfer instance.
823 * @param fast If this is <code>true</code>, sets the remote timeout to be as fast
826 * @return <code>true</code>, if the acquire had been got.
829 gmyth_file_transfer_settimeout( GMythFileTransfer *transfer, gboolean fast )
832 GMythStringList *strlist = NULL;
834 g_return_val_if_fail (transfer->sock != NULL, FALSE);
835 g_return_val_if_fail (transfer->control_sock != NULL, FALSE);
837 myth_control_acquire_context( transfer, TRUE );
839 strlist = gmyth_string_list_new();
840 gmyth_string_list_append_char_array( strlist, GMYTHTV_QUERY_HEADER );
841 gmyth_string_list_append_char_array( strlist, "SET_TIMEOUT" );
842 gmyth_string_list_append_int( strlist, fast );
844 gint strlist_len = gmyth_socket_sendreceive_stringlist( transfer->control_sock,
847 if ( strlist_len > 0 )
848 gmyth_debug( "Yes, timeout was changed: %s.", gmyth_string_list_get_char_array( strlist, 0 ) );
850 gmyth_debug( "Timeout cannot be changed!" );
852 myth_control_release_context( transfer );
854 gmyth_debug ( "%s setting timeout flag of this file transfer = %s\n",
855 strlist_len > 0 ? "Yes," : "NOT", fast ? "FAST" : "NOT FAST" );
857 g_object_unref (strlist);
863 * Gets the actual file size of the binary content.
865 * @param transfer The actual File Transfer instance.
867 * @return The actual file size in bytes.
870 gmyth_file_transfer_get_filesize (GMythFileTransfer *transfer)
872 g_return_val_if_fail (transfer != NULL, 0);
873 return transfer->filesize;