/* * @author Hallyson Melo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #define GST_MYTHTV_ID_NUM 1 #define MYTHTV_VERSION_DEFAULT 30 #define MYTHTV_TRANSFER_MAX_WAITS 100 #define MYTHTV_BUFFER_SIZE 1024*64 static GnomeVFSResult do_read (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, gpointer buffer, GnomeVFSFileSize num_bytes, GnomeVFSFileSize *bytes_read, GnomeVFSContext *context); typedef struct { GMythFileTransfer *file_transfer; GMythLiveTV *livetv; gint channel_num; gint mythtv_version; guint64 content_size; guint64 bytes_read; GByteArray *buffer; gsize buffer_remain; } MythtvHandle; static GnomeVFSResult do_open (GnomeVFSMethod *method, GnomeVFSMethodHandle **method_handle, GnomeVFSURI *uri, GnomeVFSOpenMode mode, GnomeVFSContext *context) { MythtvHandle *myth_handle; GMythBackendInfo *backend_info; GMythURI *gmyth_uri = NULL; gboolean ret = TRUE; gboolean is_livetv = FALSE; gint wait_to_transfer = 0; _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL); _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL); myth_handle = g_new0 (MythtvHandle, 1); if (mode & GNOME_VFS_OPEN_WRITE) { return GNOME_VFS_ERROR_NOT_PERMITTED; } if (gnome_vfs_uri_get_host_name (uri) == NULL) { return GNOME_VFS_ERROR_INVALID_HOST_NAME; } /* Initialize mythtv handler*/ myth_handle->file_transfer = NULL; myth_handle->livetv = NULL; myth_handle->mythtv_version = MYTHTV_VERSION_DEFAULT; myth_handle->bytes_read = 0; myth_handle->content_size = -1; /* Creates and fills out the backend info structure */ backend_info = gmyth_backend_info_new_with_uri ( gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) ); /* creates an instance of */ gmyth_uri = gmyth_uri_new_with_value( gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) ); /* Connect to the backend */ if ( gmyth_uri != NULL && ( is_livetv = gmyth_uri_is_livetv( gmyth_uri ) ) == TRUE ) { myth_handle->livetv = gmyth_livetv_new (); myth_handle->channel_num = gmyth_uri_get_channel_num( gmyth_uri ); if ( myth_handle->channel_num != -1 ) { if (gmyth_livetv_channel_setup (myth_handle->livetv, myth_handle->channel_num, backend_info) == FALSE) { g_object_unref( gmyth_uri ); ret = FALSE; } } else { if ( gmyth_livetv_setup (myth_handle->livetv, backend_info) == FALSE ) { g_object_unref( gmyth_uri ); ret = FALSE; } } myth_handle->file_transfer = gmyth_livetv_create_file_transfer (myth_handle->livetv); if (NULL == myth_handle->file_transfer) { ret = FALSE; } if ( gmyth_uri != NULL ) g_object_unref( gmyth_uri ); } else { myth_handle->file_transfer = gmyth_file_transfer_new (backend_info); /* Verifies if the file exists */ if (!gmyth_util_file_exists (backend_info, gnome_vfs_uri_get_path (uri))) { g_object_unref (backend_info); return GNOME_VFS_ERROR_NOT_FOUND; } /* sets the Playback monitor connection */ ret = gmyth_file_transfer_open ( myth_handle->file_transfer, gnome_vfs_uri_get_path (uri) ); } /* if - LiveTV or not? */ if (ret == FALSE) { g_warning ("MythTV FileTransfer open error\n"); return GNOME_VFS_ERROR_NOT_OPEN; } if ( is_livetv == TRUE && ret == TRUE ) { /* loop finished, set the max tries variable to zero again... */ wait_to_transfer = 0; while ( wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS && (gmyth_livetv_is_recording (myth_handle->livetv) == FALSE)) g_usleep (500); /* IS_RECORDING again, just like the MythTV backend does... */ gmyth_livetv_is_recording (myth_handle->livetv); sleep (4); /* FIXME: this is evil (tpm) */ } g_object_unref (backend_info); g_return_val_if_fail (myth_handle->file_transfer != NULL, GNOME_VFS_ERROR_NOT_OPEN); myth_handle->content_size = myth_handle->file_transfer->filesize; myth_handle->buffer = g_byte_array_sized_new (MYTHTV_BUFFER_SIZE); myth_handle->buffer_remain = 0; *method_handle = (GnomeVFSMethodHandle *) myth_handle; return GNOME_VFS_OK; } static GnomeVFSResult do_read (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, gpointer buffer, GnomeVFSFileSize num_bytes, GnomeVFSFileSize *bytes_read, GnomeVFSContext *context) { MythtvHandle *myth_handle = (MythtvHandle *) method_handle; GnomeVFSFileSize bytes_to_read; *bytes_read = 0; if (myth_handle->bytes_read >= myth_handle->content_size) return GNOME_VFS_ERROR_EOF; // fixme: change this to min math function if (num_bytes > myth_handle->content_size - myth_handle->bytes_read) bytes_to_read = myth_handle->content_size - myth_handle->bytes_read; else bytes_to_read = num_bytes; /* Loop sending the Myth File Transfer request: * Retry whilst authentication fails and we supply it. */ if ( bytes_to_read > myth_handle->buffer_remain ) { GByteArray *tmp_buffer = g_byte_array_new(); gint len = gmyth_file_transfer_read (myth_handle->file_transfer, tmp_buffer, MYTHTV_BUFFER_SIZE - myth_handle->buffer_remain, TRUE); if (len < 0) { g_byte_array_free (tmp_buffer, TRUE); g_warning ("Fail to read bytes"); return GNOME_VFS_ERROR_IO; } else if (len == 0) { g_byte_array_free (tmp_buffer, TRUE); g_warning ("End of file probably achieved"); return GNOME_VFS_ERROR_EOF; } myth_handle->buffer = g_byte_array_append (myth_handle->buffer, tmp_buffer->data, len); myth_handle->buffer_remain += len; g_byte_array_free (tmp_buffer, TRUE); tmp_buffer = NULL; } bytes_to_read = (bytes_to_read > myth_handle->buffer_remain) ? myth_handle->buffer_remain : bytes_to_read; /* gets the first buffer_size bytes from the byte array buffer variable */ g_memmove (buffer, myth_handle->buffer->data, bytes_to_read); myth_handle->bytes_read += bytes_to_read; myth_handle->buffer_remain -= bytes_to_read; /* flushs the newly buffer got from byte array */ myth_handle->buffer = g_byte_array_remove_range (myth_handle->buffer, 0, bytes_to_read); *bytes_read = bytes_to_read; return GNOME_VFS_OK; } static GnomeVFSResult do_close (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, GnomeVFSContext *context) { MythtvHandle *myth_handle = (MythtvHandle *) method_handle; if (myth_handle->file_transfer) { gmyth_file_transfer_close (myth_handle->file_transfer); g_object_unref (myth_handle->file_transfer); myth_handle->file_transfer = NULL; } if (myth_handle->livetv) { g_object_unref (myth_handle->livetv); myth_handle->livetv = NULL; } if (myth_handle->buffer) { g_byte_array_free (myth_handle->buffer, TRUE); myth_handle->buffer = NULL; } g_free (myth_handle); return GNOME_VFS_OK; } static GnomeVFSResult do_get_file_info (GnomeVFSMethod *method, GnomeVFSURI *uri, GnomeVFSFileInfo *file_info, GnomeVFSFileInfoOptions options, GnomeVFSContext *context) { GMythFileTransfer *file_transfer = NULL; GMythBackendInfo *backend_info = NULL; file_info->name = g_strdup (gnome_vfs_uri_get_path (uri)); file_info->valid_fields = file_info->valid_fields | GNOME_VFS_FILE_INFO_FIELDS_TYPE | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS; file_info->type = GNOME_VFS_FILE_TYPE_REGULAR; // fixme: get from file extension? file_info->mime_type = g_strdup ("video/x-nuv"); file_info->permissions = GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_GROUP_READ; backend_info = gmyth_backend_info_new_full (gnome_vfs_uri_get_host_name (uri), gnome_vfs_uri_get_user_name (uri), gnome_vfs_uri_get_password (uri), NULL, gnome_vfs_uri_get_host_port (uri)); file_transfer = gmyth_file_transfer_new (backend_info); if (gmyth_file_transfer_open (file_transfer, gnome_vfs_uri_get_path (uri)) == TRUE) { file_info->size = gmyth_file_transfer_get_filesize (file_transfer); file_info->block_count = GNOME_VFS_FILE_INFO_FIELDS_BLOCK_COUNT; file_info->io_block_size = GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE; } g_object_unref (file_transfer); g_object_unref (backend_info); return GNOME_VFS_OK; } static gboolean do_is_local (GnomeVFSMethod *method, const GnomeVFSURI *uri) { return FALSE; } static GnomeVFSMethod method = { sizeof (GnomeVFSMethod), do_open, NULL, do_close, do_read, NULL, NULL, NULL, NULL, NULL, NULL, NULL, do_get_file_info, NULL, do_is_local, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; GnomeVFSMethod * vfs_module_init (const char *method_name, const char *args) { return &method; } void vfs_module_shutdown (GnomeVFSMethod *method) { }