问题
In the following example what I'm trying to do is initialize a unique stream for each client that connects to the server and serve that stream to the client through html5's audio tag. Because I want a live experience I'm attempting to write the latest buffer from my transcoding to the output of the audio stream. For testing purposes I'm grabbing NPRs public stream, transcoding it via transcode.sh to speex, and serving it to my clients.
The issue is that when I connect, the transcoded stream doesn't play through the audio tag. If I attempt to open the stream through vlc using localhost:3002/stream, node outputs the following error messages several times and also doesn't play the stream.
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
at ServerResponse.EventEmitter.addListener (events.js:160:15)
at Stream.pipe (stream.js:121:8)
at CustomEmitter.<anonymous> (~/nodejs/audio_stream/sample.js:62:5)
at CustomEmitter.EventEmitter.emit (events.js:95:17)
at CustomEmitter.stream (~/nodejs/audio_stream/sample.js:23:7)
at Socket.<anonymous> (~/nodejs/audio_stream/sample.js:32:11)
at Socket.EventEmitter.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:720:14)
at Socket.EventEmitter.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:392:10)
I'm guessing that my issue has to do with how I'm writing to /stream but I'm not really sure. What exactly am I doing wrong?
Here is the sample code:
transcode.sh:
#!/bin/bash
ffmpeg -i "$1" -f ogg -acodec libspeex -ar 8000 -af 'volume=5.0' 2>/dev/null pipe:1
sample.js:
// contents of transcode.sh script:
// #!/bin/bash
// ffmpeg -i "$1" -f ogg -acodec libspeex -ar 8000 -af 'volume=5.0' 2>/dev/null pipe:1
var express = require('/usr/local/lib/node_modules/express');
var http = require('http');
var spawn = require('child_process').spawn;
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var fs = require('fs');
var stream = require('stream');
var app = express();
var webServer = http.createServer(app);
var audServer = http.createServer(app);
function CustomEmitter() {
EventEmitter.call(this);
}
util.inherits(CustomEmitter, EventEmitter);
CustomEmitter.prototype.stream = function(data) {
this.emit('stream', data);
};
var emitter = new CustomEmitter();
function getStream(arg1,arg2) {
var cmd = spawn(arg1,arg2);
//cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
emitter.stream(data);
});
}
app.get('/', function(req, res){
res.send(
"<script src='/socket.io/socket.io.js'></script>\n"+
"<script>var socket=io.connect('http://127.0.0.1:3000');</script>\n"+
"<script>\n"+
"\tsocket.on('id', function(data) {\n"+
"\t\taudio = document.getElementById('webStream');\n"+
"\t\taudio.setAttribute(\"src\",'http://127.0.0.1:3002/stream);\n"+
"\t});\n"+
"</script>\n"+
"<audio id='webStream' autoplay=\"autoplay\" controls=\"controls\"></audio>"
);
});
webServer.listen(3000);
app.get('/stream', function(req, res){
getStream('./transcode.sh',['http://nprdmp.ic.llnwd.net/stream/nprdmp_live01_mp3']);
res.header('Content-Type', "audio/ogg");
res.header('Transfer-Encoding', 'chunked');
var s = new stream.Stream();
s.readable = true;
emitter.on('stream', function(data) {
s.emit('data', data);
s.pipe(res);
});
});
audServer.listen(3002);
回答1:
The structure of the code looks incorrect for me. The major issue is how the emitter
is used. The code in the /stream
handler constantly adds listener on the stream
event and never removes it. So it is a kind of JavaScript memory leak. I think that a better approach might be returning an event emitter by the method getStream and attaching event handler to it.
来源:https://stackoverflow.com/questions/20205335/node-serving-unique-audio-streams-causing-possible-eventemitter-memory-leak-err