ALSA는 Audio Linux Sound Architecture의 약자.
리눅스에서 Audio를 구현하고자 할 때 사용되는 공개 라이브러리이다.
많이 사용되는 ALSA와 ALSA보다 몸집이 작은 tinyALSA, 이 두 라이브러리의 기본 API에 대해 설명한다.
- ALSA Overview
tinyALSA
Data Structure
- PCM Open
- PCM Read
- PCM Write
- PCM Close
- ALSA
- Data Structures
- PCM Open
- PCM HW Params
- PCM SW Params
- PCM Prepare
- PCM Start
- PCM Avail
- PCM Read
- PCM Write
- PCM Close
ALSA lib 참고 웹페이지
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 에서 확인 가능
- period size
- 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 |
참고 웹페이지 https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___h_w___params.html#ga6e2dd8efbb7a4084bd05e6cc458d84f7
<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