Getting Started with Linux Audio Development

foreword

      In fact, why use two frameworks? I won't record it here. Only care about different application scenarios.

    In terms of programming ease of use, OSS is simple, but it is found that OSS is not configured by default on ubuntu, resulting in no related device nodes. Therefore, ALSA has to be used, and this programming interface is more verbose.

      According to arch OSS's wiki   Open Sound System - ArchWiki (archlinux.org),       the main advantages and disadvantages of the two are: (By the way, arch's wiki information is relatively complete)

OSS Advantages (users)

  • Per-application volume control.
  • Some legacy (i.e. before 2002) cards can have better support.

OSS Advantages (developers)

  • Support for drivers in userspace.
  • Cross-platform (OSS runs on BSDs and Solaris).
  • Smaller and easier to use API. (The author feels deeply about this point in actual use, mainly to understand which ioctls do what, which is in line with the driver's writing ideas)

ALSA advantages over OSS

  • Better support for USB audio devices.
  • Support for Bluetooth audio devices.
  • Support for AC'97 and HD Audio dial-up soft-modems such as Si3055.
  • Better support for MIDI devices.
  • Support for suspend.
  • Better support for jack detection.
  • Better support for modern hardware.

Note:

  • OSS has experimental output support for USB audio devices, but no input.
  • OSS supports MIDI devices with the help of a software synthesizer such as Timidity or FluidSynth.

sound track

     What is a soundtrack? Is it a hardware concept or a software concept?

     The final channel needs to be output by the physical interface. The generation of data is controlled by software.

      The propagation of sound is divided into different frequencies. The sound output of a sound card can support different frequencies. For example, the front channel inputs 44K and the rear channel outputs 8K. The digital data is interleaved and stored in the internal memory. After the sound card takes out the data, it sends the data to different channels to produce different sounds.

    Written here, in fact, does this also exist for interleaved data? That is, due to the different frequencies used, the data length of each channel is inconsistent, and thus the amount of space occupied is different. For example, the following situation: Is there only one R data after three L data?

   

hardware interface

Basic framework of audio

programming interface

The interface of audio programming under linux is divided into two types, OSS and ALSA, which is a commonplace.

OSS interface

The official website explains   OSS v4.x API reference - Developing applications for Open Sound System version 4.1

Access through system calls such as open write read mmap.

 device node

 In order to control the device through open and other related interfaces, it is first necessary to know its device node. according to

OSS v4.x API reference - Device types supported by OSS (opensound.com)

 We can know that OSS supports three device types:

Open Sound System supports three kind of devices:

  • Audio devices are used to play and record digital audio such as WAV or MP3 files. See the " Audio Programming " chapter for more info. Control audio input and output. That is, the data channel ! Such devices correspond to /dev/dsp /dev/dsp1 and so on. Every time the power is turned on again, the actual physical device corresponding to /dev/dsp /dev/dsp1 will change! After turning on the device, we need to query the specific information of the device before proceeding .
  • Mixer devices are used to change volumes and all kind of "control panel" settings. See the " OSS Mixer Programming " chapter for more info. Used to adjust the volume, the corresponding device node is /dev/mixer, etc.
  • MIDI port devices are used to access musical instruments (keyboards, samplers and synthesizer modules) as well as to control various other devices such as mixers, effect processors, on stage lightning and pyrotecnics. See the "OSS MIDI Programming" chapter for more info

IOCTL interface

Reference link:  OSS v4.x API reference - The ioctl() system call (opensound.com)

 Each ioctl is introduced in the connection. For example, if the author wants to confirm the information of the current card, he can use

示例: OSS v4.x API reference - The ossinfo program that is included in the OSS package. (opensound.com)

In actual use, check whether there is a suitable interface.

ALSA interface

device node

ALSA Library API - AlsaProject (alsa-project.org)   According to the introduction of ALSA wiki, the device node is:

he currently designed interfaces are listed below:

  1. Information Interface (/proc/asound)
  2. Control Interface (/dev/snd/controlCX)
  3. Mixer Interface (/dev/snd/mixerCXDX)
  4. PCM Interface (/dev/snd/pcmCXDX)
  5. Raw MIDI Interface (/dev/snd/midiCXDX)
  6. Sequencer Interface (/dev/snd/seq)
  7. Timer Interface (/dev/snd/timer

The problem here is that we do not access these device nodes for recording and playback, but use parameters such as default or plughw:0,0, etc., and which physical device does this correspond to, and whether it is the device we expect ? This adds another layer of unfriendly shielding.

For example, in the routine in reference 3), the default device is enabled by default, and it runs normally on the x86 virtual machine; but cross-compiled to the arm embedded environment, it cannot run, and the device is opened incorrectly. And changed to plughw:0,0 can be opened normally.

----》》》You can use the lsof command to check which processes currently operate the above device nodes:

 lsof |grep snd/c

pulseaudi 1150                   gdm   32u      CHR              116,6      0t0        448 /dev/snd/controlC0
pulseaudi 1150                   gdm   39u      CHR              116,6      0t0        448 /dev/snd/controlC0
snapd-gli 1150 1202              gdm   32u      CHR              116,6      0t0        448 /dev/snd/controlC0
snapd-gli 1150 1202              gdm   39u      CHR              116,6      0t0        448 /dev/snd/controlC0
alsa-sink 1150 1338              gdm   32u      CHR              116,6      0t0        448 /dev/snd/controlC0
alsa-sink 1150 1338              gdm   39u      CHR              116,6      0t0        448 /dev/snd/controlC0
alsa-sour 1150 1356              gdm   32u      CHR              116,6      0t0        448 /dev/snd/controlC0
alsa-sour 1150 1356              gdm   39u      CHR              116,6      0t0        448 /dev/snd/controlC0

Example of an information interface device node:

1) Obtain the number and name of the cards on the board

 cat /proc/asound/cards
 0 [audiocodec     ]: audiocodec - audiocodec
                      audiocodec
 1 [sndhdmi        ]: sndhdmi - sndhdmi
                      sndhdmi

 2 ) Obtain the hardware and software parameters of a certain sound card. It can be seen that the current hardware parameters are not configured, and the sound card is not being used.

 cat /proc/asound/card0/pcm0p/info  播放参数
card: 0
device: 0
subdevice: 0
stream: PLAYBACK
id: SUNXI-CODEC sun8iw11codec-0
name: 
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1
root@T3/A40i-Tronlong:~# cat /proc/asound/card0/pcm0p/sub0/
hw_params  info       status     sw_params  
root@T3/A40i-Tronlong:~# cat /proc/asound/card0/pcm0p/sub0/hw_params   硬件参数
closed

When running the speaker-test command, check the hardware parameter information as follows:

cat /proc/asound/card0/pcm0p/sub0/status

state: RUNNING
owner_pid   : 3829             (当前进程信息都有)
trigger_time: 5889.590491875
tstamp      : 0.000000000
delay       : 32768
avail       : 0
avail_max   : 24576
-----
hw_ptr      : 15196160
appl_ptr    : 15228928


$ cat /proc/asound/card0/pcm0p/sub0/hw_params

access: RW_INTERLEAVED
format: S16_LE
subformat: STD
channels: 1
rate: 48000 (1572864000/32768)
period_size: 8192
buffer_size: 32768

device name

ALSA is divided into several layers, each layer has a device name, and the specific device information of the next layer is specified through the configuration file

Associations are established through configuration files. ( configuration file example and hierarchical structure to be supplemented )

If there is no configuration file, specify the physical device directly, similar to the parameters after -D below:

aplay -t raw -r 8000 -q -D hw:/dev/snd/controlC0 -f u8 -c 1

open interface

  Parameter meaning : The most difficult parameter to fill in here is name. For playing recordings, many routines fill in default. In our actual test, you can also fill in plughw:0,0 and hw:/dev/snd/controlC0.

   But hw:/dev/snd/pcmC0D0p cannot be filled in. When filling in this device node, an error is reported when running: 
ALSA lib pcm_hw.c:1713:(_snd_pcm_hw_open) Invalid value for card
unable to open pcm device: Inappropriate ioctl for device

Theoretically, this node is the playback node of pcm. In theory, it is OK to set this! ! A mess of bad design! ! !

snd_pcm_open()
int snd_pcm_open	(	snd_pcm_t ** 	pcmp,
const char * 	name,
snd_pcm_stream_t 	stream,
int 	mode 
)		
Opens a PCM.

Parameters
pcmp	Returned PCM handle
name	ASCII identifier of the PCM handle
stream	Wanted stream
mode	Open mode (see SND_PCM_NONBLOCK, SND_PCM_ASYNC)
Returns
0 on success otherwise a negative error code
Examples
/test/latency.c, /test/pcm.c, and /test/pcm_min.c.

common mistakes

      The device can open play, but it fails to open record. From the following code, the error message is resource busy , that is, the device is occupied.

if ((err = snd_pcm_open (&handle,"hw:/dev/snd/controlC0" , type, 0)) < 0) {
		fprintf (stderr, "cannot open  (%s)\n",
			 snd_strerror (err));
		return NULL;
	}

      At this time, because we are not familiar with it, we thought there was a problem with passing the second parameter. In fact, there is a while loop in the code that keeps receiving data or generating data. When the user presses ctrl+C, the interface is not called to release the device node. lead to.

Get hardware parameter capability value

   Values ​​that are not within the capabilities cannot be configured.

  Specific interface parameters to be added! ! ! ! ! ! ! ! ! ! ! ! ! ! !

Configure hardware parameters

Hardware parameters include (described in Reference 3)

Sampling rateRate

 An analog-to-digital converter (ADC) converts the analog voltages into discrete values, called samples, at regular intervals in time, known as the sampling rate

 Sample length Format

The size of the samples, expressed in bits, is one factor that determines how accurately the sound is represented in digital form

How many bits of data are used to represent, some macros are defined as shown in the figure below, for details, please refer to:  ALSA project - the C library reference: PCM Interface (alsa-project.org)

The parameters need hardware support. For example, if U8 is configured on the T3 board, it will prompt that it cannot be configured. On the X86 virtual machine, the configuration is normal.

Forcibly configure U8, the following error is reported:


cannot set sample format (Invalid argument)

So which interface is used to obtain the current hardware support? ! !
 

Question: Do different sample rates require different sample data lengths? For example, can 44.1K samples be represented by 8-bit data?

 Channels

The left channel and right channel we often say can be understood as a mic sample from the left and right, the sample sampled by the left mic is the left channel data, and the sample sampled by the right mic is the right channel data. An audio can have only one channel, or two channels, the latter is also called stereo. And how many channels this audio has, is what we call the number of channels .

 Frame Frame

The result of each sampling is one frame . Obviously, the size of a frame of data depends on the precision of our sampling and the number of channels.

 Interleaved Mode Interleaved

How do we save the audio frames we sample each time? Two storage ideas are provided, which is what we call interleaved mode and non-interleaved mode. We also commonly use interleaved mode.

Period Period

It is impossible for us to process 1 frame of data at a time, it is too inefficient, so let's make it into batch processing. And how many frames are processed at a time is what we call the cycle.

Switching from the end of one cycle to the next cycle requires additional processing loss, which is similar to process switching. If the cycle is large, the amount of data processed at one time will be large, and the continuous processing time will be long each time, and the switching loss will be small. However, because the data is processed after a full cycle, the data processing delay is long. Conversely, if the cycle is set to be small, the delay is short, but the cycle switching is more frequent, the loss will be greater, and it is more likely to freeze.

Buffer Size Buffer Size

What is mentioned here is the cache size of alsa's underlying DMA handling data, which is a circular cache space. We set the DMA to continuously transfer the data of one cycle at a time. What if there is another data during the transfer? We need a larger cache space to save more data. The cache space is often an integer multiple of the cycle, for example, if the cache is set for 8 cycles, and each cycle is 6000 frames, then the data of up to 8 * 6000 = 48000 frames can be cached.

system command

OSS shell command

usinfo

ALSA shell commands

root execution error problem

The error message is similar to:

 ./x86csdn
MoTTY X11 proxy: Unsupported authorisation protocol
xcb_connection_has_error() returned true
XDG_RUNTIME_DIR (/run/user/1000) is not owned by us (uid 0), but by uid 1000! (This could e g happen if you try to connect to a non-root PulseAudio as a root user, over the native protocol. Don't do that.)
ALSA lib pcm_dsnoop.c:618:(snd_pcm_dsnoop_open) unable to open slave
cannot open for capture

Pulseaudio is used to manage audio devices, and pulseaudio is not allowed to run under the root user, which will cause security problems.

Solution: Invoke commands across users [Available]

su - username -c "aplay sample.wav"

 With the same command, the above error is reported directly under ./x86csdn under root. And the following form can be used to run normally!

su - xiehj -c "/home/user/sound/x86csdn"

amixer

volume control

1)amixer  info
Card default 'audiocodec'/'audiocodec'
  Mixer name    : ''
  Components    : ''
  Controls      : 48
  Simple ctrls  : 48

child instruction

Available commands:
  scontrols show all mixer simple controls
  scontents show contents of all mixer simple controls (default command)
  sset sID P set contents for one mixer simple control
  sget sID get contents for one mixer simple control x ard
  controls show for all simple controls is just one type of controls?! )
  contents show contents of all controls for given card
  cset cID P set control contents for one control
  cget cID get control contents for one control
root@T3/A40i-Tronlong:~# amixer scontrols ( The output of this command is similar to the output of the controls command)
Simple mixer control 'Headphone',0
Simple mixer control 'Headphone volume',0
Simple mixer control 'FM gain volume',0
Simple mixer control 'Phone Out Mixer LOMIX',0
Simple mixer control 'Phone Out Mixer MIC1 Boost',0
Simple mixer control 'Phone Out Mixer MIC2 Boost',0
Simple mixer control 'Phone Out Mixer ROMIX',0
Simple mixer control 'Phoneout Speaker',0
Simple mixer control 'ADC gain volume',0
Simple mixer control 'HPL Mux',0
Simple mixer control 'HPR Mux',0
Simple mixer control 'LINEIN Mixer volume',0
Simple mixer control 'LINEIN gain volume',0
Simple mixer control 'Left Input Mixer FML',0
Simple mixer control 'Left Input Mixer LINEINL',0
Simple mixer control 'Left Input Mixer LINEINLR',0
Simple mixer control 'Left Input Mixer LOMIX',0
Simple mixer control 'Left Input Mixer MIC1 Boost',0
Simple mixer control 'Left Input Mixer MIC2 Boost',0
Simple mixer control 'Left Input Mixer ROMIX',0
Simple mixer control 'Left Output Mixer DACL',0
Simple mixer control 'Left Output Mixer DACR',0
Simple mixer control 'Left Output Mixer FML',0
Simple mixer control 'Left Output Mixer LINEINL',0
Simple mixer control 'Left Output Mixer LINEINLR',0
Simple mixer control 'Left Output Mixer MIC1 Boost',0
Simple mixer control 'Left Output Mixer MIC2 Boost',0
Simple mixer control 'MIC gain volume',0
Simple mixer control 'MIC1 boost volume',0
Simple mixer control 'MIC2 Mux',0
Simple mixer control 'MIC2 boost volume',0
Simple mixer control 'Right Input Mixer FMR',0
Simple mixer control 'Right Input Mixer LINEINLR',0
Simple mixer control 'Right Input Mixer LINEINR',0
Simple mixer control 'Right Input Mixer LOMIX',0
Simple mixer control 'Right Input Mixer MIC1 Boost',0
Simple mixer control 'Right Input Mixer MIC2 Boost',0
Simple mixer control 'Right Input Mixer ROMIX',0
Simple mixer control 'Right Output Mixer DACL',0
Simple mixer control 'Right Output Mixer DACR',0
Simple mixer control 'Right Output Mixer FMR',0
Simple mixer control 'Right Output Mixer LINEINLR',0
Simple mixer control 'Right Output Mixer LINEINR',0
Simple mixer control 'Right Output Mixer MIC1 Boost',0
Simple mixer control 'Right Output Mixer MIC2 Boost',0
Simple mixer control 'codec hub mode',0
Simple mixer control 'digital volume',0
Simple mixer control 'phoneout volume' ,0
root@T3/A40i-Tronlong:~# amixer controls (If other ifaces are supported, the output of scontrols may be different. Are these controls corresponding to physical devices? )
numid=3 ,iface=MIXER ,name= 'Headphone volume'
numid=47,iface=MIXER,name='Headphone Switch'
numid=5,iface=MIXER,name='FM gain volume'
numid=15,iface=MIXER,name='Phone Out Mixer LOMIX Switch'
numid=18,iface=MIXER,name='Phone Out Mixer MIC1 Boost Switch'
numid=17,iface=MIXER,name='Phone Out Mixer MIC2 Boost Switch'
numid=16,iface=MIXER,name='Phone Out Mixer ROMIX Switch'
numid=48,iface=MIXER,name='Phoneout Speaker Switch'
numid=11,iface=MIXER,name='ADC gain volume'
numid=13,iface=MIXER,name='HPL Mux'
numid=14,iface=MIXER,name='HPR Mux'
numid=4,iface=MIXER,name='LINEIN Mixer volume'
numid=6,iface=MIXER,name='LINEIN gain volume'
numid=28,iface=MIXER,name='Left Input Mixer FML Switch'
numid=29,iface=MIXER,name='Left Input Mixer LINEINL Switch'
numid=30,iface=MIXER,name='Left Input Mixer LINEINLR Switch'
numid=27,iface=MIXER,name='Left Input Mixer LOMIX Switch'
numid=32,iface=MIXER,name='Left Input Mixer MIC1 Boost Switch'
numid=31,iface=MIXER,name='Left Input Mixer MIC2 Boost Switch'
numid=26,iface=MIXER,name='Left Input Mixer ROMIX Switch'
numid=41,iface=MIXER,name='Left Output Mixer DACL Switch'
numid=40,iface=MIXER,name='Left Output Mixer DACR Switch'
numid=42,iface=MIXER,name='Left Output Mixer FML Switch'
numid=43,iface=MIXER,name='Left Output Mixer LINEINL Switch'
numid=44,iface=MIXER,name='Left Output Mixer LINEINLR Switch'
numid=46,iface=MIXER,name='Left Output Mixer MIC1 Boost Switch'
numid=45,iface=MIXER,name='Left Output Mixer MIC2 Boost Switch'
numid=7,iface=MIXER,name='MIC gain volume'
numid=9,iface=MIXER,name='MIC1 boost volume'
numid=12,iface=MIXER,name='MIC2 Mux'
numid=10,iface=MIXER,name='MIC2 boost volume'
numid=21,iface=MIXER,name='Right Input Mixer FMR Switch'
numid=23,iface=MIXER,name='Right Input Mixer LINEINLR Switch'
numid=22,iface=MIXER,name='Right Input Mixer LINEINR Switch'
numid=19,iface=MIXER,name='Right Input Mixer LOMIX Switch'
numid=25,iface=MIXER,name='Right Input Mixer MIC1 Boost Switch'
numid=24,iface=MIXER,name='Right Input Mixer MIC2 Boost Switch'
numid=20,iface=MIXER,name='Right Input Mixer ROMIX Switch'
numid=33,iface=MIXER,name='Right Output Mixer DACL Switch'
numid=34,iface=MIXER,name='Right Output Mixer DACR Switch'
numid=35,iface=MIXER,name='Right Output Mixer FMR Switch'
numid=37,iface=MIXER,name='Right Output Mixer LINEINLR Switch'
numid=36,iface=MIXER,name='Right Output Mixer LINEINR Switch'
numid=39,iface=MIXER,name='Right Output Mixer MIC1 Boost Switch'
numid=38,iface=MIXER,name='Right Output Mixer MIC2 Boost Switch'
numid=1,iface=MIXER,name='codec hub mode'
numid=2,iface=MIXER,name='digital volume'
numid=8,iface=MIXER,name='phoneout volume'

amixer device selection example

   For example, for a sound card device, its device node is /dev/snd/controlC0, which supports both front microphone and rear microphone, that is, there are two capture devices. So how do we choose one of them?

    Let's look at the function of mixer again:

  • Mixer interface: controls the devices on sound cards that route signals and control volume levels. It is built on top of the control interface.

     Here it is explained that besides the function of controlling the volume, the mixer also has a function of controlling signal routing. With this function, we can choose which device corresponds to the capture function of /dev/snd/controlC0.

    Example:

     1) First query the information of the current mixer      

amixer contents   

通过如下命令的输出,我们可以看到  input source 对应又两个选项: front mic和rear mic
而values = 1,表示此时采用rear mic
numid=10,iface=MIXER,name='Input Source'
  ; type=ENUMERATED,access=rw------,values=1,items=2
  ; Item #0 'Front Mic'
  ; Item #1 'Rear Mic'
  : values=1



numid=17,iface=MIXER,name='Rear Mic Boost Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=3,step=0
  : values=2,2
  | dBscale-min=0.00dB,step=10.00dB,mute=0


numid=16,iface=MIXER,name='Front Mic Boost Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=3,step=0
  : values=0,0
  | dBscale-min=0.00dB,step=10.00dB,mute=0

2) Change the input hardware source:

amixer cset numid=10 0   最后一个参数即选项的索引

numid=10,iface=MIXER,name='Input Source'
  ; type=ENUMERATED,access=rw------,values=1,items=2
  ; Item #0 'Front Mic'
  ; Item #1 'Rear Mic'
  : values=0

Example of volume adjustment

  English Chinese

volume

Volume
unmute unmute

amixer -c 1 set Line,0 80%,40% unmute cap

will set the second soundcard's left line input volume to 80% and right line input to 40%, unmute it, and select it as a source for capture (recording).

Here Line,0 means the left input volume, then the right input volume is Line,1?

amixer -c 1 -- sset Master playback -20dB

will set the master volume of the second card to -20dB. If the master has multiple channels, all channels are set to the same value.

amixer -c 1 set PCM 2dB+

will increase the PCM volume of the second card with 2dB. When both playback and capture volumes exist, this is applied to both volumes.

amixer -c 2 cset iface=MIXER,name='Line Playback Volume",index=1 40%

will set the third soundcard's second line playback volume(s) to 40%

amixer -c 2 cset numid=34 40%

will set the 34th soundcard element to 40%

Volume adjustment in practice

The environment is based on the ubuntu virtual machine x86

amixer info
Card default 'AudioPCI'/'Ensoniq AudioPCI ENS1371 at 0x2040, irq 16'
  Mixer name    : 'Cirrus Logic CS4297A rev 3'
  Components    : 'AC97a:43525913'
  Controls      : 26
  Simple ctrls  : 13

amixer scontents
Simple mixer control 'Master',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 63
  Mono:
  Front Left: Playback 63 [100%] [0.00dB] [on]
  Front Right: Playback 63 [100%] [0.00dB] [on]
Simple mixer control 'PCM',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 63
  Mono:
  Front Left: Playback 48 [76%] [37.50dB] [on]
  Front Right: Playback 48 [76%] [37.50dB] [on]
Simple mixer control 'Line',0
  Capabilities: pvolume pswitch pswitch-joined cswitch cswitch-exclusive
  Capture exclusive group: 0
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: Playback 0 - 63
  Front Left: Playback 0 [0%] [-34.50dB] [off] Capture [off]
  Front Right: Playback 0 [0%] [-34.50dB] [off] Capture [off]

初始音量信息

 

change volume action

Change the volume in the graphical interface, and then query through the command

amixer scontents,通过命令可以看到pcm的音量值发生变化,
Simple mixer control 'Master',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 63
  Mono:
  Front Left: Playback 63 [100%] [0.00dB] [on]
  Front Right: Playback 63 [100%] [0.00dB] [on]
Simple mixer control 'PCM',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 63
  Mono:
  Front Left: Playback 56 [89%] [49.50dB] [on]
  Front Right: Playback 56 [89%] [49.50dB] [on]
 

Input Volume Control

Note that in the picture below, compared with the above screenshot of the input volume, the device has also been changed, because after the microphone device is adjusted, the command cannot detect the change.

Simple mixer control 'Capture',0
  Capabilities: cvolume cswitch cswitch-joined
  Capture channels: Front Left - Front Right
  Limits: Capture 0 - 15
  Front Left: Capture 4 [27%] [6.00dB] [on]
  Front Right: Capture 4 [27%] [6.00dB] [on]
 

After the above actual combat, we still can't understand which device is used in the current system ! !

But for a development board:

 Its silkscreen marks H/P OUT and LINE IN seem to correspond to the above information obtained by amixer.

The relationship between master, PCM, etc.

 What is the scope of adjusting the influence of different nodes?

alsactl  monitor

The main function is to monitor alsa. Through the interface operation, we can know which devices are controlled by the interface, so that we can use amixer and other commands to configure
node hw:0, #4 (2,0,0,Headphone Playback Switch, 0) VALUE
node hw:0, #3 (2,0,0,Headphone Playback Volume,0) VALUE
node hw:0, #18 (2,0,0,Master Playback Volume,0) VALUE
node hw:0, #62 (2,0,0,PCM Playback Volume,0) VALUE
node hw:0, #4 (2,0,0,Headphone Playback Switch,0) VALUE
node hw:0, #4 (2,0,0 ,Headphone Playback Switch,0) VALUE
node hw:0, #3 (2,0,0,Headphone Playback Volume,0) VALUE
node hw:0, #18 (2,0,0,Master Playback Volume,0) VALUE
node hw:0, #62 (2,0,0,PCM Playback Volume,0) VALUE

programming practice

OSS programming practice

Acquisition of sound card information

   Why do we need this function, because we want to distinguish which device node is the one we expect to operate?

Volume adjustment

  Why do we need this function, because different volumes lead to changes in output and input data. 

input Output

 Why do we need this function, because this is the audio data channel.

ALSA programming practice

Record and play

      For the separate recording and playback functions, see the example in Reference 3, which is relatively clear. At the same time, another article in Reference 3 realizes playing while playing, the essence is to open the device node as play and capture at the same time, and then perform write and read operations on the play and capture handles respectively.

Experimental requirements and codes

     In the above examples, the rate is usually set to 44.1K, the channel is set to 2, and the precision is set to S16.

    In this experiment, the rate is changed to 8K, the channel is changed to 1, and the precision is changed to U8. The sample code is as follows, the main code is in Reference 3, and the hardware parameters are mainly modified for testing.


#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>

snd_pcm_t *open_sound_dev(snd_pcm_stream_t type)
{
	int err;
	snd_pcm_t *handle;
	snd_pcm_hw_params_t *hw_params;
	//unsigned int rate = 44100;
	unsigned int rate = 8000;
/*
int snd_pcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)

pcmp 打开的pcm句柄
name 要打开的pcm设备名字,默认default,或者从asound.conf或者asoundrc里面选择所要打开的设备
stream SND_PCM_STREAM_PLAYBACK 或 SND_PCM_STREAM_CAPTURE,分别表示播放和录音的PCM流
mode 打开pcm句柄时的一些附加参数 SND_PCM_NONBLOCK 非阻塞打开(默认阻塞打开), SND_PCM_ASYNC 异步模式打开
返回值 0 表示打开成功,负数表示失败,对应错误码 "plughw:0,0"
*/

	if ((err = snd_pcm_open (&handle,"hw:/dev/snd/controlC0" , type, 0)) < 0) {
		fprintf (stderr, "cannot open  (%s)\n",
			 snd_strerror (err));
		return NULL;
	}
/*
snd_pcm_hw_params_malloc( ) 在栈中分配 snd_pcm_hw_params_t 结构的空间,然后使用 snd_pcm_hw_params_any( ) 函数用声卡的全配置空间参数初始化已经分配的 snd_pcm_hw_params_t 结构。snd_pcm_hw_params_set_access ( ) 设置访问类型,常用访问类型的宏定义有:

SND_PCM_ACCESS_RW_INTERLEAVED 
交错访问。在缓冲区的每个 PCM 帧都包含所有设置的声道的连续的采样数据。比如声卡要播放采样长度是 16-bit 的 PCM 立体声数据,表示每个 PCM 帧中有 16-bit 的左声道数据,然后是 16-bit 右声道数据。

SND_PCM_ACCESS_RW_NONINTERLEAVED 
非交错访问。每个 PCM 帧只是一个声道需要的数据,如果使用多个声道,那么第一帧是第一个声道的数据,第二帧是第二个声道的数据,依此类推。

函数 snd_pcm_hw_params_set_format() 设置数据格式,主要控制输入的音频数据的类型、无符号还是有符号、是 little-endian 还是 bit-endian。比如对于 16-bit 长度的采样数据可以设置为:	
*/   
	if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
		fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
			 snd_strerror (err));
		return NULL;
	}
			 
	if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) {
		fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
			 snd_strerror (err));
		return NULL;
	}

	if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {// 交错访问
		fprintf (stderr, "cannot set access type (%s)\n",
			 snd_strerror (err));
		return NULL;
	}

	if ((err = snd_pcm_hw_params_set_format (handle, hw_params, SND_PCM_FORMAT_U8)) < 0) {  // SND_PCM_FORMAT_U8  SND_PCM_FORMAT_S16_LE      有符号16 bit Little Endian
		fprintf (stderr, "cannot set sample format (%s)\n",
			 snd_strerror (err));
		return NULL;
	}

	if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &rate, 0)) < 0) {    //snd_pcm_hw_params_set_rate_near () 函数设置音频数据的最接近目标的采样率
		fprintf (stderr, "cannot set sample rate (%s)\n",
			 snd_strerror (err));
		return NULL;
	}

	if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, 1)) < 0) {
		fprintf (stderr, "cannot set channel count (%s)\n",
			 snd_strerror (err));
		return NULL;
	}
//snd_pcm_hw_params( ) 从设备配置空间选择一个配置,让函数 snd_pcm_prepare() 准备好 PCM 设备,以便写入 PCM 数据。
	if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) {
		fprintf (stderr, "cannot set parameters (%s)\n",
			 snd_strerror (err));
		return NULL;
	}

	snd_pcm_hw_params_free (hw_params);

	return handle;
}

void close_sound_dev(snd_pcm_t *handle)
{
	snd_pcm_close (handle);
}

snd_pcm_t *open_playback(void)
{
    return open_sound_dev(SND_PCM_STREAM_PLAYBACK);
}

snd_pcm_t *open_capture(void)
{
    return open_sound_dev(SND_PCM_STREAM_CAPTURE);
}


int main (int argc, char *argv[])
{
	int err;
	unsigned char buf[512];
	unsigned char recv_buf[512];
	snd_pcm_t *playback_handle;
	snd_pcm_t *capture_handle;
	int i=0;


    playback_handle = open_playback();
    if (!playback_handle)
    {
		fprintf (stderr, "cannot open for playback\n");
        return -1;
    }
    //snd_pcm_close (playback_handle);

    capture_handle = open_capture();
    if (!capture_handle)
    {
		fprintf (stderr, "cannot open for capture\n");
		snd_pcm_close (playback_handle);

        return -1;
    }

	if ((err = snd_pcm_prepare (playback_handle)) < 0) {
		fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
			 snd_strerror (err));
			 snd_pcm_close (playback_handle);
	snd_pcm_close (capture_handle);
		return -1;
	}

	if ((err = snd_pcm_prepare (capture_handle)) < 0) {
		fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
			 snd_strerror (err));
		return -1;
	}
#if 1
	while (1) {
		if ((err = snd_pcm_readi (capture_handle, recv_buf, 128)) != 128) {
			fprintf (stderr, "read from audio interface failed (%s)\n",
				 snd_strerror (err));
				 snd_pcm_close (playback_handle);
	snd_pcm_close (capture_handle);
			return -1;
		}
	  printf("recv data:");
	  for(i=0;i<64;i++)
	      printf("0x%x ",recv_buf[i]);
     printf("\n");
     
    memset(buf,0x55,128);
    memset(buf,0x0,128);
		if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) {   //snd_pcm_writei() 用来把交错的音频数据写入到音频设备。
			fprintf (stderr, "write to audio interface failed (%s)\n",
				 snd_strerror (err));
				 snd_pcm_close (playback_handle);
	snd_pcm_close (capture_handle);
			return -1;
		}
	}
#endif 
	snd_pcm_close (playback_handle);
	snd_pcm_close (capture_handle);
    return 0;
}


Running results and problems

After running, the broken pipe appeared soon, but the code that did not modify the hardware configuration parameters did not have this problem. The exception information is as follows:

./x86csdn
MoTTY X11 proxy: Unsupported authorisation protocol
xcb_connection_has_error() returned true
XDG_RUNTIME_DIR (/run/user/1000) is not owned by us (uid 0), but by uid 1000! (This could e g happen if you try to connect to a non-root PulseAudio as a root user, over the native protocol. Don't do that.)
recv data:0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9
recv data:0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9
write to audio interface failed (Broken pipe)

Equipment recovery and statistics for problem analysis

 As follows, restore the device state through the interface pcm_prepare. And by increasing the count, we see that after 16 or 20 occurrences, it will enter a broken pipe exception

if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) {   
			fprintf (stderr, "write to audio interface failed (%s) %d\n",
				 snd_strerror (err),count); //这里打印正常输出了多少次count
				// snd_pcm_close (playback_handle);
	//snd_pcm_close (capture_handle);
	  snd_pcm_prepare(playback_handle); // 这里恢复设备状态
		//	return -1;
		count = 0;
		}
	}

The influence of period size

  /* Set period size to 32 frames. */
  capture_frames = 64;
  snd_pcm_hw_params_set_period_size_near(capture_handle,
                              capture_params, &capture_frames, &dir);

  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(capture_handle, capture_params);
  if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s\n",
            snd_strerror(rc));
    exit(1);
  }
   /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(capture_params, &capture_frames,
                                    &dir);
  capture_size = capture_frames* 4;// * 4; /* 2 bytes/sample, 2 channels */
  capture_buffer = (char *) malloc(capture_size);

       In audio programming, the period size is more important, that is, the number of frames sent or received at a time.

       If the setting is not appropriate, underrun or overrun is prone to occur. Through the following device nodes, you can see the parameters currently used. In particular, you need to view these parameters when the audio program is running, otherwise the information found is that the device is closed.

      

cat /proc/asound/card0/pcm2c/sub0/hw_params
access: RW_INTERLEAVED
format: S16_LE
subformat: STD
channels: 2
rate: 44100 (44100/1)
period_size: 32
buffer_size: 1024


cat /proc/asound/card0/pcm2c/sub0/sw_params
tstamp_mode: NONE
period_step: 1
avail_min: 32
start_threshold: 1
stop_threshold: 1024
silence_threshold: 0
silence_size: 0
boundary: 4611686018427387904

        In addition, pay attention to whether there are blocking and waiting interfaces in the code. For example, when it is used as a capture, it is blocked by default. If no data is read, the process will wait, resulting in the subsequent interface sending data not running, and then the message of underrun appears.

        Changing capture to non-blocking can solve this problem, but when processing subsequent read operations, exception handling should be performed on the return value     

 rc = snd_pcm_open(&capture_handle, "hw:/dev/snd/controlC0" ,
                    SND_PCM_STREAM_CAPTURE, SND_CTL_NONBLOCK); //  采用非阻塞模式,不然在下面写的时候,堵塞导致写的过程很慢,而INTEL HDA速率快很多,导致一直 underrun.
                    

period duration

This board is related and can be obtained through the following interface, where the second is the output parameter, the unit is us, that is, the length of the period

 

 snd_pcm_hw_params_get_period_time()
int snd_pcm_hw_params_get_period_time	(	const snd_pcm_hw_params_t * 	params,
unsigned int * 	val,
int * 	dir 
)		
Extract period time from a configuration space.

Parameters
params	Configuration space
val	Returned approximate period duration in us  //period的时长,以us为单位
dir	Sub unit direction

If we do some calculations with this as a benchmark, we need to be aware of the veneer differences. For example, the author uses the T3 evaluation board, the frequency is set to 8K, and the query parameter is 1000 000, that is, 1s, that is, it takes 1s to complete a data transmission or reception.

References

Open Sound System - ArchWiki (archlinux.org)   The arch oss wiki encyclopedia information, the introduction of shell commands, etc. are all derived from this.

2) OSS v4.x API reference - The open() system call (opensound.com) OSS programming interface. When the interface parameters are unclear, you can refer to this document.

3) Introduction to ALSA programming, this is a very detailed and high-quality article . The only downside is that playback and recording are separate and not merged together. Introduction to Sound Programming with ALSA | Linux Journal

Code for playing while playing: (9 messages) The alsa framework writes the application layer to realize recording while playing 

The simplified version of the routine on the official website is short and concise, with a clear structure ALSA project - the C library reference: /test/pcm_min.c (alsa-project.org) 

4)ALSA wiki : AlsaProject (alsa-project.org)

5)arch ALSA wiki: Advanced Linux Sound Architecture - ArchWiki (archlinux.org)

6) Amixer command line explanation and examples:  amixer: command-line mixer for ALSA soundcard driver - Linux Man Pages (1) (systutorials.com) 

7 ) ALSA official API interface description:  ALSA project - the C library reference: Index, Preamble and License (alsa-project.org)

8) ALSA Design Philosophy Map   ALSA topology - AlsaProject (alsa-project.org)

9) Device Name:  DeviceNames - AlsaProject (alsa-project.org) 

10) Mixer command help information and examples   amixer: command-line mixer for ALSA soundcard driver - Linux Man Pages (1) (systutorials.com)

11) The difference between Line in and mic in input interface:  Line In vs Mic In (Line Level Explained For Dummies) (producerhive.com) 

(9 messages) MICIN, LINEIN, LINEOUT, HPOUT, microphone, earphone, speaker once explained clearly_[qljun] qlexcel's blog-CSDN blog_hpout

12 ) The hardware map is good   ALSA overview - stm32mpu (stmicroelectronics.cn) 

Guess you like

Origin blog.csdn.net/proware/article/details/126331882