我正在开发一款从 youtube 下载音频的应用程序,这些音频将按顺序流式传输,类似于无线电广播。我无法让各个曲目连续播放。我的想法是将轨道顺序写入可读流,然后由 FFMPEG 读取。这是我遇到问题的代码......
import ytdl from "ytdl-core";
import ffmpeg from 'fluent-ffmpeg';
import { Readable } from "node:stream"
export async function startAudioStream(): Promise<void>{
const mainStream = await createStreamedQueue()
ffmpeg(mainStream)
.inputOptions([
'-re'
])
.outputOption([
// '-c:v libx264',
// '-preset veryfast',
// '-tune zerolatency',
'-c:a aac',
'-ar 44100',
])
.save('rtmp://localhost/live/main.flv');
};
async function createStreamedQueue(): Promise<Readable>{
function createStream(): Readable{
const stream = new Readable({
read(){},
highWaterMark: 1024 * 512,
});
stream._destroy = () => { stream.destroyed = true };
return stream;
}
const mainStream = createStream();
const ref1 = 'https://youtu.be/lLCEUpIg8rE'
const ref2 = 'https://youtu.be/bRdyzdXJ0KA';
function queueSong(src: string, stream: Readable): Promise<void>{
return new Promise<void>((resolve, reject) => {
ytdl(src, {
filter: 'audioonly',
quality: 'highestaudio'
})
.on('data', (data) => {
stream.push(data);
})
.on('end', () => {
resolve();
})
.on('error', (err) => {
console.error('Error downloading file from YouTube.', err);
reject(err);
})
})
}
await queueSong(ref1, mainStream);
// console.log('after firsrt: ', mainStream)
await queueSong(ref2, mainStream);
// console.log('after second: ', mainStream)
return mainStream;
};
开始,
startAudioStream
被调用以通过 FFMPEG 启动到 RTMP 服务器的可读音频流。那工作正常。我遇到麻烦的部分是将曲目“排队”到被馈送到 FFMPEG 的流中。现在,我有一个“主”流,每首歌曲数据都被推入其中,如您在queueSong
中所见。在 ytdl 流结束时,promise 被解决,允许下一首歌曲排队并将其数据推送到mainStream
。我遇到的问题是 ref1
的音频只播放过一次。
我可以在日志中看到,每次调用
mainStream
后,queueSong
的长度都会增加,但仍然只会从第一首曲目流式传输音频。我最初的想法是,在为每首歌曲写入 Steam 的最后一个数据块的末尾有一个终止符?但也许我对流的工作方式搞砸了......