[svn r661] Fixed starvation loop when reading an unlimited-size buffer (LiveTV) from the FileTransfer; MonitorHandler is a GThread now.
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
25 #include <glib/gprintf.h>
26 #include <glib/gstdio.h>
29 #include <libgnomevfs/gnome-vfs-module.h>
30 #include <libgnomevfs/gnome-vfs-utils.h>
32 #include <gmyth/gmyth_file.h>
33 #include <gmyth/gmyth_file_transfer.h>
34 #include <gmyth/gmyth_file_local.h>
35 #include <gmyth/gmyth_livetv.h>
36 #include <gmyth/gmyth_uri.h>
37 #include <gmyth/gmyth_recorder.h>
38 #include <gmyth/gmyth_backendinfo.h>
39 #include <gmyth/gmyth_util.h>
40 #include <gmyth/gmyth_remote_util.h>
41 #include <gmyth/gmyth_tvchain.h>
42 #include <gmyth/gmyth_programinfo.h>
44 #define GST_MYTHTV_ID_NUM 1
45 #define MYTHTV_VERSION_DEFAULT 30
46 #define MYTHTV_TRANSFER_MAX_WAITS 100
48 /* internal GnomeVFS plug-in buffer size ( 120 Kbytes ) */
49 #define MYTHTV_BUFFER_SIZE 80*1024
50 /* internally sized GnomeVFS plug-in buffer ( 4 Kbytes ) */
51 #define MYTHTV_MAX_VFS_BUFFER_SIZE 4096
52 /* maximum number of bytes to be requested to the MythTV backend ( 64 Kbytes ) */
53 #define MYTHTV_MAX_REQUEST_SIZE 64*1024
58 GMythBackendInfo *backend_info;
60 GMythRecorder *live_recorder;
64 gboolean is_livetv; /* it is, or not a Live TV content transfer */
65 gboolean is_local_file; /* tell if the file is local to the current content transfer */
74 static GnomeVFSResult do_read (GnomeVFSMethod * method,
75 GnomeVFSMethodHandle * method_handle,
77 GnomeVFSFileSize num_bytes,
78 GnomeVFSFileSize * bytes_read,
79 GnomeVFSContext * context);
81 static GnomeVFSResult myth_connection_start (MythtvHandle * method_handle);
82 static void myth_destroy_handle (MythtvHandle * method_handle);
83 static GnomeVFSResult myth_handle_new (GnomeVFSURI * uri,
84 MythtvHandle ** method_handle);
85 static GnomeVFSResult myth_get_file_info (MythtvHandle * myth_handle,
87 GnomeVFSFileInfo * info);
90 myth_handle_new (GnomeVFSURI * uri,
91 MythtvHandle ** method_handle)
96 _GNOME_VFS_METHOD_PARAM_CHECK (*method_handle == NULL);
98 if (gnome_vfs_uri_get_host_name (uri) == NULL) {
99 return GNOME_VFS_ERROR_INVALID_HOST_NAME;
102 *method_handle = g_new0 (MythtvHandle, 1);
103 (*method_handle)->mythtv_version = MYTHTV_VERSION_DEFAULT;
105 (*method_handle)->is_livetv = FALSE;
106 (*method_handle)->is_local_file = FALSE;
108 tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
109 tmp_str2 = gnome_vfs_unescape_string (tmp_str1, "");
111 gchar *tmp_str3 = strstr (tmp_str2, ".nuv.avi");
112 if (tmp_str3 != NULL) {
116 (*method_handle)->backend_info = gmyth_backend_info_new_with_uri (tmp_str2);
117 (*method_handle)->gmyth_uri = gmyth_uri_new_with_value (tmp_str2);
125 myth_destroy_handle (MythtvHandle * method_handle)
127 //TODO: abort if in tranfer state
129 if (method_handle->backend_info != NULL) {
130 g_object_unref (method_handle->backend_info);
131 method_handle->backend_info = NULL;
134 if (method_handle->channel_name != NULL) {
135 g_free (method_handle->channel_name);
136 method_handle->channel_name = NULL;
139 if (method_handle->livetv != NULL) {
140 g_object_unref (method_handle->livetv);
141 method_handle->livetv = NULL;
144 if (method_handle->file != NULL) {
145 g_object_unref (method_handle->file);
146 method_handle->file = NULL;
149 if (method_handle->gmyth_uri != NULL) {
150 g_object_unref (method_handle->gmyth_uri);
151 method_handle->gmyth_uri = NULL;
154 g_free (method_handle);
157 static GnomeVFSResult
158 myth_get_file_info (MythtvHandle * myth_handle,
160 GnomeVFSFileInfo * info)
163 GMythBackendInfo *backend_info;
167 _GNOME_VFS_METHOD_PARAM_CHECK (info != NULL);
169 g_debug ("%s - %d", __FUNCTION__, __LINE__);
171 if (myth_handle == NULL) {
175 tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
176 tmp_str2 = gnome_vfs_unescape_string (tmp_str1, "");
178 backend_info = gmyth_backend_info_new_with_uri (tmp_str2);
179 gmyth_uri = gmyth_uri_new_with_value (tmp_str2);
184 backend_info = g_object_ref (myth_handle->backend_info);
185 gmyth_uri = g_object_ref (myth_handle->gmyth_uri);
188 info->valid_fields = 0;
189 info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE |
190 GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE |
191 GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
193 info->type = GNOME_VFS_FILE_TYPE_REGULAR;
195 /* fixme: get from file extension? */
196 info->mime_type = g_strdup ("video/x-nuv");
197 info->permissions = GNOME_VFS_PERM_USER_READ |
198 GNOME_VFS_PERM_OTHER_READ |
199 GNOME_VFS_PERM_GROUP_READ;
201 info->name = g_strdup (gmyth_uri_get_path (gmyth_uri));
203 /* file size for remote files */
204 is_livetv = gmyth_uri_is_livetv (gmyth_uri);
206 if (is_livetv == FALSE) {
207 GMythFile *file = NULL;
208 gboolean ret = FALSE;
210 /* Verifies if the file exists */
211 if (!gmyth_util_file_exists (backend_info,
212 gmyth_uri_get_path (gmyth_uri))) {
213 g_object_unref (file);
214 g_object_unref (backend_info);
215 g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__);
216 return GNOME_VFS_ERROR_NOT_FOUND;
219 is_local = gmyth_uri_is_local_file (gmyth_uri);
220 if (is_local == TRUE ) {
221 file = GMYTH_FILE (gmyth_file_local_new(backend_info));
222 ret = gmyth_file_local_open (GMYTH_FILE_LOCAL (file));
224 file = GMYTH_FILE (gmyth_file_transfer_new(backend_info));
225 ret = gmyth_file_transfer_open (GMYTH_FILE_TRANSFER(file),
226 gmyth_uri_get_path (gmyth_uri));
230 g_object_unref (file);
231 g_object_unref (backend_info);
232 g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__);
233 return GNOME_VFS_ERROR_NOT_FOUND;
236 info->size = gmyth_file_get_filesize (file);
237 info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE;
238 g_object_unref (file);
241 g_object_unref (backend_info);
242 g_object_unref (gmyth_uri);
247 static GnomeVFSResult
248 myth_connection_start (MythtvHandle * method_handle)
250 GnomeVFSResult result = GNOME_VFS_OK;
252 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
253 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle->backend_info != NULL);
255 /* Connect to the backend */
256 if ( ( method_handle->is_livetv = gmyth_uri_is_livetv (method_handle->gmyth_uri) ) == TRUE) {
257 method_handle->livetv = gmyth_livetv_new (method_handle->backend_info);
258 method_handle->channel_name = gmyth_uri_get_channel_name (method_handle->gmyth_uri);
260 if (method_handle->channel_name != NULL) {
261 if (gmyth_livetv_channel_name_setup (method_handle->livetv,
262 method_handle->channel_name) == FALSE) {
263 result = GNOME_VFS_ERROR_INVALID_URI;
266 } else if (gmyth_livetv_setup (method_handle->livetv) == FALSE) {
267 result = GNOME_VFS_ERROR_INVALID_URI;
272 method_handle->file =
273 GMYTH_FILE( gmyth_livetv_create_file_transfer (method_handle->livetv) );
275 if (method_handle->file == NULL) {
276 result = GNOME_VFS_ERROR_INVALID_URI;
277 g_debug ("MythTV FileTransfer is NULL!\n");
281 if (!gmyth_file_transfer_open ( GMYTH_FILE_TRANSFER(method_handle->file),
282 method_handle->livetv->uri != NULL ?
283 gmyth_uri_get_path (method_handle->livetv->uri) :
284 method_handle->livetv->proginfo->pathname->str)) {
286 g_debug ("Couldn't open MythTV FileTransfer is NULL!\n");
287 result = GNOME_VFS_ERROR_NOT_OPEN;
293 /* Verifies if the file exists */
294 if (!gmyth_util_file_exists (method_handle->backend_info,
295 gmyth_uri_get_path (method_handle->gmyth_uri))) {
297 g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__);
301 if ( ( method_handle->is_local_file = gmyth_uri_is_local_file(method_handle->gmyth_uri) ) == TRUE )
303 method_handle->file = GMYTH_FILE( gmyth_file_local_new(method_handle->backend_info) );
304 ret = gmyth_file_local_open ( GMYTH_FILE_LOCAL( method_handle->file ) );
306 method_handle->file = GMYTH_FILE( gmyth_file_transfer_new(method_handle->backend_info) );
307 ret = gmyth_file_transfer_open ( GMYTH_FILE_TRANSFER(method_handle->file),
308 gmyth_uri_get_path (method_handle->gmyth_uri));
311 /* sets the Playback monitor connection */
314 g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__);
315 result = GNOME_VFS_ERROR_NOT_FOUND;
318 } /* if - LiveTV or not? */
320 method_handle->configured = TRUE;
322 if (method_handle->file == NULL) {
323 result = GNOME_VFS_ERROR_NOT_OPEN;
331 static GnomeVFSResult
332 do_open (GnomeVFSMethod * method,
333 GnomeVFSMethodHandle ** method_handle,
335 GnomeVFSOpenMode mode, GnomeVFSContext * context)
337 MythtvHandle *myth_handle = NULL;
338 GnomeVFSResult result = GNOME_VFS_OK;
340 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
341 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
343 if (mode & GNOME_VFS_OPEN_WRITE) {
344 return GNOME_VFS_ERROR_INVALID_OPEN_MODE;
347 result = myth_handle_new (uri, &myth_handle);
348 if (result != GNOME_VFS_OK)
351 result = myth_connection_start (myth_handle);
352 if (result != GNOME_VFS_OK) {
353 myth_destroy_handle (myth_handle);
358 *method_handle = (GnomeVFSMethodHandle *) myth_handle;
363 static GnomeVFSResult
364 do_create (GnomeVFSMethod *method,
365 GnomeVFSMethodHandle **method_handle,
367 GnomeVFSOpenMode mode,
370 GnomeVFSContext *context)
372 return GNOME_VFS_ERROR_NOT_SUPPORTED;
375 static GnomeVFSResult
376 do_close (GnomeVFSMethod * method,
377 GnomeVFSMethodHandle * method_handle,
378 GnomeVFSContext * context)
380 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
382 myth_destroy_handle (myth_handle);
388 static GnomeVFSResult
389 do_read (GnomeVFSMethod * method,
390 GnomeVFSMethodHandle * method_handle,
392 GnomeVFSFileSize num_bytes,
393 GnomeVFSFileSize * bytes_read,
394 GnomeVFSContext * context)
396 GnomeVFSResult retval = GNOME_VFS_OK;
397 MythtvHandle *myth_handle;
398 GMythFileReadResult result;
399 GByteArray *myth_buffer = g_byte_array_new ();
401 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
403 myth_handle = (MythtvHandle *) method_handle;
404 if ( myth_handle->is_local_file )
405 result = gmyth_file_local_read ( GMYTH_FILE_LOCAL(myth_handle->file),
407 num_bytes, myth_handle->is_livetv );
409 result = gmyth_file_transfer_read ( GMYTH_FILE_TRANSFER(myth_handle->file),
411 num_bytes, myth_handle->is_livetv );
413 if (result == GMYTH_FILE_READ_ERROR) {
414 retval = GNOME_VFS_ERROR_IO;
417 if (result == GMYTH_FILE_READ_EOF) {
418 retval = GNOME_VFS_ERROR_EOF;
421 if (myth_buffer->len > 0) {
422 g_memmove (buffer, myth_buffer->data, myth_buffer->len);
423 *bytes_read = (GnomeVFSFileSize) myth_buffer->len;
424 myth_handle->offset += myth_buffer->len;
425 g_byte_array_free (myth_buffer, TRUE);
431 static GnomeVFSResult
432 do_write (GnomeVFSMethod *method,
433 GnomeVFSMethodHandle *method_handle,
434 gconstpointer buffer,
435 GnomeVFSFileSize num_bytes,
436 GnomeVFSFileSize *bytes_written,
437 GnomeVFSContext *context)
439 return GNOME_VFS_ERROR_NOT_SUPPORTED;
442 static GnomeVFSResult
443 do_seek (GnomeVFSMethod *method,
444 GnomeVFSMethodHandle *method_handle,
445 GnomeVFSSeekPosition whence,
446 GnomeVFSFileOffset offset,
447 GnomeVFSContext *context)
449 MythtvHandle *myth_handle;
450 //guint64 whence_p = 0;
451 //gint64 new_offset =0;
453 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
455 myth_handle = (MythtvHandle *) method_handle;
457 g_debug ("seek offset%"G_GINT64_FORMAT" whence %d", offset, whence);
459 return GNOME_VFS_ERROR_NOT_SUPPORTED;
461 if (gmyth_uri_is_livetv (myth_handle->gmyth_uri))
465 case GNOME_VFS_SEEK_START:
468 case GNOME_VFS_SEEK_CURRENT:
469 whence_p = myth_handle->offset;
471 case GNOME_VFS_SEEK_END:
472 return GNOME_VFS_ERROR_NOT_SUPPORTED;
475 new_offset = gmyth_file_transfer_seek (myth_handle->file, offset, whence_p);
476 if (new_offset != 0) {
477 myth_handle->offset = new_offset;
481 return GNOME_VFS_ERROR_NOT_SUPPORTED;
485 static GnomeVFSResult
486 do_tell (GnomeVFSMethod *method,
487 GnomeVFSMethodHandle *method_handle,
488 GnomeVFSFileSize *offset_return)
490 MythtvHandle *myth_handle = NULL;
492 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
494 myth_handle = (MythtvHandle *) method_handle;
495 *offset_return = myth_handle->offset;
500 static GnomeVFSResult
501 do_truncate_handle (GnomeVFSMethod *method,
502 GnomeVFSMethodHandle *method_handle,
503 GnomeVFSFileSize where,
504 GnomeVFSContext *context)
506 return GNOME_VFS_ERROR_READ_ONLY;
509 static GnomeVFSResult
510 do_open_directory (GnomeVFSMethod *method,
511 GnomeVFSMethodHandle **method_handle,
513 GnomeVFSFileInfoOptions options,
514 GnomeVFSContext *context)
516 return GNOME_VFS_ERROR_NOT_SUPPORTED;
519 static GnomeVFSResult
520 do_close_directory (GnomeVFSMethod *method,
521 GnomeVFSMethodHandle *method_handle,
522 GnomeVFSContext *context)
524 return GNOME_VFS_ERROR_NOT_SUPPORTED;
527 static GnomeVFSResult
528 do_read_directory (GnomeVFSMethod *method,
529 GnomeVFSMethodHandle *method_handle,
530 GnomeVFSFileInfo *file_info,
531 GnomeVFSContext *context)
533 return GNOME_VFS_ERROR_NOT_SUPPORTED;
537 static GnomeVFSResult
538 do_get_file_info (GnomeVFSMethod * method,
540 GnomeVFSFileInfo * file_info,
541 GnomeVFSFileInfoOptions options,
542 GnomeVFSContext * context)
544 return myth_get_file_info (NULL, uri, file_info);
547 static GnomeVFSResult
548 do_get_file_info_from_handle (GnomeVFSMethod *method,
549 GnomeVFSMethodHandle *method_handle,
550 GnomeVFSFileInfo *file_info,
551 GnomeVFSFileInfoOptions options,
552 GnomeVFSContext *context)
554 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
556 return myth_get_file_info (myth_handle, NULL, file_info);
560 do_is_local (GnomeVFSMethod * method, const GnomeVFSURI * uri)
565 static GnomeVFSResult
566 do_make_directory (GnomeVFSMethod *method,
569 GnomeVFSContext *context)
571 return GNOME_VFS_ERROR_READ_ONLY;
574 static GnomeVFSResult
575 do_remove_directory (GnomeVFSMethod *method,
577 GnomeVFSContext *context)
579 return GNOME_VFS_ERROR_READ_ONLY;
582 static GnomeVFSResult
583 do_move (GnomeVFSMethod *method,
584 GnomeVFSURI *old_uri,
585 GnomeVFSURI *new_uri,
586 gboolean force_replace,
587 GnomeVFSContext *context)
589 return GNOME_VFS_ERROR_READ_ONLY;
592 static GnomeVFSResult
593 do_unlink (GnomeVFSMethod *method,
595 GnomeVFSContext *context)
597 return GNOME_VFS_ERROR_READ_ONLY;
600 static GnomeVFSResult
601 do_check_same_fs (GnomeVFSMethod *method,
604 gboolean *same_fs_return,
605 GnomeVFSContext *context)
607 return GNOME_VFS_ERROR_NOT_SUPPORTED;
610 static GnomeVFSResult
611 do_set_file_info (GnomeVFSMethod *method,
613 const GnomeVFSFileInfo *info,
614 GnomeVFSSetFileInfoMask mask,
615 GnomeVFSContext *context)
617 return GNOME_VFS_ERROR_READ_ONLY;
620 static GnomeVFSResult
621 do_truncate (GnomeVFSMethod *method,
623 GnomeVFSFileSize where,
624 GnomeVFSContext *context)
626 return GNOME_VFS_ERROR_READ_ONLY;
629 static GnomeVFSResult
630 do_find_directory (GnomeVFSMethod *method,
631 GnomeVFSURI *near_uri,
632 GnomeVFSFindDirectoryKind kind,
633 GnomeVFSURI **result_uri,
634 gboolean create_if_needed,
635 gboolean find_if_needed,
637 GnomeVFSContext *context)
639 return GNOME_VFS_ERROR_NOT_SUPPORTED;
642 static GnomeVFSResult
643 do_create_symbolic_link (GnomeVFSMethod *method,
645 const char *target_reference,
646 GnomeVFSContext *context)
648 return GNOME_VFS_ERROR_READ_ONLY;
651 static GnomeVFSResult
652 do_monitor_add (GnomeVFSMethod *method,
653 GnomeVFSMethodHandle **method_handle_return,
655 GnomeVFSMonitorType monitor_type)
657 return GNOME_VFS_ERROR_NOT_SUPPORTED;
660 static GnomeVFSResult
661 do_monitor_cancel (GnomeVFSMethod *method,
662 GnomeVFSMethodHandle *method_handle)
664 return GNOME_VFS_ERROR_NOT_SUPPORTED;
667 static GnomeVFSResult
668 do_file_control (GnomeVFSMethod *method,
669 GnomeVFSMethodHandle *method_handle,
670 const char *operation,
671 gpointer operation_data,
672 GnomeVFSContext *context)
674 return GNOME_VFS_ERROR_NOT_SUPPORTED;
677 static GnomeVFSMethod method = {
678 sizeof (GnomeVFSMethod),
691 do_get_file_info_from_handle,
701 do_create_symbolic_link,
709 vfs_module_init (const char *method_name, const char *args)
715 vfs_module_shutdown (GnomeVFSMethod * method)