Scripting a media player
Now that the FM transmitter is working, we can make it do something a little more useful; in this case, we will use it to broadcast a personalized radio station with a collection of your own music.
To do this, we will write a Python script that manages to search for MP3 files and calls PiFM to broadcast them.
Calling PiFM from Python
In the PiFM download and on the PiFM website, you may have noticed that there is a Python library that can be used to control PiFM. Although, looking at the source code for it, you can see that all the library can do is call the pifm
executable with the minimum number of commands, and therefore will not allow us to play MP3 files.
However, it is a simple process to create our own function that will allow us to pass the filename of an MP3, a frequency, and that will allow Python to call ffmpeg
and PiFM in order to broadcast the audio in the file for us:
def play_file(filename, frequency): command = 'ffmpeg -i "%s" -f s16le -ar 22.05k -ac 2 - | sudo ./pifm - %f 22050 stereo' % (filename, frequency) subprocess.call(command, shell=True)
This code is an extract from the player.py
file; all we are doing here is taking the shell commands used to play an MP3 file and replacing the filename and broadcast frequency with values that are passed to the function as parameters. Then, we are using the Python subprocess module to execute the command as if it was typed into a shell.
Tip
Downloading the example code
You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
Searching for MP3 files
For our script to play any MP3 files, it needs to be able to find them first. Finding an MP3 file involves taking a look at each file in a starting directory to check whether a file is an MP3 file, and then repeating this process for every directory within the start directory. Thankfully, Python makes this very easy:
mp3_files = list() for root, dirs, files in os.walk(directory): for filename in files: if filename.endswith(".mp3"): mp3_files.append(os.path.join(root, filename))
Here, directory
is the directory we want to search for files media in. The os.walk
function returns a tuple; the first element (root
) is a string that contains the absolute path to the search directory, dirs
is a list of directories within the search directory and its subdirectories, and files
is a list of all the files within the search directory and its subdirectories.
The if
statement is a simple way to check whether a file is an MP3 file based solely on its file extension. If it has the .mp3
extension, it is added to the mp3_files
list, which is then passed to the playlist code.
Getting input from a command line
In order to set various settings for our player script, for example, the directory in which you can search for files, we need a way to get input from the user via a command line, and in this case, from the arguments passed to the script when it is started. To do this, we will use the argparse
Python module:
parser = argparse.ArgumentParser(description='Broadcast a set of MP3s over FM') parser.add_argument( '-f', '--frequency', default=101.1, type=float, help='Frequency on which to broadcast') params = parser.parse_args()
The argparse
Python module allows you to define a set of arguments that can be passed to a Python program, it allows you to parse the arguments when the script is run, and it automatically allows you to generate a help page (accessed by passing -h
to the script).
In this case, we will add an argument for the broadcast frequency, which is set using either -f
or --frequency
; type
is used to validate input from the user, default
is what is read by the program if the user does not set a value, and help
is what is shown for this argument on the help page.
Queuing the media files to be played
Our media player will also need a way to manage which file should be played next. We will implement this in two ways: linear playback in the order the files were discovered and randomized playback:
file_number = -1 while True: if params.random: file_number = random.randint(0, len(filenames) - 1) else: file_number += 1 if file_number >= len(filenames): return play_file(filenames[file_number], params.frequency)
Here, if the --random
parameter has been passed to our script, whenever we are about to play a file, the file to be played will be selected at random using the randint
function in the random
Python module. This number is then used to get a certain file from the list of filenames that were previously discovered.
Using the media player script
The player.py
script can be invoked using the following command:
python player.py -d music -f 99.9 --random
This will search for all MP3 files under the music directory and broadcast them at 99.9 MHz in a random order. A full list of commands will be available to you if you run:
python player.py -h
Since the radio is not much of use when you have to SSH into it to start playing the music, we will add a cron job that will start the player.py
script when the Pi boots up.
To do this, we will use a shell script to start the Python script (start_player.sh
):
#!/bin/bash sleep 20 cd /home/pi python player.py -d music --random -f 99.9 &
This will ensure that the player script is executed in the correct folder, in this case, /home/pi
, as this is where our PiFM executables and music directories are.
Next, we will add an entry in the crontab, which is where cron jobs are defined. This can be edited with the following command:
sudo crontab -e
This command will open the default command-line text edit on the Pi, nano
, which will allow you to add entries to the crontab. To start our media player script, we will need to add the following line to the end of the crontab that is opened:
@reboot /home/pi/start_player.sh
In our case, we will use the @reboot
cron rule instead of specifying a time for the command to be run, and as the name suggests, this will run the given command when the OS starts.
Press Ctrl + X followed by Y and Enter to save the changes to the crontab, then use the following command to reboot the Pi, and if all goes as planned, start your personalized radio station:
sudo reboot