[svn r414] Fixes unrestricted and continuous reads to movie stream when it is a comoon recorded file.
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 /* internal GnomeVFS plug-in buffer size ( 120 Kbytes ) */
45 #define MYTHTV_BUFFER_SIZE 1024*80
46 /* internally sized GnomeVFS plug-in buffer ( 4 Kbytes ) */
47 #define MYTHTV_MAX_VFS_BUFFER_SIZE 4096
48 /* maximum number of bytes to be requested to the MythTV backend ( 64 Kbytes ) */
49 #define MYTHTV_MAX_REQUEST_SIZE 1024*64
51 static GnomeVFSResult do_read (GnomeVFSMethod * method,
52 GnomeVFSMethodHandle * method_handle,
54 GnomeVFSFileSize num_bytes,
55 GnomeVFSFileSize * bytes_read,
56 GnomeVFSContext * context);
59 GMythFileTransfer *file_transfer;
75 //static MythtvHandle *myth_handle = NULL;
78 do_open (GnomeVFSMethod * method,
79 GnomeVFSMethodHandle ** method_handle,
81 GnomeVFSOpenMode mode, GnomeVFSContext * context)
83 MythtvHandle *myth_handle = NULL;
84 GMythBackendInfo *backend_info = NULL;
85 GMythURI *gmyth_uri = NULL;
88 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
89 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
91 if (mode & GNOME_VFS_OPEN_WRITE) {
92 return GNOME_VFS_ERROR_NOT_PERMITTED;
95 if (gnome_vfs_uri_get_host_name (uri) == NULL) {
96 return GNOME_VFS_ERROR_INVALID_HOST_NAME;
99 if ((NULL == myth_handle) || !myth_handle->configured) {
100 myth_handle = g_new0 (MythtvHandle, 1);
102 myth_handle->configured = FALSE;
104 myth_handle->is_livetv = FALSE;
106 /* Initialize mythtv handler */
107 myth_handle->file_transfer = NULL;
108 myth_handle->livetv = NULL;
109 myth_handle->mythtv_version = MYTHTV_VERSION_DEFAULT;
110 myth_handle->bytes_read = 0;
111 myth_handle->content_size = (GnomeVFSFileSize) - 1;
113 /* Creates and fills out the backend info structure */
115 gmyth_backend_info_new_with_uri
116 (gnome_vfs_unescape_string
117 (gnome_vfs_uri_to_string
118 (uri, GNOME_VFS_URI_HIDE_NONE), ""));
120 /* creates an instance of */
122 gmyth_uri_new_with_value (gnome_vfs_unescape_string
123 (gnome_vfs_uri_to_string
125 GNOME_VFS_URI_HIDE_NONE),
128 myth_handle->is_livetv = gmyth_uri_is_livetv (gmyth_uri);
130 /* Connect to the backend */
131 if (gmyth_uri != NULL && myth_handle->is_livetv == TRUE) {
133 if (NULL == myth_handle->livetv) {
134 myth_handle->livetv = gmyth_livetv_new ();
136 myth_handle->channel_name =
137 gmyth_uri_get_channel_name (gmyth_uri);
139 g_debug ("[%s] Channel name = %s\n",
141 myth_handle->channel_name);
143 if (myth_handle->channel_name != NULL) {
144 if (gmyth_livetv_channel_name_setup
145 (myth_handle->livetv,
146 myth_handle->channel_name,
147 backend_info) == FALSE) {
148 g_object_unref (gmyth_uri);
152 if (gmyth_livetv_setup
153 (myth_handle->livetv,
154 backend_info) == FALSE) {
155 g_object_unref (gmyth_uri);
161 if (NULL == myth_handle->file_transfer) {
162 myth_handle->file_transfer =
163 gmyth_livetv_create_file_transfer
164 (myth_handle->livetv);
166 if (NULL == myth_handle->file_transfer) {
169 ("MythTV FileTransfer is NULL!\n");
170 return GNOME_VFS_ERROR_NOT_OPEN;
173 if (!gmyth_file_transfer_open
174 (myth_handle->file_transfer,
175 myth_handle->livetv->uri !=
177 gmyth_uri_get_path (myth_handle->
180 myth_handle->livetv->proginfo->
183 ("Couldn't open MythTV FileTransfer is NULL!\n");
184 g_object_unref (myth_handle->
186 myth_handle->file_transfer = NULL;
190 /* if - FileTransfer is NULL, or not */
193 if (NULL == myth_handle->file_transfer) {
195 myth_handle->file_transfer =
196 gmyth_file_transfer_new (backend_info);
198 /* Verifies if the file exists */
199 if (!gmyth_util_file_exists
201 gmyth_uri_get_path (gmyth_uri))) {
202 g_object_unref (backend_info);
206 /* sets the Playback monitor connection */
208 gmyth_file_transfer_open (myth_handle->
215 } /* if - LiveTV or not? */
218 g_debug ("MythTV FileTransfer open error.\n");
219 return GNOME_VFS_ERROR_NOT_OPEN;
222 myth_handle->configured = TRUE;
224 g_object_unref (backend_info);
226 if (gmyth_uri != NULL)
227 g_object_unref (gmyth_uri);
229 myth_handle->buffer =
230 g_byte_array_sized_new (MYTHTV_BUFFER_SIZE);
231 myth_handle->buffer_remain = 0;
233 g_return_val_if_fail (myth_handle->file_transfer != NULL,
234 GNOME_VFS_ERROR_NOT_OPEN);
236 if ( /*myth_handle->file_transfer->filesize <= 0 && */
237 myth_handle->is_livetv) {
238 myth_handle->content_size =
239 gmyth_recorder_get_file_position (myth_handle->
243 myth_handle->content_size =
244 myth_handle->file_transfer->filesize;
248 /* if - configured or not? */
249 *method_handle = (GnomeVFSMethodHandle *) myth_handle;
254 static GnomeVFSResult
255 do_read (GnomeVFSMethod * method,
256 GnomeVFSMethodHandle * method_handle,
258 GnomeVFSFileSize num_bytes,
259 GnomeVFSFileSize * bytes_read, GnomeVFSContext * context)
261 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
262 GnomeVFSFileSize bytes_to_read = num_bytes;
264 if (!myth_handle->is_livetv
265 && (myth_handle->bytes_read >= myth_handle->content_size))
266 return GNOME_VFS_ERROR_EOF;
268 /* fixme: change this to min math function */
269 if ((myth_handle->content_size > 0)) {
270 if (!myth_handle->is_livetv &&
272 (myth_handle->content_size -
273 myth_handle->bytes_read))) {
275 myth_handle->content_size -
276 myth_handle->bytes_read;
280 /* Loop sending the Myth File Transfer request:
281 * Retry whilst authentication fails and we supply it. */
282 if ((myth_handle->buffer_remain =
283 myth_handle->buffer->len) < bytes_to_read) {
286 while (MYTHTV_BUFFER_SIZE != myth_handle->buffer_remain) {
288 /* resize buffer length request to no more than MYTHTV_MAX_REQUEST_SIZE */
289 if ((MYTHTV_BUFFER_SIZE -
290 myth_handle->buffer_remain) <=
291 MYTHTV_MAX_REQUEST_SIZE)
294 myth_handle->buffer_remain;
296 buffer_size = MYTHTV_MAX_REQUEST_SIZE;
298 GByteArray *tmp_buffer = g_byte_array_new ();
301 ("Asking %d bytes (there is %d bytes in the buffer)\n",
302 buffer_size, myth_handle->buffer_remain);
305 gmyth_file_transfer_read (myth_handle->
310 if ( !myth_handle->is_livetv ) {
312 g_byte_array_free (tmp_buffer, TRUE);
313 g_debug ("Fail to read bytes");
314 return GNOME_VFS_ERROR_IO;
315 } else if ( len == 0 ) {
316 g_byte_array_free (tmp_buffer, TRUE);
317 g_warning ("End of file probably achieved");
318 return GNOME_VFS_ERROR_EOF;
322 myth_handle->buffer =
323 g_byte_array_append (myth_handle->buffer,
324 tmp_buffer->data, len);
326 myth_handle->buffer_remain += len;
328 if (tmp_buffer != NULL) {
329 g_byte_array_free (tmp_buffer, TRUE);
332 } /* while - iterates until fills the internal buffer */
335 /* if - got from the network, or not */
338 myth_handle->buffer_remain) ? myth_handle->
339 buffer_remain : bytes_to_read;
340 /* gets the first buffer_size bytes from the byte array buffer variable */
342 g_memmove (buffer, myth_handle->buffer->data, bytes_to_read);
344 myth_handle->bytes_read += bytes_to_read;
345 myth_handle->buffer_remain -= bytes_to_read;
347 /* flushs the newly buffer got from byte array */
348 myth_handle->buffer =
349 g_byte_array_remove_range (myth_handle->buffer, 0,
352 ("Got from %llu bytes from internal buffer. (there are %d bytes in the buffer, from a total of %llu dispatched.)\n",
353 bytes_to_read, myth_handle->buffer_remain,
354 myth_handle->bytes_read);
356 *bytes_read = bytes_to_read;
361 static GnomeVFSResult
362 do_close (GnomeVFSMethod * method,
363 GnomeVFSMethodHandle * method_handle, GnomeVFSContext * context)
366 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
368 //if ( NULL == myth_handle || myth_handle->configured ) {
370 if (myth_handle->file_transfer != NULL) {
371 g_object_unref (myth_handle->file_transfer);
372 myth_handle->file_transfer = NULL;
375 if (myth_handle->is_livetv && myth_handle->livetv != NULL) {
376 g_object_unref (myth_handle->livetv);
377 myth_handle->livetv = NULL;
380 if (myth_handle->buffer) {
381 g_byte_array_free (myth_handle->buffer, TRUE);
382 myth_handle->buffer = NULL;
385 myth_handle->configured = FALSE;
387 g_free (myth_handle);
396 static GnomeVFSResult
397 do_get_file_info (GnomeVFSMethod * method,
399 GnomeVFSFileInfo * file_info,
400 GnomeVFSFileInfoOptions options,
401 GnomeVFSContext * context)
403 GMythFileTransfer *file_transfer = NULL;
404 GMythRecorder *recorder = NULL;
405 GMythTVChain *tvchain = NULL;
406 GMythBackendInfo *backend_info = NULL;
407 GMythURI *gmyth_uri = NULL;
408 GMythSocket *socket = NULL;
409 gboolean is_livetv = FALSE;
413 /* Creates and fills out the backend info structure */
415 gmyth_backend_info_new_with_uri (gnome_vfs_unescape_string
416 (gnome_vfs_uri_to_string
418 GNOME_VFS_URI_HIDE_NONE),
421 /* creates an instance of */
423 gmyth_uri_new_with_value (gnome_vfs_unescape_string
424 (gnome_vfs_uri_to_string
425 (uri, GNOME_VFS_URI_HIDE_NONE),
428 is_livetv = gmyth_uri_is_livetv (gmyth_uri);
430 file_info->valid_fields = file_info->valid_fields
431 | GNOME_VFS_FILE_INFO_FIELDS_TYPE
432 | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
433 | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
434 file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
435 /* fixme: get from file extension? */
436 file_info->mime_type = g_strdup ("video/x-nuv");
437 file_info->permissions =
438 GNOME_VFS_PERM_USER_READ |
439 GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_GROUP_READ;
441 g_debug ("gnome_vfs_uri == %s | gmyth_uri == %s.\n",
442 gnome_vfs_uri_get_path (uri),
443 gmyth_uri_get_path (gmyth_uri));
445 /* Connect to the backend */
446 if (gmyth_uri != NULL && is_livetv == TRUE) {
448 /* start to get file info from LiveTV remote encoder */
449 socket = gmyth_socket_new ();
451 /* FIME: Implement this at gmyth_socket */
453 gmyth_socket_connect_to_backend (socket,
459 g_debug ("[%s] LiveTV can not connect to backend",
465 if (gmyth_remote_util_get_free_recorder_count (socket) <=
467 g_debug ("No free remote encoder available.");
472 /* Gets the recorder num */
473 recorder = remote_request_next_free_recorder (socket, -1);
475 if ( socket != NULL )
476 g_object_unref (socket);
478 if (recorder == NULL) {
479 g_debug ("[%s] None remote encoder available",
485 /* Init remote encoder. Opens its control socket. */
486 res = gmyth_recorder_setup (recorder);
489 ("[%s] Fail while setting remote encoder\n",
495 /* Creates livetv chain handler */
496 tvchain = gmyth_tvchain_new ();
497 gmyth_tvchain_initialize (tvchain, backend_info);
499 if (tvchain == NULL || tvchain->tvchain_id == NULL) {
503 /* Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly) */
504 res = gmyth_recorder_spawntv (recorder,
508 g_warning ("[%s] Fail while spawn tv\n",
517 GMythProgramInfo *prog_info =
518 gmyth_recorder_get_current_program_info (recorder);
520 if (prog_info != NULL) {
522 g_debug ("path = %s", prog_info->pathname->str);
526 (prog_info->pathname->str, "/"));
529 file_info->name = g_strdup ("LiveTV.nuv");
531 gmyth_recorder_get_file_position (recorder);
534 if (recorder != NULL)
535 g_object_unref (recorder);
537 if (prog_info != NULL)
538 g_object_unref (prog_info);
541 g_object_unref (tvchain);
543 file_info->size = (GnomeVFSFileSize) - 1;
547 /* start to get file info from remote file encoder */
548 file_transfer = gmyth_file_transfer_new (backend_info);
550 /* Verifies if the file exists */
551 if (!gmyth_util_file_exists
552 (backend_info, gmyth_uri_get_path (gmyth_uri))) {
553 g_object_unref (backend_info);
554 return GNOME_VFS_ERROR_NOT_FOUND;
557 /* sets the Playback monitor connection */
559 gmyth_file_transfer_open (file_transfer,
563 file_info->name = g_strdup (gnome_vfs_uri_get_path (uri));
565 } /* if - LiveTV or not? */
568 g_debug ("MythTV FileTransfer open error\n");
569 return GNOME_VFS_ERROR_NOT_OPEN;
572 if (ret == TRUE && file_transfer != NULL) {
574 gmyth_file_transfer_get_filesize (file_transfer);
576 g_object_unref (file_transfer);
579 file_info->block_count = GNOME_VFS_FILE_INFO_FIELDS_BLOCK_COUNT;
580 file_info->io_block_size =
581 GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE;
585 g_object_unref (backend_info);
588 return GNOME_VFS_ERROR_IO;
594 do_is_local (GnomeVFSMethod * method, const GnomeVFSURI * uri)
599 static GnomeVFSMethod method = {
600 sizeof (GnomeVFSMethod),
631 vfs_module_init (const char *method_name, const char *args)
637 vfs_module_shutdown (GnomeVFSMethod * method)