web-dev-qa-db-fra.com

Fichier audio de tuyau Linux vers l'entrée microphone

Je cherche un moyen d'alimenter les données audio d'un fichier dans le microphone donc quand des applications tierces (comme sont enregistrées ou la recherche vocale de Chromium "fonctionnalité) utiliser le microphone pour l'entrée audio, ils reçoivent à la place les données audio du fichier.

Voici mon scénario: Une application que j'ai écrite enregistre les données audio du microphone (en utilisant ALSA) et les enregistre dans un fichier (audioFile0.raw). À un moment inconnu dans le futur, une application tierce inconnue (comme dans quelque chose que je n'ai pas développé, donc je n'ai aucun contrôle sur le développement, comme la fonction "recherche vocale" du navigateur Web Chromium) utilisera le microphone pour obtenir des données audio. Je voudrais que les données audio que l'application tierce recueille proviennent de audioFile.raw plutôt que du microphone lui-même.

Je me demandais s'il était possible de changer le périphérique d'entrée audio par défaut en un fichier audio, ou peut-être un canal nommé et de faire quelque chose comme cat audioFile0.raw > mypipe (puisque je ne sais pas quand une autre application essaiera de lire depuis le microphone). Peut-être existe-t-il un moyen plus simple de procéder?

J'espère avoir fourni suffisamment de détails et de clarté. Veuillez me faire savoir si quelque chose n'est pas clair.


EDIT: J'ai donc compris comment créer un microphone virtuel en créant le fichier .asoundrc suivant dans mon répertoire personnel:

pcm.!virtmic {
    type file
    slave.pcm "hw:0,0"
    file /dev/null
    infile "/home/charles/audioFiles/audioFile0.raw"
}

pcm.!default {
    type hw
    card 0
}

ctl.!default {
    type hw
    card 0
}

J'appelle ensuite arecord test.raw -c 1 -f S16_LE -r 16000 -t raw -D virtmic à partir de la ligne de commande et je peux enregistrer les données audio qui sont dans audioFile0.raw à test.raw.

Mon objectif est maintenant de remplacer le périphérique par défaut par mon microphone virtuel afin que toute application accédant au microphone lise les données audio dans audioFile0.raw au lieu du microphone lui-même. J'ai donc édité mon fichier .asoundrc pour qu'il apparaisse comme suit:

pcm.!virtmic {
    type file
    slave.pcm "hw:0,0"
    file /dev/null
    infile "/home/charles/audioFiles/audioFile0.raw"
}

pcm.!default {
    type asym
    playback.pcm {
        type hw
        card 0
    }
    capture.pcm {
       type plug
       slave.pcm "virtmic"
    }
}

ctl.!default {
    type hw
    card 0
}

Ensuite, j'ai appelé arecord test.raw -c 1 -f S16_LE -r 16000 -t raw depuis la ligne de commande. J'ai ensuite relu test.raw mais il semblait enregistrer à partir du microphone lui-même et non audioFile0.raw.

Qu'est-ce que je fais mal? Comment changer exactement le périphérique de capture par défaut pour qu'il lise les données de audioFile0.raw plutôt que l'entrée du microphone?


EDIT 2: D'accord, j'étais donc sur la bonne voie. J'utilise le même fichier .asoundrc dans mon répertoire personnel que j'ai montré plus tôt où j'ai changé le périphérique par défaut pour être virtmic. Je devais changer le fichier /usr/share/alsa/alsa.conf.d/Pulse.conf donc ça ressemble à ça:

# PulseAudio alsa plugin configuration file to set the pulseaudio plugin as
# default output for applications using alsa when pulseaudio is running.
hook_func.Pulse_load_if_running {
    lib "libasound_module_conf_Pulse.so"
    func "conf_Pulse_hook_load_if_running"
}

@hooks [
    {
        func Pulse_load_if_running
        files [
#           "/usr/share/alsa/Pulse-alsa.conf"
            "/home/charles/.asoundrc"
        ]
        errors false
    }
]

La seule chose que j'ai faite a été de commenter la ligne "/usr/share/alsa/Pulse-alsa.conf" et l'a remplacé par "/home/charles/.asoundrc" donc le plugin pulseaudio n'est pas la valeur par défaut pour les applications utilisant ALSA, mais utilise plutôt mon micro virtuel par défaut. Ce n'est peut-être pas la meilleure solution, mais cela fonctionne.

Cela a fonctionné quand j'ai fait arecord test.raw -t raw -c 1 -f S16_LE -r 16000. Il a obtenu les données de audiofile0.raw au lieu du microphone! J'ai utilisé la commande lsof /dev/snd/* pour voir exactement ce qui accédait au périphérique audio pendant l'exécution de la commande arecord. Le résultat était le suivant:

COMMAND    PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
pulseaudi 2044 charles   22u   CHR  116,6      0t0 8977 /dev/snd/controlC0
pulseaudi 2044 charles   29u   CHR  116,6      0t0 8977 /dev/snd/controlC0
arecord   4051 charles  mem    CHR  116,5          8976 /dev/snd/pcmC0D0c
arecord   4051 charles    4u   CHR  116,5      0t0 8976 /dev/snd/pcmC0D0c

J'ai ensuite essayé d'utiliser la fonction de recherche vocale du navigateur Chromium et j'ai constaté que je ne pouvais pas l'enregistrer à partir de audioFile0.raw. J'ai ensuite utilisé lsof /dev/snd/* pour voir exactement ce qui accédait au périphérique audio.

COMMAND    PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
pulseaudi 2044 charles  mem    CHR  116,5          8976 /dev/snd/pcmC0D0c
pulseaudi 2044 charles   22u   CHR  116,6      0t0 8977 /dev/snd/controlC0
pulseaudi 2044 charles   29u   CHR  116,6      0t0 8977 /dev/snd/controlC0
pulseaudi 2044 charles   30r   CHR 116,33      0t0 7992 /dev/snd/timer
pulseaudi 2044 charles   31u   CHR  116,5      0t0 8976 /dev/snd/pcmC0D0c

Je vois qu'ils ont tous le même PID, 2044. Ils utilisent tous le démon pulseaudio, ne passant pas par ALSA.

Ma question: Comment puis-je faire en sorte que pulseaudio utilise mon microphone virtuel par défaut pour que toutes les applications qui passent par pulseaudio pour l'entrée audio obtiennent à la place les données audio de mon fichier plutôt que du microphone?

12
cheerupcharlie

Après de nombreuses heures minutieuses, j'ai finalement obtenu quelque chose de acceptable. J'ai défait tout ce que j'ai fait avec ALSA (car la valeur par défaut est qu'ALSA utilise PulseAudio à la place, que j'ai initialement remplacé). J'ai créé un simple script bash install_virtmic.sh pour créer un "microphone virtuel" pour PulseAudio à utiliser ainsi que pour les clients PulseAudio:

#!/bin/bash

# This script will create a virtual microphone for PulseAudio to use and set it as the default device.

# Load the "module-pipe-source" module to read audio data from a FIFO special file.
echo "Creating virtual microphone."
pactl load-module module-pipe-source source_name=virtmic file=/home/charles/audioFiles/virtmic format=s16le rate=16000 channels=1

# Set the virtmic as the default source device.
echo "Set the virtual microphone as the default device."
pactl set-default-source virtmic

# Create a file that will set the default source device to virtmic for all 
PulseAudio client applications.
echo "default-source = virtmic" > /home/charles/.config/Pulse/client.conf

# Write the audio file to the named pipe virtmic. This will block until the named pipe is read.
echo "Writing audio file to virtual microphone."
while true; do
    cat audioFile0.raw > /home/charles/audioFiles/virtmic
done

Un script rapide uninstall_virtmic.sh pour annuler tout ce qui est fait par le script d'installation:

#!/bin/bash

# Uninstall the virtual microphone.

pactl unload-module module-pipe-source
rm /home/charles/.config/Pulse/client.conf

J'ai ensuite lancé Chromium et cliqué sur le microphone pour utiliser sa fonction de recherche vocale et cela a fonctionné! J'ai aussi essayé avec arecord test.raw -t raw -f S16_LE -c 1 -r 16000 et ça a marché aussi! Ce n'est pas parfait, car je continue à écrire dans le tube nommé virtmic dans une boucle infinie dans le script (ce qui a rapidement fait mon test.raw fichier incroyablement grand), mais il fera l'affaire pour l'instant.

N'hésitez pas à me faire savoir si quelqu'un trouve une meilleure solution!

14
cheerupcharlie