diff --git a/darkice/branches/darkice-rtp/darkice.cfg b/darkice/branches/darkice-rtp/darkice.cfg index 0c7f935..ed57a9f 100644 --- a/darkice/branches/darkice-rtp/darkice.cfg +++ b/darkice/branches/darkice-rtp/darkice.cfg @@ -79,4 +79,14 @@ aim = aim here # AIM info related to the stream icq = I see you too # ICQ info related to the stream - +# this section describes a streaming udp to an specific IP +# there may be up to 8 of these sections, named [rtp-0] ... [rtp-7] +# these can be mixed with [icecast-x] and [shoutcast-x] sections +[rtp-0] +bitrateMode = cbr # average bit rate +format = aac # format of the stream: ogg vorbis +bitrate = 96 # bitrate of the stream sent to the server +dstip = 239.2.2.2 # destination address +port = 5004 # destination port, usually 5004 +isRaw = no # force raw UDP stream instead RTP? +localDumpFile = dump.aac # local dump file diff --git a/darkice/branches/darkice-rtp/src/DarkIce.cpp b/darkice/branches/darkice-rtp/src/DarkIce.cpp index 6ff4cfe..f786da1 100644 --- a/darkice/branches/darkice-rtp/src/DarkIce.cpp +++ b/darkice/branches/darkice-rtp/src/DarkIce.cpp @@ -190,6 +190,7 @@ DarkIce :: init ( const Config & config ) throw ( Exception ) configIceCast( config, bufferSecs); configIceCast2( config, bufferSecs); configShoutCast( config, bufferSecs); + configRtpCast( config, bufferSecs); configFileCast( config); } @@ -679,6 +680,268 @@ DarkIce :: configIceCast2 ( const Config & config, } +/*------------------------------------------------------------------------------ + * Look for the RtpCast stream outputs in the config file + *----------------------------------------------------------------------------*/ +void +DarkIce :: configRtpCast ( const Config & config, + unsigned int bufferSecs ) + throw ( Exception ) +{ + // look for RtpCast encoder output streams, + // sections [rtpcast-0], [rtpcast-1], ... + char stream[] = "rtp- "; + size_t streamLen = Util::strLen( stream); + unsigned int u; + + for ( u = noAudioOuts; u < maxOutput; ++u ) { + const ConfigSection * cs; + + // ugly hack to change the section name to "stream0", "stream1", etc. + stream[streamLen-1] = '0' + (u - noAudioOuts); + + if ( !(cs = config.get( stream)) ) { + break; + } + + const char * str; + + IceCast2::StreamFormat format; + unsigned int sampleRate = 0; + unsigned int channel = 0; + AudioEncoder::BitrateMode bitrateMode; + unsigned int bitrate = 0; + unsigned int maxBitrate = 0; + double quality = 0.0; + const char * dstip = 0; + unsigned int port = 0; + bool isRaw = false; + + int lowpass = 0; + int highpass = 0; + const char * localDumpName = 0; + FileSink * localDumpFile = 0; + bool fileAddDate = false; + const char * fileDateFormat = 0; + + str = cs->getForSure( "format", " missing in section ", stream); + if ( Util::strEq( str, "vorbis") ) { + format = IceCast2::oggVorbis; + } else if ( Util::strEq( str, "mp3") ) { + format = IceCast2::mp3; + } else if ( Util::strEq( str, "mp2") ) { + format = IceCast2::mp2; + } else if ( Util::strEq( str, "aac") ) { + format = IceCast2::aac; + } else if ( Util::strEq( str, "aacp") ) { + format = IceCast2::aacp; + } else { + throw Exception( __FILE__, __LINE__, + "unsupported stream format: ", str); + } + + + str = cs->get( "sampleRate"); + sampleRate = str ? Util::strToL( str) : dsp->getSampleRate(); + str = cs->get( "channel"); + channel = str ? Util::strToL( str) : dsp->getChannel(); + + // determine fixed bitrate or variable bitrate quality + str = cs->get( "bitrate"); + bitrate = str ? Util::strToL( str) : 0; + str = cs->get( "maxBitrate"); + maxBitrate = str ? Util::strToL( str) : 0; + str = cs->get( "quality"); + quality = str ? Util::strToD( str) : 0.0; + + str = cs->getForSure( "bitrateMode", + " not specified in section ", + stream); + if ( Util::strEq( str, "cbr") ) { + bitrateMode = AudioEncoder::cbr; + + if ( bitrate == 0 ) { + throw Exception( __FILE__, __LINE__, + "bitrate not specified for CBR encoding"); + } + } else if ( Util::strEq( str, "abr") ) { + bitrateMode = AudioEncoder::abr; + + if ( bitrate == 0 ) { + throw Exception( __FILE__, __LINE__, + "bitrate not specified for ABR encoding"); + } + } else if ( Util::strEq( str, "vbr") ) { + bitrateMode = AudioEncoder::vbr; + + if ( cs->get( "quality" ) == 0 ) { + throw Exception( __FILE__, __LINE__, + "quality not specified for VBR encoding"); + } + } else { + throw Exception( __FILE__, __LINE__, + "invalid bitrate mode: ", str); + } + + dstip = cs->getForSure( "dstip", " missing in section ", stream); + str = cs->getForSure( "port", " missing in section ", stream); + str = cs->get( "isRaw"); + isRaw = str ? (Util::strEq( str, "yes") ? true : false) : false; + str = cs->get( "lowpass"); + lowpass = str ? Util::strToL( str) : 0; + str = cs->get( "highpass"); + highpass = str ? Util::strToL( str) : 0; + str = cs->get( "fileAddDate"); + fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false; + fileDateFormat = cs->get( "fileDateFormat"); + + localDumpName = cs->get( "localDumpFile"); + + // go on and create the things + + // check for and create the local dump file if needed + if ( localDumpName != 0 ) { + if ( fileAddDate ) { + if (fileDateFormat == 0) { + localDumpName = Util::fileAddDate(localDumpName); + } + else { + localDumpName = Util::fileAddDate( localDumpName, + fileDateFormat ); + } + } + + localDumpFile = new FileSink( stream, localDumpName); + if ( !localDumpFile->exists() ) { + if ( !localDumpFile->create() ) { + reportEvent( 1, "can't create local dump file", + localDumpName); + localDumpFile = 0; + } + } + if ( fileAddDate ) { + delete[] localDumpName; + } + } + + // streaming related stuff + audioOuts[u].socket = new NetSocket( server, port); + audioOuts[u].server = new RtpCast( audioOuts[u].socket.get(), + format, + bitrate, + sampleRate, + channel, + isRaw, + localDumpFile, + bufferSecs ); + + switch ( format ) { + case IceCast2::mp3: +#ifndef HAVE_LAME_LIB + throw Exception( __FILE__, __LINE__, + "DarkIce not compiled with lame support, " + "thus can't create mp3 stream: ", + stream); +#else + audioOuts[u].encoder = new LameLibEncoder( + audioOuts[u].server.get(), + dsp.get(), + bitrateMode, + bitrate, + quality, + sampleRate, + channel, + lowpass, + highpass ); +#endif // HAVE_LAME_LIB + break; + + + case IceCast2::oggVorbis: +#ifndef HAVE_VORBIS_LIB + throw Exception( __FILE__, __LINE__, + "DarkIce not compiled with Ogg Vorbis support, " + "thus can't Ogg Vorbis stream: ", + stream); +#else + audioOuts[u].encoder = new VorbisLibEncoder( + audioOuts[u].server.get(), + dsp.get(), + bitrateMode, + bitrate, + quality, + sampleRate, + dsp->getChannel(), + maxBitrate); +#endif // HAVE_VORBIS_LIB + break; + + case IceCast2::mp2: +#ifndef HAVE_TWOLAME_LIB + throw Exception( __FILE__, __LINE__, + "DarkIce not compiled with TwoLame support, " + "thus can't create mp2 stream: ", + stream); +#else + audioOuts[u].encoder = new TwoLameLibEncoder( + audioOuts[u].server.get(), + dsp.get(), + bitrateMode, + bitrate, + sampleRate, + channel ); +#endif // HAVE_TWOLAME_LIB + break; + + + case IceCast2::aac: +#ifndef HAVE_FAAC_LIB + throw Exception( __FILE__, __LINE__, + "DarkIce not compiled with AAC support, " + "thus can't aac stream: ", + stream); +#else + audioOuts[u].encoder = new FaacEncoder( + audioOuts[u].server.get(), + dsp.get(), + bitrateMode, + bitrate, + quality, + sampleRate, + dsp->getChannel()); +#endif // HAVE_FAAC_LIB + break; + + case IceCast2::aacp: +#ifndef HAVE_AACPLUS_LIB + throw Exception( __FILE__, __LINE__, + "DarkIce not compiled with AAC+ support, " + "thus can't aacp stream: ", + stream); +#else + audioOuts[u].encoder = new aacPlusEncoder( + audioOuts[u].server.get(), + dsp.get(), + bitrateMode, + bitrate, + quality, + sampleRate, + channel ); +#endif // HAVE_AACPLUS_LIB + break; + + default: + throw Exception( __FILE__, __LINE__, + "Illegal stream format: ", format); + } + + encConnector->attach( audioOuts[u].encoder.get()); + } + + noAudioOuts += u; +} + + /*------------------------------------------------------------------------------ * Look for the ShoutCast stream outputs in the config file *----------------------------------------------------------------------------*/ diff --git a/darkice/branches/darkice-rtp/src/Makefile.am b/darkice/branches/darkice-rtp/src/Makefile.am index d82cc1c..686251f 100644 --- a/darkice/branches/darkice-rtp/src/Makefile.am +++ b/darkice/branches/darkice-rtp/src/Makefile.am @@ -42,6 +42,8 @@ darkice_SOURCES = AudioEncoder.h\ ShoutCast.h\ FileCast.h\ FileCast.cpp\ + RtpCast.cpp\ + RtpCast.h\ LameLibEncoder.cpp\ LameLibEncoder.h\ TwoLameLibEncoder.cpp\ diff --git a/darkice/branches/darkice-rtp/src/NetSocket.cpp b/darkice/branches/darkice-rtp/src/NetSocket.cpp index ced259b..49eb9c0 100644 --- a/darkice/branches/darkice-rtp/src/NetSocket.cpp +++ b/darkice/branches/darkice-rtp/src/NetSocket.cpp @@ -114,10 +114,12 @@ static const char fileid[] = "$Id$"; *----------------------------------------------------------------------------*/ void NetSocket :: init ( const char * host, - unsigned short port ) throw ( Exception ) + unsigned short port, + bool isUdp ) throw ( Exception ) { this->host = Util::strDup( host); this->port = port; + this->isUdp = isUdp; this->sockfd = 0; } @@ -144,7 +146,7 @@ NetSocket :: NetSocket ( const NetSocket & ss ) throw ( Exception ) { int fd; - init( ss.host, ss.port); + init( ss.host, ss.port, ss.isUdp ); if ( (fd = ss.sockfd ? dup( ss.sockfd) : 0) == -1 ) { strip(); @@ -172,7 +174,7 @@ NetSocket :: operator= ( const NetSocket & ss ) throw ( Exception ) Sink::operator=( ss ); Source::operator=( ss ); - init( ss.host, ss.port); + init( ss.host, ss.port, ss.isUdp ); if ( (fd = ss.sockfd ? dup( ss.sockfd) : 0) == -1 ) { strip(); @@ -197,11 +199,12 @@ NetSocket :: open ( void ) throw ( Exception ) #ifdef HAVE_ADDRINFO struct addrinfo hints struct addrinfo * ptr; - struct sockaddr_storage addr; + struct sockaddr_storage addr, laddr; char portstr[6]; #else - struct sockaddr_in addr; + struct sockaddr_in addr, laddr; struct hostent * pHostEntry; + struct ip_mreq mreq; #endif if ( isOpen() ) { @@ -210,11 +213,11 @@ NetSocket :: open ( void ) throw ( Exception ) #ifdef HAVE_ADDRINFO memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; + hints.ai_socktype = isUdp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_family = AF_ANY; snprintf(portstr, sizeof(portstr), "%d", port); - if (getaddrinfo(host , portstr, &hints, &ptr)) { + if (getaddrinfo(isUdp ? "0.0.0.0" : host , portstr, &hints, &ptr)) { sockfd = 0; throw Exception( __FILE__, __LINE__, "getaddrinfo error", errno); } @@ -229,19 +232,63 @@ NetSocket :: open ( void ) throw ( Exception ) memset( &addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); - addr.sin_addr.s_addr = *((long*) pHostEntry->h_addr_list[0]); + addr.sin_addr.s_addr = isUdp ? INADDR_ANY : *((long*) pHostEntry->h_addr_list[0]); #endif - if ( (sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) { + if ( (sockfd = socket( AF_INET, isUdp ? SOCK_DGRAM : SOCK_STREAM, isUdp ? IPPROTO_UDP : IPPROTO_TCP)) == -1 ) { sockfd = 0; throw Exception( __FILE__, __LINE__, "socket error", errno); } - // set TCP keep-alive + // set TCP keep-alive / UDP reuse address optval = 1; optlen = sizeof(optval); - if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) == -1) { - reportEvent(5, "can't set TCP socket keep-alive mode", errno); + if (isUdp) { + if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen) == -1) { + reportEvent(5, "can't set UDP reuse address", errno); + } + } else { + if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) == -1) { + reportEvent(5, "can't set TCP socket keep-alive mode", errno); + } + } + + if (isUdp) { +#ifdef HAVE_ADDRINFO + //todo: implement when ADDRINFO used + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_family = AF_ANY; + snprintf(portstr, sizeof(portstr), "%d", port); + + if (getaddrinfo(host , portstr, &hints, &ptr)) { + sockfd = 0; + throw Exception( __FILE__, __LINE__, "getaddrinfo error", errno); + } + memcpy ( laddr, ptr->ai_addr, ptr->ai_addrlen); + freeaddrinfo(ptr); +#else + memset(&mreq, 0, sizeof(struct ip_mreq)); + mreq.imr_multiaddr = *((long*) pHostEntry->h_addr_list[0]); + + if (IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) { + mreq.imr_interface.s_addr=INADDR_ANY; + if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { + ::close( sockfd); + sockfd = 0; + throw Exception( __FILE__, __LINE__, "can't join multicast address", errno); + } + } + memset( &laddr, 0, sizeof(addr)); + laddr.sin_family = AF_INET; + laddr.sin_port = htons(port); + laddr.sin_addr.s_addr = INADDR_ANY; +#endif + if (bind(sockfd, (struct sockaddr*)&laddr, sizeof(laddr))) { + ::close( sockfd); + sockfd = 0; + throw Exception( __FILE__, __LINE__, "can't bind UDP socket", errno); + } } // connect @@ -267,7 +314,7 @@ NetSocket :: canRead ( unsigned int sec, sigset_t sigset; int ret; - if ( !isOpen() ) { + if ( !isOpen() || isUdp ) { return false; } @@ -302,7 +349,7 @@ NetSocket :: read ( void * buf, { int ret; - if ( !isOpen() ) { + if ( !isOpen() || isUdp ) { return 0; } @@ -342,6 +389,8 @@ NetSocket :: canWrite ( unsigned int sec, if ( !isOpen() ) { return false; + } else if ( isUdp ) { + return true; } FD_ZERO( &fdset); @@ -382,7 +431,7 @@ NetSocket :: write ( const void * buf, #ifdef HAVE_MSG_NOSIGNAL ret = send( sockfd, buf, len, MSG_NOSIGNAL); #else - ret = send( sockfd, buf, len, 0); + ret = send( sockfd, buf, len, isUdp ? MSG_DONTWAIT : 0); #endif if ( ret == -1 ) { diff --git a/darkice/branches/darkice-rtp/src/NetSocket.h b/darkice/branches/darkice-rtp/src/NetSocket.h index 8342ab6..b4f8f69 100644 --- a/darkice/branches/darkice-rtp/src/NetSocket.h +++ b/darkice/branches/darkice-rtp/src/NetSocket.h @@ -74,6 +74,11 @@ class NetSocket : public Source, public Sink, public virtual Reporter */ int sockfd; + /** + * Type of socket. + */ + bool isUdp; + /** * Initialize the object. * @@ -83,7 +88,8 @@ class NetSocket : public Source, public Sink, public virtual Reporter */ void init ( const char * host, - unsigned short port ) throw ( Exception ); + unsigned short port, + bool isUdp ) throw ( Exception ); /** * De-initialize the object. @@ -119,9 +125,10 @@ class NetSocket : public Source, public Sink, public virtual Reporter */ inline NetSocket( const char * host, - unsigned short port ) throw ( Exception ) + unsigned short port, + bool isUdp ) throw ( Exception ) { - init( host, port); + init( host, port, isUdp ); } /** diff --git a/darkice/branches/darkice-rtp/src/RtpCast.cpp b/darkice/branches/darkice-rtp/src/RtpCast.cpp new file mode 100644 index 0000000..b09d505 --- /dev/null +++ b/darkice/branches/darkice-rtp/src/RtpCast.cpp @@ -0,0 +1,104 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved. + + Tyrell DarkIce + + File : RtpCast.cpp + Version : $Revision: 462 $ + Author : $Author: rafael@riseup.net $ + Location : $HeadURL$ + + Copyright notice: + + This program 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. + + This program 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. + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#else +#error need stdio.h +#endif + +#ifdef HAVE_STRING_H +#include +#else +#error need string.h +#endif + +#ifdef HAVE_MATH_H +#include +#else +#error need math.h +#endif + + +#include "Exception.h" +#include "Source.h" +#include "Sink.h" +#include "Util.h" +#include "RtpCast.h" + + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +/*------------------------------------------------------------------------------ + * File identity + *----------------------------------------------------------------------------*/ +static const char fileid[] = "$Id$"; + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Initialize the object + *----------------------------------------------------------------------------*/ +void +RtpCast :: init ( StreamFormat format, + const char * mountPoint, + const char * description ) + throw ( Exception ) +{ + this->format = format; + this->mountPoint = Util::strDup( mountPoint); + this->description = description ? Util::strDup( description) : 0; +} + + +/*------------------------------------------------------------------------------ + * De-initialize the object + *----------------------------------------------------------------------------*/ +void +RtpCast :: strip ( void ) throw ( Exception ) +{ + delete[] mountPoint; + if ( description ) { + delete[] description; + } +} + + diff --git a/darkice/branches/darkice-rtp/src/RtpCast.h b/darkice/branches/darkice-rtp/src/RtpCast.h new file mode 100644 index 0000000..523c697 --- /dev/null +++ b/darkice/branches/darkice-rtp/src/RtpCast.h @@ -0,0 +1,415 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved. + + Tyrell DarkIce + + File : RtpCast.h + Version : $Revision: 466 $ + Author : $Author: piratfm $ + Location : $HeadURL$ + + Copyright notice: + + This program 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. + + This program 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. + +------------------------------------------------------------------------------*/ +#ifndef ICE_CAST2_H +#define ICE_CAST2_H + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#include "Ref.h" +#include "Reporter.h" +#include "Sink.h" +#include "NetSocket.h" +#include "BufferedSink.h" + + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * Class representing output to an RtpCast server with + * ice login + * + * @author $Author: piratfm $ + * @version $Revision: 466 $ + */ +class RtpCast : public Sink, public virtual Reporter +{ + public: + + /** + * Type for specifying the format of the stream. + */ + enum StreamFormat { mp3, mp2, oggVorbis, aac, aacp }; + + + private: + + /** + * The format of the stream. + */ + StreamFormat format; + + /** + * The socket connection to the server. + */ + Ref socket; + + /** + * The BufferedSink encapsulating the socket connection to the server. + */ + Ref bufferedSink; + + /** + * An optional Sink to enable stream dumps. + */ + Ref streamDump; + + /** + * Duration of the BufferedSink buffer in seconds. + */ + unsigned int bufferDuration; + + + /** + * Initalize the object. + * + * @param mountPoint mount point of the stream on the server. + * @param remoteDumpFile remote dump file (may be NULL). + * @param description description of the stream. + * @exception Exception + */ + void + init ( StreamFormat format, + const char * mountPoint, + const char * description ) + throw ( Exception ); + + /** + * De-initalize the object. + * + * @exception Exception + */ + void + strip ( void ) throw ( Exception ); + + + protected: + + /** + * Default constructor. Always throws an Exception. + * + * @exception Exception + */ + inline + RtpCast ( void ) throw ( Exception ) + { + throw Exception( __FILE__, __LINE__); + } + + /** + * Get the Sink underneath this CastSink. + * + * @return pointer to the Sink underneath this CastSink. + */ + inline Sink * + getSink ( void ) const throw () + { + return bufferedSink.get(); + } + + /** + * Get the NetSocket underneath this CastSink. + * + * @return pointer to the NetSocket underneath this CastSink. + */ + inline NetSocket * + getSocket ( void ) const throw () + { + return socket.get(); + } + + + public: + + /** + * Constructor. + * + * @param socket socket connection to the server. + * @param password password to the server. + * @param mountPoint mount point of the stream on the server. + * @param format the format of the stream. + * @param name name of the stream. + * @param description description of the stream. + * @param url URL associated with the stream. + * @param genre genre of the stream. + * @param bitRate bitrate of the stream (e.g. mp3 bitrate). + * @param isPublic is the stream public? + * @param streamDump an optional sink to dump the binary stream + * data to. + * @param bufferDuration duration of the BufferedSink buffer + * in seconds. + * @exception Exception + */ + inline + RtpCast ( NetSocket * socket, + const char * password, + const char * mountPoint, + StreamFormat format, + unsigned int bitRate, + const char * name = 0, + const char * description = 0, + const char * url = 0, + const char * genre = 0, + bool isRtp = false, + Sink * streamDump = 0, + unsigned int bufferDuration = 10 ) + throw ( Exception ) + : CastSink( socket, + password, + bitRate, + name, + url, + genre, + isPublic, + streamDump, + bufferDuration ) + { + init( format, mountPoint, description); + } + + /** + * Copy constructor. + * + * @param cs the RtpCast to copy. + */ + inline + RtpCast( const RtpCast & cs ) throw ( Exception ) + : CastSink( cs ) + { + init( cs.getFormat(), + cs.getMountPoint(), + cs.getDescription() ); + } + + /** + * Destructor. + * + * @exception Exception + */ + inline virtual + ~RtpCast( void ) throw ( Exception ) + { + strip(); + } + + /** + * Assignment operator. + * + * @param cs the RtpCast to assign this to. + * @return a reference to this RtpCast. + * @exception Exception + */ + inline virtual RtpCast & + operator= ( const RtpCast & cs ) throw ( Exception ) + { + if ( this != &cs ) { + strip(); + CastSink::operator=( cs ); + init( cs.getFormat(), + cs.getMountPoint(), + cs.getDescription() ); + } + return *this; + } + + /** + * Get the format of the stream. + * + * @return the format of the stream. + */ + inline StreamFormat + getFormat ( void ) const throw () + { + return format; + } + + + + + + + + + /** + * Open the CastSink. + * Logs in to the server. + * + * @return true if opening was successfull, false otherwise. + * @exception Exception + */ + virtual bool + open ( void ) throw ( Exception ); + + /** + * Check if the CastSink is open. + * + * @return true if the CastSink is open, false otherwise. + */ + inline virtual bool + isOpen ( void ) const throw () + { + return bufferedSink != NULL ? bufferedSink->isOpen() : false; + } + + /** + * Check if the CastSink is ready to accept data. + * Blocks until the specified time for data to be available. + * + * @param sec the maximum seconds to block. + * @param usec micro seconds to block after the full seconds. + * @return true if the CastSink is ready to accept data, + * false otherwise. + * @exception Exception + */ + inline virtual bool + canWrite ( unsigned int sec, + unsigned int usec ) throw ( Exception ) + { + return getSink()->canWrite( sec, usec); + } + + /** + * Write data to the CastSink. + * + * @param buf the data to write. + * @param len number of bytes to write from buf. + * @return the number of bytes written (may be less than len). + * @exception Exception + */ + inline virtual unsigned int + write ( const void * buf, + unsigned int len ) throw ( Exception ) + { + if ( streamDump != 0 ) { + streamDump->write( buf, len); + } + + return getSink()->write( buf, len); + } + + + + + + + + + + + + /** + * Flush all data that was written to the CastSink to the server. + * + * @exception Exception + */ + inline virtual void + flush ( void ) throw ( Exception ) + { + if ( streamDump != 0 ) { + streamDump->flush(); + } + + return getSink()->flush(); + } + + /** + * Cut what the sink has been doing so far, and start anew. + * This usually means separating the data sent to the sink up + * until now, and start saving a new chunk of data. + */ + inline virtual void + cut ( void ) throw () + { + if ( streamDump != 0 ) { + streamDump->cut(); + } + } + + + + /** + * Close the CastSink. + * + * @exception Exception + */ + inline virtual void + close ( void ) throw ( Exception ) + { + if ( streamDump != 0 ) { + streamDump->close(); + } + + return getSink()->close(); + } + + + /** + * Get the bitrate of the stream (e.g. mp3 bitrate). + * + * @return the bitrate of the stream (e.g. mp3 bitrate). + */ + inline unsigned int + getBitRate ( void ) const throw () + { + return bitRate; + } + + /** + * Get the duration of the BufferedSink buffer in seconds. + * + * @return the the duration of the BufferedSink buffer in seconds. + */ + inline unsigned int + getBufferDuration ( void ) const throw () + { + return bufferDuration; + } + +}; + + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + + +#endif /* ICE_CAST2_H */ +