由於想知道為什麼 jackd 會發生 mmap-based 之問題?
pi@raspberrypi:~ more seeed-4mic-voicecard-overlay.dts
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2708";
fragment@0 {
target = <&i2s>;
__overlay__ {
#sound-dai-cells = <0>;
status = "okay";
};
};
fragment@1 {
target-path = "/clocks";
__overlay__ {
ac108_mclk: codec-mclk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24000000>;
};
};
};
fragment@2 {
target = <&i2c1>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
ac108_a: ac108@3b{
compatible = "x-power,ac108_0";
reg = <0x3b>;
#sound-dai-cells = <0>;
data-protocol = <1>;
};
};
};
fragment@3 {
target = <&sound>;
sound_overlay: __overlay__ {
compatible = "simple-audio-card";
simple-audio-card,format = "i2s";
simple-audio-card,name = "seeed-4mic-voicecard";
status = "okay";
simple-audio-card,bitclock-master = <&dailink0_slave>;
simple-audio-card,frame-slave = <&dailink0_slave>;
dailink0_slave: simple-audio-card,cpu {
sound-dai = <&i2s>;
};
codec_dai: simple-audio-card,codec {
sound-dai = <&ac108_a>;
clocks = <&ac108_mclk>;
};
};
};
__overrides__ {
card-name = <&sound_overlay>,"seeed-voicecard,name";
};
};
pi@raspberrypi:~/seeed-voicecard arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: seeed4micvoicec [seeed-4mic-voicecard], device 0: bcm2835-i2s-ac108-codec0 ac108-codec0-0 []
Subdevices: 1/1
Subdevice #0: subdevice #0
pi@raspberrypi:~ more asound_4mic.conf
# The IPC key of dmix or dsnoop plugin must be unique
# If 555555 or 666666 is used by other processes, use another one
pcm.!default {
type asym
playback.pcm "playback"
capture.pcm "ac108"
}
pcm.playback {
type plug
slave.pcm "dmixed"
}
pcm.dmixed {
type dmix
slave.pcm "hw:0,0"
ipc_key 555555
}
pcm.ac108 {
type ac108
slavepcm "hw:1,0"
channels 4
}
pi@raspberrypi:~/seeed-voicecard $
雖然查覽列出其所用之
PCM (digital audio) plugins
PCM plugins extends functionality and features of PCM devices. The plugins take care about various sample conversions, sample copying among channels and so on.
的定義與範例︰
Slave definition
The slave plugin can be specified directly with a string or the definition can be entered inside a compound configuration node. Some restrictions can be also specified (like static rate or count of channels).
pcm_slave.NAME {
pcm STR # PCM name
# or
pcm { } # PCM definition
format STR # Format or "unchanged"
channels INT # Count of channels or "unchanged" string
rate INT # Rate in Hz or "unchanged" string
period_time INT # Period time in us or "unchanged" string
buffer_time INT # Buffer time in us or "unchanged" string
}
Example:
pcm_slave.slave_rate44100Hz {
pcm "hw:0,0"
rate 44100
}
pcm.rate44100Hz {
type plug
slave slave_rate44100Hz
}
The equivalent configuration (in one compound):
pcm.rate44100Hz {
type plug
slave {
pcm "hw:0,0"
rate 44100
}
}
…
Plugin: asym
This plugin is a combination of playback and capture PCM streams. Slave PCMs can be defined asymmetrically for both directions.
pcm.name {
type asym # Asym PCM
playback STR # Playback slave name
# or
playback { # Playback slave definition
pcm STR # Slave PCM name
# or
pcm { } # Slave PCM definition
}
capture STR # Capture slave name
# or
capture { # Capture slave definition
pcm STR # Slave PCM name
# or
pcm { } # Slave PCM definition
}
}
For example, you can combine a dmix plugin and a dsnoop plugin as as a single PCM for playback and capture directions, respectively.
pcm.duplex {
type asym
playback.pcm "dmix"
capture.pcm "dsnoop"
}
By defining only a single direction, the resultant PCM becomes half-duplex.
……
Plugin: dmix
This plugin provides direct mixing of multiple streams. The resolution for 32-bit mixing is only 24-bit. The low significant byte is filled with zeros. The extra 8 bits are used for the saturation.
pcm.name {
type dmix # Direct mix
ipc_key INT # unique IPC key
ipc_key_add_uid BOOL # add current uid to unique IPC key
ipc_perm INT # IPC permissions (octal, default 0600)
slave STR
# or
slave { # Slave definition
pcm STR # slave PCM name
# or
pcm { } # slave PCM definition
format STR # format definition
rate INT # rate definition
channels INT
period_time INT # in usec
# or
period_size INT # in bytes
buffer_time INT # in usec
# or
buffer_size INT # in bytes
periods INT # when buffer_size or buffer_time is not specified
}
bindings { # note: this is client independent!!!
N INT # maps slave channel to client channel N
}
slowptr BOOL # slow but more precise pointer updates
}
ipc_key
specfies the unique IPC key in integer. This number must be unique for each different dmix definition, since the shared memory is created with this key number. When ipc_key_add_uid
is set true, the uid value is added to the value set in ipc_key
. This will avoid the confliction of the same IPC key with different users concurrently.
Note that the dmix plugin itself supports only a single configuration. That is, it supports only the fixed rate (default 48000), format (S16
), channels (2), and period_time (125000). For using other configuration, you have to set the value explicitly in the slave PCM definition. The rate, format and channels can be covered by an additional plug plugin, but there is only one base configuration, anyway.
An example configuration for setting 44100 Hz, S32_LE
format as the slave PCM of “hw:0” is like below:
pcm.dmix_44 {
type dmix
ipc_key 321456 # any unique value
ipc_key_add_uid true
slave {
pcm "hw:0"
format S32_LE
rate 44100
}
}
You can hear 48000 Hz samples still using this dmix pcm via plug plugin like:
% aplay -Dplug:dmix_44 foo_48k.wav
尚且難知又頭大呦!!仍得爬文乎??
From the ALSA wiki
Jump to: navigation, search
Contents
Notes
WARNING NOTE added by LudwigSchwardt: (comments welcome!)
Be careful when using this scheme for capturing (recording) audio data. It might work with multiple sample-synchronized cards (i.e. Hammerfall/ICE1712) that have a single sample clock signal driving all of them, or when the dummy soundcard is combined with another soundcard for testing. It will definitely fail when combining two or more unlinked soundcards. When using JACK, I typically got an error message of
snd_pcm_mmap_commit: Assertion `frames \<= snd_pcm_mmap_avail(pcm)’ failed
and jackd hangs in the process. This error may take a while to pop up, but it is inevitable, since this is a basic hardware limitation.
Each soundcard has its own sample clock. If these aren’t linked to the same clock in some way (eg. wordclock), the clock frequencies will differ, sometimes substantially, due to manufacturing tolerances on the crystals, etc. This means that the hardware interrupts announcing the availability of new data will be out of sync. Even worse, the cards with faster clocks will produce more data than the slower cards during the same time interval. Therefore, even if a program like JACK waited until all the soundcards had audio data available and then presented this data to its callback, at some stage data from the soundcard with a faster sample clock will have to be discarded to keep up with the rest. At the very least xruns will occur.
It might be possible to write a software layer (ALSA driver/plugin?) to hide the clock differences by effectively resampling the streams to a common frequency. This will be the only way to keep programs like JACK completely happy. As this will inevitably involve the discarding and/or generation of samples, it is still not a pretty solution. It will probably also increase the latency of the system.
On the other hand, this .asoundrc trick seems to work OK for playback. During playback, programs dump audio data into soundcard buffers and let the hardware decide when the data will reach the output terminals. These buffers in effect hide the difference in clock frequencies. However, xruns are probably still going to happen, for instance when the faster card runs out of data or the slower card’s buffer is full.
regards, Ludwig
樂知好學者或早先登耶◎