lambda-audio
lambda-audio copied to clipboard
Error: spawn /tmp/soxi ENOENT
Hello,
I think I will need your help with my issue. I'm using serverless framework and have lambda function that downloads mp3 file from a bucket, then saves it in /tmp/input.mp3
Next I'm executing code:
import lambdaAudio from 'lambda-audio'
const doAudioMagic = () => {
console.log('executing soxi')
lambdaAudio.soxi('/tmp/input.mp3')
.then(response => {
// Do something with the info
console.log(response)
})
.catch(errorResponse => {
console.log('Error from the soxi command:', errorResponse)
})
}
And I get following error:
Error: spawn /tmp/soxi ENOENT
at exports._errnoException (util.js:1018:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:193:32)
at onErrorNT (internal/child_process.js:367:16)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
So the soxi file is not present the the path, but why? How should I "install" lambda-audio so the file is properly copied to the /tmp/ path?
Hey, it's possible that input.mp3 is not present at that location at the moment you are executing soxi. Can you do following:
- Check if index.mp3 exists (ie. log
fs.existsSync('/tmp/input.mp3')
). - Check if
sox
works,soxi
is just a symlink to it, ifsox
works it's a symlink issue. - If file exists, please provide a minimal project that I can run and reproduce the issue.
Thanks
Hi @stojanovic
I changed soxi to lame, the effect is the same:
Here is my lambda function code
// eslint-disable-next-line import/prefer-default-export
import {getS3File, uploadToBucket} from "./Common"
// import lambdaAudio from 'lambda-audio'
import fs from 'fs'
export const main = (event, context, callback) => {
const p = new Promise((resolve) => {
resolve('success');
});
console.log('Extract info from mp3')
console.log('Input data', event)
const doAudioMagic = () => {
const lambdaAudio = require('lambda-audio')
console.log('executing lambda-audio')
lambdaAudio.lame('-b 64 /tmp/input.mp3 /tmp/output.mp3')
.then(response => {
fs.readFile("/tmp/output2.mp3", (err, file) => {
if (err) throw err;
console.log(data);
uploadToBucket(event.bucket, 'output2.mp3', file, '', data.ContentType)
.then(console.log('Uploaded'))
})
})
.catch(errorResponse => {
console.log('Error from the lame command:', errorResponse)
})
}
const processFile = data => {
fs.writeFile("/tmp/input.mp3", data.Body, function (err) {
if (err) {
return console.log(err);
}
console.log("File saved successfully!");
const mp3Exists = fs.existsSync('/tmp/input.mp3')
console.log('result of fs.existsSync(\'/tmp/input.mp3\'): ', mp3Exists)
console.log('Readdir /tmp')
fs.readdirSync('/tmp/').forEach(console.log)
if (mp3Exists) {
doAudioMagic()
}
})
}
const data = getS3File(event.bucket, event.key, processFile)
const results = {
message: 'Go Serverless Step Function',
}
p
.then(() => callback(null, JSON.stringify(results)))
.catch(e => callback(e));
};
and the logs
Extract info from mp3
Input data { bucket: 'REDACTED', key: 'REDACTED.mp3' }
getS3File with those params: REDACTED.mp3 from REDACTED
File saved successfully!
result of fs.existsSync('/tmp/input.mp3'): true
Readdir /tmp
input.mp3 0 [ 'input.mp3' ]
executing lambda-audio
Error: spawn /bin/lame ENOENT
at exports._errnoException (util.js:1018:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:193:32)
at onErrorNT (internal/child_process.js:367:16)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
Looks like soxi
, sox
, and lame
files are not copied over to /tmp/
directory. But why?
Hm, are you using babel?
If you are using "files" in package.json it's possible that you are not deploying sox at all. It shouldn't be in /tmp, sox is bundled with the module, but soxi is symlink, and lib creates it in /tmp because npm pack
ignores symlinks and Claudia.js that I am using is using npm pack
under the hood.
Can you try without babel or make sure sox is deployed? ie. code can look like this (not tested):
// eslint-disable-next-line import/prefer-default-export
cons {getS3File, uploadToBucket} = require('./Common')
const lambdaAudio = require('lambda-audio')
const fs = require('fs')
function doAudioMagic() {
return lambdaAudio.lame('-b 64 /tmp/input.mp3 /tmp/output.mp3')
.then(response => {
// This is ok, because Lambda function is not doing anything else anyway
const file = fs.readFile('/tmp/output2.mp3')
return uploadToBucket(event.bucket, 'output2.mp3', file, '', data.ContentType)
}
function processFile(data) {
return new Promise((resolve, reject) => {
fs.writeFile('/tmp/input.mp3', data.Body, (err, file) => {
if (err) {
return reject(err)
}
return file
})
})
}
exports.handler = function(event, context, callback) {
getS3File(event.bucket, event.key, processFile)
.then(data => processFile(data))
.then(() => doAudioMagic())
.then(() => {
const results = { message: 'Go Serverless Step Function' }
callback(null, JSON.stringify(results))
})
.catch(e => callback(e));
}
Hi, I'm using serverless framework with aws-nodejs-ecma-script https://github.com/serverless/serverless/tree/master/lib/plugins/create/templates/aws-nodejs-ecma-script which automatically transpiles code using webpack
I'll try your code today
Hm, I am not sure what that template sends to AWS Lambda, but you need to make sure that sox exists. You can probably download it from S3 as an alternative.
Hi @stojanovic
Finally, I managed to include sox
and lame
binaries in the generated .zip
that is uploaded into lambda. Unfortunately, I still have problems, though.
No matter if the contents of the zip file are like that:
unzip -l .serverless\musicquiz.zip
Archive: .serverless\musicquiz.zip
Length Date Time Name
--------- ---------- ----- ----
484896 1980-01-01 00:00 bin/lame
2913860 1980-01-01 00:00 bin/sox
763687 1980-01-01 00:00 ExtractInfo.js
3316 1980-01-01 00:00 SaveIntoDynamo.js
3062571 1980-01-01 00:00 TriggerOrchestrator.js
--------- -------
7228330 5 files
or
Archive: .serverless\musicquiz.zip
Length Date Time Name
--------- ---------- ----- ----
763689 1980-01-01 00:00 ExtractInfo.js
484896 1980-01-01 00:00 node_modules/lambda-audio/bin/lame
2913860 1980-01-01 00:00 node_modules/lambda-audio/bin/sox
3316 1980-01-01 00:00 SaveIntoDynamo.js
3062571 1980-01-01 00:00 TriggerOrchestrator.js
--------- -------
7228332 5 files
I still get the same error from lambda function:
Error: spawn /bin/lame ENOENT
at exports._errnoException (util.js:1018:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:193:32)
at onErrorNT (internal/child_process.js:367:16)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
Files are available to the functions. Following code:
const myPath = "bin/lame"
console.log(`File ${myPath} exists ${fs.existsSync(myPath)}`)
console.log(`File /${myPath} exists ${fs.existsSync('/'+myPath)}`)
generates:
File bin/lame exists true
File /bin/lame exists false
So I think this is just a matter of putting sox
and lame
files in proper path in the zip file, so they are where lambda-audio
expectes them to be.
Could you please tell me where those files should be located? Where they are in the .zip
file generated by ClaudiaJS?