add RtpCast skeleton

This commit is contained in:
piratfm 2010-01-16 17:31:06 +00:00
parent d3eb9525dc
commit 9bca6850a7
7 changed files with 869 additions and 19 deletions

View File

@ -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

View File

@ -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
*----------------------------------------------------------------------------*/

View File

@ -42,6 +42,8 @@ darkice_SOURCES = AudioEncoder.h\
ShoutCast.h\
FileCast.h\
FileCast.cpp\
RtpCast.cpp\
RtpCast.h\
LameLibEncoder.cpp\
LameLibEncoder.h\
TwoLameLibEncoder.cpp\

View File

@ -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 ) {

View File

@ -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 );
}
/**

View File

@ -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 <stdio.h>
#else
#error need stdio.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#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;
}
}

View File

@ -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<NetSocket> socket;
/**
* The BufferedSink encapsulating the socket connection to the server.
*/
Ref<BufferedSink> bufferedSink;
/**
* An optional Sink to enable stream dumps.
*/
Ref<Sink> 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 */