안드로이드 아나토미 정리



Android Audio System
(PCM데이터 출력요청-
  서비스 클라이언트)




                            박철희

                       1
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
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
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
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
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

Android audio system(pcm데이터출력요청-서비스클라이언트)

  • 1.
    안드로이드 아나토미 정리 AndroidAudio System (PCM데이터 출력요청- 서비스 클라이언트) 박철희 1
  • 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 전달(vmheap -> 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. 공유메모리에 audiodata 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