커널에서 여러 원시 PCM 데이터 스트림을 결합하고 이를 TDM 프레임으로 라우팅하여 iMX 8M Mini의 SAI 인터페이스를 통해 전송하는 방법

커널에서 여러 원시 PCM 데이터 스트림을 결합하고 이를 TDM 프레임으로 라우팅하여 iMX 8M Mini의 SAI 인터페이스를 통해 전송하는 방법

iMX8(PCM -48Kz, 16비트, 2ch)에서 여러 오디오 스트림(8개 스트림)을 결합하려고 합니다. 사용자 공간의 테스트 모드는 RAW PCM이 포함된 wav 파일을 재생하기 위해 8개의 gst_launch/aplay 인스턴스를 동시에 실행하는 것과 유사합니다.
제가 겪고 있는 문제는 iMX8에 연결된 보드에 오디오를 종료할 수 있는 오디오 하드웨어 장치(카드)가 없다는 것입니다. 대신 오디오(PCM)는 SAI 인터페이스로 라우팅되어야 하며 8개 스트림의 샘플은 TDM 프레임으로 다중화되어 iMX8의 SAI 인터페이스를 통해 전송됩니다. SAI 라인은 오디오 FPGA에 연결되어 TDM 출력을 역다중화하고 이를 메인 CPU 보드에 연결된 서로 다른 보드의 8개 포트로 보냅니다. iMX8 프로세서용 커널 드라이버 솔루션을 제공해야 합니다. 우리는 Yocto에서 iMX8M Mini 애플리케이션 프로세서와 Linux 4.14.98을 사용하고 있습니다.
나는 ALSA를 처음 접했습니다. 내 전체 배경은 커널의 비디오/디스플레이/PCI 하위 시스템에 있습니다.

ALSA에 대해 더 자세히 살펴보면 전체 ALSA 코어/하드웨어 아키텍처는 오디오 하드웨어 터미네이션을 중심으로 구축되었으며 그 아키텍처는 다음과 같습니다.Linux BSP에서 사용자 정의 오디오 코덱 포팅작성자: Gopinath Srinivasan:
Alsa 커널 드라이버 ⟺ [Coder/Dec ⟺ 머신 드라이버 ⟺ 플랫폼 드라이버] ⟺ 프로세서 HW(오디오).

나는 가능한 한 많이 읽으려고 노력했으며 이것이 지금까지 내가 이해한 것입니다.

하드웨어 장비가 없기 때문입니다.

  1. 오디오를 커널에 전달하기 위해 snd_dummy 또는 snd_aloop(dummy/aloop 오디오 드라이버를 활성화하는 데 사용됨)을 활성화할 수 있습니까? 이러한 기능을 활성화하고 Seller_test 및 aplay를 실행하여 테스트했는데 앱이 충돌 없이 작동하는 것 같았습니다.
  2. 코어에서 샘플을 읽고 결합한 후 SAI FIFO(TDR/TFR)에 쓰고 해당 BCLK/MCLK를 설정합니다. 아마도 이를 달성하기 위해 SAI의 비동기 모드를 사용할 수 있습니다. 현재 Alsa 드라이버 모델에서 이 경로를 활성화하는 방법을 잘 모르겠습니다.

위의 방법에 대해 몇 가지 질문이 있습니다. 또한 이것이 오디오를 처리하는 올바른 방법인지도 모르므로 제가 틀렸다면 정정해 주시기 바랍니다. 또 다른 문제는 SAI 인터페이스에서 나오는 WCLK/MCLK/BCLK/TX0 라인을 검색하는 것 외에는 이를 테스트할 수 있는 다른 방법이 없다는 것입니다. 그것은 완전히 다른 질문입니다. 일단 거기에 가면 그것에 대해 걱정할 것입니다.

내 질문은 다음과 같습니다.

  1. 이 방법으로 시작하는 것이 맞나요?
  2. 플러그인(Dmix)에 대해 읽었습니다. DMIX 플러그인은 어떻게 작동하나요? 이 경우 이 플러그인을 사용하여 conf 파일(asoundrc, alsa.conf 등)에 작성된 일부 구성을 통해 어떻게든 TDM fifo에 기록되는 8개의 포트와 샘플을 모두 구성할 수 있습니까? 이것이 어떻게 작동하는지 모르겠습니다. 몇 가지 질문을 제기합니다. 이것이 의미가 있는지 모르겠습니다.
  3. HW 장치가 없으므로 DTS에서 SAI를 구성하는 방법은 무엇입니까? snd_aloop/snd_dummy를 사용할 때 어떤 코덱을 활성화해야 합니까(오디오가 커널에 전달되는 방식이라고 가정)? 여기처럼. 이는 Freescale iMX8M Mini 평가 보드를 기반으로 합니다.
    sound-ak4458 {                                          
           compatible = "fsl,imx-audio-ak4458";            
           model = "ak4458-audio";                         
           audio-cpu = <&sai1>;                      <-------      
           audio-codec = <&ak4458_1>, <&ak4458_2>;         <--------
           ak4458,pdn-gpio = <&pca6416 4 GPIO_ACTIVE_HIGH>;
    };                                                      
    
  4. 커널의 alsa 드라이버에 오디오가 어떻게 전달됩니까? 샘플이 ioclts/sysfs를 통해 버퍼로 전달되거나 메모리에 기록되거나(DMA?), audioHW/코덱에서 메모리(DMA)를 통해 직접 액세스되거나 다른 방법으로 액세스됩니까?
  5. ALSA는 데이터를 이 방식으로 전송해야 하는 경우 aloop.c/dummy.c 드라이버에서 직접 SAI 인터페이스(fsl_sai.c/h)에 액세스하는 것을 지원합니까?
  6. snd_dummy 드라이버를 활성화하면 8개의 하위 장치가 생성됩니다. 사용자 공간 애플리케이션이 이러한 8개 하위 장치를 8개의 서로 다른 하드웨어 포트(hw:0,0; hw:0,1; hw:0,2 등)로 사용할 수 있습니까, 아니면 8개의 별도 개발 노드(hw:0, 0;hw:0,0;hw:0,2 등)? hw:1,0; hw:2,0 등)을 애플리케이션에 보낼 것인가? 후자가 맞다면 가상/루프 드라이버에서 별도의 개발 노드를 만들 수 있습니까?

나를 올바른 방향으로 안내하는 데 도움을 주시면 대단히 감사하겠습니다. 질문이나 세부정보를 추가해야 하는 경우 알려주시기 바랍니다.

답변1

dshare 플러그인을 사용하여 8개 채널에서 작동하는 TDM 프레임을 만들 수 있었습니다. 그런데 16채널로 늘리려고 했더니 폴링 기능에서 재생이 멈추는 문제가 발생했습니다. 바라보다내 다른 기사는 여기에 있습니다..

/dev/snd/timer나는 dshare/dmix 플러그인이 사용하는 것 대신 서버를 사용하는 공유 "share" 플러그인을 사용해 보았습니다 .

그러나 여러 클라이언트를 동시에 재생하려고 하면 하나의 클라이언트를 재생한 후 오디오 장치 사용 중 오류가 발생합니다. 여러 소스를 재생하려면 구성 파일에 다른 것이 필요합니까?

보다 asound.conf:

# Crestron DNA_AUDIO x specific configurations
# NOTE: this is for sharing multiple channels on a single (TDM) audio device
# with multple ALSA clients

# shared buffer for playback
pcm_slave.tdmshare {
    pcm "hw:0"
    channels 16
    rate 48000          # fixed, because all dshare devices must use the same samplerate.
    format S24_LE
}

# src1 shared pcm device and corresponding virtual playback device
pcm.src1_share {
    type share
    slave tdmshare
    bindings.0 0
    bindings.1 4
}
pcm.src1 {
    type plug
    slave.pcm "src1_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 0 channel 0/1 for audio playback"
        }
}

# src2 shared pcm device and corresponding virtual playback device
pcm.src2_share {
    type share
    slave tdmshare
    bindings.0 8
    bindings.1 12
}
pcm.src2 {
    type plug
    slave.pcm "src2_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 1 channel 2/3 for audio playback"
        }
}

# src3 shared pcm device and corresponding virtual playback device
pcm.src3_share {
    type share
    slave tdmshare
    bindings.0 1
    bindings.1 5
}
pcm.src3 {
    type plug
    slave.pcm "src3_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 2 channel 4/5 for audio playback"
        }
}

# src4 shared pcm device and corresponding virtual playback device
pcm.src4_share {
    type share
    slave tdmshare
    bindings.0 9
    bindings.1 13
}
pcm.src4 {
    type plug
    slave.pcm "src4_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 3 channel 6/7 for audio playback"
        }
}

# src5 shared pcm device and corresponding virtual playback device
pcm.src5_share {
    type share
    slave tdmshare
    bindings.0 2
    bindings.1 6
}
pcm.src5 {
    type plug
    slave.pcm "src5_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 4 channel 8/9 for audio playback"
        }
}

# src6 shared pcm device and corresponding virtual playback device
pcm.src6_share {
    type share
    slave tdmshare
    bindings.0 10
    bindings.1 14
}
pcm.src6 {
    type plug
    slave.pcm "src6_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 5channel 10/11 for audio playback"
        }
}

# src7 shared pcm device and corresponding virtual playback device
pcm.src7_share {
    type share
    slave tdmshare
    bindings.0 3
    bindings.1 7
}
pcm.src7 {
    type plug
    slave.pcm "src7_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 6 channel 12/13 for audio playback"
        }
}

# src8 shared pcm device and corresponding virtual playback device
pcm.src8_share {
    type share
    slave tdmshare
    bindings.0 11
    bindings.1 15
}
pcm.src8 {
    type plug
    slave.pcm "src8_share"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 7 channel 14/15 for audio playback"
        }
}

관련 정보