[svn r356] Solved bug on read method callback.
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>
39 #define GST_MYTHTV_ID_NUM 1
40 #define MYTHTV_VERSION_DEFAULT 30
41 #define MYTHTV_TRANSFER_MAX_WAITS 100
43 #define MYTHTV_BUFFER_SIZE 1024*80
44 #define MYTHTV_MAX_VFS_BUFFER_SIZE 4096
45 #define MYTHTV_MAX_REQUEST_SIZE 1024*64
47 static GnomeVFSResult do_read (GnomeVFSMethod *method,
48 GnomeVFSMethodHandle *method_handle,
50 GnomeVFSFileSize num_bytes,
51 GnomeVFSFileSize *bytes_read,
52 GnomeVFSContext *context);
55 GMythFileTransfer *file_transfer;
70 do_open (GnomeVFSMethod *method,
71 GnomeVFSMethodHandle **method_handle,
73 GnomeVFSOpenMode mode,
74 GnomeVFSContext *context)
76 MythtvHandle *myth_handle;
77 GMythBackendInfo *backend_info;
78 GMythURI *gmyth_uri = NULL;
81 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
82 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
84 myth_handle = g_new0 (MythtvHandle, 1);
86 myth_handle->is_livetv = FALSE;
88 if (mode & GNOME_VFS_OPEN_WRITE) {
89 return GNOME_VFS_ERROR_NOT_PERMITTED;
92 if (gnome_vfs_uri_get_host_name (uri) == NULL) {
93 return GNOME_VFS_ERROR_INVALID_HOST_NAME;
96 /* Initialize mythtv handler*/
97 myth_handle->file_transfer = NULL;
98 myth_handle->livetv = NULL;
99 myth_handle->mythtv_version = MYTHTV_VERSION_DEFAULT;
100 myth_handle->bytes_read = 0;
101 myth_handle->content_size = (GnomeVFSFileSize) - 1;
103 /* Creates and fills out the backend info structure */
104 backend_info = gmyth_backend_info_new_with_uri (
105 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
107 /* creates an instance of */
108 gmyth_uri = gmyth_uri_new_with_value(
109 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
111 myth_handle->is_livetv = gmyth_uri_is_livetv( gmyth_uri );
113 /* Connect to the backend */
114 if ( gmyth_uri != NULL && myth_handle->is_livetv == TRUE ) {
116 if ( NULL == myth_handle->livetv )
118 myth_handle->livetv = gmyth_livetv_new ();
120 myth_handle->channel_name = gmyth_uri_get_channel_name( gmyth_uri );
122 g_debug( "[%s] Channel name = %s\n", __FUNCTION__, myth_handle->channel_name );
124 if ( myth_handle->channel_name != NULL ) {
125 if (gmyth_livetv_channel_name_setup (myth_handle->livetv, myth_handle->channel_name,
126 backend_info) == FALSE) {
127 g_object_unref( gmyth_uri );
131 if ( gmyth_livetv_setup (myth_handle->livetv, backend_info) == FALSE ) {
132 g_object_unref( gmyth_uri );
138 if ( NULL == myth_handle->file_transfer ) {
139 myth_handle->file_transfer = gmyth_livetv_create_file_transfer (myth_handle->livetv);
141 if (NULL == myth_handle->file_transfer) {
143 g_debug ("MythTV FileTransfer is NULL!\n");
144 return GNOME_VFS_ERROR_NOT_OPEN;
147 if ( !gmyth_file_transfer_open( myth_handle->file_transfer, myth_handle->livetv->uri != NULL ?
148 gmyth_uri_get_path(myth_handle->livetv->uri) :
149 myth_handle->livetv->proginfo->pathname->str ) )
151 g_debug ("Couldn't open MythTV FileTransfer is NULL!\n");
152 g_object_unref( myth_handle->file_transfer );
153 myth_handle->file_transfer = NULL;
156 } /* if - FileTransfer is NULL, or not */
160 if (NULL == myth_handle->file_transfer ) {
162 myth_handle->file_transfer = gmyth_file_transfer_new (backend_info);
164 /* Verifies if the file exists */
165 if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) {
166 g_object_unref (backend_info);
170 /* sets the Playback monitor connection */
171 ret = gmyth_file_transfer_open ( myth_handle->file_transfer,
172 gmyth_uri_get_path (gmyth_uri) );
176 } /* if - LiveTV or not? */
179 g_debug ("MythTV FileTransfer open error.\n");
180 return GNOME_VFS_ERROR_NOT_OPEN;
183 //g_object_unref (backend_info);
185 //if ( gmyth_uri != NULL )
186 // g_object_unref( gmyth_uri );
188 g_return_val_if_fail (myth_handle->file_transfer != NULL, GNOME_VFS_ERROR_NOT_OPEN);
190 if ( /*myth_handle->file_transfer->filesize <= 0 && */myth_handle->is_livetv ) {
191 myth_handle->content_size = (GnomeVFSFileSize) - 1;
192 //myth_handle->content_size = gmyth_recorder_get_file_position( myth_handle->livetv->recorder );
194 myth_handle->content_size = myth_handle->file_transfer->filesize;
196 myth_handle->buffer = g_byte_array_sized_new (MYTHTV_BUFFER_SIZE);
197 myth_handle->buffer_remain = 0;
199 *method_handle = (GnomeVFSMethodHandle *) myth_handle;
204 static GnomeVFSResult
205 do_read (GnomeVFSMethod *method,
206 GnomeVFSMethodHandle *method_handle,
208 GnomeVFSFileSize num_bytes,
209 GnomeVFSFileSize *bytes_read,
210 GnomeVFSContext *context)
212 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
213 GnomeVFSFileSize bytes_to_read;
217 g_debug ("XXXXXXXXXX Requested %llu bytes...\n", (guint64)num_bytes);
219 if ( !myth_handle->is_livetv && ( myth_handle->bytes_read >= myth_handle->content_size ) )
220 return GNOME_VFS_ERROR_EOF;
222 // fixme: change this to min math function
223 if (!myth_handle->is_livetv && ( myth_handle->content_size > 0 ) &&
224 ( num_bytes > ( myth_handle->content_size - myth_handle->bytes_read ) ) )
225 bytes_to_read = myth_handle->content_size - myth_handle->bytes_read;
227 bytes_to_read = num_bytes;
229 /* Loop sending the Myth File Transfer request:
230 * Retry whilst authentication fails and we supply it. */
231 //if (myth_handle->buffer_remain < MYTHTV_BUFFER_SIZE) {
232 if ( ( myth_handle->buffer_remain = myth_handle->buffer->len ) < MYTHTV_MAX_VFS_BUFFER_SIZE ) {
233 gint buffer_size = MYTHTV_BUFFER_SIZE - myth_handle->buffer_remain;
235 /* resize buffer length request to no more than MYTHTV_MAX_REQUEST_SIZE */
236 if ( buffer_size > MYTHTV_MAX_REQUEST_SIZE )
237 buffer_size = MYTHTV_MAX_REQUEST_SIZE;
239 GByteArray *tmp_buffer = g_byte_array_new();
241 g_debug ("XXXXXXXXXX Pedindo %d (restam apenas %d no buffer)\n", buffer_size, myth_handle->buffer_remain);
243 gint len = gmyth_file_transfer_read (myth_handle->file_transfer,
244 tmp_buffer, buffer_size, TRUE);
246 if (!myth_handle->is_livetv && len < 0) {
247 g_byte_array_free (tmp_buffer, TRUE);
248 g_debug ("Fail to read bytes");
249 return GNOME_VFS_ERROR_IO;
250 } /*else if (len == 0) {
251 g_byte_array_free (tmp_buffer, TRUE);
252 g_warning ("End of file probably achieved");
253 return GNOME_VFS_ERROR_EOF;
256 myth_handle->buffer = g_byte_array_append (myth_handle->buffer,
257 tmp_buffer->data, len);
259 myth_handle->buffer_remain += len;
261 if ( tmp_buffer != NULL )
263 g_byte_array_free (tmp_buffer, TRUE);
266 } /* if - got from the network, or not */
268 bytes_to_read = (bytes_to_read > myth_handle->buffer_remain) ? myth_handle->buffer_remain : bytes_to_read;
269 /* gets the first buffer_size bytes from the byte array buffer variable */
271 g_memmove (buffer, myth_handle->buffer->data, bytes_to_read);
273 myth_handle->bytes_read += bytes_to_read;
274 myth_handle->buffer_remain -= bytes_to_read;
276 /* flushs the newly buffer got from byte array */
277 myth_handle->buffer = g_byte_array_remove_range (myth_handle->buffer, 0, bytes_to_read);
278 *bytes_read = bytes_to_read;
283 static GnomeVFSResult
284 do_close (GnomeVFSMethod *method,
285 GnomeVFSMethodHandle *method_handle,
286 GnomeVFSContext *context)
289 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
291 if (myth_handle->file_transfer != NULL) {
292 g_object_unref (myth_handle->file_transfer);
293 myth_handle->file_transfer = NULL;
296 if (myth_handle->is_livetv && myth_handle->livetv != NULL) {
297 g_object_unref (myth_handle->livetv);
298 myth_handle->livetv = NULL;
301 if (myth_handle->buffer) {
302 g_byte_array_free (myth_handle->buffer, TRUE);
303 myth_handle->buffer = NULL;
306 g_free (myth_handle);
311 static GnomeVFSResult
312 do_get_file_info (GnomeVFSMethod *method,
314 GnomeVFSFileInfo *file_info,
315 GnomeVFSFileInfoOptions options,
316 GnomeVFSContext *context)
318 GMythFileTransfer *file_transfer = NULL;
319 GMythRecorder *recorder = NULL;
320 GMythTVChain *tvchain = NULL;
321 GMythBackendInfo *backend_info = NULL;
322 GMythURI *gmyth_uri = NULL;
323 GMythSocket *socket = NULL;
324 gboolean is_livetv = FALSE;
328 /* Creates and fills out the backend info structure */
329 backend_info = gmyth_backend_info_new_with_uri (
330 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
332 /* creates an instance of */
333 gmyth_uri = gmyth_uri_new_with_value(
334 gnome_vfs_unescape_string( gnome_vfs_uri_to_string( uri, GNOME_VFS_URI_HIDE_NONE ), "" ) );
336 is_livetv = gmyth_uri_is_livetv( gmyth_uri );
338 file_info->valid_fields = file_info->valid_fields
339 | GNOME_VFS_FILE_INFO_FIELDS_TYPE
340 | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
341 | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
342 file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
343 /* fixme: get from file extension? */
344 file_info->mime_type = g_strdup ("video/x-nuv");
345 file_info->permissions =
346 GNOME_VFS_PERM_USER_READ |
347 GNOME_VFS_PERM_OTHER_READ |
348 GNOME_VFS_PERM_GROUP_READ;
350 g_print( "gnome_vfs_uri == %s | gmyth_uri == %s.\n",
351 gnome_vfs_uri_get_path (uri),
352 gmyth_uri_get_path (gmyth_uri) );
354 /* Connect to the backend */
355 if ( gmyth_uri != NULL && is_livetv == TRUE ) {
357 /* start to get file info from LiveTV remote encoder */
358 socket = gmyth_socket_new ();
360 /* FIME: Implement this at gmyth_socket */
361 res = gmyth_socket_connect_to_backend (socket, backend_info->hostname,
362 backend_info->port, TRUE);
364 g_print ("[%s] LiveTV can not connect to backend", __FUNCTION__);
369 if ( gmyth_remote_util_get_free_recorder_count (socket) <= 0 ) {
370 g_print ("No free remote encoder available.");
375 /* Gets the recorder num */
376 recorder = remote_request_next_free_recorder (socket, -1);
378 //if ( socket != NULL )
379 // g_object_unref (socket);
381 if ( recorder == NULL ) {
382 g_print ("[%s] None remote encoder available", __FUNCTION__);
387 /* Init remote encoder. Opens its control socket. */
388 res = gmyth_recorder_setup(recorder);
390 g_print ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
395 /* Creates livetv chain handler */
396 tvchain = gmyth_tvchain_new();
397 gmyth_tvchain_initialize ( tvchain, backend_info );
399 if ( tvchain == NULL || tvchain->tvchain_id == NULL ) {
404 // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly)
405 res = gmyth_recorder_spawntv ( recorder,
406 gmyth_tvchain_get_id(tvchain) );
408 g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__);
413 //gchar* channel_name = gmyth_uri_get_channel_name( gmyth_uri );
416 GMythProgramInfo* prog_info = gmyth_recorder_get_current_program_info( recorder );
418 if ( prog_info != NULL )
420 gmyth_program_info_print( prog_info );
422 g_print( "path = %s", prog_info->pathname->str );
424 file_info->name = g_strdup ( g_strrstr( prog_info->pathname->str, "/" ) );
427 file_info->name = g_strdup ( "LiveTV.nuv" );
428 file_info->size = gmyth_recorder_get_file_position( recorder );
431 if ( recorder != NULL )
432 g_object_unref (recorder);
434 if ( prog_info != NULL )
435 g_object_unref( prog_info );
437 if ( tvchain != NULL )
438 g_object_unref (tvchain);
440 file_info->size = (GnomeVFSFileSize) - 1;
444 /* start to get file info from remote file encoder */
445 file_transfer = gmyth_file_transfer_new (backend_info);
447 /* Verifies if the file exists */
448 if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) {
449 g_object_unref (backend_info);
450 return GNOME_VFS_ERROR_NOT_FOUND;
453 /* sets the Playback monitor connection */
454 ret = gmyth_file_transfer_open ( file_transfer, gmyth_uri_get_path (gmyth_uri) );
456 file_info->name = g_strdup ( gnome_vfs_uri_get_path (uri) );
458 } /* if - LiveTV or not? */
461 g_debug ("MythTV FileTransfer open error\n");
462 return GNOME_VFS_ERROR_NOT_OPEN;
465 if ( ret == TRUE && file_transfer != NULL ) {
466 file_info->size = gmyth_file_transfer_get_filesize (file_transfer);
468 g_object_unref (file_transfer);
471 file_info->block_count = GNOME_VFS_FILE_INFO_FIELDS_BLOCK_COUNT;
472 file_info->io_block_size = GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE;
476 g_object_unref (backend_info);
479 return GNOME_VFS_ERROR_IO;
485 do_is_local (GnomeVFSMethod *method,
486 const GnomeVFSURI *uri)
491 static GnomeVFSMethod method = {
492 sizeof (GnomeVFSMethod),
523 vfs_module_init (const char *method_name, const char *args)
529 vfs_module_shutdown (GnomeVFSMethod *method)