icecast-stack
Version:
A `StreamStack` implementation for parsing and/or injecting metadata with SHOUTcast/Icecast radio streams.
68 lines (58 loc) • 2.47 kB
JavaScript
var net = require('net')
, parse = require('url').parse
, HttpRequestStack = require('http-stack').HttpRequestStack
, IcecastReadStack = require('./icecast-stack').IcecastReadStack
/**
* A full-blown Icecast/SHOUTcast compliant Client class. Conveniently takes
* care of creating a low-level TCP connection, sending an HTTP request, and
* filtering the 'metadata' events out of the resulting audio stream.
*/
function Client(url, headers, retainMetadata) {
// parse the URL into a usable object
var parsedUrl = parse(url);
// ensure an HTTP based path and port
parsedUrl.pathname = parsedUrl.pathname || '/';
parsedUrl.port || (parsedUrl.port = parsedUrl.protocol == "https:" ? 443 : 80);
// Create the low-level TCP connection to the remote server.
var stream = net.createConnection(parsedUrl.port, parsedUrl.hostname);
stream.allowHalfOpen = true;
stream.remoteAddress = parsedUrl.hostname;
stream.remotePort = parsedUrl.port;
// Stack an 'HttpRequstStack' instance on it, and send an HTTP request
// to the specified URL.
stream = new HttpRequestStack(stream);
headers.push('Host: ' + parsedUrl.host);
headers.push('Icy-MetaData: 1');
stream.get(parsedUrl.pathname, headers);
stream.end();
// Next stack "this" 'IcecastReadStack' instance on top of that, setting the
// inital 'metaint' value to Infinity. Setting to Infinity is just a hack
// that allows us to have the 'createClient' function return immediately,
// instead of invoking a callback with the stream instance.
IcecastReadStack.call(this, stream, Infinity, retainMetadata);
// Keep a reference to the URL used to connect to the Icecast server.
this.url = url;
// When the 'response' event is fired (bubbled down from the
// HttpRequestStack instance), check for the 'icy-metaint' response header.
this.on('response', function(res) {
this.headers = res.headers;
if (res.headers['icy-metaint']) {
this.metaint = Number(res.headers['icy-metaint']);
}
});
}
exports.Client = Client;
require('util').inherits(Client, IcecastReadStack);
/**
* Convenience function to create a new Icecast 'Client' instance.
*/
function createClient(url, headers, retainMetadata) {
if (headers === true || headers === false) {
retainMetadata = headers;
headers = [];
} else if (!Array.isArray(headers)) {
headers = [];
}
return new Client(url, headers, retainMetadata);
}
exports.createClient = createClient;