
This is a port of the 5-star rated RadioTunes SDK for iOS component which was originally developed for the iOS platform. Now you can use this powerful radio streaming engine in your Appcelerator apps too and start writing radio apps in Javascript!
Behind the scenes RadioTunes relies on the iOS AudioQueue framework and the open source LGPL licensed FFmpeg library. If your app does not require mms/wma codec functionality you can also use the RadioTunes SDK without including the FFmpeg library. The code for mms streaming is completely separated from the code for http streaming so that you can choose which portions of code you want to include in your project.
Disclaimer: RadioTunes SDK can play all Window Media Audio version 9 streams but some streams based on version 10 could fail. This Appcelerator module will only work on iOS devices and does not support Android!
Be sure to check out the Radiojive Template if you want a great looking design for your radio app. This template also includes a fully working radio app that uses RadioTunes SDK!
To access this module from JavaScript, you would do the following:
var radiotunes = require("yl.radiotunes");
The radiotunes variable now holds a reference to the Module object.
The radiotunes module fires 3 events to nofity you about audio session interruptions. You should handle these events like this:
radiotunes.addEventListener('begin_interruption', function(e) {
if(myapp.radio === null) {
return;
}
myapp.radio.pause();
});
radiotunes.addEventListener('end_interruption', function(e) {
if(myapp.radio === null) {
return;
}
if(myapp.radio.isPaused()) {
myapp.radio.play();
}
});
radiotunes.addEventListener('headphone_unplugged', function(e) {
if(myapp.radio === null) {
return;
}
// Pause radio if it's playing while headphones are unplugged
if(myapp.radio.isPlaying()) {
myapp.radio.pause();
}
});
If you want to respond to the audio control buttons on the iPhone lock screen you should handle the following events:
radiotunes.addEventListener('remote_control_toggle_play_pause', function(e) {
if(myapp.radio == null) {
return;
}
if(myapp.radio.isPaused()) {
myapp.radio.play();
} else {
myapp.radio.pause();
}
});
radiotunes.addEventListener('remote_control_next_track', function(e) {
// Add code to play next radio station here.
});
radiotunes.addEventListener('remote_control_previous_track', function(e) {
// Add code to play previous radio station here.
});
Use this function to create a Radio object for http streaming.
var radio = radiotunes.createHTTPRadio("http://some-host.com/radio")
Use this function to create a Radio object for mms streaming.
var radio = radiotunes.createMMSRadio("http://some-host.com/radio")
The connection type parameter passed as argument to some of the functions must have one of the following values:
0 = All connection types
1 = WWAN connection type
2 = WiFi connection type
metadata - Fired when the Shoutcast/Icecast metadata for the radio is parsed and ready.
myapp.radio.addEventListener('metadata', function(e) {
if(e.name !== undefined) {
Ti.API.info("Radio name: " + e.name);
}
if(e.genre !== undefined) {
Ti.API.info("Radio genre: " + e.genre);
}
if(e.url !== undefined) {
Ti.API.info("Radio url: " + e.url);
}
});
title - Fired when the current playing item title is changed.
myapp.radio.addEventListener('title', function(e) {
myapp.ui.titleLabel.setText("Now playing: " + e.title);
});
state - Fired when the state of the radio object is changed.
myapp.radio.addEventListener('state', function(e) {
var state = e.state;
if(state == 0) {
myapp.ui.statusLabel.setText("Status: Stopped");
} else if(state == 1) {
myapp.ui.statusLabel.setText("Status: Connecting");
} else if(state == 2) {
myapp.ui.statusLabel.setText("Status: Buffering");
} else if(state == 3) {
myapp.ui.statusLabel.setText("Status: Playing");
} else if(state == 4) {
myapp.ui.statusLabel.setText("Status: Error");
var error = e.error;
if(error == 1) {
myapp.ui.titleLabel.setText("Playlist could not be parsed.");
} else if(error == 2) {
myapp.ui.titleLabel.setText("File stream get property failed.");
} else if(error == 3) {
myapp.ui.titleLabel.setText("File stream could not be opened.");
} else if(error == 4) {
myapp.ui.titleLabel.setText("Audio queue could not be created.");
} else if(error == 5) {
myapp.ui.titleLabel.setText("Audio buffers could not be created.");
} else if(error == 6) {
myapp.ui.titleLabel.setText("Audio queue enqueue failed.");
} else if(error == 7) {
myapp.ui.titleLabel.setText("Audio queue could not be started.");
} else if(error == 8) {
myapp.ui.titleLabel.setText("Audio decoding error.");
} else if(error == 9) {
myapp.ui.titleLabel.setText("Radio host not reachable.");
} else if(error == 10) {
myapp.ui.titleLabel.setText("Network connection error.");
}
}
});
recording_started - Fired when recording has started.
myapp.radio.addEventListener('recording_started', function(e) {
Ti.API.info("Recording started to path: " + e.path);
});
recording_stopped - Fired when recording has stopped successfully.
myapp.radio.addEventListener('recording_stopped', function(e) {
Ti.API.info("Recording available at path: " + e.path);
});
recording_failed - Fired when recording has failed.
myapp.radio.addEventListener('recording_failed', function(e) {
Ti.API.info("Recording failed: " + e.description);
var code = e.code;
if(code == 0) {
Ti.API.info("Recording failed: initialisation error");
} else if(error == 1) {
Ti.API.info("Recording failed: file error");
} else if(error == 2) {
Ti.API.info("Recording failed: format error");
} else if(error == 3) {
Ti.API.info("Recording failed: write error");
}
myapp.ui.main.recButton.setImage('record_off.png');
});
Good communication, very responsive about updates, great module!
It works perfectly without any problem.
Questions & Comments