使用 fluent-ffmpeg 与之前录制的音频重叠
Posted
技术标签:
【中文标题】使用 fluent-ffmpeg 与之前录制的音频重叠【英文标题】:Audio overlapping from previous recording with fluent-ffmpeg 【发布时间】:2020-12-04 06:44:37 【问题描述】:const Discord = require('discord.js');
const client = new Discord.Client();
const ffmpegInstaller = require('@ffmpeg-installer/ffmpeg');
const ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath(ffmpegInstaller.path);
const fs = require('fs-extra')
const mergeStream = require('merge-stream');
const config = require('./config.json');
const cp = require('child_process');
const path1 = require('path');
class Readable extends require('stream').Readable _read()
let recording = false;
let currently_recording = ;
let mp3Paths = [];
const silence_buffer = new Uint8Array(3840);
const express = require('express')
const app = express()
const port = 3000
const publicIP = require('public-ip')
const program = require('commander');
const path = require('@ffmpeg-installer/ffmpeg');
const version = '0.0.1'
program.version(version);
let debug = false
let runProd = false
let fqdn = "";
require("dotenv").config()
function bufferToStream(buffer)
let stream = new Readable();
stream.push(buffer);
return stream;
client.on('ready', async () =>
console.log(`Logged in as $client.user.tag`);
let host = "localhost"
let ip = await publicIP.v4();
let protocol = "http";
if (!runProd)
host = "localhost"
else
host = ip;
fqdn = `$protocol://$host:$port`
app.listen(port, host, () =>
console.log(`Listening on port $port for $host at fqdn $fqdn`)
)
);
let randomArr = []
let randomArr2 = []
let finalArrWithIds = []
let variable = 0
client.on('message', async message =>
if(message.content === `$record`)
finalArrWithIds = []
let membersToScrape = Array.from(message.member.voice.channel.members.values());
membersToScrape.forEach((member) =>
if(member.id === `740372581118640149`)
console.log(`botid`);
else
finalArrWithIds.push(member.id)
)
const randomNumber = Math.floor(Math.random() * 100)
randomArr = []
randomArr.push(randomNumber)
const randomNumber2 = Math.floor(Math.random() * 100)
randomArr2 = []
randomArr.push(randomNumber2)
console.log(finalArrWithIds)
console.log(`HERE IT IS !!!!!!!!!!!! $randomArr[0]`)
const generateSilentData = async (silentStream, memberID) =>
while(recording)
if (!currently_recording[memberID])
silentStream.push(silence_buffer);
await new Promise(r => setTimeout(r, 20));
return "done";
function generateOutputFile(channelID, memberID)
const dir = `./recordings/$channelID/$memberID`;
fs.ensureDirSync(dir);
const fileName = `$dir/$randomArr[0].mp3`;
return fs.createWriteStream(fileName);
if (!fs.existsSync("public"))
fs.mkdirSync("public");
app.use("/public", express.static("./public"));
if (!message.guild) return;
if (message.content === config.prefix + config.record_command)
if (recording)
message.reply("bot is already recording");
return
if (message.member.voice.channel)
recording = true;
const connection = await message.member.voice.channel.join();
const dispatcher = connection.play('./audio.mp3');
connection.on('speaking', (user, speaking) =>
if (speaking.has('SPEAKING'))
currently_recording[user.id] = true;
else
currently_recording[user.id] = false;
)
let members = Array.from(message.member.voice.channel.members.values());
members.forEach((member) =>
if (member.id != client.user.id)
let memberStream = connection.receiver.createStream(member, mode : 'pcm', end : 'manual')
let outputFile = generateOutputFile(message.member.voice.channel.id, member.id);
console.log(outputFile);
mp3Paths.push(outputFile.path);
silence_stream = bufferToStream(new Uint8Array(0));
generateSilentData(silence_stream, member.id).then(data => console.log(data));
let combinedStream = mergeStream(silence_stream, memberStream);
ffmpeg(combinedStream)
.inputFormat('s32le')
.audioFrequency(48000)
.audioChannels(2)
.on('error', (error) => console.log(error))
.audioCodec('libmp3lame')
.format('mp3')
// .audioFilters('silenceremove=stop_periods=-1:stop_duration=1:stop_threshold=-90dB')
.pipe(outputFile)
)
else
message.reply('You need to join a voice channel first!');
if (message.content === config.prefix + config.stop_command)
let currentVoiceChannel = message.member.voice.channel;
if (currentVoiceChannel)
recording = false;
await currentVoiceChannel.leave();
let mergedOutputFolder = './recordings/' + message.member.voice.channel.id + `/$randomArr[0]/`;
fs.ensureDirSync(mergedOutputFolder);
let file_name = `$randomArr[0]` + '.mp3';
let mergedOutputFile = mergedOutputFolder + file_name;
let download_path = message.member.voice.channel.id + `/$randomArr[0]/` + file_name;
let mixedOutput = new ffmpeg();
mp3Paths.forEach((mp3Path) =>
mixedOutput.addInput(mp3Path);
)
//mixedOutput.complexFilter('amix=inputs=2:duration=longest');
mixedOutput.complexFilter('amix=inputs=' + mp3Paths.length + ':duration=longest');
function saveMp3(mixedData, outputMixed)
return new Promise((resolve, reject) =>
mixedData.on('error', reject).on('progress',
(progress) =>
console.log('Processing: ' + progress.targetSize + ' KB converted');
).on('end', () =>
console.log('Processing finished !');
resolve()
).saveToFile(outputMixed);
)
// mixedOutput.saveToFile(mergedOutputFile);
await saveMp3(mixedOutput, mergedOutputFile);
// We saved the recording, now copy the recording
if (!fs.existsSync(`./public`))
fs.mkdirSync(`./public`);
let sourceFile = `$__dirname/recordings/$download_path`
console.log(`DOWNLOAD PATH HERE $download_path`)
const guildName = message.guild.id;
const serveExist = `/public/$guildName`
if (!fs.existsSync(`.$serveExist`))
fs.mkdirSync(`.$serveExist`)
let destionationFile = `$__dirname$serveExist/$member-$file_name`
let errorThrown = false
try
fs.copySync(sourceFile, destionationFile);
catch (err)
errorThrown = true
await message.channel.send(`Error: $err.message`)
if (!errorThrown)
message.channel.send(`Link to full recording located at: $fqdn/public/$guildName/$member-$file_name`);
else
message.reply('You need to join a voice channel first!');
else
if (message.content.split(/\r\n|\r|\n/).length > config.line_length_limit && config.channel_name_log.includes(message.channel.name))
file = `./recordings/$'text_logs'/$message.member.id/logs.txt`;
fs.ensureFileSync(file);
fs.appendFileSync(file, 'Channel: ' + message.channel.name + '\n' + message.createdAt + '\n' + message.content + '\n\n');
let date = [`a`,`b`,`c`,`d`]
let tmp_file_name = date[0] + date[1] + date[2];
let daily_file = `./recordings/$'text_logs'/$tmp_file_name.txt`;
fs.ensureFileSync(daily_file);
fs.appendFileSync(daily_file, 'Channel: ' + message.channel.name + '\n' + message.createdAt + '\n' + message.content + '\n\n');
);
async function main()
program.option('-debug')
program.option('-prod')
program.parse(process.argv)
console.log(program.opts())
if (program.Debug != undefined)
debug = !debug
if (program.Prod != undefined)
runProd = !runProd
if (runProd)
client.login(process.env.DISCORD_TOKEN_PROD).catch(e =>
console.log("ERROR")
console.log(e)
)
else
client.login(process.env.DISCORD_TOKEN_TEST).catch(e =>
console.log("ERROR")
console.log(e)
)
main()
所以我正在开发一个不和谐的机器人,它会在用户写入 !record 时在语音通道中记录用户的音频,并在他们写入 !stop 时停止录制。
现在,问题是如果你录制一次完全没问题,但是当你第二次录制时,randomArr[0]
文件夹中的文件也有之前录制的音频重叠,为什么会发生这种情况?如果我重新启动服务器,那么它工作正常,直到我记录第二次..
【问题讨论】:
【参考方案1】:把它修好了。 mp3Paths 提出了问题, 必须在记录消息事件中清空它。 修复了它。
【讨论】:
以上是关于使用 fluent-ffmpeg 与之前录制的音频重叠的主要内容,如果未能解决你的问题,请参考以下文章