# start the daemon & play something ./playdaemon -i mytest play "../Music/Snow Patrol - Run.mp3" # command the daemon to pause the track ./playdaemon -i mytest pause # resume where it left off ./playdaemon -i mytest play # stop it altogether ./playdaemon -i mytest stop # restart it again (it remembers the last file loaded) ./playdaemon -i mytest play # play a different track ./playdaemon -i mytest play "/media/flash/Music/Coldplay - Viva La Vida.mp3" # we're done, kill the server ./playdaemon -i mytest exit #### #!/usr/bin/perl -w # usage: playdaemon [--id uniqueid, opts] {play|pause|stop} use strict; use warnings; use Getopt::Long; use Cwd "abs_path"; use threads; use threads::shared; # Media player to use? our $os = ''; if ($^O =~ /^MSWin/) { # Windows support not yet implemented! require Win32::MediaPlayer; require Win32::Pipe; $os = 'Windows'; die "Win32 support not yet implemented!"; } elsif ($^O =~ /linux/i) { require GStreamer; $os = 'Linux'; } else { die "Don't know what media library to use"; } # Collect command-line arguments. my %o = ( id => "playdaemon", # --id, unique ID to use debug => 0, # --debug, debug mode fg => 0, # --foreground, --fg, -f, don't fork to background server => 0, # --server, -s force server mode help => 0, # --help, wanting help ); GetOptions ( 'id|i=s' => \$o{id}, 'debug' => \$o{debug}, 'foreground|fg|f' => \$o{fg}, 'server|s' => \$o{server}, 'help|h|?' => \$o{help}, ); # Help? if ($o{help}) { &help(); exit(0); } # Validate the commands. my ($cmd,$file) = (lc(shift(@ARGV)), shift(@ARGV)); if ($cmd !~ /^play|pause|stop|exit$/ || (defined $file && !-f $file)) { print "Usage: playdaemon [--id uniqueid, opts] {play|pause|stop|exit} [audiofile]\n" . "See playdaemon --help for help.\n"; exit(1); } if (defined $file && -f $file) { $file = fullpath($file); } # See if the named pipe exists. my $pipe = 'playdaemon-' . $o{id}; my $mode = ''; # server or client if ($os eq 'Linux') { # See if the pipe exists in /tmp. if (!-e "/tmp/$pipe") { # It doesn't; so we are the server. Create the pipe. &debug("Creating named pipe at /tmp/$pipe - we are the server."); system("mkfifo /tmp/$pipe"); $mode = 'server'; } else { # The pipe exists. We are the client. &debug("Found existing pipe at /tmp/$pipe - we are the client."); $mode = 'client'; } # Are we forcing server mode? if ($o{server}) { # We are the server even if the pipe was left behind from another process. &debug("Forcing server mode."); $mode = 'server'; } } # Set up kill handlers. sub DESTROY () { if ($^O eq 'Linux') { if (-e "/tmp/$pipe") { unlink("/tmp/$pipe"); } } exit(0); } $SIG{HUP} = sub { DESTROY(); }; $SIG{INT} = sub { DESTROY(); }; END { if ($os eq 'Linux' && $mode eq 'server') { if (-e "/tmp/$pipe") { print "Unlink named pipe\n"; unlink("/tmp/$pipe"); } } } # Go to the background so we can return. unless ($o{fg}) { my $pid = fork(); if ($pid) { &debug("Forking to background as PID $pid"); exit(0); } close (STDOUT); close (STDERR); close (STDIN); } # Are we the server? if ($mode eq 'server') { # Spawn a thread that'll watch the pipe. my @frompipe : shared; my $thread = threads->create (sub { # Read from the pipe. while (1) { open (READ, "/tmp/$pipe"); my $line = ; chomp $line; print "Read from pipe: $line\n"; push (@frompipe, $line); if ($line =~ /^shutdown/i) { close(READ); last; } } }); # Initialize the media player. my $play; if ($os eq 'Linux') { # Initialize GStreamer. GStreamer->init(); # Set it up. $play = GStreamer::ElementFactory->make("playbin", "play"); $play->set_state("null"); if ($cmd eq "play" && $file) { $play->set (uri => Glib::filename_to_uri ($file, "localhost")); $play->set_state("playing"); } } # Wait for inputs. while (1) { select(undef,undef,undef,0.1); if (scalar(@frompipe)) { my $next = shift(@frompipe); ($cmd,$file) = split(/\s+/, $next, 2); if (defined $file && length $file && !-f $file) { next; } elsif (defined $file && -f $file) { $file = fullpath($file); } if ($cmd eq "stop") { if ($os eq 'Linux') { print "Stopping playback.\n"; $play->set_state("null"); } } elsif ($cmd eq "pause") { if ($os eq 'Linux') { print "Pausing playback.\n"; $play->set_state("paused"); } } elsif ($cmd eq "play") { if ($os eq 'Linux') { # Did they give us a new file? if ($file) { # Yes; stop and load the new file. print "Loading new file: $file\n"; $play->set_state("null"); $play->set (uri => Glib::filename_to_uri ($file, "localhost")); $play->set_state("playing"); } else { # No; just resume playing. print "Resuming play\n"; $play->set_state("playing"); } } } elsif ($cmd eq "exit") { print "Shutting down - unlinking /tmp/$pipe\n"; unlink("/tmp/$pipe") or warn "Can't delete? $! $@"; $thread->join(); exit(0); } } } } elsif ($mode eq 'client') { # Add the commands to the pipe. if (!-e "/tmp/$pipe") { die "Can't write to pipe: file not found!"; } open (PIPE, ">/tmp/$pipe"); print PIPE "$cmd $file"; close (PIPE); } # Turn a relative path into a full one. sub fullpath { return abs_path($_[0]); } # Print a debug line. sub debug { if ($o{debug}) { print $_, "\n"; } } sub help { print "Help TODO\n"; }