Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

linted

  • Loading branch information...
commit 977d3bd493e72e5037b70d7df88cfe438c53bfe2 1 parent b0f8d1b
Christopher Biscardi authored
6 Readme.md
View
@@ -2,14 +2,15 @@ Icecast with node
=======================
Deps:
+node v0.4.7
+
ffmpeg
lame
oggenc (vorbis-tools)
NPM:
-icecast-stack
colors
-express 2.x
+express
Step 1
==============
@@ -52,6 +53,5 @@ Will stream .ogg or .mp3 based on browser
TODO
===============
Similar artists list, client side
-make it look nicer and clean up code (jslint)
test on ipod
test on Android, (support for audio tag, no support for codecs? AKA sometimes it works, sometimes it doesn't)
2  app.js
View
@@ -8,7 +8,7 @@ require("colors");
var fs = require("fs");
var http = require("http");
var spawn = require("child_process").spawn;
-var icecast = require("icecast-stack");
+//var icecast = require("icecast-stack");
var util = require('util'),
exec = require('child_process').exec,
ffmpeg,
253 lintedapp.js
View
@@ -0,0 +1,253 @@
+
+/**
+ * Module dependencies.
+ */
+
+ var express = require('express'),
+ fs = require("fs"),
+ http = require("http"),
+ spawn = require("child_process").spawn,
+ util = require('util'),
+ exec = require('child_process').exec,
+ ffmpeg,
+ mp3,
+ ogg,
+ headers,
+ currentSongNo = 0,
+ songList = [],
+ song = '',
+ app = module.exports = express.createServer(),
+ // Ecoder stdin is expecting raw PCM data of the format:
+ SAMPLE_SIZE = 16, // 16-bit samples, Little-Endian, Signed
+ CHANNELS = 2, // 2 channels (left and right)
+ SAMPLE_RATE = 44100,// 44,100 Hz sample rate.
+
+// If we're getting raw PCM data as expected, calculate the number of bytes
+// that need to be read for `1 Second` of audio data.
+ BLOCK_ALIGN = SAMPLE_SIZE / 8 * CHANNELS, // Number of 'Bytes per Sample'
+ BYTES_PER_SECOND = SAMPLE_RATE * BLOCK_ALIGN,
+
+// Needed for throttling stdin.
+ startTime = new Date(),
+ totalBytes = 0,
+ name = "Node-Icecast-Streamer",
+ metaint = 4096,
+// Array of HttpServerResponse objects that are listening clients.
+ clients = [],
+// The max number of listening clients allowed at a time.
+ maxClients = 15,
+
+ currentTrack = "unknown",
+ currentTrackStartTime,
+ duration,
+ dId;
+
+require("colors");
+
+
+
+
+// Configuration
+
+app.configure(function(){
+ app.set('views', __dirname + '/views');
+ app.set('view engine', 'jade');
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(app.router);
+ app.use(express.static(__dirname + '/public'));
+});
+
+app.configure('development', function(){
+ app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
+});
+
+app.configure('production', function(){
+ app.use(express.errorHandler());
+});
+
+
+//FFMPEG
+//read music directory
+songList = fs.readdirSync(__dirname + '/music');
+
+
+function spawnnewffmpeg(req,res,next){
+ console.log(req.headers);
+ console.log(req.url);
+ console.log(req.params);
+ console.log("current song is" + req.params.song);
+
+ song = __dirname + '/music/' + req.params.song;
+ console.log(song);
+ var otherparams = ['-i', song, '-f', 's16le', '-acodec', 'pcm_s16le', '-ac', '2', '-ar', '44100', '-'];
+ ffmpeg = spawn('ffmpeg', otherparams);
+ //ffmpeg.stdout.on("data", outChunk)
+ ffmpeg.on('exit', function (code) {
+ console.log('ffmpeg Exit');
+ });
+ next();
+ }
+
+
+// Routes
+
+function encode(req,res,next){
+ console.log('encoder');
+ if(req.params.type === 'mp3'){
+ console.log('mp3');
+
+ headers = {
+ "Content-Type": "audio/mpeg",
+ "Connection": "close",
+ "Transfer-Encoding": "identity"
+ };
+ /* if (acceptsMetadata) {
+ headers['icy-name'] = name;
+ headers['icy-metaint'] = metaint;
+ }*/
+ res.writeHead(200, headers);
+
+ /* if (acceptsMetadata) {
+ res = new icecast.IcecastWriteStack(res, metaint);
+ res.queueMetadata(currentTrack);
+ }*/
+
+ mp3 = spawn("lame", [
+ "-S", // Operate silently (nothing to stderr)
+ "-r", // Input is raw PCM
+ "-s", SAMPLE_RATE / 1000, // Input sampling rate: 44,100
+ "-", // Input from stdin
+ "-" // Output to stderr
+ ]);
+ mp3.on("exit", function(exitCode) {
+ console.error("mp3.onExit: "+ exitCode);
+ });
+ mp3.on("error", function(error) {
+ console.error("mp3.onError: ", error);
+ });
+ mp3.stdin.on("error", function(error) {
+ console.error("mp3.stdin.onError: ", error);
+ });
+ mp3.stdout.on("error", function(error) {
+ console.error("mp3.stdout.onError: ", error);
+ });
+ mp3.stdout.on("data", function(chunk) {
+ res.write(chunk);
+ });
+
+ // Then start sending the incoming PCM data to the MP3 encoder
+ var callback = function(chunk) {
+ if (mp3.stdin.writable){
+ mp3.stdin.write(chunk);
+ }}
+ ffmpeg.stdout.on("data", callback);
+ clients.push(res);
+ // console.error((("New MP3 " + (acceptsMetadata ? "Icecast " : "") + "Client Connected: "+req.connection.remoteAddress+"!").bold + " Total " + clients.length).green);
+
+ req.connection.on("close", function() {
+ // This occurs when the HTTP client closes the connection.
+ clients.splice(clients.indexOf(res), 1);
+ ffmpeg.stdout.removeListener("data", callback);
+ mp3.kill();
+ // console.error((("MP3 " + (acceptsMetadata ? "Icecast " : "") + "Client Disconnected: "+req.connection.remoteAddress+" :(").bold + " Total " + clients.length).red);
+ });
+
+ }
+ else if(req.params.type == 'ogg'){
+ console.log('oggenc');
+ // Sorry, too busy, try again later!
+ if (clients.length >= maxClients) {
+ res.writeHead(503);
+ return res.end("The maximum number of clients ("+maxClients+") are aleady connected, try connecting again later...")
+ }
+
+ var headers = {
+ "Content-Type": "application/ogg",
+ "Connection": "close",
+ "Transfer-Encoding": "identity"
+ };
+ /* if (acceptsMetadata) {
+ headers['icy-name'] = name;
+ headers['icy-metaint'] = metaint;
+ }*/
+ res.writeHead(200, headers);
+
+ /* if (acceptsMetadata) {
+ res = new icecast.IcecastWriteStack(res, metaint);
+ res.queueMetadata(currentTrack);
+ }*/
+
+ var ogg = spawn("oggenc", [
+ "--silent", // Operate silently (nothing to stderr)
+ "-r", // Raw input
+ "--ignorelength", // Ignore length
+ "--raw-rate=" + SAMPLE_RATE, // Raw input rate: 44100
+ "-" // Input from stdin, Output to stderr
+ ]);
+ ogg.on("exit", function(exitCode) {
+ console.error("ogg.onExit: "+ exitCode);
+ });
+ ogg.on("error", function(error) {
+ console.error(error);
+ });
+ ogg.stdin.on("error", function(error) {
+ console.error("ogg.stdin.onError: ", error);
+ });
+ ogg.stdout.on("error", function(error) {
+ console.error("ogg.stdout.onError: ", error);
+ });
+ ogg.stdout.on("data", function(chunk) {
+ res.write(chunk);
+ });
+
+ // Then start sending the incoming PCM data to the OGG encoder
+ var callback = function(chunk) {
+ if (ogg.stdin.writable)
+ ogg.stdin.write(chunk);
+ }
+ ffmpeg.stdout.on("data", callback);
+ clients.push(res);
+ console.error((("New OGG " + "Client Connected: "+req.connection.remoteAddress+"!").bold + " Total " + clients.length).green);
+
+ req.connection.on("close", function() {
+ // This occurs when the HTTP client closes the connection.
+ clients.splice(clients.indexOf(res), 1);
+ ffmpeg.stdout.removeListener("data", callback);
+ ogg.kill();
+ console.error((("OGG " + "Client Disconnected: "+req.connection.remoteAddress+" :(").bold + " Total " + clients.length).red);
+ });
+ }
+ else{
+ console.log('no supported format');
+ }
+ }
+
+app.get('/', function(req, res){
+ res.render('index', {
+ title: 'Mediabox'
+ });
+});
+app.get('/music/:type/:song', spawnnewffmpeg, encode, function(req,res,next) {
+
+ });
+app.all('/json', function(req, res){
+
+});
+app.all('/playlist', function(req, res){
+ res.render('playlist', {
+ layout: false,
+ songs: songList
+ });
+ });
+
+// Only listen on $ node app.js
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log("Express server listening on port %d", app.address().port)
+}
+
+//mediatags = [{"ID3v2":{"TALB":"Promo Only Mainstream Radio September 2008","TRCK":"6","TPE1":"Katy Perry","TCON":"12","PRIV":["PCDJ GAIN","PCDJ RATING","PCDJ CD CODE"],"TIT2":"Hot N Cold"},"ID3v1":{"Title":"Hot N Cold [PO Clean Edit]","Artist":"Katy Perry","Album":"Promo Only Mainstream Radio Se","Comment":"","Genre":"Other","Year":0,"Track":6},"fullpath":"/mnt/data/Music/Shared/Katy Perry/One of the Boys/Katy Perry - Hot N Cold [PO Clean Edit].mp3"},{"©nam":"Grapevine Fires","©ART":"Death Cab For Cutie","©wrt":"Benjamin Gibbard","©alb":"Narrow Stairs","©gen":"Alternative & Punk","trkn":"7 of 11","disk":"1 of 1","©day":"2008","cpil":"false","pgap":"0","tmpo":"0","©too":"iTunes 8.2.1, QuickTime 7.6.2","----[iTunSMPB]":"00000000 00000840 00000304 0000000000A8B8BC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000","----[EncodingParams]":"hex 0x76657273 00000001 61636266 00000002 62726174 0003E800 73726371 0000007F\n \t\t\t63646376 00010606 ","----[iTunNORM]":"00000806 000009E7 000032DC 00003FAF 00033FC6 00027516 00008000 00008000 00002321 00007D55","----[iTunes_CDDB_IDs]":"11+C99902453154605CDFC831DEB6D68737+11240120","----[UFIDhttp://www.cddb.com/id3/taginfo1.html]":"3CD3N29Q159277411U26872617EBF956F428FCFDACD28940993EDP1","fullpath":"/mnt/data/Music/AJ's Music/Death Cab For Cutie/Narrow Stairs/07 Grapevine Fires.m4a"}];
+
+
16 views/index.jade
View
@@ -1,7 +1,9 @@
-h1= title
-p Welcome to #{title}
-#thePlayer
-#next Next
-#back Back
-#playlist
- ul
+.container
+ .row
+ h1= title
+ p Welcome to #{title}
+ #thePlayer
+ #next Next
+ #back Back
+ #playlist.twocol
+ ul
2  views/layout.jade
View
@@ -3,6 +3,8 @@ html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
+ link(rel='stylesheet', href='/stylesheets/1140.css')
script(type='text/javascript', src='/javascripts/jquery.min.js')
script(type='text/javascript', src='/javascripts/player.js')
+ script(type='text/javascript', src='/javascripts/css3-mediaqueries.js')
body!= body
Please sign in to comment.
Something went wrong with that request. Please try again.