2. 1.Audio 출력 준비 과정 안드로이드 아나토미 정리
AudioFlinger.cpp
uint32_t AudioFlinger::MixerThread::prepareTracks_l()
{
for (size_t i=0 ; i<count ; i++) {
sp<Track> t = activeTracks[i].promote(); 활성화 트랙을 가져온다.
Track* const track = t.get();
audio_track_cblk_t* cblk = track->cblk(); 활성화 트랙의 컨트롤 블록을 얻어온다.
if (cblk->framesReady() && track->isReady() && !track->isPaused() && !track->isTerminated())
{ 공유 메모리에 할당할 메모리가 남아 있고, track 이 준비되었다면
mAudioMixer->setBufferProvider(track); (1)오디오 버퍼 제공자 설정
mAudioMixer->enable(AudioMixer::MIXING); (2) 트랙의 믹싱 활성화
mAudioMixer->setParameter(AudioMixer::TRACK,
AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer()); (3) 메인 버퍼 설정
mAudioMixer->setParameter(AudioMixer::RESAMPLE, AudioMixer::SAMPLE_RATE,(void *)(cblk->sampleRate));
(4)리샘플링 함수 등록
mixerStatus = MIXER_TRACKS_READY; (5)오디오 믹서 상태 설정
}
}
(1) mAudioMixer->setBufferProvider(track); 오디오 버퍼 제공자 설정
-오디오 믹서는 활성화된 트랙의 PCM 데이터를 믹싱하기 위해 개별 트랙의 PCM 공유 버퍼에서 데이터를 읽어와야 함.
status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer) AudioBufferProvider
{
mState.tracks[ mActiveTrack ].bufferProvider = buffer;
return NO_ERROR; Trackbase
}
Track
2
3. 1.Audio 출력 준비 과정 안드로이드 아나토미 정리
(2)mAudioMixer->enable(AudioMixer::MIXING); 트랙의 믹싱 활성화
-해당 트랙을 오디오 믹서의 믹싱처리에 추가 한다.(믹싱 함수를 process__validate 로 설정 함.)
status_t AudioMixer::enable(int name)
{
switch (name) {
case MIXING: {
if (mState.tracks[ mActiveTrack ].enabled != 1) {
mState.tracks[ mActiveTrack ].enabled = 1;
LOGV("enable(%d)", mActiveTrack);
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
}
void AudioMixer::invalidateState(uint32_t mask)
{
if (mask) {
mState.needsChanged |= mask;
mState.hook = process__validate;
}
}
(3)mAudioMixer->setParameter(AudioMixer::TRACK,AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
audiomixer의 메인 버퍼를 믹서버퍼로 설정 함.
status_t AudioMixer::setParameter(int target, int name, void *value)
{
mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
valuebuf가 playbackThread->mixBuffer();를 의미함.
}
3
4. 1.Audio 출력 준비 과정 안드로이드 아나토미 정리
(4)(mAudioMixer->setParameter(AudioMixer::RESAMPLE, AudioMixer::SAMPLE_RATE,(void *)(cblk->sampleRate));
- 리샘플링 함수 등록
status_t AudioMixer::setParameter(int target, int name, void *value)
{
if (track.setResampler(uint32_t(valueInt), mSampleRate)){
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
}
bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
{
if (value!=devSampleRate || resampler) {
audiohardware에서 설정된 sameplerate(devSampleRate)와 track의 sample rate(value)가 다를 경우
resampler = AudioResampler::create(
format, channelCount, devSampleRate);
}
Audioresampler.cpp
AudioResampler* AudioResampler::create()
{
pcm 데이터의 음질에 따라 리샘플링을 처리하는 클래스가 결정 됨.
switch (quality) {
case LOW_QUALITY:
resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate); break;
case MED_QUALITY:
resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate); break;
case HIGH_QUALITY:
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate); break;
}
4
6. 2.PCM 데이터 리샘플링과 믹싱 안드로이드 아나토미 정리
MixerThread::prepareTracks_l() 에서 mixerStatus 가 MIXER_TRACKS_READY 이면
리샘플링과 믹싱 과정을 수행한다.
bool AudioFlinger::MixerThread::threadLoop()
{
if (LIKELY(mixerStatus == MIXER_TRACKS_READY))
{
mAudioMixer->process();
}
int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
mixbuffer에 있는 data를 audio driver에 write한다.
}
void AudioMixer::process()
{
mState.hook(&mState);
mState.hook은 process__validate로 설정되어 있음.(invalidateState함수)
}
void AudioMixer::process__validate(state_t* state)
{
uint32_t en = state->enabledTracks;
활성화 트랙을 다시 가져온다.
while (en) {
n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
리샘플링 여부 결정
6
7. 2.PCM 데이터 리샘플링과 믹싱 안드로이드 아나토미 정리
믹싱 함수 결정
if (resampling) {
state->hook = process__genericResampling; 리샘플링과 믹싱을 동시에 처리
}
Else{
state->hook = process__genericNoResampling; 믹싱 처리
if (all16BitsStereoNoResample && !volumeRamp) {
if (countActiveTracks == 1) {
오디오 트랙이 하나이면 믹싱처리를 하지 않는 아래 함수가 호출 됨.
state->hook = process__OneTrack16BitsStereoNoResampling;
}
}
}
state->hook(state); 믹싱 함수 호출
}
void AudioMixer::process__OneTrack16BitsStereoNoResampling()
{
int32_t* out = t.mainBuffer; mixerthread의 믹서 버퍼를 out으로 설정한다.
while (numFrames) {
t.bufferProvider->getNextBuffer(&b); PCM 데이터 공유 버퍼에서 write된 data를 b로 가져온다.
*out++ = (r<<16) | (l & 0xFFFF); 가져온 data를 믹서 버퍼로 copy한다.
복사된 데이터는 pcm 데이터 출력 단계에서 소리로 출력 된다.
t.bufferProvider->releaseBuffer(&b); 오디오 컨트록 블락에서 server 변수의 값을 갱신한다.
}
7
8. 3. PCM 데이터 출력 안드로이드 아나토미 정리
bool AudioFlinger::MixerThread::threadLoop()
{
if (LIKELY(mixerStatus == MIXER_TRACKS_READY))
{
mAudioMixer->process(); 믹서 버퍼에 PCM 데이터가 복사됨.
}
int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
}
ssize_t AudioHardware::AudioStreamOutMSM72xx::write(const void* buffer, size_t bytes)
{
size_t count = bytes; write할 data size
const uint8_t* p = static_cast<const uint8_t*>(buffer); mixer buffer
ssize_t written = ::write(mFd, p, count); mFd file descriptor가 가르키는 곳에 mixer buffer의 내용을 write한다.
mFd는 status = ::open("/dev/msm_pcm_out", O_WRONLY/*O_RDWR*/); 에 대한 file descriptor이다.
if(msm_route_stream(PCM_PLAY, dec_id, DEV_ID(cur_rx), 1)) {
LOGE("msm_route_stream failed");
return 0;
}
ioctrl로 PCM_PLAY 를 driver로 전달해서 play됨.
8