[svn r359] Now it is running; removed some GStaticMutex race conditions.
2 * @author Hallyson Melo <hallyson.melo@indt.org.br>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <libgnomevfs/gnome-vfs-module.h>
28 #include <libgnomevfs/gnome-vfs-utils.h>
30 #include <gmyth/gmyth_file_transfer.h>
31 #include <gmyth/gmyth_livetv.h>
32 #include <gmyth/gmyth_uri.h>
33 #include <gmyth/gmyth_recorder.h>
34 #include <gmyth/gmyth_backendinfo.h>
35 #include <gmyth/gmyth_util.h>
36 #include <gmyth/gmyth_remote_util.h>
37 #include <gmyth/gmyth_tvchain.h>
38 #include <gmyth/gmyth_programinfo.h>
40 #define GST_MYTHTV_ID_NUM 1
41 #define MYTHTV_VERSION_DEFAULT 30
42 #define MYTHTV_TRANSFER_MAX_WAITS 100
44 #define MYTHTV_BUFFER_SIZE 1024*140
45 #define MYTHTV_MAX_VFS_BUFFER_SIZE 4096
46 #define MYTHTV_MAX_REQUEST_SIZE 1024*64
48 static GnomeVFSResult do_read (GnomeVFSMethod *method,
49 GnomeVFSMethodHandle *method_handle,
51 GnomeVFSFileSize num_bytes,
52 GnomeVFSFileSize *bytes_read,
53 GnomeVFSContext *context);
56 GMythFileTransfer *file_transfer;
72 //static MythtvHandle *myth_handle = NULL;
75 do_open (GnomeVFSMethod *method,
76 GnomeVFSMethodHandle **method_handle,
78 GnomeVFSOpenMode mode,
79 GnomeVFSContext *context)
81 MythtvHandle *myth_handle = NULL;
82 GMythBackendInfo *backend_info = NULL;
83 GMythURI *gmyth_uri = NULL;
86 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
87 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
89 if (mode & GNOME_VFS_OPEN_WRITE) {
90 return GNOME_VFS_ERROR_NOT_PERMITTED;
93 if (gnome_vfs_uri_get_host_name (uri) == NULL) {
94 return GNOME_VFS_ERROR_INVALID_HOST_NAME;
98 if ( method_handle != NULL && *method_handle != NULL )
100 myth_handle = (MythtvHandle*)*method_handle;
101 //if ( !myth_handle->configured )
105 if ( ( NULL == myth_handle ) || !myth_handle->configured ) {
106 myth_handle = g_new0 (MythtvHandle, 1);
108 myth_handle->configured = FALSE;
110 myth_handle->is_livetv = FALSE;
112 /* Initialize mythtv handler*/
113 myth_handle->file_transfer = NULL;
114 myth_handle->livetv = NULL;
115 myth_handle->mythtv_version = MYTHTV_VERSION_DEFAULT;
116 myth_handle->bytes_read = 0;
117 myth_handle->content_size = (GnomeVFSFileSize) - 1;
119 /* Creates and fills out the backend info structure */
120 backend_info = gmyth_backend_info_new_with_uri (
121 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
123 /* creates an instance of */
124 gmyth_uri = gmyth_uri_new_with_value(
125 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
127 myth_handle->is_livetv = gmyth_uri_is_livetv( gmyth_uri );
129 /* Connect to the backend */
130 if ( gmyth_uri != NULL && myth_handle->is_livetv == TRUE ) {
132 if ( NULL == myth_handle->livetv )
134 myth_handle->livetv = gmyth_livetv_new ();
136 myth_handle->channel_name = gmyth_uri_get_channel_name( gmyth_uri );
138 g_debug( "[%s] Channel name = %s\n", __FUNCTION__, myth_handle->channel_name );
140 if ( myth_handle->channel_name != NULL ) {
141 if (gmyth_livetv_channel_name_setup (myth_handle->livetv, myth_handle->channel_name,
142 backend_info) == FALSE) {
143 g_object_unref( gmyth_uri );
147 if ( gmyth_livetv_setup (myth_handle->livetv, backend_info) == FALSE ) {
148 g_object_unref( gmyth_uri );
154 if ( NULL == myth_handle->file_transfer ) {
155 myth_handle->file_transfer = gmyth_livetv_create_file_transfer (myth_handle->livetv);
157 if (NULL == myth_handle->file_transfer) {
159 g_debug ("MythTV FileTransfer is NULL!\n");
160 return GNOME_VFS_ERROR_NOT_OPEN;
163 if ( !gmyth_file_transfer_open( myth_handle->file_transfer, myth_handle->livetv->uri != NULL ?
164 gmyth_uri_get_path(myth_handle->livetv->uri) :
165 myth_handle->livetv->proginfo->pathname->str ) )
167 g_debug ("Couldn't open MythTV FileTransfer is NULL!\n");
168 g_object_unref( myth_handle->file_transfer );
169 myth_handle->file_transfer = NULL;
172 } /* if - FileTransfer is NULL, or not */
176 if (NULL == myth_handle->file_transfer ) {
178 myth_handle->file_transfer = gmyth_file_transfer_new (backend_info);
180 /* Verifies if the file exists */
181 if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) {
182 g_object_unref (backend_info);
186 /* sets the Playback monitor connection */
187 ret = gmyth_file_transfer_open ( myth_handle->file_transfer,
188 gmyth_uri_get_path (gmyth_uri) );
192 } /* if - LiveTV or not? */
195 g_debug ("MythTV FileTransfer open error.\n");
196 return GNOME_VFS_ERROR_NOT_OPEN;
199 myth_handle->configured = TRUE;
201 g_object_unref (backend_info);
203 if ( gmyth_uri != NULL )
204 g_object_unref( gmyth_uri );
206 myth_handle->buffer = g_byte_array_sized_new (MYTHTV_BUFFER_SIZE);
207 myth_handle->buffer_remain = 0;
209 g_return_val_if_fail (myth_handle->file_transfer != NULL, GNOME_VFS_ERROR_NOT_OPEN);
211 if ( /*myth_handle->file_transfer->filesize <= 0 && */myth_handle->is_livetv ) {
212 myth_handle->content_size = gmyth_recorder_get_file_position(myth_handle->livetv->recorder);
214 myth_handle->content_size = myth_handle->file_transfer->filesize;
217 } /* if - configured or not? */
219 *method_handle = (GnomeVFSMethodHandle *) myth_handle;
224 static GnomeVFSResult
225 do_read (GnomeVFSMethod *method,
226 GnomeVFSMethodHandle *method_handle,
228 GnomeVFSFileSize num_bytes,
229 GnomeVFSFileSize *bytes_read,
230 GnomeVFSContext *context)
232 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
233 GnomeVFSFileSize bytes_to_read = num_bytes;
234 gint64 size_stream = *bytes_read;
238 g_debug ("XXXXXXXXXX Requested %llu bytes (remains %d bytes on buffer...) file_size = %lld\n",
239 (guint64)num_bytes, myth_handle->buffer->len, *bytes_read );
241 if ( !myth_handle->is_livetv && ( myth_handle->bytes_read >= myth_handle->content_size ) )
242 return GNOME_VFS_ERROR_EOF;
244 // fixme: change this to min math function
245 if (( myth_handle->content_size > 0 ) )
247 if ( !myth_handle->is_livetv &&
248 ( num_bytes > ( myth_handle->content_size - myth_handle->bytes_read ) ) )
250 bytes_to_read = myth_handle->content_size - myth_handle->bytes_read;
252 size_stream = gmyth_recorder_get_file_position(myth_handle->livetv->recorder);
253 if ( size_stream > myth_handle->content_size ) {
254 g_debug( "New file size %lld, old size = %lld.", size_stream, myth_handle->content_size );
255 myth_handle->content_size = size_stream;
256 num_bytes = ( myth_handle->content_size - myth_handle->bytes_read );
257 } else if ( num_bytes > ( myth_handle->content_size - myth_handle->bytes_read ) )
258 num_bytes = MYTHTV_MAX_VFS_BUFFER_SIZE;
262 /* Loop sending the Myth File Transfer request:
263 * Retry whilst authentication fails and we supply it. */
264 /* if (myth_handle->buffer_remain < MYTHTV_BUFFER_SIZE) { */
265 if ( ( myth_handle->buffer_remain = myth_handle->buffer->len ) < bytes_to_read )
269 //while ( MYTHTV_BUFFER_SIZE != myth_handle->buffer_remain ) {
271 /* resize buffer length request to no more than MYTHTV_MAX_REQUEST_SIZE */
272 if ( ( MYTHTV_BUFFER_SIZE - myth_handle->buffer_remain ) <= MYTHTV_MAX_REQUEST_SIZE )
273 buffer_size = MYTHTV_BUFFER_SIZE - myth_handle->buffer_remain;
275 buffer_size = MYTHTV_MAX_REQUEST_SIZE;
277 GByteArray *tmp_buffer = g_byte_array_new();
279 g_debug ("XXXXXXXXXX Asking %d bytes (there is %d bytes in the buffer)\n",
280 buffer_size, myth_handle->buffer_remain);
282 gint len = gmyth_file_transfer_read (myth_handle->file_transfer,
283 tmp_buffer, buffer_size, TRUE);
285 if (!myth_handle->is_livetv && len < 0) {
286 g_byte_array_free (tmp_buffer, TRUE);
287 g_debug ("Fail to read bytes");
288 return GNOME_VFS_ERROR_IO;
289 } /*else if (len == 0) {
290 g_byte_array_free (tmp_buffer, TRUE);
291 g_warning ("End of file probably achieved");
292 return GNOME_VFS_ERROR_EOF;
295 myth_handle->buffer = g_byte_array_append ( myth_handle->buffer,
296 tmp_buffer->data, len );
298 myth_handle->buffer_remain += len;
300 if ( tmp_buffer != NULL )
302 g_byte_array_free ( tmp_buffer, TRUE );
305 //} /* while - iterates until fills the internal buffer */
307 } /* if - got from the network, or not */
309 bytes_to_read = ( bytes_to_read > myth_handle->buffer_remain ) ? myth_handle->buffer_remain : bytes_to_read;
310 /* gets the first buffer_size bytes from the byte array buffer variable */
312 g_memmove (buffer, myth_handle->buffer->data, bytes_to_read);
314 myth_handle->bytes_read += bytes_to_read;
315 myth_handle->buffer_remain -= bytes_to_read;
317 /* flushs the newly buffer got from byte array */
318 myth_handle->buffer = g_byte_array_remove_range (myth_handle->buffer, 0, bytes_to_read);
319 g_debug ("Got from %llu bytes from internal buffer. (there are %d bytes in the buffer, from a total of %llu dispatched.)\n",
320 bytes_to_read, myth_handle->buffer_remain, myth_handle->bytes_read );
322 *bytes_read = bytes_to_read;
327 static GnomeVFSResult
328 do_close (GnomeVFSMethod *method,
329 GnomeVFSMethodHandle *method_handle,
330 GnomeVFSContext *context)
333 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
335 //if ( NULL == myth_handle || myth_handle->configured ) {
337 if (myth_handle->file_transfer != NULL) {
338 g_object_unref (myth_handle->file_transfer);
339 myth_handle->file_transfer = NULL;
342 if (myth_handle->is_livetv && myth_handle->livetv != NULL) {
343 g_object_unref (myth_handle->livetv);
344 myth_handle->livetv = NULL;
347 if (myth_handle->buffer) {
348 g_byte_array_free (myth_handle->buffer, TRUE);
349 myth_handle->buffer = NULL;
352 myth_handle->configured = FALSE;
354 g_free (myth_handle);
363 static GnomeVFSResult
364 do_get_file_info (GnomeVFSMethod *method,
366 GnomeVFSFileInfo *file_info,
367 GnomeVFSFileInfoOptions options,
368 GnomeVFSContext *context)
370 GMythFileTransfer *file_transfer = NULL;
371 GMythRecorder *recorder = NULL;
372 GMythTVChain *tvchain = NULL;
373 GMythBackendInfo *backend_info = NULL;
374 GMythURI *gmyth_uri = NULL;
375 GMythSocket *socket = NULL;
376 gboolean is_livetv = FALSE;
380 /* Creates and fills out the backend info structure */
381 backend_info = gmyth_backend_info_new_with_uri (
382 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
384 /* creates an instance of */
385 gmyth_uri = gmyth_uri_new_with_value(
386 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
388 is_livetv = gmyth_uri_is_livetv( gmyth_uri );
390 file_info->valid_fields = file_info->valid_fields
391 | GNOME_VFS_FILE_INFO_FIELDS_TYPE
392 | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
393 | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
394 file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
395 /* fixme: get from file extension? */
396 file_info->mime_type = g_strdup ("video/x-nuv");
397 file_info->permissions =
398 GNOME_VFS_PERM_USER_READ |
399 GNOME_VFS_PERM_OTHER_READ |
400 GNOME_VFS_PERM_GROUP_READ;
402 g_print( "gnome_vfs_uri == %s | gmyth_uri == %s.\n",
403 gnome_vfs_uri_get_path (uri),
404 gmyth_uri_get_path (gmyth_uri) );
406 /* Connect to the backend */
407 if ( gmyth_uri != NULL && is_livetv == TRUE ) {
409 /* start to get file info from LiveTV remote encoder */
410 socket = gmyth_socket_new ();
412 /* FIME: Implement this at gmyth_socket */
413 res = gmyth_socket_connect_to_backend (socket, backend_info->hostname,
414 backend_info->port, TRUE);
416 g_print ("[%s] LiveTV can not connect to backend", __FUNCTION__);
421 if ( gmyth_remote_util_get_free_recorder_count (socket) <= 0 ) {
422 g_print ("No free remote encoder available.");
427 /* Gets the recorder num */
428 recorder = remote_request_next_free_recorder (socket, -1);
430 //if ( socket != NULL )
431 // g_object_unref (socket);
433 if ( recorder == NULL ) {
434 g_print ("[%s] None remote encoder available", __FUNCTION__);
439 /* Init remote encoder. Opens its control socket. */
440 res = gmyth_recorder_setup(recorder);
442 g_print ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
447 /* Creates livetv chain handler */
448 tvchain = gmyth_tvchain_new();
449 gmyth_tvchain_initialize ( tvchain, backend_info );
451 if ( tvchain == NULL || tvchain->tvchain_id == NULL ) {
456 // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly)
457 res = gmyth_recorder_spawntv ( recorder,
458 gmyth_tvchain_get_id(tvchain) );
460 g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__);
465 //gchar* channel_name = gmyth_uri_get_channel_name( gmyth_uri );
468 GMythProgramInfo* prog_info = gmyth_recorder_get_current_program_info( recorder );
470 if ( prog_info != NULL )
472 //gmyth_program_info_print( prog_info );
473 g_debug( "Program Info: %s\n", gmyth_program_info_to_string( prog_info ) );
475 g_print( "path = %s", prog_info->pathname->str );
477 file_info->name = g_strdup ( g_strrstr( prog_info->pathname->str, "/" ) );
480 file_info->name = g_strdup ( "LiveTV.nuv" );
481 file_info->size = gmyth_recorder_get_file_position( recorder );
484 if ( recorder != NULL )
485 g_object_unref (recorder);
487 if ( prog_info != NULL )
488 g_object_unref( prog_info );
490 if ( tvchain != NULL )
491 g_object_unref (tvchain);
493 file_info->size = (GnomeVFSFileSize) - 1;
497 /* start to get file info from remote file encoder */
498 file_transfer = gmyth_file_transfer_new (backend_info);
500 /* Verifies if the file exists */
501 if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) {
502 g_object_unref (backend_info);
503 return GNOME_VFS_ERROR_NOT_FOUND;
506 /* sets the Playback monitor connection */
507 ret = gmyth_file_transfer_open ( file_transfer, gmyth_uri_get_path (gmyth_uri) );
509 file_info->name = g_strdup ( gnome_vfs_uri_get_path (uri) );
511 } /* if - LiveTV or not? */
514 g_debug ("MythTV FileTransfer open error\n");
515 return GNOME_VFS_ERROR_NOT_OPEN;
518 if ( ret == TRUE && file_transfer != NULL ) {
519 file_info->size = gmyth_file_transfer_get_filesize (file_transfer);
521 g_object_unref (file_transfer);
524 file_info->block_count = GNOME_VFS_FILE_INFO_FIELDS_BLOCK_COUNT;
525 file_info->io_block_size = GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE;
529 g_object_unref (backend_info);
532 return GNOME_VFS_ERROR_IO;
538 do_is_local (GnomeVFSMethod *method,
539 const GnomeVFSURI *uri)
544 static GnomeVFSMethod method = {
545 sizeof (GnomeVFSMethod),
576 vfs_module_init (const char *method_name, const char *args)
582 vfs_module_shutdown (GnomeVFSMethod *method)