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_transfer.h>
33 #include <gmyth/gmyth_livetv.h>
34 #include <gmyth/gmyth_uri.h>
35 #include <gmyth/gmyth_recorder.h>
36 #include <gmyth/gmyth_backendinfo.h>
37 #include <gmyth/gmyth_util.h>
38 #include <gmyth/gmyth_remote_util.h>
39 #include <gmyth/gmyth_tvchain.h>
40 #include <gmyth/gmyth_programinfo.h>
42 #define GST_MYTHTV_ID_NUM 1
43 #define MYTHTV_VERSION_DEFAULT 30
44 #define MYTHTV_TRANSFER_MAX_WAITS 100
46 /* internal GnomeVFS plug-in buffer size ( 120 Kbytes ) */
47 #define MYTHTV_BUFFER_SIZE 80*1024
48 /* internally sized GnomeVFS plug-in buffer ( 4 Kbytes ) */
49 #define MYTHTV_MAX_VFS_BUFFER_SIZE 4096
50 /* maximum number of bytes to be requested to the MythTV backend ( 64 Kbytes ) */
51 #define MYTHTV_MAX_REQUEST_SIZE 64*1024
53 static GnomeVFSResult do_read (GnomeVFSMethod * method,
54 GnomeVFSMethodHandle * method_handle,
56 GnomeVFSFileSize num_bytes,
57 GnomeVFSFileSize * bytes_read,
58 GnomeVFSContext * context);
61 GMythFileTransfer *file_transfer;
77 //static MythtvHandle *myth_handle = NULL;
79 static FILE *fpout = NULL;
80 static gboolean first = TRUE;
84 do_open (GnomeVFSMethod * method,
85 GnomeVFSMethodHandle ** method_handle,
87 GnomeVFSOpenMode mode, GnomeVFSContext * context)
89 MythtvHandle *myth_handle = NULL;
90 GMythBackendInfo *backend_info = NULL;
91 GMythURI *gmyth_uri = NULL;
94 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
95 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
97 if (mode & GNOME_VFS_OPEN_WRITE) {
98 return GNOME_VFS_ERROR_NOT_PERMITTED;
101 if (gnome_vfs_uri_get_host_name (uri) == NULL) {
102 return GNOME_VFS_ERROR_INVALID_HOST_NAME;
105 // FIXME: myth_handle is always NULL here
106 if ((NULL == myth_handle) || !myth_handle->configured) {
107 myth_handle = g_new0 (MythtvHandle, 1);
109 myth_handle->configured = FALSE;
111 myth_handle->is_livetv = FALSE;
113 /* Initialize mythtv handler */
114 myth_handle->file_transfer = NULL;
115 myth_handle->livetv = NULL;
116 myth_handle->mythtv_version = MYTHTV_VERSION_DEFAULT;
117 myth_handle->bytes_read = 0;
118 myth_handle->content_size = (GnomeVFSFileSize) - 1;
120 /* Creates and fills out the backend info structure */
122 gmyth_backend_info_new_with_uri
123 (gnome_vfs_unescape_string
124 (gnome_vfs_uri_to_string
125 (uri, GNOME_VFS_URI_HIDE_NONE), ""));
127 /* creates an instance of */
129 gmyth_uri_new_with_value (gnome_vfs_unescape_string
130 (gnome_vfs_uri_to_string
132 GNOME_VFS_URI_HIDE_NONE),
135 myth_handle->is_livetv = gmyth_uri_is_livetv (gmyth_uri);
137 /* Connect to the backend */
138 if (gmyth_uri != NULL && myth_handle->is_livetv == TRUE) {
140 if (NULL == myth_handle->livetv) {
141 myth_handle->livetv = gmyth_livetv_new (backend_info);
143 myth_handle->channel_name =
144 gmyth_uri_get_channel_name (gmyth_uri);
146 g_debug ("[%s] Channel name = %s\n",
148 myth_handle->channel_name);
150 if (myth_handle->channel_name != NULL) {
151 if (gmyth_livetv_channel_name_setup (myth_handle->livetv,
152 myth_handle->channel_name) == FALSE) {
153 g_object_unref (gmyth_uri);
157 if (gmyth_livetv_setup (myth_handle->livetv) == FALSE) {
158 g_object_unref (gmyth_uri);
164 if (NULL == myth_handle->file_transfer) {
165 myth_handle->file_transfer =
166 gmyth_livetv_create_file_transfer (myth_handle->livetv);
168 if (NULL == myth_handle->file_transfer) {
171 ("MythTV FileTransfer is NULL!\n");
172 return GNOME_VFS_ERROR_NOT_OPEN;
175 if (!gmyth_file_transfer_open
176 (myth_handle->file_transfer,
177 myth_handle->livetv->uri !=
179 gmyth_uri_get_path (myth_handle->
182 myth_handle->livetv->proginfo->
185 ("Couldn't open MythTV FileTransfer is NULL!\n");
186 g_object_unref (myth_handle->
188 myth_handle->file_transfer = NULL;
191 } /* 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->
214 } /* if - LiveTV or not? */
217 g_debug ("MythTV FileTransfer open error.\n");
218 return GNOME_VFS_ERROR_NOT_OPEN;
221 myth_handle->configured = TRUE;
223 g_object_unref (backend_info);
225 if (gmyth_uri != NULL)
226 g_object_unref (gmyth_uri);
228 myth_handle->buffer =
229 g_byte_array_sized_new (MYTHTV_BUFFER_SIZE);
230 myth_handle->buffer_remain = 0;
232 g_return_val_if_fail (myth_handle->file_transfer != NULL,
233 GNOME_VFS_ERROR_NOT_OPEN);
235 if ( /*myth_handle->file_transfer->filesize <= 0 && */
236 myth_handle->is_livetv) {
237 myth_handle->content_size =
238 gmyth_recorder_get_file_position (myth_handle->livetv->recorder);
240 myth_handle->content_size =
241 myth_handle->file_transfer->filesize;
245 /* if - configured or not? */
246 *method_handle = (GnomeVFSMethodHandle *) myth_handle;
251 static GnomeVFSResult
252 do_read (GnomeVFSMethod * method,
253 GnomeVFSMethodHandle * method_handle,
255 GnomeVFSFileSize num_bytes,
256 GnomeVFSFileSize * bytes_read,
257 GnomeVFSContext * context)
259 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
260 GnomeVFSFileSize bytes_to_read = num_bytes;
262 if (!myth_handle->is_livetv
263 && (myth_handle->bytes_read >= myth_handle->content_size))
264 return GNOME_VFS_ERROR_EOF;
266 /* fixme: change this to min math function */
267 if ((myth_handle->content_size > 0)) {
268 if (!myth_handle->is_livetv &&
270 (myth_handle->content_size -
271 myth_handle->bytes_read))) {
273 myth_handle->content_size -
274 myth_handle->bytes_read;
278 /* Loop sending the Myth File Transfer request:
279 * Retry whilst authentication fails and we supply it. */
280 if ((myth_handle->buffer_remain =
281 myth_handle->buffer->len) < bytes_to_read) {
284 while (MYTHTV_BUFFER_SIZE != myth_handle->buffer_remain) {
285 /* resize buffer length request to no more than MYTHTV_MAX_REQUEST_SIZE */
286 if ((MYTHTV_BUFFER_SIZE -
287 myth_handle->buffer_remain) <=
288 MYTHTV_MAX_REQUEST_SIZE)
291 myth_handle->buffer_remain;
293 buffer_size = MYTHTV_MAX_REQUEST_SIZE;
295 GByteArray *tmp_buffer = g_byte_array_new ();
297 g_debug ("Asking %d bytes (there is %d bytes in the buffer)\n",
298 buffer_size, myth_handle->buffer_remain);
301 gmyth_file_transfer_read (myth_handle->
306 if ( !myth_handle->is_livetv ) {
308 g_byte_array_free (tmp_buffer, TRUE);
309 g_debug ("Fail to read bytes");
310 return GNOME_VFS_ERROR_IO;
311 } else if ( len == 0 ) {
312 g_byte_array_free (tmp_buffer, TRUE);
313 g_warning ("End of file probably achieved");
314 return GNOME_VFS_ERROR_EOF;
318 myth_handle->buffer =
319 g_byte_array_append (myth_handle->buffer,
320 tmp_buffer->data, len);
322 myth_handle->buffer_remain += len;
324 if (tmp_buffer != NULL) {
325 g_byte_array_free (tmp_buffer, TRUE);
328 } /* while - iterates until fills the internal buffer */
332 /* if - got from the network, or not */
335 myth_handle->buffer_remain) ? myth_handle->
336 buffer_remain : bytes_to_read;
337 /* gets the first buffer_size bytes from the byte array buffer variable */
339 g_memmove (buffer, myth_handle->buffer->data, bytes_to_read);
341 myth_handle->bytes_read += bytes_to_read;
342 myth_handle->buffer_remain -= bytes_to_read;
344 /* flushs the newly buffer got from byte array */
345 myth_handle->buffer =
346 g_byte_array_remove_range (myth_handle->buffer, 0,
349 ("Got from %llu bytes from internal buffer. (there are %d bytes in the buffer, from a total of %llu dispatched.)\n",
350 bytes_to_read, myth_handle->buffer_remain,
351 myth_handle->bytes_read);
353 *bytes_read = bytes_to_read;
358 static GnomeVFSResult
359 do_close (GnomeVFSMethod * method,
360 GnomeVFSMethodHandle * method_handle, GnomeVFSContext * context)
363 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
365 //if ( NULL == myth_handle || myth_handle->configured ) {
367 if (myth_handle->is_livetv && myth_handle->livetv != NULL) {
368 g_object_unref (myth_handle->livetv);
369 myth_handle->livetv = NULL;
372 if (myth_handle->file_transfer != NULL) {
373 g_object_unref (myth_handle->file_transfer);
374 myth_handle->file_transfer = NULL;
377 if (myth_handle->buffer) {
378 g_byte_array_free (myth_handle->buffer, TRUE);
379 myth_handle->buffer = NULL;
382 myth_handle->configured = FALSE;
384 g_free (myth_handle->channel_name);
386 g_free (myth_handle);
395 static GnomeVFSResult
396 do_get_file_info (GnomeVFSMethod * method,
398 GnomeVFSFileInfo * file_info,
399 GnomeVFSFileInfoOptions options,
400 GnomeVFSContext * context)
402 GMythFileTransfer *file_transfer = NULL;
403 GMythRecorder *recorder = NULL;
404 GMythTVChain *tvchain = NULL;
405 GMythBackendInfo *backend_info = NULL;
406 GMythURI *gmyth_uri = NULL;
407 GMythSocket *socket = NULL;
408 gboolean is_livetv = FALSE;
412 /* Creates and fills out the backend info structure */
414 gmyth_backend_info_new_with_uri (gnome_vfs_unescape_string
415 (gnome_vfs_uri_to_string
417 GNOME_VFS_URI_HIDE_NONE),
420 /* creates an instance of */
422 gmyth_uri_new_with_value (gnome_vfs_unescape_string
423 (gnome_vfs_uri_to_string
424 (uri, GNOME_VFS_URI_HIDE_NONE),
427 is_livetv = gmyth_uri_is_livetv (gmyth_uri);
429 file_info->valid_fields = 0;
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,
454 backend_info->hostname,
458 g_debug ("[%s] LiveTV can not connect to backend", __FUNCTION__);
463 if (gmyth_remote_util_get_free_recorder_count (socket) <= 0) {
464 g_debug ("No free remote encoder available.");
469 /* Gets the recorder num */
470 recorder = remote_request_next_free_recorder (socket, -1);
473 g_object_unref (socket);
475 if (recorder == NULL) {
476 g_debug ("[%s] None remote encoder available", __FUNCTION__);
481 /* Init remote encoder. Opens its control socket. */
482 res = gmyth_recorder_setup (recorder);
484 g_debug ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
489 /* Creates livetv chain handler */
490 tvchain = gmyth_tvchain_new ();
491 gmyth_tvchain_initialize (tvchain, backend_info);
493 if (tvchain == NULL || tvchain->tvchain_id == NULL) {
497 /* Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly) */
498 res = gmyth_recorder_spawntv (recorder, gmyth_tvchain_get_id(tvchain));
500 g_warning ("[%s] Fail while spawn tv\n",
509 GMythProgramInfo *prog_info =
510 gmyth_recorder_get_current_program_info (recorder);
512 if (prog_info != NULL) {
514 g_debug ("path = %s", prog_info->pathname->str);
518 (prog_info->pathname->str, "/"));
521 file_info->name = g_strdup ("LiveTV.nuv");
522 /* Size being overrided below ... */
523 //file_info->size = gmyth_recorder_get_file_position (recorder);
526 if (recorder != NULL)
527 g_object_unref (recorder);
529 if (prog_info != NULL)
530 g_object_unref (prog_info);
533 g_object_unref (tvchain);
535 //file_info->size = (GnomeVFSFileSize) - 1;
539 /* start to get file info from remote file encoder */
540 file_transfer = gmyth_file_transfer_new (backend_info);
542 /* Verifies if the file exists */
543 if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) {
544 g_object_unref (backend_info);
545 return GNOME_VFS_ERROR_NOT_FOUND;
548 /* sets the Playback monitor connection */
549 ret = gmyth_file_transfer_open (file_transfer,
550 gmyth_uri_get_path (gmyth_uri));
552 file_info->name = g_strdup (gnome_vfs_uri_get_path (uri));
554 } /* if - LiveTV or not? */
557 g_debug ("MythTV FileTransfer open error\n");
558 return GNOME_VFS_ERROR_NOT_OPEN;
561 /* Just for recorded content */
562 if (ret == TRUE && file_transfer != NULL) {
564 gmyth_file_transfer_get_filesize (file_transfer);
566 file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE;
569 g_object_unref (file_transfer);
574 g_object_unref (backend_info);
577 return GNOME_VFS_ERROR_IO;
583 do_is_local (GnomeVFSMethod * method, const GnomeVFSURI * uri)
588 static GnomeVFSMethod method = {
589 sizeof (GnomeVFSMethod),
620 vfs_module_init (const char *method_name, const char *args)
626 vfs_module_shutdown (GnomeVFSMethod * method)