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;
96 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
97 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
99 if (mode & GNOME_VFS_OPEN_WRITE) {
100 return GNOME_VFS_ERROR_NOT_PERMITTED;
103 if (gnome_vfs_uri_get_host_name (uri) == NULL) {
104 return GNOME_VFS_ERROR_INVALID_HOST_NAME;
107 // FIXME: myth_handle is always NULL here
108 if ((NULL == myth_handle) || !myth_handle->configured) {
109 myth_handle = g_new0 (MythtvHandle, 1);
111 myth_handle->configured = FALSE;
112 myth_handle->is_livetv = FALSE;
114 /* Initialize mythtv handler */
115 myth_handle->file_transfer = NULL;
116 myth_handle->livetv = NULL;
117 myth_handle->mythtv_version = MYTHTV_VERSION_DEFAULT;
118 myth_handle->bytes_read = 0;
119 myth_handle->content_size = (GnomeVFSFileSize) - 1;
121 /* Creates and fills out the backend info structure */
122 tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
123 tmp_str2 = gnome_vfs_unescape_string (tmp_str1, "");
125 backend_info = gmyth_backend_info_new_with_uri (tmp_str2);
130 /* creates an instance of */
131 tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
132 tmp_str2 = gnome_vfs_unescape_string (tmp_str1, "");
134 gmyth_uri = gmyth_uri_new_with_value (tmp_str2);
139 myth_handle->is_livetv = gmyth_uri_is_livetv (gmyth_uri);
141 /* Connect to the backend */
142 if (gmyth_uri != NULL && myth_handle->is_livetv == TRUE) {
144 if (NULL == myth_handle->livetv) {
145 myth_handle->livetv = gmyth_livetv_new (backend_info);
147 myth_handle->channel_name =
148 gmyth_uri_get_channel_name (gmyth_uri);
150 g_debug ("[%s] Channel name = %s\n",
152 myth_handle->channel_name);
154 if (myth_handle->channel_name != NULL) {
155 if (gmyth_livetv_channel_name_setup (myth_handle->livetv,
156 myth_handle->channel_name) == FALSE) {
157 g_object_unref (gmyth_uri);
161 if (gmyth_livetv_setup (myth_handle->livetv) == FALSE) {
162 g_object_unref (gmyth_uri);
168 if (NULL == myth_handle->file_transfer) {
169 myth_handle->file_transfer =
170 gmyth_livetv_create_file_transfer (myth_handle->livetv);
172 if (NULL == myth_handle->file_transfer) {
174 g_debug ("MythTV FileTransfer is NULL!\n");
175 return GNOME_VFS_ERROR_NOT_OPEN;
178 if (!gmyth_file_transfer_open (myth_handle->file_transfer,
179 myth_handle->livetv->uri != NULL ?
180 gmyth_uri_get_path (myth_handle->livetv->uri) :
181 myth_handle->livetv->proginfo->pathname->str)) {
182 g_debug ("Couldn't open MythTV FileTransfer is NULL!\n");
183 g_object_unref (myth_handle->file_transfer);
184 myth_handle->file_transfer = NULL;
187 } /* if - FileTransfer is NULL, or not */
189 if (NULL == myth_handle->file_transfer) {
191 myth_handle->file_transfer =
192 gmyth_file_transfer_new (backend_info);
194 /* Verifies if the file exists */
195 if (!gmyth_util_file_exists (backend_info,
196 gmyth_uri_get_path (gmyth_uri))) {
197 g_object_unref (backend_info);
201 /* sets the Playback monitor connection */
202 ret = gmyth_file_transfer_open (myth_handle->file_transfer,
203 gmyth_uri_get_path (gmyth_uri));
205 } /* if - LiveTV or not? */
208 g_debug ("MythTV FileTransfer open error.\n");
209 return GNOME_VFS_ERROR_NOT_OPEN;
212 myth_handle->configured = TRUE;
214 g_object_unref (backend_info);
216 if (gmyth_uri != NULL)
217 g_object_unref (gmyth_uri);
219 myth_handle->buffer =
220 g_byte_array_sized_new (MYTHTV_BUFFER_SIZE);
221 myth_handle->buffer_remain = 0;
223 g_return_val_if_fail (myth_handle->file_transfer != NULL,
224 GNOME_VFS_ERROR_NOT_OPEN);
226 if ( /*myth_handle->file_transfer->filesize <= 0 && */
227 myth_handle->is_livetv) {
228 myth_handle->content_size =
229 gmyth_recorder_get_file_position (myth_handle->livetv->recorder);
231 myth_handle->content_size =
232 myth_handle->file_transfer->filesize;
236 /* if - configured or not? */
237 *method_handle = (GnomeVFSMethodHandle *) myth_handle;
242 static GnomeVFSResult
243 do_read (GnomeVFSMethod * method,
244 GnomeVFSMethodHandle * method_handle,
246 GnomeVFSFileSize num_bytes,
247 GnomeVFSFileSize * bytes_read,
248 GnomeVFSContext * context)
250 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
251 GnomeVFSFileSize bytes_to_read = num_bytes;
253 if (!myth_handle->is_livetv
254 && (myth_handle->bytes_read >= myth_handle->content_size))
255 return GNOME_VFS_ERROR_EOF;
257 /* fixme: change this to min math function */
258 if ((myth_handle->content_size > 0)) {
259 if (!myth_handle->is_livetv &&
261 (myth_handle->content_size -
262 myth_handle->bytes_read))) {
264 myth_handle->content_size -
265 myth_handle->bytes_read;
269 /* Loop sending the Myth File Transfer request:
270 * Retry whilst authentication fails and we supply it. */
271 if ((myth_handle->buffer_remain =
272 myth_handle->buffer->len) < bytes_to_read) {
275 while (MYTHTV_BUFFER_SIZE != myth_handle->buffer_remain) {
276 /* resize buffer length request to no more than MYTHTV_MAX_REQUEST_SIZE */
277 if ((MYTHTV_BUFFER_SIZE - myth_handle->buffer_remain) <=
278 MYTHTV_MAX_REQUEST_SIZE)
279 buffer_size = MYTHTV_BUFFER_SIZE - myth_handle->buffer_remain;
281 buffer_size = MYTHTV_MAX_REQUEST_SIZE;
283 GByteArray *tmp_buffer = g_byte_array_new ();
285 g_debug ("Asking %d bytes (there is %d bytes in the buffer)\n",
286 buffer_size, myth_handle->buffer_remain);
288 gint len = gmyth_file_transfer_read (myth_handle->file_transfer,
292 if ( !myth_handle->is_livetv ) {
294 g_byte_array_free (tmp_buffer, TRUE);
295 g_debug ("Fail to read bytes");
296 return GNOME_VFS_ERROR_IO;
297 } else if ( len == 0 ) {
298 g_byte_array_free (tmp_buffer, TRUE);
299 g_warning ("End of file probably achieved");
300 return GNOME_VFS_ERROR_EOF;
304 myth_handle->buffer =
305 g_byte_array_append (myth_handle->buffer,
306 tmp_buffer->data, len);
308 myth_handle->buffer_remain += len;
310 if (tmp_buffer != NULL) {
311 g_byte_array_free (tmp_buffer, TRUE);
314 } /* while - iterates until fills the internal buffer */
318 /* if - got from the network, or not */
319 bytes_to_read = (bytes_to_read > myth_handle->buffer_remain) ?
320 myth_handle->buffer_remain : bytes_to_read;
321 /* gets the first buffer_size bytes from the byte array buffer variable */
323 g_memmove (buffer, myth_handle->buffer->data, bytes_to_read);
325 myth_handle->bytes_read += bytes_to_read;
326 myth_handle->buffer_remain -= bytes_to_read;
328 /* flushs the newly buffer got from byte array */
329 myth_handle->buffer =
330 g_byte_array_remove_range (myth_handle->buffer, 0,
333 ("Got from %llu bytes from internal buffer. (there are %d bytes in the buffer, from a total of %llu dispatched.)\n",
334 bytes_to_read, myth_handle->buffer_remain,
335 myth_handle->bytes_read);
337 *bytes_read = bytes_to_read;
342 static GnomeVFSResult
343 do_close (GnomeVFSMethod * method,
344 GnomeVFSMethodHandle * method_handle, GnomeVFSContext * context)
347 MythtvHandle *myth_handle = (MythtvHandle *) method_handle;
349 //if ( NULL == myth_handle || myth_handle->configured ) {
351 if (myth_handle->is_livetv && myth_handle->livetv != NULL) {
352 g_object_unref (myth_handle->livetv);
353 myth_handle->livetv = NULL;
356 if (myth_handle->file_transfer != NULL) {
357 g_object_unref (myth_handle->file_transfer);
358 myth_handle->file_transfer = NULL;
361 if (myth_handle->buffer) {
362 g_byte_array_free (myth_handle->buffer, TRUE);
363 myth_handle->buffer = NULL;
366 myth_handle->configured = FALSE;
368 g_free (myth_handle->channel_name);
370 g_free (myth_handle);
379 static GnomeVFSResult
380 do_get_file_info (GnomeVFSMethod * method,
382 GnomeVFSFileInfo * file_info,
383 GnomeVFSFileInfoOptions options,
384 GnomeVFSContext * context)
386 GMythFileTransfer *file_transfer = NULL;
387 GMythRecorder *recorder = NULL;
388 GMythTVChain *tvchain = NULL;
389 GMythBackendInfo *backend_info = NULL;
390 GMythURI *gmyth_uri = NULL;
391 GMythSocket *socket = NULL;
392 gboolean is_livetv = FALSE;
399 /* Creates and fills out the backend info structure */
400 tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
401 tmp_str2 = gnome_vfs_unescape_string (tmp_str1, "");
403 backend_info = gmyth_backend_info_new_with_uri (tmp_str2);
407 /* creates an instance of */
408 tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
409 tmp_str2 = gnome_vfs_unescape_string (tmp_str1, "");
411 gmyth_uri = gmyth_uri_new_with_value (tmp_str2);
415 is_livetv = gmyth_uri_is_livetv (gmyth_uri);
417 file_info->valid_fields = 0;
418 file_info->valid_fields = file_info->valid_fields
419 | GNOME_VFS_FILE_INFO_FIELDS_TYPE
420 | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
421 | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
422 file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
423 /* fixme: get from file extension? */
424 file_info->mime_type = g_strdup ("video/x-nuv");
425 file_info->permissions =
426 GNOME_VFS_PERM_USER_READ |
427 GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_GROUP_READ;
429 g_debug ("gnome_vfs_uri == %s | gmyth_uri == %s.\n",
430 gnome_vfs_uri_get_path (uri),
431 gmyth_uri_get_path (gmyth_uri));
433 /* Connect to the backend */
434 if (gmyth_uri != NULL && is_livetv == TRUE) {
436 /* start to get file info from LiveTV remote encoder */
437 socket = gmyth_socket_new ();
439 /* FIME: Implement this at gmyth_socket */
441 gmyth_socket_connect_to_backend (socket,
442 backend_info->hostname,
446 g_debug ("[%s] LiveTV can not connect to backend", __FUNCTION__);
451 if (gmyth_remote_util_get_free_recorder_count (socket) <= 0) {
452 g_debug ("No free remote encoder available.");
457 /* Gets the recorder num */
458 recorder = remote_request_next_free_recorder (socket, -1);
461 g_object_unref (socket);
463 if (recorder == NULL) {
464 g_debug ("[%s] None remote encoder available", __FUNCTION__);
469 /* Init remote encoder. Opens its control socket. */
470 res = gmyth_recorder_setup (recorder);
472 g_debug ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
477 /* Creates livetv chain handler */
478 tvchain = gmyth_tvchain_new ();
479 gmyth_tvchain_initialize (tvchain, backend_info);
481 if (tvchain == NULL || tvchain->tvchain_id == NULL) {
485 /* Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly) */
486 res = gmyth_recorder_spawntv (recorder, gmyth_tvchain_get_id(tvchain));
488 g_warning ("[%s] Fail while spawn tv\n",
497 GMythProgramInfo *prog_info =
498 gmyth_recorder_get_current_program_info (recorder);
500 if (prog_info != NULL) {
502 g_debug ("path = %s", prog_info->pathname->str);
506 (prog_info->pathname->str, "/"));
509 file_info->name = g_strdup ("LiveTV.nuv");
510 /* Size being overrided below ... */
511 //file_info->size = gmyth_recorder_get_file_position (recorder);
514 if (recorder != NULL)
515 g_object_unref (recorder);
517 if (prog_info != NULL)
518 g_object_unref (prog_info);
521 g_object_unref (tvchain);
523 //file_info->size = (GnomeVFSFileSize) - 1;
527 /* start to get file info from remote file encoder */
528 file_transfer = gmyth_file_transfer_new (backend_info);
530 /* Verifies if the file exists */
531 if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) {
532 g_object_unref (backend_info);
533 return GNOME_VFS_ERROR_NOT_FOUND;
536 /* sets the Playback monitor connection */
537 ret = gmyth_file_transfer_open (file_transfer,
538 gmyth_uri_get_path (gmyth_uri));
540 file_info->name = g_strdup (gnome_vfs_uri_get_path (uri));
542 } /* if - LiveTV or not? */
545 g_debug ("MythTV FileTransfer open error\n");
546 return GNOME_VFS_ERROR_NOT_OPEN;
549 /* Just for recorded content */
550 if (ret == TRUE && file_transfer != NULL) {
552 gmyth_file_transfer_get_filesize (file_transfer);
554 file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE;
557 g_object_unref (file_transfer);
562 g_object_unref (backend_info);
565 return GNOME_VFS_ERROR_IO;
571 do_is_local (GnomeVFSMethod * method, const GnomeVFSURI * uri)
576 static GnomeVFSMethod method = {
577 sizeof (GnomeVFSMethod),
608 vfs_module_init (const char *method_name, const char *args)
614 vfs_module_shutdown (GnomeVFSMethod * method)