add RtpCast skeleton
This commit is contained in:
parent
d3eb9525dc
commit
9bca6850a7
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
|
|
@ -42,6 +42,8 @@ darkice_SOURCES = AudioEncoder.h\
|
|||
ShoutCast.h\
|
||||
FileCast.h\
|
||||
FileCast.cpp\
|
||||
RtpCast.cpp\
|
||||
RtpCast.h\
|
||||
LameLibEncoder.cpp\
|
||||
LameLibEncoder.h\
|
||||
TwoLameLibEncoder.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 ) {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue