#!/usr/bin/perl ##################################################################### # # MIXICE # # Logs in to an ICE/SHOUTCAST server (relay) and streams audio from # the sound card (ie. /dev/dsp). # # The script has dependencies on the IO::Socket perl module, catdsp # (http://www.lns.com/papers/catdsp) and a codec that will work with # raw PCM audio coming into STDIN and will send a Layer 3 stream STDOUT # such as LAME. # # Copyright (C) 1999-2000 Timothy Pozar pozar@lns.com # # 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. # # $Id: mixice.pl,v 1.12 2001/02/05 19:35:05 pozar Exp $ # ##################################################################### print "MIXICE - ICY/SHOUTCAST live streaming program\n"; use IO::Socket; $bufsize = 512; ##################################################################### # Audio... $ksamplerate = 32; # Sample rate in KHz; $samplerate = $ksamplerate * 1000; # Sample rate in Hz; $kbitrate = 96; # Bit rate in Kb/s; $bitrate = $kbitrate * 1000; # Bit rate in Hz; $mono = 0; # 1=mono; 0=stereo # Stereo arguments... $mp3encmono = ""; $catdspmono = ""; $lamemono = ""; $device = "/dev/dspW0"; ##################################################################### # Server to send to... $hostname = "server.com"; $port = 8081; # shoutcast server/control port # $port = 8080; # icecast server/control port $password = "hackme"; $audiocast_login = 0; $audiocast_mountpoint = "/foo-$kbitrate"; ##################################################################### # Description of stream... $name = "KXXX-FM - Anytown, CA"; $genre = "various"; $url = "http://www.kxxx.com"; $public = 1; # 1=Public; 0=Private (not announced) stream if ($mono) { $mp3encmono = "-nc 1"; $catdspmono = "-m"; $lamemono = "-m m"; } # To unbuffer prints to STDOUT... select(STDOUT); $| = 1; # $SIG{'QUIT'} = \&sig_int; # $SIG{'PIPE'} = 'IGNORE'; $SIG{'PIPE'} = \&sig_pipe; $SIG{'INT'} = \&sig_int; $SIG{'HUP'} = \&sig_int; while(1){ # We really want the program to never die... # I haven't found all of the signals to capture and # deal with so you may want to run a wrapper around # this program such as a sh script like: # # #!/bin/sh # while true # do # /usr/local/sbin/mixice.pl # sleep 3 # done print "Attempting to open the connection.\n"; # Open the connection... my $relay = new IO::Socket::INET ( PeerAddr => $hostname, PeerPort => $port, Proto => 'tcp', ); sleep (2); die "Could not open connection to $hostname at $port\n" unless $relay; print "Opened connection.\n"; if ($audiocast_login) { print $relay "SOURCE $password $audiocast_mountpoint\r\n\r\n"; print $relay "x-audiocast-name:$name\r\n"; print $relay "x-audiocast-genre:$genre\r\n"; print $relay "x-audiocast-url:$url\r\n"; print $relay "x-audiocast-public:$public\r\n"; # 1 = public print $relay "x-audiocast-bitrate:$kbitrate\r\n"; print $relay "x-audiocast-description: \r\n"; } else { print $relay "$password\r\n"; print $relay "icy-name:$name\r\n"; print $relay "icy-br:$kbitrate\r\n"; print $relay "icy-genre:$genre\r\n"; print $relay "icy-url:$url\r\n"; print $relay "icy-pub:$public\r\n"; # 1 = public } print $relay "\r\n"; print "Logged in.\n"; # Start the stream here... # for LAME... open(STREAM, "/usr/local/sbin/catdsp -d $device -r $samplerate $catdspmono | /usr/local/bin/lame -h -s $ksamplerate -p -S $lamemono -b $kbitrate -f -x -r - |"); # An example for Fraunhofer codec... # open(STREAM, "catdsp -d $device -r $samplerate $catdspmono | /usr/local/mp3enc31/mp3enc31 -sti -sto -l3wav -qual 3 $mp3encmono -br $bitrate -sr $samplerate |"); $i = 0; SENDSTREAM: while(1){ $i++; $result = read(STREAM, $buffer, $bufsize); if(($result > 0) || (defined $result)){ print " Read packet $i. \r"; print $relay "$buffer"; # if($relay->timed_out){ # print "Stream to $hostname timed out.\n"; # last; # } print "Wrote packet $i. \r"; } else { print "End of MPEG stream.\n"; exit; } } # The connection failed to the relay for some reason. # Let's close the connection nicely, hang for a bit and restart # the whole thing again. close($relay); sleep (10); } sub sig_pipe { # 1st argument is signal name $date=`date`; chop($date); my($sig) = @_; print "$date: Caught a SIG$sig\n"; close($relay); goto SENDSTREAM; } sub sig_int { # 1st argument is signal name $date=`date`; chop($date); my($sig) = @_; print "$date: Caught a SIG$sig\n"; close($relay); exit; }