MP3-Icecast

 view release on metacpan or  search on metacpan

Icecast.pm  view on Meta::CPAN

package MP3::Icecast;

=head1 NAME

MP3::Icecast - Generate Icecast streams, as well as M3U and PLSv2 playlists.

=head1 SYNOPSIS

  use MP3::Icecast;
  use MP3::Info;
  use IO::Socket;


  my $listen_socket = IO::Socket::INET->new(
    LocalPort => 8000, #standard Icecast port
    Listen    => 20,
    Proto     => 'tcp',
    Reuse     => 1,
    Timeout   => 3600);

  #create an instance to find all files below /usr/local/mp3
  my $finder = MP3::Icecast->new();
  $finder->recursive(1);
  $finder->add_directory('/usr/local/mp3');
  my @files = $finder->files;

  #accept TCP 8000 connections
  while(1){
    next unless my $connection = $listen_socket->accept;

    defined(my $child = fork()) or die "Can't fork: $!";
    if($child == 0){
      $listen_socket->close;

      my $icy = MP3::Icecast->new;

      #stream files that have an ID3 genre tag of "jazz"
      while(@files){
        my $file = shift @files;
        my $info = new MP3::Info $file;
        next unless $info;
        next unless $info->genre =~ /jazz/i;
        $icy->stream($file,0,$connection);
      }
      exit 0;
    }

    #a contrived example to demonstrate that MP3::Icecast
    #can generate M3U and PLSv2 media playlists.
    print STDERR $icy->m3u, "\n";
    print STDERR $icy->pls, "\n";

    $connection->close;
  }


=head1 ABSTRACT

MP3::Icecast supports streaming Icecast protocol over socket
or other filehandle (including STDIN).  This is useful for writing
a streaming media server.

MP3::Icecast also includes support for generating M3U and PLSv2
playlist files.  These are common formats supported by most modern
media players, including XMMS, Windows Media Player 9, and Winamp.

=head1 SEE ALSO

  The Icecast project
  http://www.icecast.org

  Namp! (Apache::MP3)
  http://namp.sourceforge.net

  Unofficial M3U and PLS specifications
  http://forums.winamp.com/showthread.php?threadid=65772

=head1 AUTHOR

 Allen Day, E<lt>allenday@ucla.eduE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright 2003, Allen Day

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

use strict;
use File::Spec;
use File::Basename 'dirname','basename','fileparse';
use URI::Escape;
use IO::File;
use MP3::Info;

use constant DEBUG => 0;

our $VERSION = '0.02';

our %AUDIO = (
               '.mp3' => 'audio/x-mp3',
             );
our %FORMAT_FIELDS = (
                      a => 'artist',
                      c => 'comment',
                      d => 'duration',
                      f => 'filename',
                      g => 'genre',
                      l => 'album',
                      m => 'min',
		              n => 'track',
                      q => 'samplerate',
		              r => 'bitrate',
		              s => 'sec',
		              S => 'seconds',
		              t => 'title',
		              y => 'year',
		                );

Icecast.pm  view on Meta::CPAN


   return $output;
}

=head2 pls

 Title   : pls
 Usage   : $pls_text = $icy->pls
 Function: generates a PLSv2 string from the
           contents of the list returned by files().
           files not recognized by MP3::Info are
           silently ignored.
 Returns : a PLSv2 string
 Args    : none


=cut

sub pls{
   my $self = shift;

   my $output = undef;

   $output .= "[playlist]$CRLF" if $self->files;
   my $c = 0;
   foreach my $file ($self->files){
     my $info = $self->_get_info($file);

     next unless defined($info);

     $c++;

     $file = $self->_mangle_path($file);

     my $time   = $info->secs   || -1;
     my $artist = $info->artist || 'Unknown Artist';
     my $album  = $info->album  || 'Unknown Album';
     my $title  = $info->title  || 'Unknown Title';

     $output .= uri_escape(sprintf("File%d=%s${CRLF}Title%d=%s - %s (%s)${CRLF}Length%d=%d$CRLF",$c,$file,$c,$title,$artist,$album,$c,$time));
   }

   $output .= "NumberOfEntries=$c$CRLF" if $self->files;
   $output .= "Version=2$CRLF"          if $self->files;

   return $output;
}

=head2 stream

 Title   : streamll: 1 at /raid5a/allenday/projects/MP3/Icecast.pm line 459.

 Usage   : $icy->stream('/usr/local/mp3/meow.mp3',0);
           $icy->stream('/usr/local/mp3/meow.mp3',0,$io_handle);
 Function: stream an audio file.  prints to STDOUT unless a
           third argument is given, in which case ->print() is
           called on the second argument.  An IO::Handle or
           Apache instance will work here.
 Returns : true on success, false on failure
 Args    : 1) system path to the file to stream
           2) offset in file to start streaming
           3) (optional) object to call ->print() on, rather
              than printing to STDOUT


=cut

sub stream{
   my ($self,$file,$offset,$handle) = @_;

   return undef unless -f $file;
   my $info = $self->_get_info($file);
   return undef unless defined($info);

   my $genre = $info->genre                    || 'unknown genre';
   my $description = $self->description($file) || 'unknown';
   my $bitrate = $info->bitrate                || 0;
   my $size = -s $file                         || 0;
   my $mime = $AUDIO{ lc((fileparse($file,keys(%AUDIO)))[2]) };
   my $path = $self->_mangle_path($file);

   my $fh = $self->_open_file($file) || die "couldn't open file $file: $!";
   binmode($fh);
   seek($fh,$offset,0);

   my $output = '';
   $output .= "ICY ". ($offset ? 206 : 200) ." OK$CRLF";
   $output .= "icy-notice1:<BR>This stream requires a shoutcast/icecast compatible player.<BR>$CRLF";
   $output .= "icy-notice2:MP3::Icecast<BR>$CRLF";
   $output .= "icy-name:$description$CRLF";
   $output .= "icy-genre:$genre$CRLF";
   $output .= "icy-url: $path$CRLF";
   $output .= "icy-pub:1$CRLF";
   $output .= "icy-br:$bitrate$CRLF";
   $output .= "Accept-Ranges: bytes$CRLF";
   if($offset){ $output .= "Content-Range: bytes $offset-" . ($size-1) . "/$size$CRLF" }
   $output .= "Content-Length: $size$CRLF";
   $output .= "Content-Type: $mime$CRLF";
   $output .= "$CRLF";

   if(!ref($handle)){
     print $output;
   } elsif($handle->can('print')) {
     $handle->print($output);
   } else {
     return undef;
   }

   my $bytes = $size;
   while($bytes > 0){
     my $data;
     my $b = read($fh,$data,2048) || last;
     $bytes -= $b;

     if(!ref($handle)){
       print $data;
     } else {
       $handle->print($data);
     }
   }



( run in 0.618 second using v1.01-cache-2.11-cpan-2398b32b56e )