feat: decode silk

This commit is contained in:
linyuchen 2024-06-17 16:05:38 +08:00
parent 52a065542e
commit 52850d172e
2 changed files with 48 additions and 6 deletions

View File

@ -1,9 +1,10 @@
import fs from 'fs'
import { encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm'
import fsAsync from 'fs/promises'
import fsPromise from 'fs/promises'
import { decode, encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm'
import { log } from './log'
import path from 'node:path'
import { DATA_DIR, TEMP_DIR } from './index'
import { TEMP_DIR } from './index'
import { v4 as uuidv4 } from 'uuid'
import { getConfigUtil } from '../config'
import { spawn } from 'node:child_process'
@ -79,7 +80,8 @@ export async function encodeSilk(filePath: string) {
if (code == null || EXIT_CODES.includes(code)) {
sampleRate = 24000
const data = fs.readFileSync(pcmPath)
fs.unlink(pcmPath, (err) => {})
fs.unlink(pcmPath, (err) => {
})
return resolve(data)
}
log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`)
@ -128,3 +130,41 @@ export async function encodeSilk(filePath: string) {
return {}
}
}
export async function decodeSilk(inputFilePath: string, outFormat: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac' = 'mp3') {
const silkArrayBuffer = await fsAsync.readFile(inputFilePath)
const data = (await decode(silkArrayBuffer, 24000)).data
const fileName = path.join(TEMP_DIR, uuidv4())
const outPCMPath = fileName + '.pcm'
const outFilePath = fileName + '.' + outFormat
await fsAsync.writeFile(outPCMPath, data)
const convert = () => {
return new Promise<string>((resolve, reject) => {
const ffmpegPath = getConfigUtil().getConfig().ffmpeg || process.env.FFMPEG_PATH || 'ffmpeg'
const cp = spawn(ffmpegPath, [
'-y',
'-f', 's16le', // PCM format
'-ar', '24000', // Sample rate
'-ac', '1', // Number of audio channels
'-i', outPCMPath,
outFilePath,
])
cp.on('error', (err) => {
log(`FFmpeg处理转换出错: `, err.message)
return reject(err)
})
cp.on('exit', (code, signal) => {
const EXIT_CODES = [0, 255]
if (code == null || EXIT_CODES.includes(code)) {
fs.unlink(outPCMPath, (err) => {
})
return resolve(outFilePath)
}
const exitErr = `FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`
log(exitErr)
reject(Error(`FFmpeg处理转换失败,${exitErr}`))
})
})
}
return convert()
}

View File

@ -1,5 +1,6 @@
import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile'
import { ActionName } from '../types'
import {decodeSilk} from "@/common/utils/audio";
interface Payload extends GetFilePayload {
out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
@ -8,8 +9,9 @@ interface Payload extends GetFilePayload {
export default class GetRecord extends GetFileBase {
actionName = ActionName.GetRecord
protected async _handle(payload: Payload): Promise<GetFileResponse> {
let res = super._handle(payload)
return res
protected async _handle(payload: Payload): Promise<{file: string}> {
let res = await super._handle(payload)
res.file = await decodeSilk(res.file, payload.out_format)
return {file: res.file}
}
}