File Coverage

blib/lib/MP3/Icecast/Simple.pm
Criterion Covered Total %
statement 18 79 22.7
branch 0 14 0.0
condition 0 17 0.0
subroutine 6 11 54.5
pod 5 5 100.0
total 29 126 23.0


line stmt bran cond sub pod time code
1             package MP3::Icecast::Simple;
2              
3             =head1 NAME
4              
5             MP3::Icecast::Simple - Simple MP3::Icecast wrapper
6              
7             =head1 SYNOPSIS
8              
9             use MP3::Icecast::Simple;
10              
11             $icy = MP3::Icecast::Simple->new(
12             description => "Station",
13             server => '127.0.0.1:8000',
14             password => 'password',
15             local_port => 1234,
16             bitrate => 96
17             );
18             $icy->play("/path/to/files");
19              
20             =head1 ABSTRACT
21              
22             MP3::Icecast::Simple is a simple MP3::Icecast wrapper, that can be
23             used to create a SHOUTcast/Icecast broadcast source easy.
24              
25             =head1 SEE ALSO
26              
27             MP3::Icecast module by Allen Day (MP3::Icecast)
28              
29             Nullsoft SHOUTcast DNAS home
30             http://www.shoutcast.com
31              
32             =cut
33              
34 1     1   33751 use strict;
  1         2  
  1         37  
35 1     1   4 use base 'MP3::Icecast';
  1         3  
  1         677  
36 1     1   1245 use Time::HiRes qw(sleep);
  1         2060  
  1         4  
37 1     1   1343 use IO::Socket;
  1         30171  
  1         5  
38 1     1   2074 use LWP::UserAgent;
  1         71972  
  1         39  
39 1     1   12 use vars qw(@ISA $VERSION);
  1         2  
  1         6982  
40              
41             $VERSION = "0.2";
42              
43             =head1 METHODS
44              
45             =head2 new
46              
47             Title : new
48             Usage : $icy = MP3::Icecast::Simple->new(%arg)
49             Function: Create a new MP3::Icecast::Simple instance
50             Returns : MP3::Icecast::Simple object
51             Args : description Name of the radiostation
52             server Address and port of SHOUTcast server
53             password Password to SHOUTcast server
54             local_port Local port
55             bitrate Initial bitrate
56              
57             =cut
58              
59             sub new {
60 0     0 1   my ($class, %arg) = @_;
61 0           my $self = bless {%arg}, $class;
62              
63 0           return $self;
64             }
65              
66             =head2 play
67              
68             Title : play
69             Usage : $icy->play($dir, $resursive);
70             Function: Play a directory of .mp3 files
71             Returns :
72             Args : dirname Path to direactory with .mp3 files
73             recursive Flag determining whether a directory is recursively searched for files (optional)
74              
75             =cut
76              
77             sub play {
78 0     0 1   my $self = shift;
79 0           my $dir = shift;
80 0   0       my $recursive = shift || 0;
81              
82 0           my $listen_socket = IO::Socket::INET->new(
83             LocalPort => $self->{local_port},
84             Listen => 20,
85             Proto => 'tcp',
86             Reuse => 0,
87             Timeout => 3600
88             );
89              
90 0           $self->recursive($recursive);
91 0           $self->add_directory($dir);
92              
93 0           my @files = $self->files;
94 0           while(1) {
95 0 0         next unless my $connection = $listen_socket->accept;
96 0 0         defined(my $child = fork()) or die "Can't fork: $!";
97 0 0         if($child == 0) {
98 0           $listen_socket->close;
99 0           $connection->print($self->header);
100 0   0       $self->stream($_, $connection) || last for(@files);
101             }
102 0           $connection->close;
103             }
104 0           exit 0;
105             }
106              
107             =head2 stream
108              
109             Title : stream (rewrited from original MP3::Icecast package with improvements)
110             Usage : $icy->stream($file, $handle);
111             Function: Play a file via socket
112             Returns : 1 if file was transmitted successfully,
113             undef if an error occured
114             Args : file File to stream
115             handle Socket handler
116              
117             =cut
118              
119             sub stream {
120 0     0 1   my ($self, $file, $handle) = @_;
121 0 0         return undef unless -f $file;
122              
123 0           my $info = $self->_get_info($file);
124 0 0         return undef unless defined($info);
125              
126 0   0       my $size = -s $file || 0;
127 0   0       my $bitrate = $info->bitrate || 1;
128 0   0       my $description = $self->description($file) || 'unknown';
129 0   0       my $fh = $self->_open_file($file) || die "couldn't open file $file: $!";
130              
131 0           binmode $fh;
132              
133 0 0 0       if(ref($handle) and $handle->can('print')) {
134 0           my $bytes = $size;
135 0           print $description."\n";
136 0           $self->updinfo($description);
137 0           while($bytes > 0) {
138 0           my $data;
139 0   0       my $b = read($fh, $data, $bitrate * 128) || last;
140 0           $bytes -= $b;
141 0           $handle->print($data);
142 0           sleep $b / ($bitrate * 128);
143             }
144 0           return 1;
145             }
146 0           return undef;
147             }
148              
149             =head2 updinfo
150              
151             Title : updinfo
152             Usage : Not a publick method
153             Function: Update current song title on the SHOUTcast server
154             Returns : 1 if song title updated successfully,
155             undef if an error occured
156             Args : description Name of current song
157              
158             =cut
159              
160             sub updinfo {
161 0     0 1   my ($self, $songname) = @_;
162 0           my $ua = LWP::UserAgent->new;
163 0           $ua->timeout(10);
164 0           $ua->env_proxy;
165 0           $ua->agent('Mozilla/5.0');
166 0           my $response = $ua->get("http://$self->{server}/admin.cgi?mode=updinfo&pass=$self->{password}&song=" . $songname);
167 0 0         return undef unless ($response->is_success);
168 0           return 1;
169             }
170              
171             =head2 header
172              
173             Title : header
174             Usage : Not a publick method
175             Function: Create a ICY response header
176             Returns : ICY response header
177             Args : none
178              
179             =cut
180              
181             sub header {
182 0     0 1   my $self = shift;
183 0           my $output = '';
184 0           my $CRLF = "\015\012";
185              
186 0           $output .= "ICY 200 OK$CRLF";
187 0           $output .= "icy-notice1:
This stream requires a shoutcast/icecast compatible player.
$CRLF";
188 0           $output .= "icy-notice2:MP3::Icecast::Simple
$CRLF";
189 0           $output .= "icy-name:" . $self->{description} . $CRLF;
190 0           $output .= "icy-pub:1$CRLF";
191 0           $output .= "icy-br:" . $self->{bitrate} . $CRLF;
192 0           $output .= "Accept-Ranges: bytes$CRLF";
193 0           $output .= "Content-Type: audio/x-mp3$CRLF";
194 0           $output .= "$CRLF";
195              
196 0           return $output;
197             }
198              
199             1;
200              
201             =head1 AUTHOR
202              
203             Gregory A. Rozanoff, rozanoff@gmail.com
204              
205             =head1 COPYRIGHT AND LICENSE
206              
207             Copyright 2006, Gregory A. Rozanoff
208              
209             This library is free software; you can redistribute it and/or modify
210             it under the same terms as Perl itself.
211              
212             =cut