A little while ago I was driving my car and a traffic report came on the radio. It gave some useful information but also a lot of information about roads I was not going to be using. As the report was trying to satisfy lots of people it ended up telling me lots of information I didn't need to know while missing out information that could be useful. I began thinking it would be great to have a personalised traffic report and given that my mobile has text to speech functionality and can connect to the Internet on the move maybe it could generate it (especially as I purchased the SVOX Victoria app which gives the mobile a rather charming accent). Digging around I found that the Highways Agency publishes some great RSS feeds for key roads so I thought I would have a go at building an app. To keep the development time for this experiment to a minimum I decided to use PhoneGap.
To use PhoneGap you need to set up your own development environment. I use Eclipse as my development environment which already had the Android Development Tools set up. To get up and running quickly with PhoneGap I used the MDS AppLaud plug in for Eclipse, a handy guide on how to get up and running with this can be found on the PhoneGap Wiki. Usefully this plugin also includes JQuery and JQuery Mobile. Previously I have experimented with using PhoneGap Build and the Ripple Emulator to build mobile apps, but we can't take this approach here as we need a bit of non standard functionality.
Sadly PhoneGap does not functionality as standard to access text-to-speech services on a phone, but Simon MacDonald has written a plugin that provides this missing functionality. It is pretty easy to use, I needed to include two files from his plugin in my project and then the text to speech service became accessible through JavaScript. So now all I needed to do was to parse the incoming RSS feed, extract the descriptions and read them out using the TTS plugin. I found Raymond Camden's post on building an RSS reader for PhoneGap very useful here. I ended up with the Javascript below.
var entries = [];
window.addEventListener('load', function() {
document.addEventListener('deviceready', function() {
window.plugins.tts.startup(startupTTS, fail);
populate();
}, false);
}, false);
function startupTTS(result) {
if (result == TTS.STARTED) {
$('#readAloud').removeClass("hidden");
$('#loading').addClass("hidden");
window.plugins.tts
.speak("Welcome to Traffic Reports, press the \"Read Aloud\" button to hear the report");
}
}
function fail(result) {
alert("Error = " + result);
console.log("Error = " + result);
}
// Modify the text here to make it easier to listen to.
function modify(text) {
// No need to keep including the year
var today = new Date();
text = text.replace(today.getFullYear(), "");
// turn "Junction J" to just "Junction"
var re = /junction J(\d+)/;
text = text.replace(re, "junction $1");
re = /junctions J(\d+) and J(\d+)/;
text = text.replace(re, "junctions $1 and $2");
return text;
}
function populate() {
$('#readAloud').on("click", function() {
for ( var entry in entries) {
window.plugins.tts.speak(modify(entries[entry]));
}
});
var RSS = "http://hatrafficinfo.dft.gov.uk/feeds/rss/AllEvents/M1.xml";
$.get(RSS, {}, function(res, code) {
entries = [];
var xml = $(res);
var title = xml.find("channel > title");
entries.push(title.text());
$("#info").text(title.text());
var description = xml.find("channel > description");
entries.push(description.text());
var items = xml.find("item");
$.each(items, function(i, v) {
entries.push($.trim($(v).find("description").text()));
});
});
}
A slight challenge with this code is that the resources it needs to work are not available immediately after the app is launched. The RSS feed must first be retrieved and processed, and the text-to-speech service needs time to initialise. The window.addEventListener block adds a handler to listen for PhoneGap's device ready event. When it gets this it starts up the TTS service and sends for the data. The descriptions from the feed and each data item are all read into an array which is read out once the user presses a button. To make the announcements easier on the ear the text is passed through the modify() function which slightly manipulates the text to my preferences (not reading out the year with every date and saying "Junction 13" instead of "Junction J13"). This section can be expanded with different rules to make the report flow a little better.