#!/usr/bin/perl # mpg123 remote serial player using remote feature of mpg123(version r and above) # March 17, 2001 Bob Blick use Fcntl; #allows non-blocking reads of mpg123 use IPC::Open2; #allows simultaneous read-write access of mpg123 $Remoteport = "/dev/ttyS0"; #change to match your port $playlist_list_file = '/home/bob/playlist_list'; $player_cmdline = 'mpg123 -R - 2>/dev/null'; #discarding STDERR $player = 'mpg123'; $ENV{PATH} = "/bin:/usr/bin"; $ENV{BASH_ENV} = "/bin:/usr/bin"; open(REMOTE,"+<$Remoteport") or die "Couldn't open REMOTE : $!\n"; system("/bin/stty 2400 -echo -parenb raw < $Remoteport"); #change baud rate here $|=1; #do not buffer files srand; #seed the random number generator &open_player; &get_playlist_list(); $old_id3_title = ""; $old_id3_artist = ""; &get_playlist(0); #opening just the first playlist $random_play = 1; $player_state = 0; # 0 no song, 1 paused, 2 playing $sleep_loop_counter = 0; $sleep_timer = 0; $keep_alive_counter = 0; while(1) { if ($player_state == 0) { #no song loaded? Load one &next_song; } &parse_player; if(&key_ready) { &parse_remote; } if ($id3_title ne $old_id3_title) { $old_id3_title = $id3_title; $lcd_line = $id3_artist; #$lcd_line =~ s/\s+$//; $lcd_line = substr($lcd_line,0,30); select REMOTE; $|=1; print("\r"); print ($lcd_line); $lcd_line = $id3_title; #$lcd_line =~ s/\s+$//; $lcd_line = substr($lcd_line,0,30); print ("\r\x01\x28".$lcd_line); } if($sleep_loop_counter) { $sleep_loop_counter--; #used in sub car_sleeps } $keep_alive_counter++; if ($keep_alive_counter > 19) { #approx one second has elapsed $keep_alive_counter = 0; #do keepalive stuff here select REMOTE; print("\x00"); #send null character so remote knows we're alive } select(undef,undef,undef,0.05); #sleep for .05 second } #does serial port have data? sub key_ready { my($rin,$nfd); vec($rin,fileno(REMOTE),1) = 1; return $nfd = select($rin,undef,undef,0); } #if this was C I could use switch and case, but this is perl damnit so too bad sub parse_remote { my $key; sysread(REMOTE, $key, 1); if($key eq "A") { &toggle_pause; } elsif ($key eq "B") { &prev_song; } elsif ($key eq "C") { &next_song; } elsif ($key eq "D") { &jump_back; } elsif ($key eq "E") { &jump_fwd; } elsif ($key eq "F") { &toggle_random; } elsif ($key eq "G") { &ten_back; } elsif ($key eq "H") { &ten_fwd; } elsif ($key eq "Z") { &car_sleeps; } } #check each line returned by mp3 player, updating variables to current values #call this regularly because mpg123 will back up and stop after a few seconds otherwise sub parse_player { my $playerline; my @fields; my $prefix; my @filename; my @playeroutput = ; foreach $playerline (@playeroutput) { chomp $playerline; $prefix = substr($playerline,0,2); #get first two chars if ($prefix eq '@I') { #ID3 or path/filename ahead if(substr($playerline,3,4) eq 'ID3:') { $id3_title = substr($playerline,7,30); $id3_artist = substr($playerline,37,30); } else { @filename = split(/\//,$current_song_filename); $id3_title = $filename[-1]; $id3_artist = $filename[-3]; } } @fields = split(/\s+/, $playerline); if ($fields[0] eq '@P') { $player_state = $fields[1]; #set the player state } } #do some alphabet soup here to update $player_state, $player_framecurrent $player_frameremain } #start mpg123 and set its output to not block if I read and it has no data sub open_player { open2(*PLAYERREAD, *PLAYERWRITE, $player_cmdline); $flags = ''; fcntl(PLAYERREAD, F_GETFL, $flags) or die "Couldn't get flags for PLAYERREAD : $!\n"; $flags |= O_NONBLOCK; fcntl(PLAYERREAD, F_SETFL, $flags) or die "Couldn't set flags for PLAYERREAD: $!\n"; } #if I ever decide to trap errors and need to restart sub close_player { print PLAYERWRITE "q\n"; close(PLAYERWRITE); close(PLAYERREAD); sleep(1); system("killall ".$player."\n"); } #gets list of available playlists, only need to call once sub get_playlist_list { open(PLAYLIST_LIST_FILE, "<$playlist_list_file") or die "Couldn't open PLAYLIST_LIST_FILE : $!\n"; @playlist_list = ; close PLAYLIST_LIST_FILE; } #enter with number of which playlist you want opened whenever you choose one sub get_playlist { $playlist_file = $playlist_list[@_[0]]; open(PLAYLIST_FILE, "<$playlist_file") or die "Couldn't open PLAYLIST_FILE : $!\n"; @playlist = ; close PLAYLIST_FILE; } #pulls the next song out of the playlist or picks one at random sub next_song { if($random_play == 1) { $current_song_number = int(rand(@playlist)); } else { $current_song_number++; if ($current_song_number >= @playlist) { $current_song_number = 0; } } $current_song_filename = $playlist[$current_song_number]; chomp $current_song_filename; print PLAYERWRITE "LOAD $current_song_filename\n"; $player_state = 2; } #goes to the previous song in the playlist even if in random mode, sorry sub prev_song { $current_song_number--; if ($current_song_number <= 0) { $current_song_number = @playlist - 1; } $current_song_filename = $playlist[$current_song_number]; chomp $current_song_filename; print PLAYERWRITE "LOAD $current_song_filename\n"; $player_state = 2; } #jumps 150 frames ahead sub jump_fwd { print PLAYERWRITE "JUMP +150\n"; } sub jump_back { print PLAYERWRITE "JUMP -150\n"; } sub pause { if ($player_state == 2) { $player_state = 1; print PLAYERWRITE "PAUSE\n"; } } sub unpause { if ($player_state == 1) { $player_state = 2; print PLAYERWRITE "PAUSE\n"; } } sub toggle_pause { if($player_state == 1) { $player_state = 2; } elsif ($player_state == 2) { $player_state = 1; } print PLAYERWRITE "PAUSE\n"; } sub toggle_random { if ($random_play == 1) { $random_play = 0; } else { $random_play = 1; } } #car sends "Z" every second if it is asleep sub car_sleeps { if ($sleep_loop_counter == 0) { #more than 2.5 seconds since car slept $sleep_loop_counter = 50; $sleep_timer = 0; #initialize the timer &pause(); #pause the player } else { $sleep_loop_counter = 50; $sleep_timer++; if ($sleep_timer > 900) { #15 minutes to get a pack of smokes &save_and_shutdown; } } } sub save_and_shutdown { select REMOTE; print("\x03"); print("system going down for halt now"); close REMOTE; &close_player(); system("/sbin/shutdown -h now"); while(1) { }; } sub ten_back { $current_song_number = $current_song_number - 10; if ($current_song_number <= 0) { $current_song_number = @playlist - 1; } $current_song_filename = $playlist[$current_song_number]; chomp $current_song_filename; print PLAYERWRITE "LOAD $current_song_filename\n"; $player_state = 2; } sub ten_fwd { $current_song_number = $current_song_number + 10; if ($current_song_number >= @playlist) { $current_song_number = 0; } $current_song_filename = $playlist[$current_song_number]; chomp $current_song_filename; print PLAYERWRITE "LOAD $current_song_filename\n"; $player_state = 2; }