Reputation: 1709
I'm trying to stream a custom mp3 datastream to Icecast2. Icecast recognises there's a mountpoint, however the streamed data won't play and I have no idea why.
import ffmpeg from 'fluent-ffmpeg';
import { request } from 'node:http';
const req = request(
{
host: 'localhost',
port: 8000,
path: '/radio',
method: 'PUT',
auth: 'source:password',
headers: {
'Content-Type': 'audio/mpeg',
Expect: '100-continue',
'Ice-Public': 0,
'Ice-Name': 'Testing Stream!',
'Ice-Description': 'Testing Stream!',
'Ice-Genre': 'Various',
'Icy-MetaData': 1
//'Icy-MetaInt': metaInt
}
},
(res) => {
console.log('Server responded with status code:', res.statusCode);
res.on('data', (chunk) => {
console.log('Response chunk:', chunk.toString());
});
}
);
req.on('error', (err) => {
console.error('Error streaming to Icecast server:', err);
});
req.on('close', () => {
console.error('Icecast server closed connection');
process.exit(1);
});
req.on('continue', () => {
console.log('Continue event received');
ffmpeg({ source: 'test.mp3' })
.native()
.outputOption(['-map 0:a'])
.audioBitrate(320)
.audioCodec('libmp3lame')
.audioFrequency(44100)
.audioChannels(2)
.format('mp3')
.on('progress', (progress) => {
console.log('Is open:' + req.socket.writable + ' - ' + progress.timemark);
})
.on('start', function (commandLine) {
console.log('Spawned Ffmpeg with command: ' + commandLine);
})
.on('end', () => {
console.log('Processing finished !');
req.end();
})
.on('error', (err) => {
console.error('FFmpeg error:', err);
})
.pipe(req);
});
Note that when I try to do this with ffmpeg using the icecast protocol, it works without issues: ffmpeg -re -i test.mp3 -b:a 320k -acodec libmp3lame -ar 44100 -ac 2 -map 0:a -f mp3 icecast://source:password@localhost:8000/radio
. It looks like something is not right with request
.
Upvotes: 1
Views: 38
Reputation: 1709
I implemented a lower-lever version, using createConnection instead of going through the request. This works.
import ffmpeg from 'fluent-ffmpeg';
import { Writer } from 'icy';
import { createReadStream, createWriteStream } from 'node:fs';
import { request } from 'node:http';
import { createConnection } from 'node:net';
const METAINT = 8192;
const socket = createConnection(8000, '127.0.0.1', () => {
let auth = Buffer.from('source:password').toString('base64');
let headers = `PUT /radio HTTP/1.1\r\n`;
headers += `Host: 127.0.0.1:8000\r\n`;
headers += `Authorization: Basic ${auth}\r\n`;
headers += `User-Agent: Streamline/0.1\r\n`;
headers += `Content-Type: audio/mpeg\r\n`;
headers += `Expect: 100-continue\r\n`;
headers += `Ice-Public: 0\r\n`;
headers += `Ice-Name: Testing Stream\r\n`;
headers += `Ice-Description: Testing Stream\r\n`;
headers += `Ice-Genre: Various\r\n`;
headers += `Icy-MetaInt: ${METAINT}\r\n`;
headers += `\r\n`;
socket.write(headers);
socket.on('data', (data) => {
if (data.toString().includes('HTTP/1.1 100 Continue')) {
console.log('Continue event received');
const icyWriter = Writer(METAINT, {});
ffmpeg(createReadStream('test.mp3'))
.native()
.outputOptions(['-map 0:a'])
.audioCodec('libmp3lame')
.audioBitrate(320)
.audioFrequency(44100)
.audioChannels(2)
.format('mp3')
.on('progress', (progress) => {
console.log('Is open:' + socket.writable + ' - ' + progress.timemark);
})
.on('start', (commandLine) => {
console.log('Spawned Ffmpeg with command: ' + commandLine);
})
.on('end', () => {
console.log('Processing finished!');
socket.end();
})
.on('error', (err) => {
console.error('FFmpeg error:', err);
})
.pipe(icyWriter);
icyWriter.on('data', (chunk) => {
socket.write(chunk);
});
setInterval(() => {
icyWriter.queue('Alice DJ - Better Off Alone');
}, 5000);
}
});
});
Upvotes: 0