ALSA의 Application에서 주로 사용하는 Interface는 다음과 같다.
- PCM interface: PCM을 open하여 capture와 playback을 조절한다.
- Timer interface: Timer를 제공하여, PCM Interface와 함게 event를 제공하다.
- Mixer interface: Volume 조절 및 PCM의 설정 제공한다.
http://elinux.org/images/8/82/Elc2011_lorriaux.pdf
http://free-electrons.com/doc/embedded_linux_audio.pdf
1.1 ALSA PCM Buffer 구성 및 설명
아래의 그림은 기본적인 2Ch인 Stereo 방식의 Buffer 구성이며 기본구성
Buffer는 일반적으로 Stereo 로 사용할 경우 1 Frame: 2 CH * 2byte로 구성이 되지만, 각 PCM의 설정에 따라 변경된다.
이 기본 Frame은 기본 한구성이 있는데 다음과 같다.
- frame_size (기본 2 Ch 설정)
ALSA의 기본단위는 Frame이며 아래와 같이 계산된다.
1 Frame : Number of CH * Number of Sample
(Ex: 2CH * 1 Sample: 2 * 2byte = 4byte)
그리고, period 로 frame을 묶어 주기적으로 Timer interrupt를 사용하여 전송하며, 이 전체사이즈를 buffer라고 한다.
ALSA는 위와 같이 playback or capture를 위와 같이 buffer size 만큼의 delay 가 발생하며,즉 latency 발생된다.
- period_size
Buffer를 크기를 크게하면, Power consumption 약간 증가한다 그래서 적절히 다운시켜 사용해야 하는 것으로 보인다.
struct snd_pcm_hardware 구조체관련내용
http://egloos.zum.com/furmuwon/v/11008641
http://egloos.zum.com/furmuwon/v/11008641
ALSA buffer overflow(XRUN)
https://ffmpeg.org/pipermail/ffmpeg-user/2013-March/014090.html
설정은 buffer_size = period_size x period_count, 주로 Application에서 사용한다.
이 크기는 playback 시 delay가 되는 latency를 의미한다.
1.2 Threshold 설정 과 XRun
https://ffmpeg.org/pipermail/ffmpeg-user/2013-March/014090.html
- buffer_size
설정은 buffer_size = period_size x period_count, 주로 Application에서 사용한다.
이 크기는 playback 시 delay가 되는 latency를 의미한다.
1.2 Threshold 설정 과 XRun
Threshold 설정은 주로 보면 Buffer Xrun을 조절하기 위해서 사용되어지며, 관련설정들의 의미를 정확하게 알아두자
설정방법
start threadhold 인 경우,이설정값이 지난 후에, 동작가능하다.
- start_threshold
audio stream, data들이 들어왔을 경우, start point, 시작지점 설정을 말하며, underrun과 관련이 있다.
(The start threshold parameter is used to determine the start point in the stream.)
(The start threshold parameter is used to determine the start point in the stream.)
설정방법
if available frames >= threadhold, it is possible to play or capture i.e: period_count * period_size snd_pcm_sw_params_set_start_threshold
start threadhold 인 경우,이설정값이 지난 후에, 동작가능하다.
- stop_threshold
overrun(buffer의 overflow)을 체크하기 위한 level이라고 생각하면 되며. 이 값을 넘으면,자동적으로 stop이 된다.
(the stop threshold parameter is used to automatically stop the running stream when the available samples crosses this boundary for checking underrun or overun.)
(the stop threshold parameter is used to automatically stop the running stream when the available samples crosses this boundary for checking underrun or overun.)
설정방법
if available frames >= threadhold , pcm is automatically stoping the running system. for playback, capture threadhold > buffer size with xrun for playback, capture threadhold = buffer size without xrun if (avail >= runtime->stop_threshold) //pcm_lib.c xrun(substream); i.e: period_count * period_size snd_pcm_sw_params_set_stop_thresholdstart or stop threshold를 보면 start point와 stop point를 정확히 설정하는 것이다.
threshold라는 것이 문턱 or 설정한 level이라고 생각하면되겠다.
이는 xrun과 밀접한 관련이 있으며 audio가 주로 멈추는 현상은 이 xrun 현상이며,
이부분은 period_size 과 stop_Threadhold 값을 잘 조절해서 맞추어 가며 재 설정해 간다
- silence threshold
playback 시 미리 silent sample을 채워 이를 재생을 하는 것이다.
(sample's number filled with silence ahead of the current application pointer for playback.)
(sample's number filled with silence ahead of the current application pointer for playback.)
i.e: 0 snd_pcm_sw_params_set_silence_threshold
- XRUN
이는 두 device간의 read 와 write 간의 속도차로 발생하여, buffer 부족하면, underrun 이라고 하고,
buffer가 넘치면 이를 overrun이라고 한다.
자주 발생하는 XRUN 현상
- playback일 경우, empty buffer로 인하여, underrun 발생 하여 재생불능 상태 발생
- capture 일 경우, buffer가 데이타 넘쳐 overrun 발생하여, 더이상 녹음 불능 발생
XRUN Debug
http://www.alsa-project.org/main/index.php/XRUN_Debug
- Sound buffers and Data Transfer
- 기본예제 및 Buffer의 기본개념 XRUN 설명
http://www.alsa-project.org/main/index.php/FramesPeriods
1.3 Kernel PCM Driver 관련설정
- Kernel driver에서 PCM에 관한 설정
$ vi include/sound/pcm.h // DM368 struct snd_pcm_hardware { unsigned int info; /* SNDRV_PCM_INFO_* */ u64 formats; /* SNDRV_PCM_FMTBIT_* */ unsigned int rates; /* SNDRV_PCM_RATE_* */ unsigned int rate_min; /* min rate */ unsigned int rate_max; /* max rate */ unsigned int channels_min; /* min channels */ unsigned int channels_max; /* max channels */ size_t buffer_bytes_max; /* max buffer size */ size_t period_bytes_min; /* min period size */ size_t period_bytes_max; /* max period size */ unsigned int periods_min; /* min # of periods */ unsigned int periods_max; /* max # of periods */ size_t fifo_size; /* fifo size in bytes */ }; $ vi ./sound/soc/davinci/davinci-pcm.c //DM368 HW Setting . PCM Driver static struct snd_pcm_hardware pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_KNOT), .rate_min = 8000, .rate_max = 96000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 128 * 1024, // max buffer_size =128 x 1024 = 131072 .period_bytes_min = 32, // min period_size = 32 .period_bytes_max = 8 * 1024, // max period_size = 8x 1024 = 8192 .periods_min = 16, // min period_count .periods_max = 255, // max period_count .fifo_size = 0, }; static struct snd_pcm_hardware pcm_hardware_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_KNOT), .rate_min = 8000, .rate_max = 96000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 32, .period_bytes_max = 8 * 1024, .periods_min = 16, .periods_max = 255, .fifo_size = 0, };
http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/ch05s05.html#pcm-interface-runtime-hw
- HW/SW Params 확인
관련부분들 확인
2. Application 의 설정속성
Linux Kernel에서 ALSA관련 Device Interface를 제공하고, App은 이것을 이용을 DATA전송및 Control을 하게되고, Timer를 이용한다.
하지만 Embedded에서는 이 모든 기능을 다 제공하지는 않는다.
대부분 Control과 PCM과 Timer를 제공하고 다른 기능은 거의 제공하지는 않는다.
$ vi ./include/sound/pcm.h struct snd_pcm_runtime { /* -- Status -- */ struct snd_pcm_substream *trigger_master; struct timespec trigger_tstamp; /* trigger timestamp */ int overrange; snd_pcm_uframes_t avail_max; snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ /* -- HW params -- */ snd_pcm_access_t access; /* access mode */ snd_pcm_format_t format; /* SNDRV_PCM_FORMAT_* */ snd_pcm_subformat_t subformat; /* subformat */ unsigned int rate; /* rate in Hz */ unsigned int channels; /* channels */ snd_pcm_uframes_t period_size; /* period size */ unsigned int periods; /* periods */ snd_pcm_uframes_t buffer_size; /* buffer size */ snd_pcm_uframes_t min_align; /* Min alignment for the format */ size_t byte_align; unsigned int frame_bits; unsigned int sample_bits; unsigned int info; unsigned int rate_num; unsigned int rate_den; /* -- SW params -- */ int tstamp_mode; /* mmap timestamp is updated */ unsigned int period_step; snd_pcm_uframes_t start_threshold; snd_pcm_uframes_t stop_threshold; snd_pcm_uframes_t silence_threshold; /* Silence filling happens when noise is nearest than this */ snd_pcm_uframes_t silence_size; /* Silence filling size */ snd_pcm_uframes_t boundary; /* pointers wrap point */ snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ snd_pcm_uframes_t silence_filled; /* size filled with silence */ union snd_pcm_sync_id sync; /* hardware synchronization ID */ ......
2. Application 의 설정속성
Linux Kernel에서 ALSA관련 Device Interface를 제공하고, App은 이것을 이용을 DATA전송및 Control을 하게되고, Timer를 이용한다.
하지만 Embedded에서는 이 모든 기능을 다 제공하지는 않는다.
대부분 Control과 PCM과 Timer를 제공하고 다른 기능은 거의 제공하지는 않는다.
- Control Interface (/dev/snd/controlCX)
- Mixer Interface (/dev/snd/mixerCXDX)
- PCM Interface (/dev/snd/pcmCXDX)
- Raw MIDI Interface (/dev/snd/midiCXDX)
- Sequencer Interface (/dev/snd/seq)
- Timer Interface (/dev/snd/timer)
http://www.alsa-project.org/alsa-doc/alsa-lib/
http://www.alsa-project.org/main/index.php/ALSA_Library_API
2.1 PCM Device Interface
Application 에서 주요하게 다루는 Interface는 PCM이다. (/dev/snd/pcmCxDx)
PCM Interface를 이용하여, Audio Data를 전송하여 Play하고 Capture를 하며, Block Mode와 Non Block Mode 및 XRUN 감지 및 parameter 관리등을 다룬다.
아래는 TI의 PCM device file을 보여주며, 모든 ALSA의 기능을 제공해주지는 않는다.
Embedded 에서는 아래와 같이 기본기능만을 사용한다.
- 실제의 사용되어지는 예
Caputre/Playback/Timer/Control 만 사용되며, App에서는 이를 이용하여 ALSA를 이용
$ ls /dev/snd/ controlC0 pcmC0D0c pcmC0D0p timer
관련내용
http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html
2.2 Timer Interface
Timer는 ALSA를 NonBlock 모드사용할 경우 주로 사용하는 것 같다.
http://www.alsa-project.org/alsa-doc/alsa-lib/timer.html
http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2timer_8c-example.html#a1
2.3 HW/SW Parameters
Kernel에서 Parameter의 기능의 제한이 되고, Application에서 이 설정의 변경이 가능하다.
이 설정을 변경을 함으로써, 성능 및 XRUN 문제의 오류를 방지하고 변경하자.
.channels = mono or stero 으로 설정 (2 or 1) .rate = Sample rate 값 설정 .period_size = P-Frame으로 설정. (unit: frame) .period_count = P-Frame Count .format = PCM_FORMAT_S16_LE or PCM_FORMAT_S32_LE , 다른 값. .start_threshold = minum , .silence_threshold = 0 .stop_threshold = > buffer size
default start_threshold : period_count * period_size, default setting values stop_threshold : period_count * period_size, default setting values (XRUN control) silence_threshold : 0 frame_size = num of channel * a sample (i.e 2* 1 sample = 4 byte) buffer_size = period_size * period_count (unit: frame) period_bytes = period_size * bytes_per_frame (unit: frame) bytes_per_frame = channels * bytes_per_sample (unit: byte) (4byte ,Stereo-2Ch))
http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_min_8c-example.html#a6
- period_size
PMIC와 같이 사용하는 것에는 Power Consumption 영향을 미치며. 크기를 크게하면, Power consumption 약간 증가한다.
그래서 적절히 다운시켜 사용해야 하는 것 같다.
아래는 Period Size를 구하는 간단한 예제이다, Interrupt Time을 아래와 같이 설정하고
아래는 Period Size를 구하는 간단한 예제이다, Interrupt Time을 아래와 같이 설정하고
- period_size = Sample rate x ( Interrupt Time) , unit : frame
5292 = 44100 x (P Time 120/1000, interrupt time)
5760 = 48000 x (P Time 120/1000, interrupt time)
(ABE, Only 48KHz used. if used 44.1KHz resampling by Speex )
참고로, 48KHz로만 사용할것이다, 44.1KHz는 Resample이 필요할 것이다.
1056 = 48000 x (22/1000)
- 아래의 Link는 byte단위로 계산을 했지만, 위 계산은 Frame 단위이다.
- buffer_size :
설정은 buffer_size = period_size x period_count, 주로 Application에서 사용한다.
- B Time: P Time * period_count= Latency
B Frame이 소비되는 시간을 말하며, 정확하게는 Latency.
** Latency: Buffer Time
아래는 tinyalsa lib의 기본소스
https://github.com/tinyalsa/tinyalsa
https://github.com/tinyalsa/tinyalsa
3. ALSA 기타 설정 항목 설명 (추후 삭제)
boundary
sw_param 1937768448
avail
runtime->status->hw_ptr : the number of frame that kernel write.
runtime->control->appl_ptr : the number of frame that application write, x4 ( 2byt and 2xchannel)
Playback (pcm_mmap_playback_avail/ pcm.c application)
avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
Capture (pcm_mmap_capture_avail)
int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
start threadhold
The start threshold parameter is used to determine the start point in stream.
sample's number if available frames >= threadhold, it is possible to play or capture
i.e: period_count * period_size
snd_pcm_sw_params_set_start_threshold
stop threadhold
the stop threshold parameter is used to automatically stop the running stream when the available samples crosses this boundary.
for checking underrun or overun.
sample's number if available frames >= threadhold , pcm is automatically stoping the running system.
for playback, capture threadhold > buffer size with xrun
for playback, capture threadhold = buffer size without xrun
if (avail >= runtime->stop_threshold) //pcm_lib.c
xrun(substream);
i.e: period_count * period_size
snd_pcm_sw_params_set_stop_threshold
- Android HAL
https://source.android.com/devices/audio/
https://source.android.com/devices/audio/implement.html
https://android.googlesource.com/device/ti/panda/+/master/audio/audio_hw.c
https://www.google.co.kr/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=audio_hw.c
https://source.android.com/devices/audio/implement.html
- Android HAL Examples
https://android.googlesource.com/device/ti/panda/+/master/audio/audio_hw.c
https://www.google.co.kr/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=audio_hw.c
- ALSA 기본설명
- ALSA 기본 예제