2. 1.Audio data 전달 안드로이드 아나토미 정리
Audiotrack.java
public int write(byte[] audioData,int offsetInBytes, int sizeInBytes)
{
//audioData:audioData the array that holds the data to play.
//the offset expressed in bytes in audioData where the data to play starts.
//the number of bytes to read in audioData after the offset.
//the number of bytes that were written
return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
}
Android_media_AudioTrack.cpp
static jint android_media_AudioTrack_native_write()
{
if (javaAudioData) {
cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL); ----------------(1)
if (cAudioData == NULL) {
LOGE("Error retrieving source of audio data to play, can't play");
return 0; // out of memory or no data to load
}
}
jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes); ---------(2)
}
2
3. 2.Audio data 전달(vm heap -> process heap -> 공유 메모리) 안드로이드 아나토미 정리
(1) cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
가상머신 heap(java영역)에 있는 audio data를 process heap(네이티브 공간)으로 copy한다.
Music process
Java 계층 Native 계층
Process heap
Dalvik VM
VM heap
Music
application copy
Audio buffer audiotrack
(2) jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
music Process heap에 있는 audiodata를 adiotrack을 위한 공유 메모리에 write한다.
(공유 메모리:audio track과 audio flinger가 data를 공유하기 위한 메모리
AudioTrack++ Audioflinger
audiob
uffer
write read
android
kernel
Track[3 32kbyte
1]
AudioFlinger::Client
(shared memory) 1M
Track[0]
3
4. 3. 공유메모리에 audio data copy과정 안드로이드 아나토미 정리
jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data, jint offsetInBytes, jint sizeInBytes)
{
written = pTrack->write(data + offsetInBytes, sizeInBytes);
}
AudioTrack.cpp
ssize_t AudioTrack::write(const void* buffer, size_t userSize)
{
const int8_t *src = (const int8_t *)buffer; process heap의 audio buffer를 가리킨다.
Buffer audioBuffer;
do {
status_t err = obtainBuffer(&audioBuffer, -1);
공유 메모리에서 유저 오프셋이 가리키는 곳의 메모리를 할당 받아 audiobuffer에 저장 한다.
toWrite = audioBuffer.size;
할당된 버퍼의 크기
memcpy(audioBuffer.i8, src, toWrite);
audio buffer의 data를 할당받은 공유메모리에 copy한다.
releaseBuffer(&audioBuffer);
오디오 트랙 컨트롤 블록의 유저 변수 값을 재계산 함.
}
}
4
5. 4.obtainbuffer 안드로이드 아나토미 정리
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
uint32_t framesAvail = cblk->framesAvailable();
공유 메모리에 할당 받을 메모리가 있는지 check한다.
if (framesAvail == 0) {
while (framesAvail == 0) {
공유 메모리에 할당 받을 메모리가 없을 경우,
audio driver에서 data를 출력해서 빈 메모리가 생길때까지 기다린다.
}
}
남아 있는 메모리가 요구한 메모리보다 적게 남아 있으면 남아 있는 메모리를 넣는다.
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
audioBuffer->size = framesReq * cblk->frameSize;
audioBuffer->raw = (int8_t *)cblk->buffer(u);
공유 메모리에 buffer를 할당 받고 그 위치를 return한다. audiobuffer
User
}
server
userBase serverBase
오디오 컨트롤 블록
5
6. 5.releaseBuffer 안드로이드 아나토미 정리
void AudioTrack::releaseBuffer(Buffer* audioBuffer)
{
audio_track_cblk_t* cblk = mCblk;
cblk->stepUser(audioBuffer->frameCount);
}
uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
{
uint32_t u = this->user;
u += frameCount;
현재 user 변수에 할당 된 frameCount을 더한다.
this->user = u;
갱신된 user 값을 설정한다.
}
User
audiobuffer
server
userBase serverBase
오디오 컨트롤 블록
6