f41b98 | 2009-05-07 | Martin Stjernholm | |
|
d69ba5 | 2001-09-03 | Martin Nilsson | |
|
650fea | 2001-04-10 | Per Hedbor | | inherit "module";
|
0917d3 | 2013-03-04 | Anders Johansson | | constant cvs_version="$Id$";
|
650fea | 2001-04-10 | Per Hedbor | | constant thread_safe=1;
|
b779eb | 2001-04-10 | Per Hedbor | | #define BSIZE 8192
#define METAINTERVAL 4192
|
650fea | 2001-04-10 | Per Hedbor | | #include <module.h>
#include <roxen.h>
#include <stat.h>
#include <request_trace.h>
#define _(X,Y) _DEF_LOCALE("mod_icecast",X,Y)
constant module_type = MODULE_LOCATION;
LocaleString module_name = _(0,"Icecast: Server");
|
4f76ba | 2001-04-10 | Per Hedbor | | LocaleString module_doc = _(0, "Supports the ICY and Audio-cast protocols "
"for streaming MPEG sound. Relies on other "
"modules for the actual mpeg streams." );
|
650fea | 2001-04-10 | Per Hedbor | | constant module_unique = 0;
class Playlist
{
inherit RoxenModule;
Stdio.File next_file();
string pl_name();
mapping metadata();
void add_md_callback( function(mapping:void) f );
void remove_md_callback( function(mapping:void) f );
};
class MPEGStream( Playlist playlist )
{
array(function) callbacks = ({});
|
c0c9b9 | 2001-04-11 | Per Hedbor | | int bitrate;
int stream_start=realtime(), stream_position;
|
650fea | 2001-04-10 | Per Hedbor | | Stdio.File fd;
|
b779eb | 2001-04-10 | Per Hedbor | |
string status()
{
return ""+playlist->status()+"<br />"+
|
c0c9b9 | 2001-04-11 | Per Hedbor | | sprintf( "Stream position: %.1fs Bitrate: %dKbit/sec",
stream_position/1000000.0,
|
b779eb | 2001-04-10 | Per Hedbor | | bitrate/1000 );
}
|
c0c9b9 | 2001-04-11 | Per Hedbor | |
|
650fea | 2001-04-10 | Per Hedbor | | void add_callback( function callback )
{
callbacks += ({ callback });
}
void remove_callback( function callback )
{
callbacks -= ({ callback });
}
void call_callbacks( mixed ... args )
{
foreach( callbacks, function f )
|
b779eb | 2001-04-10 | Per Hedbor | | if( mixed e = catch( f(@args) ) )
{
werror(describe_backtrace( e ) );
|
6877ce | 2001-04-11 | Per Hedbor | | remove_callback( f );
|
b779eb | 2001-04-10 | Per Hedbor | | }
|
650fea | 2001-04-10 | Per Hedbor | | }
|
c0c9b9 | 2001-04-11 | Per Hedbor | |
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected int last_hrtime, base_time;
|
650fea | 2001-04-10 | Per Hedbor | |
int realtime()
{
|
c0c9b9 | 2001-04-11 | Per Hedbor | | if(!last_hrtime)
{
last_hrtime = gethrtime();
base_time = 0;
}
else
{
int nt = gethrtime();
base_time += nt-last_hrtime;
last_hrtime = nt;
}
return base_time;
|
650fea | 2001-04-10 | Per Hedbor | | }
|
b779eb | 2001-04-10 | Per Hedbor | | void destroy()
{
catch(fd->set_blocking());
catch(fd->close());
}
|
650fea | 2001-04-10 | Per Hedbor | | void feeder_thread( )
{
|
6877ce | 2001-04-11 | Per Hedbor | | while( sizeof(callbacks) &&
|
c0c9b9 | 2001-04-11 | Per Hedbor | | ((realtime()-stream_start) > stream_position) )
|
650fea | 2001-04-10 | Per Hedbor | | {
string frame = get_frame();
while( !frame )
{
|
b779eb | 2001-04-10 | Per Hedbor | | fd->set_blocking();
|
650fea | 2001-04-10 | Per Hedbor | | fd->close();
fd = playlist->next_file();
|
b779eb | 2001-04-10 | Per Hedbor | | buffer = 0;
|
650fea | 2001-04-10 | Per Hedbor | | bpos = 0;
frame = get_frame();
}
|
c0c9b9 | 2001-04-11 | Per Hedbor | |
stream_position += strlen(frame)*8000000 / bitrate;
|
650fea | 2001-04-10 | Per Hedbor | | call_callbacks( frame );
|
6877ce | 2001-04-11 | Per Hedbor | | }
if(!sizeof(callbacks))
{
stream_position = 0;
|
c0c9b9 | 2001-04-11 | Per Hedbor | | stream_start = realtime();
|
6877ce | 2001-04-11 | Per Hedbor | | }
|
650fea | 2001-04-10 | Per Hedbor | | call_out( feeder_thread, 0.02 );
}
void start()
{
feeder_thread( );
}
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected string buffer;
protected int bpos;
|
650fea | 2001-04-10 | Per Hedbor | |
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected string|int getbytes( int n, int|void s )
|
650fea | 2001-04-10 | Per Hedbor | | {
if( !fd )
fd = playlist->next_file();
|
6877ce | 2001-04-11 | Per Hedbor | | if( !fd )
return s?0:-1;
|
b779eb | 2001-04-10 | Per Hedbor | | if( !buffer || !strlen(buffer) )
{
bpos = 0;
|
650fea | 2001-04-10 | Per Hedbor | | buffer = fd->read( BSIZE );
|
b779eb | 2001-04-10 | Per Hedbor | | }
if( !strlen(buffer) )
return s?0:-1;
|
650fea | 2001-04-10 | Per Hedbor | | if( s )
{
if( strlen(buffer) - bpos > n )
{
string d = buffer[bpos..bpos+n-1];
buffer = buffer[bpos+n..];
bpos=0;
return d;
}
else
{
buffer = buffer[bpos..];
bpos=0;
string t = fd->read( BSIZE );
if( !t || !strlen(t) )
return -1;
buffer+=t;
return getbytes(n,1);
}
}
int res=0;
while( n-- )
{
res<<=8;
res|=buffer[ bpos++ ];
if( bpos == strlen(buffer) )
{
bpos = 0;
buffer = fd->read( BSIZE );
if( !buffer || !strlen( buffer ) )
return -1;
}
}
return res;
}
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected int rate_of(int r)
|
650fea | 2001-04-10 | Per Hedbor | | {
switch(r)
{
case 0: return 44100;
case 1: return 48000;
case 2: return 32000;
default:return 44100;
}
}
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected array(array(int)) bitrates =
|
650fea | 2001-04-10 | Per Hedbor | | ({
({0,32,64,96,128,160,192,224,256,288,320,352,384,416,448}),
({0,32,48,56,64,80,96,112,128,160,192,224,256,320,384}),
({0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}),
});
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected string get_frame()
|
650fea | 2001-04-10 | Per Hedbor | | {
string data;
int trate = 0;
int patt = 0;
int by, p=0, sw=0;
while( (by = getbytes( 1 )) > 0 )
{
patt <<= 8;
patt |= by;
p++;
if( (patt & 0xfff0) == 0xfff0 )
{
|
b90c0f | 2008-06-24 | Jonas Wallden | | int srate, layer, ID, pad, blen;
|
650fea | 2001-04-10 | Per Hedbor | | int header = ((patt&0xffff)<<16);
if( (by = getbytes( 2 )) < 0 )
break;
header |= by;
string data = sprintf("%4c",header);
patt=0;
header <<= 12;
int getbits( int n )
{
int res = 0;
while( n-- )
{
res <<= 1;
if( header&(1<<31) ) res |= 1;
header<<=1;
}
return res;
};
ID = getbits(1);
if(!ID)
continue;
layer = (4-getbits(2));
header<<=1;
bitrate = getbits(4);
srate = getbits(2);
if((layer>3) || (layer<2) || (bitrate>14) || (srate>2))
continue;
pad = getbits(1);
bitrate = bitrates[ layer-1 ][ bitrate ] * 1000;
srate = rate_of( srate );
switch( layer )
{
case 1:
blen = (int)(12 * bitrate / (float)srate + (pad?4:0))-4;
break;
case 2:
case 3:
blen = (int)(144 * bitrate / (float)srate + pad )-4;
break;
}
|
b779eb | 2001-04-10 | Per Hedbor | | string q = getbytes( blen,1 );
if(!q)
return 0;
return data + q;
|
650fea | 2001-04-10 | Per Hedbor | | }
}
return 0;
}
}
class Location( string location,
string initial,
MPEGStream stream,
|
c0c9b9 | 2001-04-11 | Per Hedbor | | int max_connections,
string url,
string name )
|
650fea | 2001-04-10 | Per Hedbor | |
{
int accessed, denied;
int connections;
|
b779eb | 2001-04-10 | Per Hedbor | | int total_time, max_time, successful;
|
650fea | 2001-04-10 | Per Hedbor | | array(Connection) conn = ({});
mapping handle( RequestID id )
{
|
b779eb | 2001-04-10 | Per Hedbor | | NOCACHE();
|
650fea | 2001-04-10 | Per Hedbor | | accessed++;
if( connections == max_connections )
{
denied++;
return Roxen.http_string_answer( "Too many listeners\n" );
}
|
6877ce | 2001-04-11 | Per Hedbor | | if( !stream->fd )
stream->fd = stream->playlist->next_file();
|
b779eb | 2001-04-10 | Per Hedbor | | mapping meta = stream->playlist->metadata();
if( !meta )
{
denied++;
return Roxen.http_string_answer( "Too early\n" );
}
connections++;
int use_metadata;
string i, metahd="";
|
9c812a | 2001-04-10 | Per Hedbor | | string protocol = "ICY";
|
650fea | 2001-04-10 | Per Hedbor | |
|
b779eb | 2001-04-10 | Per Hedbor | | werror("%O\n", id->request_headers );
|
d3cea9 | 2001-05-16 | Per Hedbor | | if( 0 && id->request_headers[ "icy-metadata" ] )
|
b779eb | 2001-04-10 | Per Hedbor | | {
|
d3cea9 | 2001-05-16 | Per Hedbor | | use_metadata = (int)id->request_headers[ "icy-metadata" ];
if( use_metadata )
metahd = "icy-metaint:"+METAINTERVAL+"\r\n";
|
b779eb | 2001-04-10 | Per Hedbor | | }
if( id->request_headers[ "x-audiocast-udpport" ] )
{
protocol = "AudioCast";
i = ("HTTP/1.0 200 OK\r\n"
"Server: "+roxen.version()+"\r\n"
"Content-type: audio/mpeg\r\n"
"x-audiocast-gengre:"+(meta->gengre||"unknown")+"\r\n"
|
c0c9b9 | 2001-04-11 | Per Hedbor | | +((meta->url||url)?"x-audiocast-url:"+(meta->url||url)+"\r\n":"")+
"x-audiocast-name:"+(meta->name||name||meta->path)+"\r\n"
|
b779eb | 2001-04-10 | Per Hedbor | | "x-audiocast-streamid:1\r\n"+metahd+
"x-audiocast-public:1\r\n"
"x-audiocast-bitrate:"+(stream->bitrate/1000)+"\r\n"
"x-audiocast-description:Served by Roxen\r\n"
"\r\n" );
}
else
{
i = ("ICY 200 OK\r\n"
"Server: "+roxen.version()+"\r\n"
"Content-type: audio/mpeg\r\n"
"icy-notice1:This stream requires a shoutcast compatible player.\r\n"
"icy-notice2:Roxen mod_mp3\r\n"+metahd+
|
c0c9b9 | 2001-04-11 | Per Hedbor | | "icy-name:"+(meta->name||name||meta->path)+"\r\n"
|
b779eb | 2001-04-10 | Per Hedbor | | "icy-gengre:"+(meta->gengre||"unknown")+"\r\n"
|
c0c9b9 | 2001-04-11 | Per Hedbor | | +((meta->url||url)?"icy-url:"+(meta->url||url)+"\r\n":"")+
|
b779eb | 2001-04-10 | Per Hedbor | | "icy-pub:1\r\n"
"icy-br:"+(stream->bitrate/1000)+"\r\n"
"\r\n" );
}
|
650fea | 2001-04-10 | Per Hedbor | | if( initial )
i += initial;
|
b779eb | 2001-04-10 | Per Hedbor | | conn += ({ Connection( id->my_fd, i,protocol,use_metadata,
|
d3cea9 | 2001-05-16 | Per Hedbor | | stream, this_object(),
|
650fea | 2001-04-10 | Per Hedbor | | lambda( Connection c ){
|
b779eb | 2001-04-10 | Per Hedbor | | int pt = time()-c->connected;
|
862687 | 2001-04-17 | Per Hedbor | | conn -= ({ c });
|
b779eb | 2001-04-10 | Per Hedbor | | total_time += pt;
if( pt > max_time )
max_time = pt;
successful++;
|
650fea | 2001-04-10 | Per Hedbor | | connections--;
} ) });
return Roxen.http_pipe_in_progress( );
}
|
b779eb | 2001-04-10 | Per Hedbor | |
string format_time( int t )
{
if( t > 60*60 )
return sprintf( "%d:%02d:%02d", t/3600, (t/60)%60, t%60 );
return sprintf( "%2d:%02d", (t/60)%60, t%60 );
}
string avg_listen_time()
{
int tt = total_time;
int n = successful;
foreach( conn, Connection c )
{
n++;
tt += time()-c->connected;
}
int t = tt / (n||1);
return format_time( t );
}
string longest_listen_time()
{
foreach( conn, Connection c )
if( time()-c->connected > max_time )
max_time = time()-c->connected;
return format_time( max_time );
}
string status()
{
string res = "<table>";
res += "<tr> <td colspan=2>"+
""+stream->status()+"</td></tr>"
"<tr><td>Connections:</td><td>"+connections+"/"+max_connections+" ("+
accessed+" since server start, "+denied+" denied)</td></tr><tr>"
"<tr><td>Average listen time:</td><td>"+avg_listen_time()+"</td></tr>"
"<tr><td>Longest listen time:</td><td>"+longest_listen_time()+"</td></tr>"
"<tr><td>Current connections:</td><td>";
foreach( conn, Connection c )
|
862687 | 2001-04-17 | Per Hedbor | | catch {
res += " "+c->status()+"\n";
};
|
b779eb | 2001-04-10 | Per Hedbor | | return res+"</td></tr></table>";
}
|
650fea | 2001-04-10 | Per Hedbor | | }
mapping(string:Location) locations = ([]);
|
b779eb | 2001-04-10 | Per Hedbor | | int __id=1;
|
650fea | 2001-04-10 | Per Hedbor | | class Connection
{
Stdio.File fd;
MPEGStream stream;
|
d3cea9 | 2001-05-16 | Per Hedbor | | Location location;
int do_meta, meta_cnt;
|
b779eb | 2001-04-10 | Per Hedbor | | string protocol;
|
650fea | 2001-04-10 | Per Hedbor | | int sent, skipped;
|
d3cea9 | 2001-05-16 | Per Hedbor | | int sent_bytes, sent_meta;
|
b779eb | 2001-04-10 | Per Hedbor | | int id = __id++;
|
650fea | 2001-04-10 | Per Hedbor | | array buffer = ({});
string current_block;
function _ccb;
|
b779eb | 2001-04-10 | Per Hedbor | | mapping current_md;
int connected = time();
string status()
{
|
862687 | 2001-04-17 | Per Hedbor | | if(!fd)
return "Closed stream\n";
|
b779eb | 2001-04-10 | Per Hedbor | | return sprintf( "%d. %s Time: %ds Remote: %s "
"%d sent, %d skipped<br />",id,protocol,
time()-connected,
(fd->query_address()/" ")[0],
|
6877ce | 2001-04-11 | Per Hedbor | | sent, skipped );
|
b779eb | 2001-04-10 | Per Hedbor | | }
|
d3cea9 | 2001-05-16 | Per Hedbor | | string old_mdkey;
|
b779eb | 2001-04-10 | Per Hedbor | | string gen_metadata( )
{
|
d3cea9 | 2001-05-16 | Per Hedbor | | string s = " ";
if( !current_md )
|
b779eb | 2001-04-10 | Per Hedbor | | current_md = stream->playlist->metadata();
|
d3cea9 | 2001-05-16 | Per Hedbor | | if( (current_md->name||current_md->path)+current_md->url != old_mdkey )
{
old_mdkey = (current_md->name||current_md->path)+current_md->url;
s = sprintf( " StreamTitle='%s';StreamUrl='%s';",
current_md->name || current_md->path,
current_md->url || location->url );
}
while( strlen(s) & 15 )
s+= "\0";
s[ 0 ]=strlen(s)/16;
werror("%O\n", s );
|
b779eb | 2001-04-10 | Per Hedbor | | return s;
}
|
650fea | 2001-04-10 | Per Hedbor | |
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected void callback( string frame )
|
650fea | 2001-04-10 | Per Hedbor | | {
buffer += ({ frame });
|
c0c9b9 | 2001-04-11 | Per Hedbor | | if( sizeof( buffer ) > 100 )
|
650fea | 2001-04-10 | Per Hedbor | | {
skipped++;
buffer = buffer[1..];
}
|
6877ce | 2001-04-11 | Per Hedbor | | if( sizeof( buffer ) == 1 )
|
c0c9b9 | 2001-04-11 | Per Hedbor | | {
remove_call_out( send_more );
call_out( send_more, 0.01 );
}
|
650fea | 2001-04-10 | Per Hedbor | | }
|
b779eb | 2001-04-10 | Per Hedbor | | int headers_done;
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected void send_more()
|
650fea | 2001-04-10 | Per Hedbor | | {
if( !strlen(current_block) )
{
|
b779eb | 2001-04-10 | Per Hedbor | | headers_done = 1;
|
650fea | 2001-04-10 | Per Hedbor | | if( !sizeof(buffer) )
return;
current_block = buffer[0];
|
b779eb | 2001-04-10 | Per Hedbor | |
if( do_meta )
{
|
d3cea9 | 2001-05-16 | Per Hedbor | | meta_cnt += strlen( current_block );
if( meta_cnt >= METAINTERVAL )
|
b779eb | 2001-04-10 | Per Hedbor | | {
|
d3cea9 | 2001-05-16 | Per Hedbor | | string meta;
meta_cnt -= METAINTERVAL;
int rest = strlen(current_block)-meta_cnt-1;
sent_meta += strlen(meta = gen_metadata());
current_block = current_block[..rest]+meta+current_block[rest];
|
b779eb | 2001-04-10 | Per Hedbor | | }
}
|
650fea | 2001-04-10 | Per Hedbor | | buffer = buffer[1..];
sent++;
}
int n = fd->write( current_block );
|
6877ce | 2001-04-11 | Per Hedbor | | if( n > 0 )
{
if( headers_done )
sent_bytes += n;
current_block = current_block[n..];
}
|
862687 | 2001-04-17 | Per Hedbor | | else if( n < 0 )
closed();
|
650fea | 2001-04-10 | Per Hedbor | | }
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected void md_callback( mapping metadata )
|
b779eb | 2001-04-10 | Per Hedbor | | {
current_md = metadata;
}
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected void closed( )
|
650fea | 2001-04-10 | Per Hedbor | | {
|
6877ce | 2001-04-11 | Per Hedbor | | fd->set_blocking( );
|
650fea | 2001-04-10 | Per Hedbor | | fd = 0;
stream->remove_callback( callback );
|
b779eb | 2001-04-10 | Per Hedbor | | stream->playlist->remove_md_callback( md_callback );
|
650fea | 2001-04-10 | Per Hedbor | | _ccb( this_object() );
|
6877ce | 2001-04-11 | Per Hedbor | | werror("Closed from client side\n");
|
650fea | 2001-04-10 | Per Hedbor | | }
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected void create( Stdio.File _fd, string buffer,
string prot, int _meta, MPEGStream _stream,
Location _loc, function _closed )
|
650fea | 2001-04-10 | Per Hedbor | | {
|
d3cea9 | 2001-05-16 | Per Hedbor | | location = _loc;
|
b779eb | 2001-04-10 | Per Hedbor | | protocol = prot;
|
650fea | 2001-04-10 | Per Hedbor | | fd = _fd;
|
b779eb | 2001-04-10 | Per Hedbor | | do_meta = _meta;
|
650fea | 2001-04-10 | Per Hedbor | | stream = _stream;
_ccb = _closed;
current_block = buffer;
|
862687 | 2001-04-17 | Per Hedbor | | fd->set_nonblocking( lambda(){}, send_more, closed );
|
b779eb | 2001-04-10 | Per Hedbor | | if( stream )
stream->add_callback( callback );
if( stream->playlist )
stream->playlist->add_md_callback( md_callback );
|
650fea | 2001-04-10 | Per Hedbor | | }
}
class VarStreams
{
inherit Variable.List;
constant type="StreamList";
|
c0c9b9 | 2001-04-11 | Per Hedbor | |
|
650fea | 2001-04-10 | Per Hedbor | |
|
c0c9b9 | 2001-04-11 | Per Hedbor | |
|
650fea | 2001-04-10 | Per Hedbor | | string render_row( string prefix, mixed val, int width )
{
string res = "<input type=hidden name='"+prefix+"' value='"+prefix+"' />";
|
c0c9b9 | 2001-04-11 | Per Hedbor | |
mapping m = decode_stream( val );
res += "<table>";
res += "<tr><td>Location "+query_location()+"</td><td>";
res += ("<input name='"+prefix+"loc' value='"+
Roxen.html_encode_string(m->location||"")+"' size=20/>");
res += "</td><td>Source</td><td>";
|
650fea | 2001-04-10 | Per Hedbor | | res += "<select name='"+prefix+"playlist'>";
mapping pl;
foreach( sort(indices(pl=playlists(0))), string p )
|
c0c9b9 | 2001-04-11 | Per Hedbor | | if( pl[ p ]->sname() == m->playlist )
res +="<option value='"+pl[p]->sname()+"' selected='t'>"+p+"</option>";
|
650fea | 2001-04-10 | Per Hedbor | | else
|
c0c9b9 | 2001-04-11 | Per Hedbor | | res +="<option value='"+pl[p]->sname()+"'>"+p+"</option>";
res += "</select></td></tr><tr>";
res += ("<td>Max. conn</td><td><input name='"+prefix+"conn' value='"+
(m->maxconn||10)+"' size=5/></td> ");
res += ("<td>Name</td><td> <input name='"+prefix+"name' value='"+
Roxen.html_encode_string(m->name || "")+"' size=20/></td></tr>");
res += ("<tr><td>Jingle</td><td colspan=3>"
"<input name='"+prefix+"jingle' value='"+
Roxen.html_encode_string(m->jingle || "")+"' size=50/></td></tr>");
res += ("<td>URL</td><td colspan=3> <input name='"+prefix+"url' value='"+
Roxen.html_encode_string(m->url || "")+"' size=50/></td>");
return res+"</tr></table>";
|
650fea | 2001-04-10 | Per Hedbor | | }
string transform_from_form( string v, mapping va )
{
if( v == "" ) return "\0\0\0\0";
v = v[strlen(path())..];
return va[v+"loc"]+"\0"+va[v+"playlist"]+"\0"+va[v+"jingle"]
|
c0c9b9 | 2001-04-11 | Per Hedbor | | +"\0"+va[v+"conn"]+"\0"+va[v+"url"]+"\0"+va[v+"name"];
|
650fea | 2001-04-10 | Per Hedbor | | }
|
c0c9b9 | 2001-04-11 | Per Hedbor | |
mapping decode_stream( string s )
{
mapping m = ([]);
array a = s/"\0";
m->location = a[0];
if( sizeof( a ) > 1 ) m->playlist = a[1];
if( sizeof( a ) > 2 ) m->jingle = a[2];
if( sizeof( a ) > 3 ) m->maxconn = (int)a[3];
if( sizeof( a ) > 4 ) m->url = a[4];
if( sizeof( a ) > 5 ) m->name = a[5];
|
d3cea9 | 2001-05-16 | Per Hedbor | | if( !m->jingle || !strlen( m->jingle ) ) m_delete( m, "jingle" );
if( !m->url || !strlen( m->url ) ) m_delete( m, "url" );
if( !m->name || !strlen( m->name ) ) m_delete( m, "name" );
|
c0c9b9 | 2001-04-11 | Per Hedbor | | return m;
}
|
650fea | 2001-04-10 | Per Hedbor | | array(mapping) get_streams()
{
|
c0c9b9 | 2001-04-11 | Per Hedbor | | return map( query(), decode_stream );
|
650fea | 2001-04-10 | Per Hedbor | | }
}
void create()
{
defvar( "streams", VarStreams( ({}), 0, _(0,"Streams"),
_(0,"All the streams") ) );
defvar("location", "/strm/",
_(0,"Mount point"), TYPE_LOCATION|VAR_INITIAL,
_(0,"Where the module will be mounted in the site's virtual "
"file system."));
}
mapping playlists(int s)
{
mapping res = ([ ]);
foreach( my_configuration()->get_providers( "icecast:playlist" ),
Playlist m )
{
if( s )
res[ m->sname() ] = m;
else
res[ m->pl_name() ] = m;
}
return res;
}
mapping streams = ([ ]);
|
b779eb | 2001-04-10 | Per Hedbor | | void st2()
|
650fea | 2001-04-10 | Per Hedbor | | {
mapping pl = playlists( 1 );
foreach( getvar( "streams" )->get_streams(), mapping strm )
{
MPEGStream mps;
|
b779eb | 2001-04-10 | Per Hedbor | | if( strm->playlist && pl[ strm->playlist ] )
|
650fea | 2001-04-10 | Per Hedbor | | if( !(mps = streams[ pl[strm->playlist] ]) )
{
mps = streams[pl[strm->playlist]] = MPEGStream( pl[strm->playlist] );
mps->start();
}
|
b779eb | 2001-04-10 | Per Hedbor | | if( !mps )
continue;
|
650fea | 2001-04-10 | Per Hedbor | | if( !locations[ strm->location ] )
locations[ strm->location ] =
Location( strm->location,
(strm->jingle?
Stdio.read_file( strm->jingle ) :
0 ),
mps,
|
c0c9b9 | 2001-04-11 | Per Hedbor | | (int)strm->maxconn,
strm->url,
strm->name );
|
650fea | 2001-04-10 | Per Hedbor | | }
}
|
b779eb | 2001-04-10 | Per Hedbor | | void start()
{
call_out( st2, 0.5 );
}
|
650fea | 2001-04-10 | Per Hedbor | | mapping find_file( string f, RequestID id )
{
if( locations[f] )
return locations[f]->handle( id );
return 0;
}
|
b779eb | 2001-04-10 | Per Hedbor | |
string status()
{
string res = "<table>";
foreach( indices( locations ), string loc )
{
res += "<tr><td valign=top>"+loc+"</td><td valign=top>"+
locations[loc]->status()+"</td></tr>";
}
return res+"</table>";
}
|