【鼎革‧革鼎】︰ Raspbian Stretch 《六之 H.3上 》

由於想知道為什麼 jackd 會發生 mmap-based 之問題?

pi@raspberrypi:~ jackd -dalsa  -r44100 -p512 -n4 -Phw:0 -Cac108 jackdmp 1.9.11 Copyright 2001-2005 Paul Davis and others. Copyright 2004-2014 Grame. jackdmp comes with ABSOLUTELY NO WARRANTY This is free software, and you are welcome to redistribute it under certain conditions; see the file COPYING for details JACK server starting in realtime mode with priority 10 self-connect-mode is "Don't restrict self connect requests" ALSA lib control.c:1373:(snd_ctl_open_noupdate) Invalid CTL ac108 control open "ac108" (No such file or directory) audio_reservation_init Acquire audio card Audio0 creating alsa driver ... hw:0|ac108|512|4|44100|0|0|nomon|swmeter|-|32bit configuring for 44100Hz, period = 512 frames (11.6 ms), buffer = 4 periods ALSA: mmap-based access is not possible for the capture stream of this audio interface ALSA: cannot configure capture channel Cannot initialize driver JackServer::Open failed with -1 Failed to open server </pre>    <span style="color: #666699;">分明 /boot/config.txt 已設定了</span>  <span style="color: #ff9900;">dtoverlay=i2s-mmap</span>  <span style="color: #666699;">的也!故爾閱讀 github 上 <a style="color: #666699;" href="https://github.com/respeaker/seeed-voicecard">seeed-voicecard</a> <a style="color: #666699;" href="http://www.freesandal.org/?p=26396">dtoverlay</a> 的原始碼︰</span> <pre class="lang:default decode:true">pi@raspberrypi:~/seeed-voicecard 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 </pre>    <span style="color: #666699;">初看唯得知其稱作 seeed-4mic-voicecard 名目之由來哩︰</span> <pre class="lang:default decode:true ">pi@raspberrypi:~ 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:~ </pre>    <span style="color: #666699;">再看它的 asound_4mic.conf 之設定︰</span> <pre class="lang:default decode:true">pi@raspberrypi:~/seeed-voicecard 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

 

尚且難知又頭大呦!!仍得爬文乎??

TwoCardsAsOne

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

 

樂知好學者或早先登耶◎

ALSA – PCM接口