3
votes

I have a microphone and I can record voice like so:

arecord test.wav -r 22050 -f S32_LE -V mono

So far so good. However, when a third party software that I'm using (which I think uses ffmpeg internally), wants to use the microphone it fails, since it does not use the above described parameters.

I tried now to move those parameters into my .asoundrc so that they will be picked up by alsa.

The Alsa Wiki tells me that the plug plugin can be used in order to specify the rate and the format:

A more complex tool for conversion is the pcm type plug. the syntax is:

type plug                  # Format adjusted PCM
slave STR               # Slave name (see pcm_slave)
# or
slave {                 # Slave definition
        pcm STR         # Slave PCM name
        # or
        pcm { }         # Slave PCM definition
        [format STR]    # Slave format (default nearest) or "unchanged"
        [channels INT]  # Slave channels (default nearest) or "unchanged"
        [rate INT]      # Slave rate (default nearest) or "unchanged"
}
route_policy STR        # route policy for automatic ttable generation
                        # STR can be 'default', 'average', 'copy', 'duplicate'
                       # average: result is average of input channels
                        # copy: only first channels are copied to destination
                        # duplicate: duplicate first set of channels
                       # default: copy policy, except for mono capture - sum
ttable {               # Transfer table (bidimensional compound of 
                       # cchannels * schannels numbers)
        CCHANNEL {
                SCHANNEL REAL     # route value (0.0 ... 1.0)
        }
}

So I setup a plugin like so:

pcm.!default {
    type            asym
    playback.pcm {
        type        plug
        slave.pcm   "softvol"
    }
    capture.pcm {
        type plug
        slave {
          pcm "plughw:0" # this works
          rate 22050 # does not apply
          format S32_LE # does not apply
        }
    }
}

The pcm "plughw:0" gets picked up however, the rate and the format fall back to 8 Bit and 8000Hz. Also I have to specify -V Mono so that I can record:

arecord test.wav -V mono
Recording WAVE 'test.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
############+                                     |

So unfortunately none of the required parameters can be added to my settings.

Update

I tried to record using ffmpeg in an attempt to mimic what :

ffmpeg -f alsa -ac 1 -i plughw:0 output.wav -ar 22050 -f S32_LE

The recording starts but no audio is recorded and the rate and format are mixed up again:

aplay output2.wav 
Playing WAVE 'output2.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono

Update with asym plugin

I did try an asymmetric approach as suggested.

pcm.my_mic {
   type hw  
   card 0
   channels 1
   format S32_LE
}

pcm.duplex {
    type asym
    playback.pcm "dmixer"
    capture.pcm "my_mic"
}

pcm.!default {
    type plug
    slave.pcm "duplex"
}

However, when I enter arecord test.wav I'm asked for the format despite the fact that it's configured in the .asoundrc.

When I do enter a format I get the following error:

arecord -f S32_LE
Recording WAVE 'stdin' : Signed 32 bit Little Endian, Rate 8000 Hz, Mono
ALSA lib pcm_params.c:2162:(snd1_pcm_hw_refine_slave) Slave PCM not usable
arecord: set_params:1270: Broken configuration for this PCM: no configurations available.

Update

With some ALSA magic by my friend Y.W. I was able to get arecord to work without parameters, however, it's still somehow using inferior settings when recording audio by default. The key here it seems was to map the mono signal of my I2s card to a stereo signal.

This is the .asoundrc content:

# This section makes a reference to your I2S hardware, adjust the card name
# to what is shown in arecord -l after card x: before the name in []
# You may have to adjust channel count also but stick with default first
pcm.dmic_hw {
  type hw
  card raspisound  
  channels 2
  format S32_LE
  rate 48000
}

# This is the software volume control, it links to the hardware above and after
# saving the .asoundrc file you can type alsamixer, press F6 to select
# your I2S mic then F4 to set the recording volume and arrow up and down to adjust the volume
# After adjusting the volume - go for 50 percent at first, you can do something like
# arecord -D dmic_sv -c2 -r 48000 -f S32_LE -t wav -V mono -v myfile.wav
pcm.dmic_sv {
  type softvol
  slave.pcm dmic_hw
  control {
    name "Boost Capture Volume"
    card raspisound
  }
  min_dB -3.0
  max_dB 30.0
}

# This plugin converts the mono input to stereo.
pcm.mono2stereo {
  type route
  slave.pcm dmic_sv
  slave.channels 2
  # ttable.input_channel.output_channel volume_gain
  ttable.0.0 1
  ttable.0.1 1
}

# The "plug" plugin converts channels, rate and format on request.
# In our case it converts the 32 format to whatever the application request.
pcm.convert {
  type plug
  slave {
    pcm mono2stereo
  }
}

pcm.convertplayback {
  type plug
  slave {
    pcm "hw:0"
  }
}

# Default capture and playback devices
pcm.!default {
  type asym
  capture.pcm convert
  playback.pcm convertplayback
}


1

1 Answers

2
votes

By specifying the slave PCM device as plughw:0, you have created a chain of two plug plugins. This means that the application can use whatever sample format it pleases, the upper plugin will convert it to 22 kHz with 32 bits, and the lower plugin will convert it to any format the hardware supports.

To force the hardware to use the specified format, use it directly as slave, with hw:0.

You cannot prevent programs like arecord from using a different format; that is the whole purpose of the plug plugin. To check what format is actually used by the hardware, add the -v parameter to the arecord call.