/dev/snd/timer의 폴링 기능에서 멈춘 dshare 플러그인을 사용한 alsa 16 채널 오디오 재생

/dev/snd/timer의 폴링 기능에서 멈춘 dshare 플러그인을 사용한 alsa 16 채널 오디오 재생

질문:Freescale IMX8m을 사용하여 SAI(5) 데이터 회선을 통해 16채널 오디오 TDM 스트림을 전송합니다. 하드웨어에는 코덱 종료가 없습니다. 데이터만 TDM에 캡슐화되어 I2S 데이터 라인을 통해 전송됩니다. Imx8m 데이터 라인의 다른 쪽 끝에서 데이터를 수신하고 이를 여러 오디오 출력 소스로 역다중화하는 FPGA가 있습니다.

질문:8개 채널(4개 스테레오 소스)을 재생할 때 TDM 프레임이 문제 없이 잘 작동하는 것 같습니다. 그러나 TDM 프레임 크기를 16채널(8개 스테레오 소스)로 늘리면 재생이 시작되기도 전에 정지되는 경우가 있습니다. poll() 함수에 갇혀서 절대 반환되지 않습니다. 폴링 함수는 /alsa-lib/src/pcm/pcm.c에 있는 snd_pcm_write_areas()의 최상위 수준에서 호출됩니다.

이것은 aplay app/alsa-lib <=> alsa-pcm-snd-driver <==> fsl_sai 드라이버 > HW 사이에서 디버깅하는 동안 발견한 것입니다.

  1. 재생이 정상적으로 되면 알 수 있어요snd_pcm_direct.spcm->hw.ptrsnd_pcm_write_areas를 호출할 때마다 프레임 크기가 *1(또는 그 이상)씩 늘어납니다. 이 포인터는 전송되어야 하는 프레임 수를 시간 내에 추적하는 것으로 보입니다. 경계가 0x40000000인 부호 없는 int 값입니다. 경계에 도달하면 ptr이 다시 반복됩니다. alsa-lib/src/pcm/pcm.c 파일에서
 static int snd_pcm_dshare_start_timer(snd_pcm_direct_t *dshare)
 {
  int err;
  snd_pcm_hwsync(dshare->spcm);
    dshare->slave_appl_ptr= dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
  1. 폴링 기능에서 재생이 중단되면 포인터가 업데이트되지 않고 기간 크기(프레임 크기 * n) 또는 프레임 크기의 일부 배수에서 중단되는 것을 발견했습니다.
  2. 온라인에서 alsa 재생 중단에 대한 여러 게시물을 보았지만 해결 방법이나 지침은 없습니다.
  3. Dshare/Dmix/Dsnoop 플러그인을 사용할 때 커널 4.14부터 존재하는 alsa 버그라는 기사도 읽어보세요.
  4. 1.1.2에서 버전 1.1.5 또는 1.1.7로 업그레이드를 시도했지만 성공하지 못했습니다. 분명히 이 문제는 하드웨어 카드를 사용할 때는 발생하지 않으며 위에서 언급한 플러그인을 사용할 때만 발생합니다.

어느 쪽이 다른 쪽의 원인인지, 어느 쪽이 수정해야 할 버그인지 잘 모르겠습니다.

타이머가 잘못된 상태로 진입하여 폴링 기능이 중단되거나 타이머가 잘못된 상태로 진입하여 폴링 기능이 중단됩니다.

TDM 프레임을 생성하는 방법에 대한 세부 정보 우리는 16채널 오디오(8개의 개별 스테레오 쌍)를 가지고 있으며 SAI 데이터 라인(4개의 데이터 라인) 중 하나에 기록되도록 하드웨어에 프레임으로 보내야 합니다. 이 8개 소스는 독립적으로 재생할 수 있으며 소스는 asound.conf 구성 파일에 지정된 채널 매핑에 따라 TDM 프레임의 시간 슬롯을 차지합니다.

이것미덕을 공유하다플러그인은 프레임이 저장될 공유 버퍼를 생성하는 데 사용됩니다. conf 파일에 각 재생 프로세스마다 하나씩 8개의 가상 소스를 만들었습니다. 각 소스는 별도의 재생 프로세스에서 사용되어 8개의 서로 다른 소스를 재생할 수 있습니다. 8개 소스를 모두 재생하는 배치 파일을 봅니다.

aplay 출력 -L/l

null
    Discard all samples (playback) or generate zero samples (capture)
src1
    TDM 0 channel 0/1 for audio playback
src2
    TDM 1 channel 2/3 for audio playback
src3
    TDM 2 channel 4/5 for audio playback
src4
    TDM 3 channel 6/7 for audio playback
src5
    TDM 4 channel 8/9 for audio playback
src6
    TDM 5channel 10/11 for audio playback
src7
    TDM 6 channel 12/13 for audio playback
src8
    TDM 7 channel 14/15 for audio playback
default:CARD=<xxxxx>
    Default Audio Device
sysdefault:CARD=<xxxxxxxx>
    Default Audio Device

asound.conf 파일

# 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
    period_size 512
    buffer_size 1024
}

# src1 shared pcm device and corresponding virtual playback device
pcm.src1_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 0
    bindings.1 4
}
pcm.src1 {
    type plug
    slave.pcm "src1_dshare"
 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_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 8
    bindings.1 12
}
pcm.src2 {
    type plug
    slave.pcm "src2_dshare"
 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_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 1
    bindings.1 5
}
pcm.src3 {
    type plug
    slave.pcm "src3_dshare"
 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_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 9
    bindings.1 13
}
pcm.src4 {
    type plug
    slave.pcm "src4_dshare"
 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_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 2
    bindings.1 6
}
pcm.src5 {
    type plug
    slave.pcm "src5_dshare"
 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_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 10
    bindings.1 14
}
pcm.src6 {
    type plug
    slave.pcm "src6_dshare"
 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_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 3
    bindings.1 7
}
pcm.src7 {
    type plug
    slave.pcm "src7_dshare"
 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_dshare {
    type dshare
    ipc_key 43544553
    slave tdmshare
    bindings.0 11
    bindings.1 15
}
pcm.src8 {
    type plug
    slave.pcm "src8_dshare"
 hint {
                show {
                        @func refer
                        name defaults.namehint.basic
                }
                description "TDM 7 channel 14/15 for audio playback"
        }
}

8개 소스를 모두 재생하기 위한 배치 파일

aplay -Dplug:src1 /data/PCMCH1-Ch2_1.wav&
aplay -Dplug:src2 /data/PCMCH3-Ch4_1.wav&
aplay -Dplug:src3 /data/PCMCH5-Ch6_1.wav&
aplay -Dplug:src4 /data/PCMCH7-Ch8_1.wav&
aplay -Dplug:src5 /data/PCMCH1-Ch2_1.wav&
aplay -Dplug:src6 /data/PCMCH3-Ch4_1.wav&
aplay -Dplug:src7 /data/PCMCH5-Ch6_1.wav&
aplay -Dplug:src8 /data/PCMCH7-Ch8_1.wav&

asound.conf 파일에 수정할 수 있는 내용이 있는지 또는 alsa-lib에서 16개 대 8개 채널을 재생할 때 직면하는 제한 사항으로 인해 이 문제가 발생하는지 알려주십시오.

이 문제와 관련하여 제가 본 다른 링크는 다음과 같습니다. 매우 오래된 링크이며 어떤 사람들은 수정되었다고 하는데 어떻게 수정되었는지, 패치가 무엇인지 잘 모르겠습니다. 우리 시스템은 alsa 버전 1.1.6과 커널 4.14를 사용하고 있으며 이 버전에 있습니다. 이 문제를 해결하는 방법을 보여주는 패치 세트나 링크를 알려주십시오. 이 분야에 대한 지식이 부족하여 현재로서는 이 문제에 대해 막다른 골목에 있습니다.

[https://bugzilla.redhat.com/show_bug.cgi?id=534130][1]

[https://www.raspberrypi.org/forums/viewtopic.php?t=64936][2]

[https://sourceforge.net/p/alsa/mailman/message/26464680/][3]

답변1

커널 사운드 코어 pcm 드라이버와 pcm 코어 dma 엔진에서 사용하는 해당 sdma 컨트롤러를 디버깅한 후 DMA 컨트롤러(/drivers/dma/imx-sdma.c)와 SAI FIFO(/sound/soc)가 발견되었습니다. /fsl /fsl_sai.c) 채널 수가 16개이고 각 채널의 폭이 32비트일 때 중지됩니다. asound.conf 파일에 지정된 DMA 버퍼 크기도 영향을 미칩니다.

Sdma 컨트롤러의 인터럽트 핸들러는 위의 질문에서 언급한 HW.ptr의 인터럽트 핸들러를 추가하는 것입니다. SDMA 인터럽트 핸들러는 alsa 사용자 공간에서 생성된 타이머를 트리거하고, 사용자 공간은 DMA 메모리 매핑된 버퍼 영역에 쓸 버퍼 수를 알기 위해 해당 타이머(고착된 위치)가 지워질 때까지 폴링 함수에서 기다립니다.

dma 인터럽트 핸들러는 트리거되지 않으므로 HW.ptr은 업데이트되지 않으며 타이머 인터럽트 핸들러도 트리거되지 않으므로 사용자 공간이 폴링 기능에서 대기하고 반환되지 않습니다.

이것이 최종 해결책은 아닐 수도 있지만 상황에 따라 해결책은 DMA 컨트롤러 펌웨어/스크립트 내에서 수정되거나 DMA 컨트롤러에 연결된 주변 FIFO가 작동하는 방식일 수 있습니다. 어느 쪽이든 특정 프로세서의 기본 하드웨어 IP 구현을 이해하는 것이 필요합니다.

관련 정보