Abe Estrada

AudioWaveForm + AWS Lambda

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: