Linux sound file to connect to microphone

I'm looking for a way to feed audio data from a file into a microphone, so when third-party applications (such as iscord or Chromium's "voice search" feature) use the microphone for audio input, they get audio data from the file.

Here's my scenario : an application I wrote records audio data from a microphone (using ALSA) and saves it to a file (audioFile0.raw). At some unknown point in time in the future, some unknown third-party application (like in, something that I have not developed, so I have no control over development, for example, the Chromium browser's "voice search" feature) will use microphone to receive audio data. I would like the audio data that the third party application collects to come from audioFile.raw, not the microphone itself.

I was wondering if it is possible to change the default audio input device to an audio file or perhaps a named pipe and do something like cat audioFile0.raw > mypipe

(since I don't know when another application will try to read from the microphone). Perhaps there is an easier way to do this?

Hopefully I've provided enough detail and clarity. Please let me know if anything is unclear.


EDIT: So I figured out how to create a virtual microphone by creating the following .asoundrc file in my home directory:

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
}

      

Then I call arecord test.raw -c 1 -f S16_LE -r 16000 -t raw -D virtmic

from the command line and I can write the audio data in audioFile0.raw

to test.raw

.

My goal now is to replace the default device with my virtual microphone, so that any application accessing the microphone reads audio data in audioFile0.raw

instead of the microphone itself. So I edited the .asoundrc file as follows:

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
}

      

Then I called arecord test.raw -c 1 -f S16_LE -r 16000 -t raw

from the command line. I then played back test.raw

, but it looks like it was recording from the mic itself, not audioFile0.raw

.

What am I doing wrong? How can I change the default capture device so that it reads data from audioFile0.raw

instead of microphone input?


EDIT 2: Ok, so I was on the right track. I use the same .asoundrc file in my home directory that I showed earlier, where I changed the default device to be virtuoso. I needed to modify the file /usr/share/alsa/alsa.conf.d/pulse.conf

to look like this:

# 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
    }
]

      

The only thing I did was comment out the line "/usr/share/alsa/pulse-alsa.conf"

and replace it with "/home/charles/.asoundrc"

, so the pulseaudio plugin is not standard for ALSA applications, but rather uses my virtual microphone as the default. This may not be the best solution, but it works.

It worked when I did arecord test.raw -t raw -c 1 -f S16_LE -r 16000

. He received data from audioFile0.raw

instead of a microphone! I used the command lsof /dev/snd/*

to find out what exactly accessed the audio unit during the command execution arecord

. The output was as follows:

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

      

Then I tried to use the Chromium browser's "search by voice" feature and saw that I couldn't get it to record from audioFile0.raw

. I then used lsof /dev/snd/*

to find out what exactly was accessed by the audio device.

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

      

I can see that they all have the same PID, 2044. They all use the pulseaudio daemon without going through ALSA.

My question is: How do I get pulseaudio to use my default virtual microphone, so all applications passing through pulseaudio for audio input will instead get audio data from my file and not the microphone?

+3


source to share


1 answer


After many painstaking hours, I finally got something acceptable. I unzipped everything I did with ALSA (as ALSA defaults to using PulseAudio instead, which I originally overridden). I created a simple bash script install_virtmic.sh

to create a "virtual microphone" for PulseAudio to use as well as PulseAudio clients:

#!/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

      

A quick script uninstall_virtmic.sh

to undo everything done by installing the script:



#!/bin/bash

# Uninstall the virtual microphone.

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

      

Then I launched Chromium and clicked on the microphone to use the voice search feature and it worked! I also tried with arecord test.raw -t raw -f S16_LE -c 1 -r 16000

and it works too! It's not ideal because I keep writing to the named pipe virtmic

in an endless loop in the script (which quickly made my file test.raw

insanely large), but it will do for now.

Please feel free to let me know if anyone finds a better solution!

+6


source







All Articles