Detección de ruido con ARecord

Publicado el 16 diciembre 2023 por Alejsanc @cdrninformatica

En el artículo Cámara 4G y WiFi con Raspberry Pi expliqué como configurar el software Motion para detectar movimientos. Además de la imagen también nos puede interesar monitorizar el sonido mediante un micrófono para detectar ruidos con un volumen fuera de lo normal.

ALSA (Advanced Linux Sound Architecture) es el sistema de audio de Linux. Este sistema tiene varias utilidades que podemos utilizar para escuchar y grabar el sonido. Mediante el programa alsamixer podemos modificar el volumen de captura de los micrófonos conectados al ordenador.

┌───────────────────────────── AlsaMixer v1.2.8 ─────────────────────────────┐
│ Card: USB PnP Audio Device                         F1:  Help               │
│ Chip: USB Mixer                                    F2:  System information │
│ View: F3: Playback  F4:[Capture] F5: All           F6:  Select sound card  │
│ Item: Mic [dB gain: 21.51]                         Esc: Exit               │
│                                                                            │
│                                    ┌──┐                                    │
│                                    │  │                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                    │▒▒│                                    │
│                                   L└──┘R                                   │
│                                  CAPTURE                                   │
│                                     95                                     │
│                                 <  Mic   >                                 │
└────────────────────────────────────────────────────────────────────────────┘

El programa arecord nos permite grabar audio. Con el parámetro -l muestra las tarjetas y dispositivos de audio capaces de capturar audio. Con el parámetro -L muestra las diferentes formas de acceder a los dispositivos.

# arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: Device [USB PnP Audio Device], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
# arecord -L
null
    Discard all samples (playback) or generate zero samples (capture)
hw:CARD=Device,DEV=0
    USB PnP Audio Device, USB Audio
    Direct hardware device without any conversions
plughw:CARD=Device,DEV=0
    USB PnP Audio Device, USB Audio
    Hardware device with all software conversions
default:CARD=Device
    USB PnP Audio Device, USB Audio
    Default Audio Device
sysdefault:CARD=Device
    USB PnP Audio Device, USB Audio
    Default Audio Device
front:CARD=Device,DEV=0
    USB PnP Audio Device, USB Audio
    Front output / input
dsnoop:CARD=Device,DEV=0
    USB PnP Audio Device, USB Audio
    Direct sample snooping device

Con el parámetro -D se le indica al programa el método de acceso. dsnoop permite que varios procesos graben del dispositivo simultáneamente. A continuación se le pasan dos números separados por una coma que indican el número de tarjeta y el número de dispositivo dentro de la tarjeta. Tanto las tarjetas como los dispositivos se empiezan a contar desde 0. En mi caso tengo un micrófono USB que es la segunda tarjeta del sistema (1) y solo tiene un dispositivo (0).

Los parámetros -f y -r fijan el formato de grabación y la frecuencia de muestreo. El parámetro -V muestra el volumen en mono o estéreo. Con -q el programa no muestra mensajes al inicio y solo se ve el indicador de volumen. Al final se indica el archivo donde grabar el audio. Si no queremos grabarlo lo podemos enviar a /dev/null.

# arecord -D dsnoop:1,0 -f S16_LE -r 44100 -V mono -q /dev/null
###########   +                                    | 27%

La salida de este programa la podemos leer en un "script" con un bucle infinito. Cada línea de volumen tiene 57 caracteres. Descartamos los primeros 54 caracteres y a continuación leemos los dos caracteres del número del volumen. Por último descartamos el carácter "%".

while read -n 54
do
    read -n 2 volume

    read -n 1
done

Podemos fijar un máximo de volumen y cuando se supere realizar acciones como grabar unos segundos de audio y enviarlos a una dirección de correo electrónico para informar del suceso. Al superarse el máximo se sale del bucle y se graba el audio. El archivo de audio lo podemos enviar por correo electrónico con un programa como s-nail.

#!/usr/bin/bash

DIRECTORY=/var/lib/noise-detection
MAX_VOLUME=75
RECORD_SECONDS=10
MICROPHONE=dsnoop:1,0

while read -n 54
do
    read -n 2 volume

    if [[ $volume > $MAX_VOLUME ]]
    then
        break
    fi

    read -n 1

done < &1)

datetime=`date +%F_%H-%M-%S`
record=$DIRECTORY/$datetime.wav
message="ND $datetime"

arecord -D $MICROPHONE -f S16_LE -r 44100 -q -d $RECORD_SECONDS $record
echo "$message" | s-nail -A cuenta-correo -s "$message" -a $record usuario@example.com

El "script" se puede guardar en /usr/local/bin y darle permisos de ejecución. Para ejecutarlo automáticamente en el inicio del sistema podemos crear un servicio de systemd. Ese servicio se debe ejecutar con un usuario perteneciente al grupo audio para que tenga acceso al micrófono. También debe tener permisos de escritura en el directorio donde se van a guardar los audios grabados. Cuando termina el "script" el servicio se encarga de reiniciarlo para seguir monitorizando el volumen.

# cp noise-detection.sh /usr/local/bin
# chmod +x /usr/local/bin/noise-detection.sh

# adduser noise-detection
# usermod -a -G audio noise-detection

# mkdir /var/lib/noise-detection
# chown noise-detection:noise-detection /var/lib/noise-detection/

# vi /lib/systemd/system/noise-detection.service

[Unit]
Description=Noise Detection
Requires=systemd-udev-settle.service
After=systemd-udev-settle.service

[Service]
Type=simple
User=noise-detection
ExecStart=/usr/local/bin/noise-detection.sh
Restart=always

[Install]
WantedBy=multi-user.target

# systemctl enable noise-detection

De esta forma ya tenemos un sencillo sistema para detectar ruidos por encima de un determinado volumen y enviar un correo electrónico informando del suceso.