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
@ChristopherBiscardi authored
View
6 Readme.md
@@ -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)
View
2  app.js
@@ -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,
View
253 lintedapp.js
@@ -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"}];
+
+
View
16 views/index.jade
@@ -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
View
2  views/layout.jade
@@ -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.