diff options
author | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2003-05-15 20:23:16 +0000 |
---|---|---|
committer | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2003-05-15 20:23:16 +0000 |
commit | 02af7a2a50311dcef6173a97157c35e98969d80c (patch) | |
tree | 7a272fad321a442fc4de8f90f6cf0a7e057af1ae /src/xine-engine | |
parent | cdb980086e034eccb6abe4fb79121c7e368dd87f (diff) | |
download | xine-lib-02af7a2a50311dcef6173a97157c35e98969d80c.tar.gz xine-lib-02af7a2a50311dcef6173a97157c35e98969d80c.tar.bz2 |
add broadcaster
CVS patchset: 4857
CVS date: 2003/05/15 20:23:16
Diffstat (limited to 'src/xine-engine')
-rw-r--r-- | src/xine-engine/Makefile.am | 4 | ||||
-rw-r--r-- | src/xine-engine/broadcaster.c | 375 | ||||
-rw-r--r-- | src/xine-engine/broadcaster.h | 49 | ||||
-rw-r--r-- | src/xine-engine/buffer.c | 8 | ||||
-rw-r--r-- | src/xine-engine/buffer.h | 10 | ||||
-rw-r--r-- | src/xine-engine/metronom.c | 4 | ||||
-rw-r--r-- | src/xine-engine/metronom.h | 3 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 8 | ||||
-rw-r--r-- | src/xine-engine/xine_interface.c | 18 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 4 |
10 files changed, 470 insertions, 13 deletions
diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am index d28686976..e1b8ecd68 100644 --- a/src/xine-engine/Makefile.am +++ b/src/xine-engine/Makefile.am @@ -13,7 +13,7 @@ libxine_la_SOURCES = xine.c metronom.c configfile.c buffer.c \ load_plugins.c video_decoder.c buffer_types.c \ audio_decoder.c video_out.c audio_out.c resample.c events.c lrb.c \ video_overlay.c osd.c scratch.c locale.c demux.c vo_scale.c \ - xine_interface.c post.c tvmode.c + xine_interface.c post.c tvmode.c broadcaster.c if HAVE_NVTV libxine_la_DEPENDENCIES = @INTLLIBS@ $(XINEUTILS_LIB) $(NVTVCLIENT_LIB) @@ -32,7 +32,7 @@ libxine_la_LDFLAGS = \ include_HEADERS = buffer.h metronom.h configfile.h vo_scale.h \ audio_out.h resample.h video_out.h xine_internal.h spu_decoder.h \ lrb.h video_overlay.h osd.h scratch.h xine_plugin.h xineintl.h \ - plugin_catalog.h audio_decoder.h video_decoder.h post.h + plugin_catalog.h audio_decoder.h video_decoder.h post.h broadcaster.h noinst_HEADERS = bswap.h diff --git a/src/xine-engine/broadcaster.c b/src/xine-engine/broadcaster.c new file mode 100644 index 000000000..271149539 --- /dev/null +++ b/src/xine-engine/broadcaster.c @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2000-2003 the xine project + * May 2003 - Miguel Freitas + * This feature was sponsored by 1Control + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: broadcaster.c,v 1.1 2003/05/15 20:23:18 miguelfreitas Exp $ + * + * broadcaster.c - xine network broadcaster + * + * how it works: + * - one xine instance must be set as master by using XINE_PARAM_BROADCASTER_PORT. + * 'xine --broadcast-port <port_number>' + * - master will wait for connections on specified port, accepting new clients. + * - several xine clients may connect to the server as "slaves", using mrl: + * slave://master_address:port + * - streams played on master will appear on every slave. + * if master is not meant to use video/audio devices it may be started with + * 'xine -V none -A none' + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <dlfcn.h> +#include <pthread.h> + +#include "xine_internal.h" +#include "buffer.h" +#include "xineutils.h" + +#define QLEN 5 /* maximum connection queue length */ +#define _BUFSIZ 512 + +struct broadcaster_s { + xine_stream_t *stream; /* stream to broadcast */ + int port; /* server port */ + int msock; /* master network socket */ + xine_list_t *connections; /* active connections */ + + int running; + pthread_t manager_thread; + pthread_mutex_t lock; +}; + + +/* network functions */ + +static int sock_check_opened(int socket) { + fd_set readfds, writefds, exceptfds; + int retval; + struct timeval timeout; + + for(;;) { + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(socket, &exceptfds); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + retval = select(socket + 1, &readfds, &writefds, &exceptfds, &timeout); + + if(retval == -1 && (errno != EAGAIN && errno != EINTR)) + return 0; + + if (retval != -1) + return 1; + } + + return 0; +} + +/* + * Write to socket. + */ +static int sock_data_write(int socket, char *buf, int len) { + ssize_t size; + int wlen = 0; + + if((socket < 0) || (buf == NULL)) + return -1; + + if(!sock_check_opened(socket)) + return -1; + + while(len) { + size = write(socket, buf, len); + + if(size <= 0) { + printf("broadcaster: error writing to socket %d\n",socket); + return -1; + } + + len -= size; + wlen += size; + buf += size; + } + + return wlen; +} + +static int sock_string_write(int socket, char *msg, ...) { + char buf[_BUFSIZ]; + va_list args; + + va_start(args, msg); + vsnprintf(buf, _BUFSIZ, msg, args); + va_end(args); + + /* Each line sent is '\n' terminated */ + if((buf[strlen(buf)] == '\0') && (buf[strlen(buf) - 1] != '\n')) + sprintf(buf, "%s%c", buf, '\n'); + + return sock_data_write(socket, buf, strlen(buf)); +} + +/* + * this is the most important broadcaster function. + * it sends data to every connected client (slaves). + */ +static void broadcaster_data_write(broadcaster_t *this, char *buf, int len) { + int *psock; + + psock = xine_list_first_content (this->connections); + while (psock) { + + /* in case of failure remove from list */ + if( sock_data_write(*psock, buf, len) < 0 ) { + + if (this->stream->xine->verbosity >= XINE_VERBOSITY_LOG) + printf("broadcaster: closing socket %d\n", *psock); + close(*psock); + free(psock); + if( this->connections->cur->next ) + psock = this->connections->cur->next->content; + else + psock = NULL; + xine_list_delete_current (this->connections); + } else + psock = xine_list_next_content (this->connections); + } +} + +static void broadcaster_string_write(broadcaster_t *this, char *msg, ...) { + char buf[_BUFSIZ]; + va_list args; + + va_start(args, msg); + vsnprintf(buf, _BUFSIZ, msg, args); + va_end(args); + + /* Each line sent is '\n' terminated */ + if((buf[strlen(buf)] == '\0') && (buf[strlen(buf) - 1] != '\n')) + sprintf(buf, "%s%c", buf, '\n'); + + broadcaster_data_write(this, buf, strlen(buf)); +} + + +/* + * this thread takes care of accepting new connections. + */ +static void *manager_loop (void *this_gen) { + broadcaster_t *this = (broadcaster_t *) this_gen; + struct sockaddr_in fsin; /* the from address of a client */ + int alen; /* from-address length */ + fd_set rfds; /* read file descriptor set */ + fd_set efds; /* exception descriptor set */ + + while( this->running ) { + FD_ZERO(&rfds); + FD_SET(this->msock, &rfds); + FD_ZERO(&efds); + FD_SET(this->msock, &efds); + + if (select(this->msock+1, &rfds, (fd_set *)0, &efds, (struct timeval *)0) > 0) { + + pthread_mutex_lock( &this->lock ); + + if (FD_ISSET(this->msock, &rfds)) + { + int ssock; + alen = sizeof(fsin); + + ssock = accept(this->msock, (struct sockaddr *)&fsin, &alen); + if (ssock >= 0) { + /* identification string, helps demuxer probing */ + if( sock_string_write(ssock,"master xine v1") > 0 ) { + int *psock = malloc(sizeof(int)); + *psock = ssock; + + if (this->stream->xine->verbosity >= XINE_VERBOSITY_LOG) + printf("broadcaster: new connection socket %d\n", *psock); + xine_list_append_content(this->connections, psock); + } + } + } + + pthread_mutex_unlock( &this->lock ); + } + } + + return NULL; +} + + + +/* + * receive xine buffers and send them through the broadcaster + */ +static void send_buf (broadcaster_t *this, char *from, buf_element_t *buf) { + int i; + + /* ignore END buffers since they would stop the slavery */ + if( buf->type == BUF_CONTROL_END ) + return; + + /* assume RESET_DECODER is result of a xine_flush_engine */ + if( buf->type == BUF_CONTROL_RESET_DECODER && !strcmp(from,"video") ) { + broadcaster_string_write(this, "flush_engine"); + } + + /* send decoder information if any */ + for( i = 0; i < BUF_NUM_DEC_INFO; i++ ) { + if( buf->decoder_info[i] ) { + broadcaster_string_write(this, "decoder_info index=%d decoder_info=%u has_data=%d", + i, buf->decoder_info[i], (buf->decoder_info_ptr[i]) ? 1 : 0); + if( buf->decoder_info_ptr[i] ) + broadcaster_data_write(this, buf->decoder_info_ptr[i], buf->decoder_info[i]); + } + } + + broadcaster_string_write(this, "buffer fifo=%s size=%ld type=%lu pts=%lld disc=%lld flags=%lu", + from, buf->size, buf->type, buf->pts, buf->disc_off, buf->decoder_flags ); + + if( buf->size ) + broadcaster_data_write(this, buf->content, buf->size); +} + + +/* buffer callbacks */ +static void video_put_cb (fifo_buffer_t *fifo, buf_element_t *buf, void *this_gen) { + broadcaster_t *this = (broadcaster_t *) this_gen; + + pthread_mutex_lock( &this->lock ); + send_buf(this, "video", buf); + pthread_mutex_unlock( &this->lock ); +} + +static void audio_put_cb (fifo_buffer_t *fifo, buf_element_t *buf, void *this_gen) { + broadcaster_t *this = (broadcaster_t *) this_gen; + + pthread_mutex_lock( &this->lock ); + send_buf(this, "audio", buf); + pthread_mutex_unlock( &this->lock ); +} + +broadcaster_t *init_broadcaster(xine_stream_t *stream, int port) +{ + broadcaster_t *this; + struct sockaddr_in servAddr; + int msock, err; + + msock = socket(PF_INET, SOCK_STREAM, 0); + if( msock < 0 ) + { + printf("broadcaster: error opening master socket.\n"); + return NULL; + } + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(port); + + if(bind(msock, (struct sockaddr *) &servAddr, sizeof(servAddr))<0) + { + printf("broadcaster: error binding to port %d\n", port); + return NULL; + } + + listen(msock,QLEN); + + signal( SIGPIPE, SIG_IGN ); + + this = xine_xmalloc(sizeof(broadcaster_t)); + this->port = port; + this->stream = stream; + this->msock = msock; + this->connections = xine_list_new(); + + pthread_mutex_init (&this->lock, NULL); + + stream->video_fifo->register_put_cb(stream->video_fifo, video_put_cb, this); + + if(stream->audio_fifo) + stream->audio_fifo->register_put_cb(stream->audio_fifo, audio_put_cb, this); + + this->running = 1; + if ((err = pthread_create (&this->manager_thread, + NULL, manager_loop, (void *)this)) != 0) { + printf ("broadcaster: can't create new thread (%s)\n", + strerror(err)); + abort(); + } + + return this; +} + +void close_broadcaster(broadcaster_t *this) +{ + int *psock; + + psock = xine_list_first_content (this->connections); + while (psock) { + if (this->stream->xine->verbosity >= XINE_VERBOSITY_LOG) + printf("broadcaster: closing socket %d\n", *psock); + close(*psock); + free(psock); + xine_list_delete_current (this->connections); + if( this->connections->cur ) + psock = this->connections->cur->content; + else + psock = NULL; + } + xine_list_free(this->connections); + + this->running = 0; + close(this->msock); + pthread_mutex_lock( &this->lock ); + pthread_cancel(this->manager_thread); + pthread_join(this->manager_thread,NULL); + + this->stream->video_fifo->unregister_put_cb(this->stream->video_fifo, video_put_cb); + + if(this->stream->audio_fifo) + this->stream->audio_fifo->unregister_put_cb(this->stream->audio_fifo, audio_put_cb); + + free(this); +} + +int get_broadcaster_port(broadcaster_t *this) +{ + return this->port; +} diff --git a/src/xine-engine/broadcaster.h b/src/xine-engine/broadcaster.h new file mode 100644 index 000000000..113f4ceb5 --- /dev/null +++ b/src/xine-engine/broadcaster.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000-2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: broadcaster.h,v 1.1 2003/05/15 20:23:18 miguelfreitas Exp $ + * + * broadcaster.h + * + */ + +#ifndef HAVE_BROADCASTER_H +#define HAVE_BROADCASTER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +typedef struct broadcaster_s broadcaster_t; + +broadcaster_t *init_broadcaster(xine_stream_t *stream, int port); +void close_broadcaster(broadcaster_t *this); +int get_broadcaster_port(broadcaster_t *this); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/xine-engine/buffer.c b/src/xine-engine/buffer.c index 0deca48b4..fb12fca94 100644 --- a/src/xine-engine/buffer.c +++ b/src/xine-engine/buffer.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: buffer.c,v 1.29 2003/05/13 16:38:05 miguelfreitas Exp $ + * $Id: buffer.c,v 1.30 2003/05/15 20:23:18 miguelfreitas Exp $ * * * contents: @@ -92,8 +92,10 @@ static buf_element_t *buffer_pool_alloc (fifo_buffer_t *this) { buf->pts = 0; buf->size = 0; buf->decoder_flags = 0; + memset(buf->decoder_info, 0, sizeof(buf->decoder_info)); + memset(buf->decoder_info_ptr, 0, sizeof(buf->decoder_info_ptr)); extra_info_reset( buf->extra_info ); - + return buf; } @@ -127,6 +129,8 @@ static buf_element_t *buffer_pool_try_alloc (fifo_buffer_t *this) { buf->pts = 0; buf->size = 0; buf->decoder_flags = 0; + memset(buf->decoder_info, 0, sizeof(buf->decoder_info)); + memset(buf->decoder_info_ptr, 0, sizeof(buf->decoder_info_ptr)); extra_info_reset( buf->extra_info ); } return buf; diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h index 91a930f06..e3339e753 100644 --- a/src/xine-engine/buffer.h +++ b/src/xine-engine/buffer.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: buffer.h,v 1.112 2003/05/13 16:38:06 miguelfreitas Exp $ + * $Id: buffer.h,v 1.113 2003/05/15 20:23:18 miguelfreitas Exp $ * * * contents: @@ -221,6 +221,8 @@ extern "C" { typedef struct extra_info_s extra_info_t; #endif +#define BUF_NUM_DEC_INFO 4 + typedef struct buf_element_s buf_element_t; struct buf_element_s { buf_element_t *next; @@ -238,8 +240,10 @@ struct buf_element_s { uint32_t decoder_flags; /* stuff like keyframe, is_header ... see below */ - uint32_t decoder_info[4]; /* additional decoder flags and other dec-spec. stuff */ - void *decoder_info_ptr[4]; /* pointers to dec-spec. stuff */ + /* additional decoder flags and other dec-spec. stuff */ + uint32_t decoder_info[BUF_NUM_DEC_INFO]; + /* pointers to dec-spec. stuff */ + void *decoder_info_ptr[BUF_NUM_DEC_INFO]; void (*free_buffer) (buf_element_t *buf); diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c index cd72cfcfd..24c6fb999 100644 --- a/src/xine-engine/metronom.c +++ b/src/xine-engine/metronom.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: metronom.c,v 1.117 2003/05/06 20:50:11 miguelfreitas Exp $ + * $Id: metronom.c,v 1.118 2003/05/15 20:23:18 miguelfreitas Exp $ */ #ifdef HAVE_CONFIG_H @@ -629,6 +629,8 @@ static int64_t metronom_get_option (metronom_t *this, int option) { return this->spu_offset; case METRONOM_FRAME_DURATION: return this->img_duration; + case METRONOM_VPTS_OFFSET: + return this->vpts_offset; } printf ("metronom: unknown option in get_option: %d\n", option); diff --git a/src/xine-engine/metronom.h b/src/xine-engine/metronom.h index 07b51b85f..2df24d87e 100644 --- a/src/xine-engine/metronom.h +++ b/src/xine-engine/metronom.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: metronom.h,v 1.48 2003/05/06 20:50:12 miguelfreitas Exp $ + * $Id: metronom.h,v 1.49 2003/05/15 20:23:18 miguelfreitas Exp $ * * metronom: general pts => virtual calculation/assoc * @@ -217,6 +217,7 @@ struct metronom_s { #define METRONOM_ADJ_VPTS_OFFSET 3 #define METRONOM_FRAME_DURATION 4 #define METRONOM_SPU_OFFSET 5 +#define METRONOM_VPTS_OFFSET 6 metronom_t *metronom_init (int have_audio, xine_stream_t *stream); diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index c4ec29622..eec327b37 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine.c,v 1.246 2003/04/25 22:27:35 f1rmb Exp $ + * $Id: xine.c,v 1.247 2003/05/15 20:23:18 miguelfreitas Exp $ * * top-level xine functions * @@ -398,7 +398,8 @@ xine_stream_t *xine_stream_new (xine_t *this, stream->next_audio_port = NULL; stream->next_video_port = NULL; stream->metronom_prebuffer = PREBUFFER_PTS_OFFSET; - + stream->broadcaster = NULL; + /* * initial master/slave */ @@ -1049,6 +1050,9 @@ void xine_dispose (xine_stream_t *stream) { stream->slave->master = NULL; } + if(stream->broadcaster) + close_broadcaster(stream->broadcaster); + if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) printf ("xine_exit: shutdown audio\n"); diff --git a/src/xine-engine/xine_interface.c b/src/xine-engine/xine_interface.c index bbcbfc214..6115b0c0e 100644 --- a/src/xine-engine/xine_interface.c +++ b/src/xine-engine/xine_interface.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_interface.c,v 1.53 2003/04/29 15:14:16 mroi Exp $ + * $Id: xine_interface.c,v 1.54 2003/05/15 20:23:18 miguelfreitas Exp $ * * convenience/abstraction layer, functions to implement * libxine's public interface @@ -422,6 +422,15 @@ void xine_set_param (xine_stream_t *stream, int param, int value) { stream->metronom_prebuffer = value; break; + case XINE_PARAM_BROADCASTER_PORT: + if( !stream->broadcaster && value ) { + stream->broadcaster = init_broadcaster(stream, value); + } else if ( stream->broadcaster && !value ) { + close_broadcaster(stream->broadcaster); + stream->broadcaster = NULL; + } + break; + default: printf ("xine_interface: unknown param %d\n", param); } @@ -511,6 +520,13 @@ int xine_get_param (xine_stream_t *stream, int param) { case XINE_PARAM_METRONOM_PREBUFFER: return stream->metronom_prebuffer; + + case XINE_PARAM_BROADCASTER_PORT: + if( stream->broadcaster ) + return get_broadcaster_port(stream->broadcaster); + else + return 0; + break; default: printf ("xine_interface: unknown param %d\n", param); diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index b2644368e..d8f234048 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_internal.h,v 1.136 2003/04/21 06:12:23 f1rmb Exp $ + * $Id: xine_internal.h,v 1.137 2003/05/15 20:23:18 miguelfreitas Exp $ * */ @@ -71,6 +71,7 @@ typedef struct extra_info_s extra_info_t; #include "plugin_catalog.h" #include "video_decoder.h" #include "audio_decoder.h" +#include "broadcaster.h" #define XINE_MAX_EVENT_LISTENERS 50 #define XINE_MAX_EVENT_TYPES 100 @@ -260,6 +261,7 @@ struct xine_stream_s { pthread_cond_t next_audio_port_wired; int64_t metronom_prebuffer; + broadcaster_t *broadcaster; }; |