static const snd_pcm_ops_t snd_pcm_ioplug_ops = {
	.close = snd_pcm_ioplug_close,
	.nonblock = snd_pcm_ioplug_nonblock,
	.async = snd_pcm_ioplug_async,
	.info = snd_pcm_ioplug_info,
	.hw_refine = snd_pcm_ioplug_hw_refine,
	.hw_params = snd_pcm_ioplug_hw_params,
	.hw_free = snd_pcm_ioplug_hw_free,
	.sw_params = snd_pcm_ioplug_sw_params,
	.channel_info = snd_pcm_ioplug_channel_info,
	.dump = snd_pcm_ioplug_dump,
	.mmap = snd_pcm_ioplug_mmap,
	.munmap = snd_pcm_ioplug_munmap,
	.query_chmaps = snd_pcm_ioplug_query_chmaps,
	.get_chmap = snd_pcm_ioplug_get_chmap,
	.set_chmap = snd_pcm_ioplug_set_chmap,
};

'alsa > alsa-lib' 카테고리의 다른 글

snd_pcm_ioplug_hw_refine  (0) 2019.12.26
snd_pcm_hw_params_any  (0) 2019.12.26
snd_interval_single  (0) 2019.12.26
snd_interval_value  (0) 2019.12.26
FramesPeriods  (0) 2019.12.26

Reference

2019/12/26 - [alsa/alsa-lib] - snd_pcm_ioplug_ops 

2019/12/24 - [alsa/alsa-lib] - interval and mask

Referred in

2019/12/26 - [alsa/alsa-lib] - snd_pcm_hw_params_any

Notice

N/A

Description

static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
  1. snd_ext_parm_mask_refine: access와 format에 대한 mask정보를 pcm으로부터 params에 refine 하여 복사 한다.
  2. snd_ext_parm_interval_refine: channel과 rate에 대한 interval정보를 pcm으로부터 refine하여 params에 복사 한다.

 

'alsa > alsa-lib' 카테고리의 다른 글

snd_pcm_ioplug_ops  (0) 2019.12.26
snd_pcm_hw_params_any  (0) 2019.12.26
snd_interval_single  (0) 2019.12.26
snd_interval_value  (0) 2019.12.26
FramesPeriods  (0) 2019.12.26

Reference

2019/12/24 - [alsa/alsa-lib] - interval and mask

2019/12/26 - [alsa/alsa-lib] - snd_pcm_ioplug_hw_refine

Description

 

입력

snd_pcm_t *pcm;
snd_pcm_hw_params_t *params;

순서

  1. _snd_pcm_hw_params_any: params를 초기화 시킴
    1. snd_mask_any: mask들은 0xff 로 설정
    2. snd_internal_any: interval들은 max: UINT_MAX로 설정하고 나머지는 0으로 설정
  2. snd_pcm_hw_refine: pcm->ops->hw_refine(pcm->op_arg, params) 수행 함

'alsa > alsa-lib' 카테고리의 다른 글

snd_pcm_ioplug_ops  (0) 2019.12.26
snd_pcm_ioplug_hw_refine  (0) 2019.12.26
snd_interval_single  (0) 2019.12.26
snd_interval_value  (0) 2019.12.26
FramesPeriods  (0) 2019.12.26

입력

const snd_interval_t *i;

 

순서

  1. i가 empty 면 assert
  2. 아래와 같은 조건시 1 return
    1. i->min이 i->max와 동일
    2. i->min + 1 == i->max이고 i->openmin이나 i->openmax 중에 하나라도 0이 아니면

'alsa > alsa-lib' 카테고리의 다른 글

snd_pcm_ioplug_hw_refine  (0) 2019.12.26
snd_pcm_hw_params_any  (0) 2019.12.26
snd_interval_value  (0) 2019.12.26
FramesPeriods  (0) 2019.12.26
interval and mask  (0) 2019.12.24

Reference

2019/12/26 - [alsa/alsa-lib] - snd_interval_single

Description

 

입력

const snd_interval_t *i;

순서

  1. i가 snd_interval_single 이 아닐 경우 assert
  2. i->openmin이 0이 아니고 i->openmax가 0이면 i->max return
  3. 그 외에는 i->min return

'alsa > alsa-lib' 카테고리의 다른 글

snd_pcm_hw_params_any  (0) 2019.12.26
snd_interval_single  (0) 2019.12.26
FramesPeriods  (0) 2019.12.26
interval and mask  (0) 2019.12.24
snd_pcm_hw_params_set_buffer_time_near  (0) 2019.12.24

Reference

https://www.alsa-project.org/wiki/FramesPeriods 

 

Description

 

하나의 Frame은 재생되는 하나의 sample과 같다. (채널 수나 비트 수와 상관없음)

  • 1 frame의 Stereo (2Ch) 48kHz 16bit PCM stream: 4byte
  • 1 frame의 5.1Ch (6Ch) 48kHz 16bit PCM stream: 12byte

하나의 Period는 각 HW의 interrupt 간의 Frame 수이다. poll()은 한 Period에 한번 return 된다.

Buffer는 Ring Buffer이다. Buffer의 크기는 항상 하나의 Period 크기보다 커야 한다. 일반적으로 2 * Period 크기이지만 어떤 HW는 Buffer당 8 Periods를 담을 수 있어야 한다. Buffer 크기는 Period 크기에 상수 배가 아닐 수 있다.

예를 들어 HW가 48kHz, 2 Period (Period당 1024 Frames)로 설정되어 있으면, 하나의 Buffer 크기가 2048개의 Frame이다. ALSA는 Buffer를 가능한 가득 채워 두려고 한다. 첫 번째 Frame이 재생되면 두 번째 Frame이 재생되는 동안 세 번째  Frame은 첫 번째 Frame이 차지했던 공간으로 전달된다. (일반적인 Ring Buffer 동작임)

 

추가적인 예제

하나의 Stereo 16bit 44.1kHz Stream을 단 방향 (재생이든 녹음이든)으로 재생한다고 하면, 

* number of channels: 2
* 1 analog sample with 16 bit: 2 bytes
* 1 frame (1 analog sample with 2 channels)
** 1 frame = (number of channels) * (1 sample in bytes) = 2 * 2 bytes = 4 bytes (32 bits)
* 2x 44.1kHz (analog rate) => data transfer rate (bytes/sec: Bps_rate)
** Bps_rate = (number of channels) * (1 sample in bytes) * (analog rate) = (1 frame) * (analog rate)
            = 2 * 2 bytes/sample * 44100 samples/sec = 2*2*44100 (bytes/sec)
            = 176400 (bytes/sec)

만약 ALSA가 1초 마다 interrupt를 한다면 16-bit stereo @ 44.1Khz를 유지하기 위해 매 초 끝에 176400bytes가 필요 하다. 

'alsa > alsa-lib' 카테고리의 다른 글

snd_interval_single  (0) 2019.12.26
snd_interval_value  (0) 2019.12.26
interval and mask  (0) 2019.12.24
snd_pcm_hw_params_set_buffer_time_near  (0) 2019.12.24
snd_pcm_set_params  (0) 2019.12.24

alsa-plugins에서는 pulseaudio plugin을 지원한다.

alsa-lib을 이용하여 parameter 설정 및 open/start/write(i)를 수행하면

alsa-plugins에서는 관련된 동작을 pulseaudio 함수로 연결해주어서 open/start/writei 가 이루어지게 된다.

files

pulse 폴더에 pulseaudio 관련 file 들이 존재한다.

kwangshik.kim@:~/sources/alsa/alsa-plugins-x.x.x/pulse$ ls -al
total 108
drwxrwxrwx  2 kwangshik.kim users  4096 Dec 23 15:40 .
drwxrwxrwx 17 kwangshik.kim users  4096 Jan  7  2019 ..
-rwxrwxrwx  1 kwangshik.kim users   242 Jan  7  2019 50-pulseaudio.conf
-rwxrwxrwx  1 kwangshik.kim users   201 Jan  7  2019 99-pulseaudio-default.conf.example
-rwxrwxrwx  1 kwangshik.kim users  2222 Jan  7  2019 conf_pulse.c
-rwxrwxrwx  1 kwangshik.kim users 16590 Jan  7  2019 ctl_pulse.c
-rwxrwxrwx  1 kwangshik.kim users  1343 Jan  7  2019 Makefile.am
-rwxrwxrwx  1 kwangshik.kim users 28664 Jan  7  2019 Makefile.in
-rwxrwxrwx  1 kwangshik.kim users 23480 Jan  7  2019 pcm_pulse.c
-rwxrwxrwx  1 kwangshik.kim users  5111 Jan  7  2019 pulse.c
-rwxrwxrwx  1 kwangshik.kim users  1512 Jan  7  2019 pulse.h

pcm_pulse.c

playback 만 예를 들면 아래와 같이 ops를 통해 start/stop/drain/.../pause 각각의 함수가 pulseaudio 용으로 mapping 되어 있다.

// alsa-plugins-x.x.x/pulse/pcm_pulse.c

static const snd_pcm_ioplug_callback_t pulse_playback_callback = {
	.start = pulse_start,
	.stop = pulse_stop,
	.drain = pulse_drain,
	.pointer = pulse_pointer,
	.transfer = pulse_write,
	.delay = pulse_delay,
	.poll_revents = pulse_pcm_poll_revents,
	.prepare = pulse_prepare,
	.hw_params = pulse_hw_params,
	.sw_params = pulse_sw_params,
	.close = pulse_close,
	.pause = pulse_pause
};

pulse_start

pulse_stop

pulse_drain

pulse_pointer

pulse_write

pulse_delay

pulse_pcm_poll_revents

pulse_prepare

pulse_hw_params (*)

  • 입력: snd_pcm_ioplug_t* io, snd_pcm_hw_params_t* params

  • 동작

    1. io로부터 pcm->frame_size 를 계산한다.

    2. io로부터 pcm->ss.format을 정의 한다.

    3. io로부터 pcm->ss.rate, channels를 정의한다.

    4. io로부터 pcm->buffer_attr.maxlength, tlength, prebuf, minreq, fragsize 등을 정의 한다.

      • tlengh = io->buffer_size * pcm->framesize
        • io->buffer_size: ioplug create 및 set param시에 정의 됨
        • pcm->framesize: format bit * channels / 8 (bytes)

pulse_sw_params

pulse_close

pulse_pause

sequence

detail

// alsa-lib.x.x.x/include/sound/asound.h

typedef int snd_pcm_hw_param_t;
#define	SNDRV_PCM_HW_PARAM_ACCESS	0	/* Access type */
#define	SNDRV_PCM_HW_PARAM_FORMAT	1	/* Format */
#define	SNDRV_PCM_HW_PARAM_SUBFORMAT	2	/* Subformat */
#define	SNDRV_PCM_HW_PARAM_FIRST_MASK	SNDRV_PCM_HW_PARAM_ACCESS
#define	SNDRV_PCM_HW_PARAM_LAST_MASK	SNDRV_PCM_HW_PARAM_SUBFORMAT

#define	SNDRV_PCM_HW_PARAM_SAMPLE_BITS	8	/* Bits per sample */
#define	SNDRV_PCM_HW_PARAM_FRAME_BITS	9	/* Bits per frame */
#define	SNDRV_PCM_HW_PARAM_CHANNELS	10	/* Channels */
#define	SNDRV_PCM_HW_PARAM_RATE		11	/* Approx rate */
#define	SNDRV_PCM_HW_PARAM_PERIOD_TIME	12	/* Approx distance between
						 * interrupts in us
						 */
#define	SNDRV_PCM_HW_PARAM_PERIOD_SIZE	13	/* Approx frames between
						 * interrupts
						 */
#define	SNDRV_PCM_HW_PARAM_PERIOD_BYTES	14	/* Approx bytes between
						 * interrupts
						 */
#define	SNDRV_PCM_HW_PARAM_PERIODS	15	/* Approx interrupts per
						 * buffer
						 */
#define	SNDRV_PCM_HW_PARAM_BUFFER_TIME	16	/* Approx duration of buffer
						 * in us
						 */
#define	SNDRV_PCM_HW_PARAM_BUFFER_SIZE	17	/* Size of buffer in frames */
#define	SNDRV_PCM_HW_PARAM_BUFFER_BYTES	18	/* Size of buffer in bytes */
#define	SNDRV_PCM_HW_PARAM_TICK_TIME	19	/* Approx tick duration in us */
#define	SNDRV_PCM_HW_PARAM_FIRST_INTERVAL	SNDRV_PCM_HW_PARAM_SAMPLE_BITS
#define	SNDRV_PCM_HW_PARAM_LAST_INTERVAL	SNDRV_PCM_HW_PARAM_TICK_TIME
// alsa-lib.x.x.x/include/sound/asound.h

struct snd_interval {
	unsigned int min, max;
	unsigned int openmin:1,
		     openmax:1,
		     integer:1,
		     empty:1;
};

#define SNDRV_MASK_MAX	256

struct snd_mask {
	__u32 bits[(SNDRV_MASK_MAX+31)/32];
};

 

TODO

  • interval과 mask의 의미는 무엇인가?
  • openmin, openmax 는 무엇인가?

'alsa > alsa-lib' 카테고리의 다른 글

snd_interval_single  (0) 2019.12.26
snd_interval_value  (0) 2019.12.26
FramesPeriods  (0) 2019.12.26
snd_pcm_hw_params_set_buffer_time_near  (0) 2019.12.24
snd_pcm_set_params  (0) 2019.12.24

+ Recent posts