| Category: | Misc |
| Author/Contact Info | hossman |
| Description: | Recently, I said to myself: "Self, you really ought to
learn more about this POE thing." So I did some
reading and thought: "This is some
dope stuff!" So I started telling some friends about it,
and making up stuff about how easy I thought it would be
to do a lot of cool stuff with POE, and then i thought
to myself: "is it really that easy?" -- so I
whiped this up in about 2 hours just to prove to myself
(and my friends) that with the right POE Components,
anything is possible.
You'll have to changed $mp3dir to something practicle for your system, but once you do start with http://localhost:8000/ and everything should be self explanitory. |
#!/usr/bin/perl -w
use strict;
use CGI; # for escape
use Data::Dumper;
use HTTP::Response;
use POE qw(Component::Server::HTTP Component::MPG123);
$| = 1;
my $port = 8000; # HTTP server port
my $mp3dir = "/home/hossman/mp3/"; # where all your mp3s are
my @song_queue =
# initial queue of songs to play (if any)
(
# $mp3dir . 'a.mp3',
# $mp3dir . 'b.mp3',
);
##################################################################
# we'll fill this up.
my $global_status = { state => 'stoped',
total_frames => 0, total_time => 0,
last_frame => 0, last_time => 0,
};
##
#
# The MPG123 Component
#
# much of this was taken verbatim from the
# POE::Component::MPG123 test script
#
POE::Component::MPG123->spawn( alias => 'song_manager' );
POE::Session->create
( inline_states => {
_start => sub {
my ($kernel, $heap) = @_[KERNEL, HEAP];
$kernel->alias_set( 'song_manager' );
# Start the first song.
&play_next($kernel);
},
_stop => sub { },
# Receive status events from mpg123.
status => sub {
my ( $kernel, $heap,
$frames_played, $frames_left,
$time_played, $time_left
) = @_[KERNEL, HEAP, ARG0..ARG3];
$global_status->{state} = "playing";
unless ($global_status->{total_frames}) {
$global_status->{total_frames} = $frames_left;
$global_status->{total_time} = $time_left;
}
$global_status->{frame_count}++;
$global_status->{last_frame} = $frames_played;
$global_status->{last_time} = $time_played;
# Rather than wait for a specific frame and call
# it the end of the song, I'll set a brief delay
# here to time out if frames
# stop playing.
$kernel->delay( song_timeout => 0.25 );
},
song_info => sub {
my ($kernel, $heap, $info) = @_[KERNEL, HEAP, ARG0];
$global_status->{song_info} = $info;
},
file_info => sub {
my ($kernel, $heap, $info) = @_[KERNEL, HEAP, ARG0];
$global_status->{file_info} = $info;
},
# The pause succeeded.
song_paused => sub {
my ($kernel, $heap) = @_[KERNEL, HEAP];
$global_status->{state} = "paused";
},
# The song resumed after we asked it to.
song_resumed => sub {
my ($kernel, $heap) = @_[KERNEL, HEAP];
$global_status->{state} = "playing";
},
# The song stopped naturally.
song_stopped => sub {
my ($kernel, $heap) = @_[KERNEL, HEAP];
$global_status->{state} = "stoped";
$global_status->{file_info} = undef;
$global_status->{song_info} = undef;
$global_status->{total_time} = 0;
$global_status->{total_frames} = 0;
$global_status->{last_time} = 0;
$global_status->{last_frame} = 0;
&play_next($kernel);
},
# The player has quit.
player_quit => sub {
my ($kernel, $heap) = @_[KERNEL, HEAP];
$global_status->{state} = "player quit";
},
### Miscellaneous event handlers.
debug => sub { },
_child => sub { },
_signal => sub { 0 },
}
);
##
#
# The HTTP Component
#
# The docs for this component are a little lacking ...
# but this seems to work
#
my $httpd = new POE::Component::Server::HTTP
(
Port => 8000,
Headers => {
'Server' => 'My Server',
'Content-type' => 'text/html',
},
ContentHandler => {
'/pause/' => \&httpd_pause_handler,
'/req/' => \&httpd_req_handler,
'/list/' => \&httpd_list_handler,
'/next/' => \&httpd_next_handler,
'/' => \&httpd_status_handler,
},
);
#
# HTTPD Handlers
#
#
sub httpd_req_handler {
# the really cool one, we unshift a song on to the head
# of the list and queue it
my ($request, $response) = @_;
my $song = CGI::unescape($request->uri->query());
my $res = "";
if (-f $song) {
push @song_queue, $song;
$res = "REQUEST ACCEPTED: $song\n";
&play_next($poe_kernel);
} else {
$res = "what are you smoking? (no $song)\n";
}
$response->content
(&make_html_response($res, &get_status_info));
$response->code(RC_OK);
return RC_OK;
}
sub httpd_list_handler {
my ($request, $response) = @_;
my @songs = `find $mp3dir -follow -name \*.mp3`;
my $links = join ' ', map {
chomp;
"<a href=\"/req/?" . CGI::escape($_) .
"\">$_</a><br>" } @songs;
$response->code(RC_OK);
$response->content
(&make_html_response("Pick a song from the list below",
$links));
return RC_OK;
}
sub httpd_pause_handler {
my ($request, $response) = @_;
$poe_kernel->post( mpg123 => 'pause' );
$response->code(RC_OK);
$response->content
(&make_html_response("The current song has been (un)paused",
&get_status_info));
return RC_OK;
}
sub httpd_next_handler {
my ($request, $response) = @_;
$poe_kernel->post( mpg123 => 'stop');
$response->code(RC_OK);
$response->content
(&make_html_response("The last song was skipped",
&get_status_info));
return RC_OK;
}
sub httpd_status_handler {
my ($request, $response) = @_;
$response->code(RC_OK);
$response->content
(&make_html_response(&get_status_info));
return RC_OK;
}
sub make_html_response {
my ($r) = ('<html><body>' .
'[ <a href="/next/">skip song</a> | ' .
'<a href="/pause/">(un)pause</a> | ' .
'<a href="/list/">Make a Request</a> | ' .
'<a href="/">Reload Status</a> ]' .
'<hr>' .
join('<hr>', @_) .
'<p></body></html>');
return $r;
}
sub play_next {
# takes a kernel,
# plays if the state is "stoped" and there's a song waiting
return unless scalar(@song_queue);
return unless 'stoped' eq $global_status->{state};
$_[0]->post( mpg123 => play => shift(@song_queue) );
}
sub get_status_info {
my $r = "<pre>";
$r .= "\nCurrent State: " . $global_status->{state} . "\n";
$r .= "Total Frames: " . $global_status->{total_frames} . "\n";
$r .= "Total Time: " . $global_status->{total_time} . "\n";
$r .= "Elapsed Frames: " . $global_status->{last_frame} . "\n";
$r .= "Elapsed Time: " . $global_status->{last_time} . "\n";
$r .= "\nSong...\n" . Dumper($global_status->{song_info});
$r .= "\nFile...\n" . Dumper($global_status->{file_info});
$r .= "\nQueue...\n" . join("\n", @song_queue);
$r .= "</pre>";
return $r
}
# Kick the kernel
$poe_kernel->run();
exit 0;
|
|
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: POE MP3/HTTP player
by Matts (Deacon) on Apr 08, 2002 at 10:58 UTC | |
by hossman (Prior) on Apr 08, 2002 at 20:32 UTC | |
|
Re: POE MP3/HTTP player
by drewbie (Chaplain) on Apr 08, 2002 at 20:51 UTC |