[svn r518] Newly added GMythFileLocal, to deal with local stream files.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/gmyth/src/gmyth_file_local.c Mon Apr 09 15:20:37 2007 +0100
1.3 @@ -0,0 +1,429 @@
1.4 +/**
1.5 + * GMyth Library
1.6 + *
1.7 + * @file_local gmyth/gmyth_file_local.c
1.8 + *
1.9 + * @brief <p> GMythFileLocal deals with the file_local streaming media remote/local
1.10 + * transfering to the MythTV frontend.
1.11 + *
1.12 + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
1.13 + * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
1.14 + *
1.15 + *//*
1.16 + *
1.17 + * This program is free software; you can redistribute it and/or modify
1.18 + * it under the terms of the GNU Lesser General Public License as published by
1.19 + * the Free Software Foundation; either version 2 of the License, or
1.20 + * (at your option) any later version.
1.21 + *
1.22 + * This program is distributed in the hope that it will be useful,
1.23 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.24 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.25 + * GNU General Public License for more details.
1.26 + *
1.27 + * You should have received a copy of the GNU Lesser General Public License
1.28 + * along with this program; if not, write to the Free Software
1.29 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.30 + */
1.31 +
1.32 +#ifdef HAVE_CONFIG_H
1.33 +#include "config.h"
1.34 +#endif
1.35 +
1.36 +#include "gmyth_file_local.h"
1.37 +#include "gmyth_recorder.h"
1.38 +#include "gmyth_util.h"
1.39 +#include "gmyth_socket.h"
1.40 +#include "gmyth_stringlist.h"
1.41 +#include "gmyth_debug.h"
1.42 +#include "gmyth_uri.h"
1.43 +#include "gmyth_marshal.h"
1.44 +
1.45 +#include <unistd.h>
1.46 +#include <glib.h>
1.47 +
1.48 +#include <arpa/inet.h>
1.49 +#include <sys/types.h>
1.50 +#include <sys/socket.h>
1.51 +#include <netdb.h>
1.52 +#include <errno.h>
1.53 +#include <stdlib.h>
1.54 +#include <assert.h>
1.55 +
1.56 +#define GMYTH_FILE_LOCAL_GET_PRIVATE(obj) \
1.57 + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_FILE_LOCAL_TYPE, GMythFileLocalPrivate))
1.58 +
1.59 +struct _GMythFileLocalPrivate {
1.60 +
1.61 + gboolean disposed;
1.62 +
1.63 + GMutex *mutex;
1.64 +
1.65 + gint fd;
1.66 +
1.67 + GIOChannel *file_io;
1.68 +
1.69 +};
1.70 +
1.71 +static void gmyth_file_local_class_init (GMythFileLocalClass *klass);
1.72 +static void gmyth_file_local_init (GMythFileLocal *object);
1.73 +static void gmyth_file_local_dispose (GObject *object);
1.74 +static void gmyth_file_local_finalize (GObject *object);
1.75 +
1.76 +static gboolean _control_acquire_context( GMythFileTransfer *transfer, gboolean do_wait );
1.77 +
1.78 +static gboolean _control_release_context( GMythFileTransfer *transfer );
1.79 +
1.80 +G_DEFINE_TYPE(GMythFileLocal, gmyth_file_local, GMYTH_FILE_TYPE)
1.81 +
1.82 +static void
1.83 +gmyth_file_local_class_init (GMythFileLocalClass *klass)
1.84 +{
1.85 + GObjectClass *gobject_class;
1.86 + GMythFileLocalClass *gtransfer_class;
1.87 +
1.88 + gobject_class = (GObjectClass *) klass;
1.89 + gtransfer_class = (GMythFileLocalClass *) gobject_class;
1.90 +
1.91 + gobject_class->dispose = gmyth_file_local_dispose;
1.92 + gobject_class->finalize = gmyth_file_local_finalize;
1.93 +
1.94 + g_type_class_add_private (gobject_class, sizeof (GMythFileLocalPrivate));
1.95 +
1.96 +}
1.97 +
1.98 +static void
1.99 +gmyth_file_local_init (GMythFileLocal *file_local)
1.100 +{
1.101 + GMythFileLocalPrivate *priv;
1.102 + g_return_if_fail( file_local != NULL );
1.103 +
1.104 + priv = GMYTH_FILE_LOCAL_GET_PRIVATE(file_local);
1.105 +
1.106 + priv->mutex = g_mutex_new();
1.107 +}
1.108 +
1.109 +static void
1.110 +gmyth_file_local_dispose (GObject *object)
1.111 +{
1.112 + GMythFileLocalPrivate *priv;
1.113 + GMythFileLocal *file_local = GMYTH_FILE_LOCAL(object);
1.114 +
1.115 + g_return_if_fail( file_local != NULL );
1.116 +
1.117 + priv = GMYTH_FILE_LOCAL_GET_PRIVATE(file_local);
1.118 +
1.119 + if (priv->disposed) {
1.120 + /* If dispose did already run, return. */
1.121 + return;
1.122 + }
1.123 +
1.124 + /* Make sure dispose does not run twice. */
1.125 + priv->disposed = TRUE;
1.126 +
1.127 + if (priv->mutex != NULL ) {
1.128 + g_mutex_free (priv->mutex );
1.129 + priv->mutex = NULL;
1.130 + }
1.131 +
1.132 + if (priv->file_io != NULL ) {
1.133 + g_io_channel_unref (priv->file_io );
1.134 + priv->file_io = NULL;
1.135 + }
1.136 +
1.137 + G_OBJECT_CLASS (gmyth_file_local_parent_class)->dispose (object);
1.138 +}
1.139 +
1.140 +static void
1.141 +gmyth_file_local_finalize (GObject *object)
1.142 +{
1.143 + g_signal_handlers_destroy (object);
1.144 +
1.145 + G_OBJECT_CLASS (gmyth_file_local_parent_class)->finalize (object);
1.146 +}
1.147 +
1.148 +/**
1.149 + * Creates a new instance of GMythFileLocal.
1.150 + *
1.151 + * @param backend_info The BackendInfo instance, with all the MythTV network
1.152 + * configuration data.
1.153 + *
1.154 + * @return a new instance of the File Transfer.
1.155 + */
1.156 +GMythFileLocal*
1.157 +gmyth_file_local_new (GMythBackendInfo *backend_info)
1.158 +{
1.159 + GMythFileLocal *file_local = GMYTH_FILE_LOCAL (g_object_new (GMYTH_FILE_TYPE, backend_info, NULL));
1.160 +
1.161 + return file_local;
1.162 +}
1.163 +
1.164 +/**
1.165 + * Creates a new instance of GMythFileLocal.
1.166 + *
1.167 + * @param uri_str The URI poiting to the MythTV backend server.
1.168 + *
1.169 + * @return a new instance of the File Transfer.
1.170 + */
1.171 +GMythFileLocal*
1.172 +gmyth_file_local_new_with_uri (const gchar* uri_str)
1.173 +{
1.174 + GMythFileLocal *file_local = GMYTH_FILE_LOCAL (g_object_new (GMYTH_FILE_TYPE, uri_str, NULL));
1.175 +
1.176 + return file_local;
1.177 +}
1.178 +
1.179 +gchar*
1.180 +gmyth_file_local_get_file_name (GMythFileLocal *file_local)
1.181 +{
1.182 + return gmyth_file_get_filename( g_type_peek_parent( file_local ) );
1.183 +}
1.184 +
1.185 +/**
1.186 + * Open a File in order to get a local file.
1.187 + *
1.188 + * @param file_local The actual File Transfer instance.
1.189 + *
1.190 + * @return <code>true</code>, if the connection opening had been done successfully.
1.191 + */
1.192 +gboolean
1.193 +gmyth_file_local_open (GMythFileLocal *file_local)
1.194 +{
1.195 + gboolean ret = TRUE;
1.196 + GMythFileLocalPrivate *priv;
1.197 + gchar *file_name_uri = NULL;
1.198 +
1.199 + g_return_val_if_fail (file_local != NULL, FALSE);
1.200 +
1.201 + priv = GMYTH_FILE_LOCAL_GET_PRIVATE (file_local);
1.202 + file_name_uri = gmyth_file_local_get_file_name(file_local);
1.203 +
1.204 + if ( file_name_uri != NULL )
1.205 + {
1.206 + GMythURI *uri = gmyth_uri_new_with_value(file_name_uri);
1.207 + gmyth_debug( "GMythURI path segment = %s", gmyth_uri_get_path(uri) );
1.208 + priv->file_io = g_io_channel_new_file( g_strdup( gmyth_uri_get_path(uri) ), "r+", NULL );
1.209 + g_object_unref( uri );
1.210 + g_free( file_name_uri );
1.211 + }
1.212 +
1.213 + if ( priv->file_io < 0 )
1.214 + ret = FALSE;
1.215 +
1.216 + return ret;
1.217 +}
1.218 +
1.219 +/**
1.220 + * Closes a remote File Transfer connection.
1.221 + *
1.222 + * @param file_local The actual File Transfer instance.
1.223 + */
1.224 +void
1.225 +gmyth_file_local_close (GMythFileLocal *file_local )
1.226 +{
1.227 + GMythFileLocalPrivate *priv;
1.228 +
1.229 + g_return_if_fail (file_local != NULL);
1.230 +
1.231 +}
1.232 +
1.233 +/**
1.234 + * Acquire access to a local file read/write pointer.
1.235 + *
1.236 + * @param transfer The actual File Local instance.
1.237 + * @param do_wait Waits or not on a GCond, when trying to read from the remote socket.
1.238 + *
1.239 + * @return <code>true</code>, if the acquire had been got.
1.240 + */
1.241 +static gboolean
1.242 +_control_acquire_context( GMythFileLocal *file_local, gboolean do_wait )
1.243 +{
1.244 + gboolean ret = TRUE;
1.245 + GMythFileLocalPrivate *priv;
1.246 +
1.247 + g_return_val_if_fail (file_local != NULL, FALSE);
1.248 + priv = GMYTH_FILE_LOCAL_GET_PRIVATE (transfer);
1.249 +
1.250 + g_mutex_lock (priv->mutex);
1.251 + return ret;
1.252 +}
1.253 +
1.254 +/**
1.255 + * Release access to a local file read/write pointer.
1.256 + *
1.257 + * @param transfer The actual File Transfer instance.
1.258 + *
1.259 + * @return <code>true</code>, if the local file read/write permissions had been releaseds.
1.260 + */
1.261 +static gboolean
1.262 +_control_release_context( GMythFileLocal *file_local )
1.263 +{
1.264 + gboolean ret = TRUE;
1.265 + GMythFileLocalPrivate *priv;
1.266 +
1.267 + g_return_val_if_fail (file_local != NULL, FALSE);
1.268 + priv = GMYTH_FILE_LOCAL_GET_PRIVATE (file_local);
1.269 +
1.270 + g_mutex_unlock (priv->mutex );
1.271 +
1.272 + return ret;
1.273 +}
1.274 +
1.275 +/**
1.276 + * Reads a block from a remote file.
1.277 + *
1.278 + * @param transfer The actual File Transfer instance.
1.279 + * @param data A GByteArray instance, where all the binary data representing
1.280 + * the remote file will be stored.
1.281 + * @param size The block size, in bytes, to be requested from a remote file.
1.282 + * @param read_unlimited Tells the backend to read indefinitely (LiveTV), or only
1.283 + * gets the actual size
1.284 + *
1.285 + * @return The actual block size (in bytes) returned by REQUEST_BLOCK message,
1.286 + * or the error code.
1.287 + */
1.288 +GMythFileReadResult
1.289 +gmyth_file_local_read(GMythFileLocal *file_local, GByteArray *data, gint size, gboolean read_unlimited)
1.290 +{
1.291 + gsize bytes_read = 0;
1.292 + gint64 total_read = 0;
1.293 + GMythFileReadResult retval = GMYTH_FILE_READ_OK;
1.294 + GMythFileLocalPrivate *priv;
1.295 +
1.296 + GError *error = NULL;
1.297 +
1.298 + GIOCondition io_cond;
1.299 + GIOStatus io_status = G_IO_STATUS_NORMAL;
1.300 +
1.301 + gboolean ret = TRUE;
1.302 +
1.303 + g_return_val_if_fail (file_local != NULL, FALSE);
1.304 + g_return_val_if_fail (data != NULL, GMYTH_FILE_READ_ERROR);
1.305 +
1.306 + priv = GMYTH_FILE_LOCAL_GET_PRIVATE (file_local);
1.307 +
1.308 + io_status = g_io_channel_set_encoding( priv->file_io, NULL, &error );
1.309 + if ( io_status == G_IO_STATUS_NORMAL )
1.310 + gmyth_debug ( "Setting encoding to binary file data stream.\n" );
1.311 +
1.312 + io_cond = g_io_channel_get_buffer_condition( priv->file_io );
1.313 +
1.314 + _control_acquire_context (file_local, TRUE );
1.315 +
1.316 + if (size > 0) {
1.317 + gchar *data_buffer = g_new0 (gchar, size);
1.318 + io_status = g_io_channel_read_chars (priv->file_io,
1.319 + data_buffer,
1.320 + (gsize) size,
1.321 + &bytes_read,
1.322 + &error);
1.323 +
1.324 + if (io_status != G_IO_STATUS_NORMAL) {
1.325 + gmyth_debug ("Error on io_channel");
1.326 + g_free (data_buffer);
1.327 + retval = GMYTH_FILE_READ_ERROR;
1.328 + goto error;
1.329 + }
1.330 +
1.331 + /* append new data to the increasing byte array */
1.332 + data = g_byte_array_append (data, (const guint8*)data_buffer, bytes_read);
1.333 + total_read += bytes_read;
1.334 +
1.335 + if (!read_unlimited && ( gmyth_file_local_get_file_size(file_local) > 0) &&
1.336 + (gmyth_file_local_get_offset(file_local) == gmyth_file_local_get_file_size(file_local))) {
1.337 + retval = GMYTH_FILE_TRANSFER_READ_EOF;
1.338 + goto error;
1.339 + }
1.340 +
1.341 + g_free (data_buffer);
1.342 + } else {
1.343 + retval = GMYTH_FILE_TRANSFER_READ_ERROR;
1.344 + }
1.345 +
1.346 +error:
1.347 + _control_release_context (file_local);
1.348 +
1.349 + if ( error != NULL ) {
1.350 + gmyth_debug ("Cleaning-up ERROR: [msg = %s, code = %d]\n", error->message,
1.351 + error->code);
1.352 + g_error_free (error);
1.353 + }
1.354 +
1.355 + if ( total_read > 0 )
1.356 + gmyth_file_local_set_offset(file_local, ( gmyth_file_local_get_offset(file_local) + total_read ) );
1.357 +
1.358 + return retval;
1.359 +}
1.360 +
1.361 +/**
1.362 + * Gets the actual file_local size of the binary content.
1.363 + *
1.364 + * @param file_local The actual File Transfer instance.
1.365 + *
1.366 + * @return The actual file_local size in bytes.
1.367 + */
1.368 +guint64
1.369 +gmyth_file_local_get_filesize (GMythFileLocal *file_local)
1.370 +{
1.371 + GMythFilePrivate *priv;
1.372 +
1.373 + g_return_val_if_fail (file_local != NULL, 0);
1.374 +
1.375 + priv = GMYTH_FILE_GET_PRIVATE ( GMYTH_FILE(g_object_peek_parent(file_local)));
1.376 + return priv->filesize;
1.377 +}
1.378 +
1.379 +/**
1.380 + * Sets the actual file_local size.
1.381 + *
1.382 + * @param file_local The actual File Transfer instance.
1.383 + * @param filesize The actual File Transfer size, in bytes.
1.384 + */
1.385 +void
1.386 +gmyth_file_local_set_filesize (GMythFileLocal *file_local, guint64 filesize)
1.387 +{
1.388 + GMythFilePrivate *priv;
1.389 +
1.390 + g_return_val_if_fail (file_local != NULL, 0);
1.391 +
1.392 + priv = GMYTH_FILE_GET_PRIVATE (GMYTH_FILE(g_object_peek_parent(file_local)));
1.393 +
1.394 + priv->filesize = filesize;
1.395 +}
1.396 +
1.397 +/**
1.398 + * Gets the actual file offset of the binary content.
1.399 + *
1.400 + * @param file_local The actual File Transfer instance.
1.401 + *
1.402 + * @return The actual file offset in bytes.
1.403 + */
1.404 +gint64
1.405 +gmyth_file_local_get_offset (GMythFileLocal *file_local)
1.406 +{
1.407 + GMythFilePrivate *priv;
1.408 +
1.409 + g_return_val_if_fail (file_local != NULL, 0);
1.410 +
1.411 + priv = GMYTH_FILE_GET_PRIVATE ( GMYTH_FILE(g_object_peek_parent(file_local)));
1.412 + return priv->offset;
1.413 +}
1.414 +
1.415 +/**
1.416 + * Sets the actual file offset.
1.417 + *
1.418 + * @param file_local The actual File Local instance.
1.419 + * @param offset The actual File Local offset, in bytes.
1.420 + */
1.421 +void
1.422 +gmyth_file_local_set_offset (GMythFileLocal *file_local, gint64 offset)
1.423 +{
1.424 + GMythFilePrivate *priv;
1.425 +
1.426 + g_return_val_if_fail (file_local != NULL, 0);
1.427 +
1.428 + priv = GMYTH_FILE_GET_PRIVATE (GMYTH_FILE(g_object_peek_parent(file_local)));
1.429 +
1.430 + priv->offset = offset;
1.431 +}
1.432 +
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/gmyth/src/gmyth_file_local.h Mon Apr 09 15:20:37 2007 +0100
2.3 @@ -0,0 +1,90 @@
2.4 +/**
2.5 + * GMyth Library
2.6 + *
2.7 + * @file gmyth/gmyth_file_local_local.h
2.8 + *
2.9 + * @brief <p> GMythFileLocal is the parent GMythFile that deals with the file streaming
2.10 + * media local transfering from the MythTV backend.
2.11 + *
2.12 + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
2.13 + * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
2.14 + *
2.15 + *//*
2.16 + *
2.17 + * This program is free software; you can redistribute it and/or modify
2.18 + * it under the terms of the GNU Lesser General Public License as published by
2.19 + * the Free Software Foundation; either version 2 of the License, or
2.20 + * (at your option) any later version.
2.21 + *
2.22 + * This program is distributed in the hope that it will be useful,
2.23 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.24 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.25 + * GNU General Public License for more details.
2.26 + *
2.27 + * You should have received a copy of the GNU Lesser General Public License
2.28 + * along with this program; if not, write to the Free Software
2.29 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2.30 + */
2.31 +
2.32 +#ifndef __GMYTH_FILE_LOCAL_H__
2.33 +#define __GMYTH_FILE_LOCAL_H__
2.34 +
2.35 +#include <glib-object.h>
2.36 +#include <glib.h>
2.37 +
2.38 +#include "gmyth_file.h"
2.39 +#include "gmyth_uri.h"
2.40 +#include "gmyth_backendinfo.h"
2.41 +
2.42 +#include <stdio.h>
2.43 +#include <stdlib.h>
2.44 +#include <string.h>
2.45 +#include <netdb.h>
2.46 +#include <sys/socket.h>
2.47 +#include <unistd.h>
2.48 +
2.49 +G_BEGIN_DECLS
2.50 +
2.51 +#define GMYTH_FILE_LOCAL_TYPE (gmyth_file_local_get_type ())
2.52 +#define GMYTH_FILE_LOCAL_(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_FILE_LOCAL_TYPE, GMythFileLocal))
2.53 +#define GMYTH_FILE_LOCAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_FILE_LOCAL_TYPE, GMythFileLocalClass))
2.54 +#define IS_GMYTH_FILE_LOCAL_(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_FILE_LOCAL_TYPE))
2.55 +#define IS_GMYTH_FILE_LOCAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_FILE_LOCAL_TYPE))
2.56 +#define GMYTH_FILE_LOCAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_FILE_LOCAL_TYPE, GMythFileLocalClass))
2.57 +
2.58 +typedef struct _GMythFileLocal GMythFileLocal;
2.59 +typedef struct _GMythFileLocalClass GMythFileLocalClass;
2.60 +typedef struct _GMythFileLocalPrivate GMythFileLocalPrivate;
2.61 +
2.62 +struct _GMythFileLocal
2.63 +{
2.64 + GMythFile parent;
2.65 +};
2.66 +
2.67 +struct _GMythFileLocalClass
2.68 +{
2.69 + GMythFileClass parent_class;
2.70 +};
2.71 +
2.72 +
2.73 +GType gmyth_file_local_get_type (void);
2.74 +GMythFileLocal* gmyth_file_local_new (GMythBackendInfo *backend_info);
2.75 +gchar* gmyth_file_local_get_file_name (GMythFileLocal *file_local);
2.76 +gboolean gmyth_file_local_open (GMythFileLocal *file_local,
2.77 + const gchar* filename);
2.78 +void gmyth_file_local_close (GMythFileLocal *file_local);
2.79 +gboolean gmyth_file_local_is_open (GMythFileLocal *file_local);
2.80 +GMythFileLocalReadResult
2.81 + gmyth_file_local_read (GMythFileLocal *file_local,
2.82 + GByteArray *data,
2.83 + gint size,
2.84 + gboolean read_unlimited);
2.85 +guint64 gmyth_file_local_get_filesize (GMythFileLocal *file_local);
2.86 +void gmyth_file_local_set_filesize (GMythFileLocal *file, guint64 filesize);
2.87 +
2.88 +gint64 gmyth_file_local_get_offset (GMythFileLocal *file_local);
2.89 +void gmyth_file_local_set_offset (GMythFileLocal *file_local, gint64 offset);
2.90 +
2.91 +G_END_DECLS
2.92 +
2.93 +#endif /* __GMYTH_FILE_LOCAL_H__ */