ALSA는 Audio Linux Sound Architecture의 약자.
리눅스에서 Audio를 구현하고자 할 때 사용되는 공개 라이브러리이다.
많이 사용되는 ALSA와 ALSA보다 몸집이 작은 tinyALSA, 이 두 라이브러리의 기본 API에 대해 설명한다.
- ALSA Overview
tinyALSA
Data Structure
- PCM config
- PCM Structure
- PCM Open
- PCM Read
- PCM Write
- PCM Close
- ALSA
- Data Structures
- PCM structure
- PCM HW config
- PCM SW config
- PCM Open
- PCM HW Params
- PCM SW Params
- PCM Prepare
- PCM Start
- PCM Avail
- PCM Read
- PCM Write
- PCM Close
- Data Structures
ALSA lib 참고 웹페이지
- ALSA
- Tiny ALSA
ALSA Overview
흔히 말하는 ALSA는 보통 User Space에서 ALSA library를 가져다 쓰는 것을 말한다.
ALSA application으로는 aplay, arecode, amixer, tinyplay 등이 있으며, 오디오 어플리케이션을 쓸 때 이 코드를 많이 참고하여 사용한다.
tinyALSA
Android에는 tinyALSA가 올라가있다.
tinyALSA의 경우에는 단순히 Open, Read/Write, Close만 해주면 audio 사용이 가능하다.
Data Structure
tinyALSA를 사용하기 위해서는 PCM Handler와 PCM Config가 필요하다.
PCM config
struct pcm_config {
unsigned int channels;
unsigned int rate;
unsigned int period_size;
unsigned int period_count;
enum pcm_format format;
/* Values to use for the ALSA start, stop and silence thresholds. Setting
* any one of these values to 0 will cause the default tinyalsa values to be
* used instead. Tinyalsa defaults are as follows.
*
* start_threshold : period_count * period_size
* stop_threshold : period_count * period_size
* silence_threshold : 0
*/
unsigned int start_threshold;
unsigned int stop_threshold;
unsigned int silence_threshold;
/* Minimum number of frames available before pcm_mmap_write() will actually
* write into the kernel buffer. Only used if the stream is opened in mmap mode
* (pcm_open() called with PCM_MMAP flag set). Use 0 for default.
*/
int avail_min;
};
pcm config 구조체에서는 channel 개수, rate, period size, period count, audio format에 대한 설정을 해준다.
- format
- PCM_FORMAT_S16_LE
- Signed 16-bit, Little Endian
- 그 외 PCM_FORMAT_S16_BE, PCM_FORMAT_S24_LE, PCM_FORMAT_S24_BE
- tinyalsa\pcm.h 에서 확인 가능
- PCM_FORMAT_S16_LE
- period size
- 한번에 읽어오는 frame의 개수
- period count
- buffer = period size * period count
- start threshold
- PCM start 하기에 최소한으로 필요한 frame 개수
- stop threshold
- PCM stop 하기에 최소한으로 필요한 frame 개수
PCM Structure
pcm 구조체
struct pcm {
int fd;
unsigned int flags;
int running:1;
int underruns;
unsigned int buffer_size;
unsigned int boundary;
char error[PCM_ERROR_MAX];
struct pcm_config config;
struct snd_pcm_mmap_status *mmap_status;
struct snd_pcm_mmap_control *mmap_control;
struct snd_pcm_sync_ptr *sync_ptr;
void *mmap_buffer;
unsigned int noirq_frames_per_msec;
int wait_for_avail_min;
};
PCM Open
struct pcm *pcm_open(unsigned int card, unsigned int device, unsigned int flags, const struct pcm_config *config)
Description pcm open을 하고 pcm 구조체를 받아온다. Parameters card - sound card 번호 device - dai-link 번호 ex) device tree에서 sound card 0의 dai-link 0번 i2S를 사용한다면, card와 device에 각각 0을 넘겨주면 된다. flags - pcm open flags ex) PCM_OUT, PCM_IN, PCM_MMAP, PCM_NOIRQ, PCM_NORESTART, PCM_MONOTONIC, PCM_NONBLOCK, PCM_STATE_PREPARED .. etc config - pcm config 구조체 Return pcm 구조체 |
PCM Read
int pcm_read(struct pcm *pcm, void *data, unsigned int count)
Description data에 pcm read한 데이터를 count만큼 가져온다. Parameters pcm - open할 때 반환받은 pcm 구조체 data - audio data를 저장할 buffer count - frame 당 byte 개수 보통 하나의 frame에 몇 byte가 있는지 반환하는 pcm_frames_to_bytes(const struct pcm *pcm, unsigned int frames) 함수를 사용해서 count 값을 넣어준다. Returns 0일 경우, 성공 -EPIPE의 경우, underrun이나 overrun 발생할 때 반환 -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 -EBADFD의 경우, 어플리케이션과 alsa-lib 사이에 연결이 끊어진 경우에 반환 -ENOTTY, -ENODEV 의 경우, device가 물리적으로 해제된 경우에 반환 |
PCM Write
int pcm_write(struct pcm *pcm, const void *data, unsigned int count)
Description data에 저장된 데이터를 count만큼 쓴다. Parameters pcm - open할 때 반환받은 pcm 구조체 data - audio data를 저장된 buffer count - frame 당 byte 개수 보통 하나의 frame에 몇 byte가 있는지 반환하는 pcm_frames_to_bytes(const struct pcm *pcm, unsigned int frames) 함수를 사용해서 count 값을 넣어준다. Returns 0 일 경우, 성공 -EPIPE의 경우, underrun이나 overrun 발생할 때 반환 -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 -EBADFD의 경우, 어플리케이션과 alsa-lib 사이에 연결이 끊어진 경우에 반환 -ENOTTY, -ENODEV 의 경우, device가 물리적으로 해제된 경우에 반환 |
PCM Close
int pcm_close(struct pcm *pcm)
Description pcm을 close한다. Parameters pcm - open할 때 반환받은 pcm 구조체 Returns 항상 0 반환 |
ALSA
Linux에서는 ALSA를 사용한다.
ALSA의 경우에는 open, hw parameter 설정, sw parameter 설정, prepare, start, (avail 체크), read/write, close 과정으로 audio를 다룬다.
Data Structures
PCM structure
typedef struct _snd_pcm snd_pcm_t
PCM HW config
typedef struct _snd_pcm_hw_params snd_pcm_hw_params_t
PCM SW config
typedef struct _snd_pcm_sw_params snd_pcm_sw_params_t
PCM Open
int snd_pcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
Description pcm을 open한다. Parameters pcmp - open할 때 반환 받을 pcm 구조체 name - PCM 식별자 (ex) "hw:0,2" stream - playback 목적으로 pcm open을 하는지, capture 목적으로 pcm open을 하는지 넘겨줌 (ex) SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE mode - open mode (ex) SND_PCM_NONBLOCK, SND_PCM_ASYNC Returns 항상 0 반환 |
PCM HW Params
Hardware Parameter란 audio format, channel 개수, sampling rate, period size, buffer size 등을 말한다.
ALSA Library FunctionDescription
snd_pcm_hw_params_malloc | snd_pcm_hw_params_t 구조체 메모리 할당 |
snd_pcm_hw_params_any | snd_pcm_hw_params_t 구조체 초기화 |
snd_pcm_hw_params_set_access | access type 설정 (ex) SND_PCM_ACCESS_RW_INTERLEAVED, SND_PCM_ACCESS_RW_NONINTERLEAVED |
snd_pcm_hw_params_set_format | audio format 설정 (ex) SND_PCM_FORMAT_S16_LE |
snd_pcm_hw_params_set_channels | audio channel 설정 |
snd_pcm_hw_params_set_buffer_size | audio buffer size 설정 |
snd_pcm_hw_params_set_rate_near | 샘플레이트 설정 시 하드웨어가 정확한 샘플레이트를 지원하지 않는다면 가장 근접한 가능한 레이트를 사용하도록 설정 |
snd_pcm_hw_params_set_period_size | alsa period_size를 설정 |
snd_pcm_hw_params |
snd_pcm_hw_params_t 구조체에 저장된 PCM hardware configuration을 하드웨어에 알려주고 snd_pcm_prepare를 호출 |
snd_pcm_hw_params_free | snd_pcm_hw_params_t 구조체 free |
<cf> interleaved access vs non-interleaved access
- Interleaved mode
- 하나의 buffer에 channel sample이 번갈아가며 저장
- Non-interleaved mode
- 각 채널별로 buffer가 존재하여 sample이 저장됨
PCM SW Params
Software Parameter란 start threshold, stop threshold, avail min 등을 말한다.
ALSA Library FunctionDescription
snd_pcm_sw_params_malloc | snd_pcm_sw_params_t 구조체 할당 |
snd_pcm_sw_params_current | 현재 SW config를 snd_pcm_sw_params_t 구조체에 저장 |
snd_pcm_sw_params_set_start_threshold | start threshold 설정 (보통 period size로 설정) ※ byte 크기로 넘겨주는 것에 유의 |
snd_pcm_sw_params_set_avail_min | 최소 avail 설정 (보통 period size으로 설정) |
snd_pcm_sw_params | snd_pcm_sw_params_t 구조체에 저장된 PCM software configuration을 아래 layer에 알려줌 |
snd_pcm_sw_params_free | snd_pcm_sw_params_t 구조체 free |
참고 웹페이지 https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___s_w___params.html
(cf) alsa에서 말하는 avail 이란, buffer에서 빈 공간 frame 개수를 말한다. delay는 buffer에 있는 데이터가 들은 frame 개수를 말한다.
PCM Prepare
int snd_pcm_prepare(snd_pcm_t *pcm)
Description pcm을 prepare한다. Parameters pcm - open할 때 반환 받은 pcm 구조체 Returns 0 일 경우, 성공 -EPIPE의 경우, underrun이나 overrun 발생할 때 반환 -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 -EBADFD의 경우, 어플리케이션과 alsa-lib 사이에 연결이 끊어진 경우에 반환 -ENOTTY, -ENODEV 의 경우, device가 물리적으로 해제된 경우에 반환 |
PCM Start
int snd_pcm_start(snd_pcm_t *pcm)
Description pcm을 start한다. Parameters pcm - open할 때 반환 받은 pcm 구조체 Returns 0 일 경우, 성공 -EPIPE의 경우, underrun이나 overrun 발생할 때 반환 -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 -EBADFD의 경우, 어플리케이션과 alsa-lib 사이에 연결이 끊어진 경우에 반환 -ENOTTY, -ENODEV 의 경우, device가 물리적으로 해제된 경우에 반환 |
PCM Avail
snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm)
Description 읽히거나 쓸 준비가 된 frame 개수를 반환한다. (ALSA에서 보통 avail은 버퍼의 비어있는 공간, delay는 버퍼의 데이터가 있는 공간을 말한다.) Parameters pcm - open할 때 반환 받은 pcm 구조체 Returns 양수일 경우, frame 개수 반환 -EPIPE의 경우, underrun이나 overrun 발생할 때 반환 -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 -EBADFD의 경우, 어플리케이션과 alsa-lib 사이에 연결이 끊어진 경우에 반환 -ENOTTY, -ENODEV 의 경우, device가 물리적으로 해제된 경우에 반환 |
PCM Read
snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void buffer, snd_pcm_uframes_t size)
Description interleaved frame을 읽는다. 만일 PCM이 blocking mode로 열렸을 경우, 모든 frame이 찰 때까지 기다린다. underrun이 발생할 경우에만 읽어온 frame 개수가 적을 수 있다. non-blocking mode일 경우, 기다리지 않는다. Parameters pcm - open할 때 반환 받은 pcm 구조체 buffer - 읽어오려는 frame을 담을 버퍼 size - 읽으려는 frame 개수 Returns 양수일 경우, 읽어온 frame 개수 반환 -EPIPE의 경우, underrun이나 overrun 발생할 때 반환 underrun이 발생 하는 경우, snd_pcm_prepare를 호출해야 함. -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 suspend 상태인 경우, snd_pcm_resume을 해준 뒤 snd_pcm_prepare 호출해야 함. -EBADFD의 경우, 올바른 state가 아닐 경우 반환 SND_PCM_STATE_PREPARED 상태나 SND_PCM_STATE_RUNNING 상태일 때만 read/write가 가능 |
snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void buffer, snd_pcm_uframes_t size)
Description non-interleaved frame을 읽는다. 만일 PCM이 blocking mode로 열렸을 경우, 모든 frame이 찰 때까지 기다린다. underrun이 발생할 경우에만 읽어온 frame 개수가 적을 수 있다. non-blocking mode일 경우, 기다리지 않는다. Parameters pcm - open할 때 반환 받은 pcm 구조체 buffer - 읽어오려는 frame을 담을 버퍼 size - 읽으려는 frame 개수 Returns 양수일 경우, 읽어온 frame 개수 반환 -EPIPE의 경우, underrun이나 overrun 발생할 때 반환 underrun이 발생 하는 경우, snd_pcm_prepare를 호출해야 함. -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 suspend 상태인 경우, snd_pcm_resume을 해준 뒤 snd_pcm_prepare 호출해야 함. -EBADFD의 경우, 올바른 state가 아닐 경우 반환 SND_PCM_STATE_PREPARED 상태나 SND_PCM_STATE_RUNNING 상태일 때만 read/write가 가능 |
PCM Write
snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, void buffer, snd_pcm_uframes_t size)
Description interleaved frame을 쓴다. 만일 PCM이 blocking mode로 열렸을 경우, 모든 frame이 play 될때까지 기다리거나 playback ring buffer에 넣을 때까지 기다린다. underrun이 발생할 경우에만 읽어온 frame 개수가 적을 수 있다. non-blocking mode일 경우, 기다리지 않는다. Parameters pcm - open할 때 반환 받은 pcm 구조체 buffer - 읽어오려는 frame을 담을 버퍼 size - 읽으려는 frame 개수 Returns 양수일 경우, 읽어온 frame 개수 반환 -EPIPE의 경우, underrun이 발생할 때 반환 underrun이 발생 하는 경우, snd_pcm_prepare를 호출해야 함 -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 suspend 상태인 경우, snd_pcm_resume을 해준 뒤 snd_pcm_prepare 호출해야 함 -EBADFD의 경우, 올바른 state가 아닐 경우 반환 SND_PCM_STATE_PREPARED 상태나 SND_PCM_STATE_RUNNING 상태일 때만 read/write가 가능 |
snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void buffer, snd_pcm_uframes_t size)
Description non-interleaved frame을 쓴다. 만일 PCM이 blocking mode로 열렸을 경우, 모든 frame이 play 될때까지 기다리거나 playback ring buffer에 넣을 때까지 기다린다. underrun이 발생할 경우에만 읽어온 frame 개수가 적을 수 있다. non-blocking mode일 경우, 기다리지 않는다. Parameters pcm - open할 때 반환 받은 pcm 구조체 buffer - 읽어오려는 frame을 담을 버퍼 size - 읽으려는 frame 개수 Returns 양수일 경우, 읽어온 frame 개수 반환 -EPIPE의 경우, underrun이 발생할 때 반환 underrun이 발생 하는 경우, snd_pcm_prepare를 호출해야 함 -ESTRPIPE 의 경우, device가 suspend 상태일 때 반환 suspend 상태인 경우, snd_pcm_resume을 해준 뒤 snd_pcm_prepare 호출해야 함 -EBADFD의 경우, 올바른 state가 아닐 경우 반환 SND_PCM_STATE_PREPARED 상태나 SND_PCM_STATE_RUNNING 상태일 때만 read/write가 가능 |
PCM Close
int snd_pcm_close(snd_pcm_t *pcm)
Description pcm을 close한다. Parameters pcm - open할 때 반환 받은 pcm 구조체 Returns 0 일 경우, 성공 음수의 경우 실패 |
ALSA library 참고 웹페이지
ALSA
ALSA libWeb Page
Tiny ALSA
ALSA libWeb Page
github | https://github.com/tinyalsa/tinyalsa |
'ALSA' 카테고리의 다른 글
ALSA DPCM (Advanced Linux Sound Architecture Dynamic PCM) 코드 분석 (0) | 2022.03.16 |
---|---|
ALSA DPCM (Advanced Linux Sound Architecture Dynamic PCM) 개념 (0) | 2022.03.16 |