I'm looking for a way to feed audio data from a file into the microphone so when 3rd party applications (such as arecord or Chromium's "search by voice" feature) use the microphone for audio input, they receive the audio data from the file instead.
Here's my scenario: An application I wrote records audio data from the microphone (using ALSA) and saves it to a file (audioFile0.raw). At some unknown point in time in the future, some unknown 3rd party application (as in, something I did not develop so I have no development control over, such as the Chromium web browser's "search by voice" feature) will use the microphone to obtain audio data. I would like the audio data that the 3rd party application is gathering to come from audioFile.raw rather than the actual microphone itself.
I was thinking if it were possible to change the default audio input device to an audio file, or maybe 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 a more simple way of doing this?
I hope I provided enough detail and clarity. Please let me know if something is unclear.
EDIT: So I figured out how to make 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
}
I then call arecord test.raw -c 1 -f S16_LE -r 16000 -t raw -D virtmic
from the command line and I'm able to record the audio data that's in audioFile0.raw
to test.raw
.
My goal now is to replace the default device with my virtual microphone so any application accessing the microphone will read the audio data in audioFile0.raw
instead of the actual microphone itself. So I edited my .asoundrc file to appear 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 seemed to be recording from the microphone itself and not audioFile0.raw
.
What am I doing wrong? How exactly do I change the default capture device so it will read the data from audioFile0.raw
rather than the input from the microphone?
EDIT 2: Okay, so I was on the right track. I'm using the same .asoundrc file in my home directory that I showed earlier where I changed the default device to be the virtmic. I needed to change the file /usr/share/alsa/alsa.conf.d/pulse.conf
so it looks 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 replaced it with "/home/charles/.asoundrc"
so the pulseaudio plugin isn't the default for applications using ALSA, but rather use my virtual mic as the default. This may not be the best solution, but it works.
This worked when I did arecord test.raw -t raw -c 1 -f S16_LE -r 16000
. It got the data from audiofile0.raw
instead of the microphone! I used the command lsof /dev/snd/*
to see what exactly was accessing the audio device while the arecord
command was running. 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
I then tried using 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 see what exactly was accessing 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 see that they all have the same PID, 2044. They are all using the pulseaudio daemon, not going through ALSA.
My Question: How do I get pulseaudio to use my virtual microphone by default so all applications that go through pulseaudio for audio input will instead get the audio data from my file rather than the microphone?
arecord
call does not specify a device name and uses the default device. (And it is always possible for a program to explicitly use a different device name.) – Zymogenesis