2017-09-19 21 views
0

가능한 한 낮은 대기 시간으로 ALSA 인터페이스를 작동 시키려고합니다. 모든 프레임/마침표/버퍼에 대한 ALSA 문서는 매우 혼란 스럽기 때문에 여기에서 묻습니다.ALSA는 인터럽트 전에 1024 개의 버퍼를 사용합니다.

아래 코드는 ALSA가 실제로 버퍼 크기의 1024 배를 읽도록합니다 (버퍼 크기를 1024 바이트로 설정 함). writeAudio 함수의 속도가 느려지려면 1024 * 1024 바이트가 필요합니다. 이 프레임을 유지하고 싶습니다. 가능한 한 낮게 계산하십시오 (예 :). 따라서 응용 프로그램 자체에서 재생 시간을 추적 할 수 있습니다. snd_pcm_hw_params_set_periods으로 기간 크기를 2로 설정하려고하면 버퍼에 2 * 1024 바이트를 쓴 후 읽기 속도가 느려지 게됩니다. 그러나이 코드를 변경해도 동작은 변경되지 않습니다. 플레이어는 여전히 1024 * 1024 바이트를 버퍼링하기 때문에 버퍼링 속도는 스피커에서 오디오가 재생되는 속도로 느려집니다.

TLDR; 1024 * 1024 바이트 버퍼링 크기가 너무 길어서 어떻게 줄일 수 있습니까? 아래는 제 코드입니다. 그리고 예, 저는 모노 출력으로 부호없는 8 비트를 재생 중입니다.

int32_t ALSAPlayer::initPlayer(ALSAConfig cfg) 
{ 
std::cout << "=== INITIALIZING ALSA ===" << std::endl; 

if(!cfg.channels || !cfg.rate) 
{ 
    std::cout << "ERROR: player config was bad" << std::endl; 
    return -1; 
} 

m_channels = cfg.channels; 

m_rate = cfg.rate; 

m_frames = 1024; 

uint32_t tmp; 
uint32_t buff_size; 

int dir = 0; 

/* Open the PCM device in playback mode */ 
if ((pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) 
{ 
    printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(pcm)); 
} 
snd_pcm_hw_params_alloca(&params); 

snd_pcm_hw_params_any(pcm_handle, params); 

if ((pcm = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 
{ 
    printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm)); 
} 

if ((pcm = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S8)) < 0) 
{ 
    printf("ERROR: Can't set format. %s\n", snd_strerror(pcm)); 
} 

if ((pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, m_channels)) < 0) 
{ 
    printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm)); 
} 

if ((pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &m_rate, &dir)) < 0) 
{ 
    printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm)); 
} 

// force the ALSA interface to use exactly *m_frames* number of frames 

snd_pcm_hw_params_set_period_size(pcm_handle, params, m_frames, dir); 

/* Write parameters */ 
if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0) 
{ 
    printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm)); 
} 

std::cout << "ALSA output device name:  " << snd_pcm_name(pcm_handle) << std::endl; 
std::cout << "ALSA output device state:  " << snd_pcm_state_name(snd_pcm_state(pcm_handle)) << std::endl; 

snd_pcm_hw_params_get_channels(params, &tmp); 
std::cout << "ALSA output device channels: " << tmp << std::endl; 

snd_pcm_hw_params_get_rate(params, &tmp, 0); 
std::cout << "ALSA output device rate:  " << tmp << std::endl; 

snd_pcm_hw_params_get_period_size(params, &m_frames, &dir); 

buff_size = m_frames * m_channels; 

std::cout << "ALSA output device frames size: " << m_frames << std::endl; 

std::cout << "ALSA output device buffer size: " << buff_size << "(should be 1024)" << std::endl; 

return 0; 
} 

int ALSAPlayer::writeAudio(byte* buffer, uint32_t buffSize) 
{ 
int pcmRetVal; 
if(buffSize == 0) 
{ 
    snd_pcm_drain(pcm_handle); 
    snd_pcm_close(pcm_handle); 
    return -1; 
} 

if((pcmRetVal = snd_pcm_writei(pcm_handle, buffer, m_frames)) == -EPIPE) 
{ 
    snd_pcm_prepare(pcm_handle); 
} 
else if(pcm < 0) 
{ 
    std::cout << "ERROR: could not write to audio interface" << std::endl; 
} 
return 0; 
} 

답변

1

는 (하나의 프레임은 반드시 1 바이트, 그들을 혼동하지 마십시오.)

이 코드는 버퍼 크기를 설정하지 않습니다.

snd_pcm_hw_params_set_periods()은 마침표 수를 설정합니다.
snd_pcm_hw_params_set_period_size()은 마침표 크기를 설정합니다.

1024 프레임마다 두주기 가진 2048 프레임 버퍼를 위해 2 기간을 설정하고, 1024

로주기 크기는 모든 기능 snd_pcm_hw_params_set_period_size() 등 오류 호출 확인한다.

+0

값 2가 마침표로 설정된'snd_pcm_hw_params_set_periods()'가 오류 코드 -22로 실패하는 것 같습니다. 편집 : 값을 8로 설정하면 재생할 수 있습니다. 따라서 전체 버퍼는 8 * 1024 바이트 = 8192 바이트가 아닙니다. ELI5에 대해 대단히 감사합니다. –