#!/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;
}

