Building a Raspberry Pi-powered Barkometer, Part 4

In the last part of this series, we started recording sound and saving it in files; now we need to get those samples off the RPi so we can analyze them.

barking main

In Part 3 of my epic series “Building a Raspberry Pi-powered Barkometer”, I covered how to capture audio using the arecord command and how I’d discovered that I got better sound out of an old USB webcam than the fancy-schmancy (but very cheap) USB sound card I started out with. I wound up in Part 3 collecting 60-second sound files in WAV format in a subdirectory on the Raspberry Pi, each named for the sample’s start time (e.g. 2016-09-07-04-42-27.wav).

We need to get these files off of the RPi so we can analyze them. In theory, this could be done on the board but for now  we’ll FTP them to another machine for analysis. So, to get the recordings to somewhere we can slice and dice them, we’re going to use ncftpput, an FTP utility included the ncftp package. To install ncftp we'll run the following command on the RPi command line (as always, when installing a new package, you should run sudo apt-get update first):

sudo apt-get install ncftp

Our recordings are in $HOME/bark so we can now FTP them to another machine using the following command line:

ncftpput -u admin \
    -p password \
    -DD \
    -V \
    ftpserver \
    /bark \

Let’s break this down (see the manual page for the ncftpput command line options):

  • -u admin and -p password are the login credentials for the target FTP server
  • -DD causes the local file to be deleted after successfully uploading it.
  • -V suppresses the display of the upload progress meter
  • ftpserver is either the IP address or name of the target FTP server
  • /bark is the remote directory to store the files in
  • $HOME/bark/*.* is the specification of the files to be FTPed

Now what we need to do is automate this so that every time a recording is completed, it gets shipped out to the FTP server. This is where we can use a really cool command, inotifywait, to monitor for changes to files and directories. inotifywait uses inotify, “a Linux kernel subsystem that acts to extend filesystems to notice changes to the filesystem, and report those changes to applications” (Wikipedia). This tool is in the package inotify-tools which is installed thusly:

sudo apt-get install inotify-tools

With inotifywait installed, we can set up a BASH script like this:

arecord -D plughw:1,0 -q --buffer-time=5000000 -f dat -c 1 -t wav --max-file-time 60 --use-strftime $HOME/bark/%Y-%m-%d-%H-%M-%S.wav &

while true
NEWFILE=`inotifywait -q --format %f -e close_write $HOME/bark`
ncftpput -u admin -p password -DD ftpserver /bark $HOME/bark/$NEWFILE

I discussed the line starting with arecord in the previous post and the & at the end of the command tells BASH to run it as a background task. The while … done creates an infinite loop and the line starting with NEWFILE breaks down as follows:

  • NEWFILE= sets a temporary environment variable
  • ` this backtick causes everything up to the next backtick to be evaluated as a whole before being passed to the command, in this case, setting the value of NEWFILE. Without this, NEWFILE would take the value “inotifywait” rather than the output of inotifywait
  • inotifywait blocks until a specific filesystem events occurs
  • -q prevents the program from printing basic status messages which we don't need
  • --buffer-time=5000000 allocates a buffer of 5 seconds (see below)
  • --format %f specifies that when the filesystem event occurs, the output from inotifywait will be the name of the file that has been affected
  • -e close_write this specifies the event to wait for, a file close
  • $HOME/bark is the subdirectory to be monitored 

So, when a file created by arecord, is closed in the $HOME/bark subdirectory, inotifywait stop blocking and print the name of the closed file which will then be stored in the environment variable NEWFILE and the script will resume. The command ncftpput will then execute and transfer the file name discovered by inotifywait to the FTP server and, voila! Job done!

Running the above BASH script on the Raspberry Pi generates output like this:

pi@RPi-01:~ $ sh 
/home/pi/bark/2016-10-01-13-18-57.wav:5.49 MB 5.28 MB/s
/home/pi/bark/2016-10-01-13-19-57.wav:5.49 MB 5.19 MB/s

Now, you may have noticed that in the parameters for arecord in the script above, I added something that wasn’t in command line I discussed in part 3. What I added was --buffer-time=5000000 because with my original arecord command line you will occasionally see overruns reported like this:

pi@RPi-01:~ $ sh 
/home/pi/bark/2016-10-01-13-18-57.wav:5.49 MB 5.28 MB/s
/home/pi/bark/2016-10-01-13-19-57.wav:5.49 MB 5.19 MB/s
/home/pi/bark/2016-10-01-13-19-57.wav:5.49 MB 5.19 MB/s
overrun!!! (at least 191.372 ms long)
/home/pi/bark/2016-10-01-13-20-57.wav:5.49 MB 5.77 MB/s
/home/pi/bark/2016-10-01-13-21-57.wav:5.49 MB 5.72 MB/s
/home/pi/bark/2016-10-01-13-22-57.wav:5.49 MB 5.79 MB/s
overrun!!! (at least 38.328 ms long) 

These errors are apparently caused by resources not being available but exactly what causes them is annoyingly mysterious. I thought that it might be due to I/O limitations of the SD card but when I tried using the /tmp subdirectory (which is RAM-based) to store that audio file I still got the same result; if you have any insight into this issue, please let me know. The solution I found was to add a 5 second buffer (the value is specified in the command line in microseconds) which fixes the problem at the cost of using a little more RAM.

Our final task in this installment is to set our script running when the RPi starts. There are multiple ways to achieve this but we’ll use one of the simplest, editing the user autostart file:

nano ~/.config/lxsession/LXDE-pi/autostart

The default desktop for Raspbian is LXDE and  the autostart file's contents will look like this unless you've made changes:

@lxpanel --profile LXDE-pi
@pcmanfm --desktop --profile LXDE-pi
@xscreensaver -no-splash

We need to add a line at the end of the file: 

@bash /home/pi/

This will invoke a new instance of BASH and have it execute our script. Because this is in the context of a user it means that the user has to be logged in so automatic login is a good idea. An important issue is that the user login can’t occur until Raspbian has completed starting all subsystems so we can be certain that, unless there’s a problem, the services we require such as a wireless connection will be established.

Now there’s lots more we can do to make the script robust such aschecking if the FTP server is accessible and taking action of some kind if it's not, logging the output of the commands we run and transferring the log to our TFP server, tidying up any WAV or log files left over from a restart, and so on but, for now, we’ve achieved our primary goal; recording the ambient audio environment and saving it to a remote server for analysis.

In the next part of this series, we’ll start figuring out how to analyze our recordings.  

Comments? Thoughts? Drop me a line or comment below then follow me on Twitter and Facebook.

Copyright © 2016 IDG Communications, Inc.

The 10 most powerful companies in enterprise networking 2022