Mientras hacía una investigación sobre reproductores de audio en la web, observe que varios utilizan un patrón con las ondas de audio, algunos muestran ondas de audio falsas y otros utilizan las reales.
La BBC tiene una aplicación para generar imagenes de estas ondas directamente de un archivo de audio llamada bbc/audiowaveform . En mi caso no puedo procesar cada archivo manualmente, por lo que me dí a la tarea de automatizar el proceso y ejecutar una función en AWS Lambda para cada archivo que es subido a un bucket de S3.
Para poder ejecutar audiowaveform
en AWS Lambda, primero debemos compilar el ejecutable para esta plataforma. Existe un script
utilizando Docker para amd64
, para poder utilizarlo con arm64
es necesario hacerle algunos cambios, como por ejemplo utilizar la imagen linux/arm64/v8
de amazonlinux:2
.
-FROM --platform=linux/amd64 amazonlinux:2
+FROM --platform=linux/arm64/v8 amazonlinux:2
Otro cambio necesario es agregar --build=aarch64-unknown-linux-gnu
a cada renglón con ./configure
.
-./configure --disable-shared --libdir=/lib64
+./configure --disable-shared --libdir=/lib64 --build=aarch64-unknown-linux-gnu
Y por último, cambiar la versión de audiowaveform
a la más reciente (hasta que se escribió este post).
-AWF_VERSION=1.7.1
+AWF_VERSION=1.8.1
Una vez que se tienen eso cambios, se ejecuta npm run build
y npm run install
y obtenemos un ejecutable en el folder bin/
el cual vamos a comprimir utilizando zip para poder subirlo a AWS Lambda Layers y que vamos a agregar a la función donde vamos a ejecutar el siguiente código:
import { promisify } from "util";
import { exec } from "child_process";
import { writeFile, readFile } from "fs/promises";
import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
const execute = promisify(exec);
const client = new S3Client({ region: "us-east-1" });
export const handler = async () => {
try {
// Obtenemos el archivo de audio de S3
const s3GetObjectCommand = new GetObjectCommand({
Bucket: "audiobucket",
Key: "files/audio.mp3"
});
const s3GetObject = await client.send(s3GetObjectCommand);
// Lo guardamos en un espacio temporal
await writeFile('/tmp/audio.mp3', s3GetObject.Body);
// Ejecutamos audiowaveform y guardamos el resultado
await execute("audiowaveform --bits 8 --pixels-per-second 20 -i /tmp/audio.mp3 -o /tmp/audiowaveform.json");
// Leemos el resultado
const data = await readFile("/tmp/audiowaveform.json", "utf8");
// Guadamos el resultado en S3
const s3PutObjectCommand = new PutObjectCommand({
Bucket: "audiobucket",
Key: "files/audiowaveform.json",
Body: data,
});
const s3PutObject = await client.send(s3PutObjectCommand);
return {
statusCode: 200,
body: "success",
};
}
catch (err) {
console.error(err);
return {
statusCode: 500,
body: JSON.stringify(err, null, 2),
};
}
};
La función va a obtener un archivo de audio, lo va a guardar temporalmente para luego ejecutar audiowaveform
que va a generar un archivo json con la información y luego ese archivo se va a guardar en S3 para posteriormente poder utilizarlo donde sea necesario.
Referencias: