안드로이드 아나토미 정리




 Android Audio System
(오디오 출력-트랙생성)




                             박철희

                        1
1.오디오 출력                                                            안드로이드 아나토미 정리


오디오 출력은 크게 3단계로 구성됨.
1)Track생성
2)Track 활성화단계
3)PCM 데이터 출력 요청 단계

Ex)Mediaplayerservice에서의 오디오 출력 예
1)선행단계 -> audiooutput class를 audiosink 함수로 설정 함.
  Audioplayer의 audiosink가 불리면 mediaplayerservice의
   audiooutput class가 호출 됨.
                            MediaplayerBase

                                AudioSink




   Mediaplayer            MediaplayerService
   Interface
                              AudioOutput       setAudioSink(AudioOutput)



   stagefrightPlayer
                                Awesomeplayer
                                                                        AudioPlayer



                                                                            2
1.오디오 출력                                                                                     안드로이드 아나토미 정리

                                                           AudioPlayer.cpp
 2)Track생성 및 활성화                                           status_t AudioPlayer::start(bool sourceAlreadyStarted) {

                                                           mAudioSink->open(
  Mediaplayerservice.cpp
                                                                   mSampleRate, numChannels,
  status_t MediaPlayerService::Client::start()
                                                                       AudioSystem::PCM_16_BIT,
  {
                                                                   DEFAULT_AUDIOSINK_BUFFERCOUNT,
     LOGV("[%d] start", mConnId);
                                                                   &AudioPlayer::AudioSinkCallback, this);
     sp<MediaPlayerBase> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
                                                           mAudioSink->start();
     p->setLooping(mLoop);
     return p->start();
                                                           }
  }

 Stagefrightplayer.cpp                                 status_t MediaPlayerService::AudioOutput::open(){
 status_t StagefrightPlayer::start() {
    LOGV("start");                                             t = new AudioTrack(…);   Track생성

     return mPlayer->play();                           }
 }
                                                       void MediaPlayerService::AudioOutput::start()
 status_t AwesomePlayer::play() {                      {
    return play_l();                                      if (mTrack) {
 }                                                                      mTrack->start(); Track활성화
                                                          }
                                                       }
 status_t AwesomePlayer::play_l() {                     ssize_t MediaPlayerService::AudioOutput::write
   mAudioPlayer = new AudioPlayer(mAudioSink, this);    {
   mAudioPlayer->start();                                  if (mTrack) {
                                                               ssize_t ret = mTrack->write(buffer, size); PCM데이터
 }
                                                               return ret;                                출력
                                                           }
2.트랙 생성 단계                           안드로이드 아나토미 정리




  AudioTrack.java



  Android_media_
  AudiioTrack.cpp


  Audiotrack.cpp




                    서비스 클라이언트   서비스 서버
2.트랙 생성 단계(서비스 클라이언트)                                                                           안드로이드 아나토미 정리


  Audiotrack.java
  public AudioTrack(…){
    int initResult = native_setup(new WeakReference<AudioTrack>(this),
              mStreamType, mSampleRate, mChannels, mAudioFormat,
              mNativeBufferSizeInBytes, mDataLoadMode, session);
  }


  Android_media_audiotrack.cpp
  android_media_AudioTrack_native_setup{
    lpTrack->set(
          atStreamType,// stream type
          sampleRateInHertz,
          format,// word length, PCM
          channels,
          frameCount,
          0,// flags
          audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
          0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
          0,// shared mem
          true,// thread can call Java
          sessionId);// audio session ID
  }


  AudioTrack.cpp
  status_t AudioTrack::set(…){
   1)출력 스트림 핸들 획득
   audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType,
         sampleRate, format, channels, (AudioSystem::output_flags)flags);
2.트랙 생성 단계(서비스 클라이언트)                                                                               안드로이드 아나토미 정리


 2)트랙 생성 요청
status_t status = createTrack(streamType, sampleRate, format, channelCount,frameCount, flags, sharedBuffer, output, true);


 status_t AudioTrack::createTrack(){
  sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
                                   streamType,
                                   sampleRate,
                                   format,
                                   channelCount,
                                   frameCount,
                                   ((uint16_t)flags) << 16,
                                   sharedBuffer,
                                   output,
                                   &mSessionId,
                                   &status);
 }

 3)트랙 핸들 서비스 프록시 획득
 mAudioTrack = track;
  mAudioTrack 은 trackhandle 서비스의 proxy를 가리킨다.
   즉,이 mAudioTrack 변수를 통해서 trackhandle 서비스로 접근해서 생성된 track을 control한다.

 4)오디오 트랙 쓰레드 생성
 if (cbf != 0) {
       mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
 }
2.트랙 생성 단계(서비스 클라이언트)                                                                             안드로이드 아나토미 정리

 AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
   : Thread(bCanCallJava), mReceiver(receiver)
 {
 }

 bool AudioTrack::AudioTrackThread::threadLoop()
 {
   return mReceiver.processAudioBuffer(this);
 }

 status_t AudioTrack::AudioTrackThread::readyToRun()
 {
    return NO_ERROR;
 }

 void AudioTrack::AudioTrackThread::onFirstRef()
 {
 }
 onFirstRef 에 아무 code 도 없기 때문에 readyToRun, threadLoop 이 불리지 않는다.
  AudioTrack::start() 에서 t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); 이 불리면
  readyToRun-> threadLoop이 호출 된다.
  threadLoop 에서는 AudioTrack::processAudioBuffer를 반복 호출 한다.
                                                           tonegenerator        AudioPlayer        Android_media_audiotrack

                                                            Audiocallback()     Audiocallback()        Audiocallback()

         AudioTrackThread

                                                                                                   EVENT_MORE_DAT
                                                                                                   A
                                                                                      event        EVENT_UNDERRU
                                                                                                   N
        processAudioBuffer
                                                                                                   EVENT_NEW_POS
2.트랙 생성 단계(서비스 클라이언트)                                                         안드로이드 아나토미 정리


 Ex) EVENT_MORE_DATA 생성 및 처리

 1) processAudioBuffer 에서 EVENT_MORE_DATA 생성
 -EVENT_MORE_DATA:오디오 버퍼에 PCM 데이터를 쓰도록 요청
 status_t err = obtainBuffer(&audioBuffer, 1);
 오디오 버퍼를 확보.
 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
 확보된 오디오 버퍼를 인자로 EVENT_MORE_DATA event 전달

                             Audioplayer.cpp에 AudioCallback이 등록된 경우

 void AudioPlayer::AudioCallback(int event, void *info) {
   if (event != AudioTrack::EVENT_MORE_DATA) {
       return;
   }
   AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
   size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
   buffer->size = numBytesWritten;
 }
                                       오디오 버퍼에 전달된 data를 copy한다.



  size_t AudioPlayer::fillBuffer(void *data, size_t size) {

  memcpy((char *)data + size_done,
         (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
         copy);
  }
2.트랙 생성 단계(서비스 서버)                                                                     안드로이드 아나토미 정리


 서비스 클라이언트로 부터 요청 받은 track 생성 요구를 서비스 서버에서 처리하는 과정이다.


 sp<IAudioTrack> AudioFlinger::createTrack(…,output..){

 PlaybackThread *thread = checkPlaybackThread_l(output);  1)playbackthread 획득

 client = new Client(this, pid);  2) 트랙 공유 메모리 생성

 track = thread->createTrack_l(client, streamType, sampleRate, format,
            channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);
             3) 트랙 생성

 trackHandle = new TrackHandle(track);  4) 트랙 핸들 리모트 서비스 생성 후 반환
 return trackHandle;


 1)playbackthread 획득
   인자로 들어온 출력스트림(output)을 이용하여 playbackthread를 획득한다.

 AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
 {
   PlaybackThread *thread = NULL;
   if (mPlaybackThreads.indexOfKey(output) >= 0) {
       thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
   }
   return thread;
 }
2.트랙 생성 단계(서비스 서버)                                                                                    안드로이드 아나토미 정리


 2) 트랙 공유 메모리 생성
   서비스 클라이언트와 서비스 서버간의 PCM 데이터를 공유하기 위한 공유 메모리 생성
   Client 객체가 생성될 때 공유 메모리 생성 됨.

 sp<IAudioTrack> AudioFlinger::createTrack{                   AudioFlinger::Client::Client()
                                                                   : mMemoryDealer(
 wclient = mClients.valueFor(pid);                                         new MemoryDealer(1024*1024, "AudioFlinger::Client")
                                                              Client 생성자는 MemoryDealer를
      if (wclient != NULL) {                                    통해 1Mbytes의 공유 메모리확보
          client = wclient.promote();
      } else {
          client = new Client(this, pid);
          mClients.add(pid, client);
      }
 }
 Singletone pattern으로 하나의 process당 하나의 Client만 존재하게 된다.
   (즉, application은 audioflinger에 있는 createtrack()함수를 여러 번 호출 할 수 있지만, 하나의 Client만 생성하게 된다.)

       AudioTrack++                            Audioflinger




                             write          read                       write              android
                                                                                          kernel
                Track[3        32kbyte
                1]
    AudioFlinger::Client
                                               1M                                     Audio
    (shared memory)
                                                                                      Driver
                  Track[0]                                                            buffer
2.트랙 생성 단계(서비스 서버)                                                                                 안드로이드 아나토미 정리


 3) 트랙 생성
 sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
 track = new Track(this, client, streamType, sampleRate, format,
           channelCount, frameCount, sharedBuffer, sessionId);



  AudioFlinger::PlaybackThread::Track::Track()
    : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId),
  {
       …
  }
             Trackbase의 생성자가 먼저 호출됨.(오디오 트랙 컨트롤 블록 생성)


 AudioFlinger::ThreadBase::TrackBase::TrackBase(){
  size_t size = sizeof(audio_track_cblk_t);
  size_t bufferSize = 0;
  if ( (format == AudioSystem::PCM_16_BIT) ||
       (format == AudioSystem::PCM_8_BIT))
  {
      bufferSize = frameCount*channelCount*sizeof(int16_t);
  }
   size += bufferSize;
   mCblkMemory = client->heap()->allocate(size);  1)size 만큼 메모리 할당
    mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
    new(mCblk) audio_track_cblk_t();  2)할당 된 메모리에 64kbyte의 audio_track_cblk_t 구조체 생성
    mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); 3)pcm 데이터 공유 버퍼 설정
    memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
    mBufferEnd = (uint8_t *)mBuffer + bufferSize;
2.트랙 생성 단계(서비스 서버)                                                               안드로이드 아나토미 정리




                                                                               Track

frameCount*ch                             PCM 데이터                            mBufferEnd
annelCount*                               공유 버퍼
sizeof(int16_t);                                                              mBuffer

                                                                              mCblk


        64kbytes                    오디오 컨트롤 블록



                                                         user
                                                                        출력 대기중인
    struct audio_track_cblk_t                                           PCM 데이터
    {                                                                                        server
                                                               User
                                                               offset
        volatile     uint32_t user;                                                       Server
        volatile     uint32_t server;                                                     offset
                   uint32_t userBase;
                   uint32_t serverBase;
                   void*    buffers;                userBase                                 serverBase
                   uint32_t frameCount;
                   …
    }                                                                   오디오 컨트롤 블록
2.트랙 생성 단계(서비스 서버)                                            안드로이드 아나토미 정리



  Useroffset 계산 과정(user-userbase)




     -512 프레임씩 write한다고 가정.
     -pcm 데이터 공유 버퍼 framecount 3,072
     -pcm 데이터 공유 버퍼가 full 인 상태(user가 3,072)에서 write할려고 할 경우
      buffer overflow 발생
      userbase를 0에서 framecount 인 3,072로 변경
      유저오프셋=user(3,072)-userbase(3,072)=0
        즉,buffer의 제일 처음 부터 다시 write함.
2.트랙 생성 단계(서비스 서버)                                                                               안드로이드 아나토미 정리



 -Track class 생성자 실행
 AudioFlinger::PlaybackThread::Track::Track()
 {
     mName = playbackThread->getTrackName_l();트랙 이름(0x1000)부터 시작,1씩 증가함.
     mMainBuffer = playbackThread->mixBuffer(); mixerbuffer를 가리킴.
     mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t);
 }
                    Audioflinger

                       Track

                     mBufferEnd
                       mBuffer
                       mCblk

                       mName                             Mixer
                     mMainBuffer                         buffer


                                                                                                        android

                                                                                                         kernel
                                                                                Audio
                          PCM 데이터                                               Driver
                          공유 버퍼                                                 buffer


                     오디오 컨트롤 블록
2.트랙 생성 단계(트랙 공유 메모리 참조)-서비스 클라이언트                                                 안드로이드 아나토미 정리


 서비스 클라이언트가(audiotrack) 트랙 생성을 요청한 이후 서비스 서버측(audioflinger)에 의해
 생성된 트랙 공유 메모리를 참조하는 과정


 status_t AudioTrack::createTrack()
 {
   sp<IAudioTrack> track = audioFlinger->createTrack();

      sp<IMemory> cblk = track->getCblk(); 1)trackhandle의 getCblk() 호출 함으로써 트랙 공유 메모리의
                                        공유 메모리 서비스 프락시를 얻어온다.
       mCblkMemory = cblk;
       mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
       트랙 공유 메모리의 오디오 컨트롤 블록을 가리킨다.
       mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
       pcm 데이터 공유 버퍼를 가리킨다.
  }



                                                                                      Track
       AudioTrack                                  PCM 데이터
                                                   공유 버퍼                           mBufferEnd

         mBuffer                                                                     mBuffer

                                                                                     mCblk
         mCblk
                                                오디오 컨트롤 블록

Android audio system(오디오 출력-트랙생성)

  • 1.
    안드로이드 아나토미 정리 Android Audio System (오디오 출력-트랙생성) 박철희 1
  • 2.
    1.오디오 출력 안드로이드 아나토미 정리 오디오 출력은 크게 3단계로 구성됨. 1)Track생성 2)Track 활성화단계 3)PCM 데이터 출력 요청 단계 Ex)Mediaplayerservice에서의 오디오 출력 예 1)선행단계 -> audiooutput class를 audiosink 함수로 설정 함. Audioplayer의 audiosink가 불리면 mediaplayerservice의 audiooutput class가 호출 됨. MediaplayerBase AudioSink Mediaplayer MediaplayerService Interface AudioOutput setAudioSink(AudioOutput) stagefrightPlayer Awesomeplayer AudioPlayer 2
  • 3.
    1.오디오 출력 안드로이드 아나토미 정리 AudioPlayer.cpp 2)Track생성 및 활성화 status_t AudioPlayer::start(bool sourceAlreadyStarted) { mAudioSink->open( Mediaplayerservice.cpp mSampleRate, numChannels, status_t MediaPlayerService::Client::start() AudioSystem::PCM_16_BIT, { DEFAULT_AUDIOSINK_BUFFERCOUNT, LOGV("[%d] start", mConnId); &AudioPlayer::AudioSinkCallback, this); sp<MediaPlayerBase> p = getPlayer(); if (p == 0) return UNKNOWN_ERROR; mAudioSink->start(); p->setLooping(mLoop); return p->start(); } } Stagefrightplayer.cpp status_t MediaPlayerService::AudioOutput::open(){ status_t StagefrightPlayer::start() { LOGV("start"); t = new AudioTrack(…); Track생성 return mPlayer->play(); } } void MediaPlayerService::AudioOutput::start() status_t AwesomePlayer::play() { { return play_l(); if (mTrack) { } mTrack->start(); Track활성화 } } status_t AwesomePlayer::play_l() { ssize_t MediaPlayerService::AudioOutput::write mAudioPlayer = new AudioPlayer(mAudioSink, this); { mAudioPlayer->start(); if (mTrack) { ssize_t ret = mTrack->write(buffer, size); PCM데이터 } return ret; 출력 }
  • 4.
    2.트랙 생성 단계 안드로이드 아나토미 정리 AudioTrack.java Android_media_ AudiioTrack.cpp Audiotrack.cpp 서비스 클라이언트 서비스 서버
  • 5.
    2.트랙 생성 단계(서비스클라이언트) 안드로이드 아나토미 정리 Audiotrack.java public AudioTrack(…){ int initResult = native_setup(new WeakReference<AudioTrack>(this), mStreamType, mSampleRate, mChannels, mAudioFormat, mNativeBufferSizeInBytes, mDataLoadMode, session); } Android_media_audiotrack.cpp android_media_AudioTrack_native_setup{ lpTrack->set( atStreamType,// stream type sampleRateInHertz, format,// word length, PCM channels, frameCount, 0,// flags audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user) 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 0,// shared mem true,// thread can call Java sessionId);// audio session ID } AudioTrack.cpp status_t AudioTrack::set(…){ 1)출력 스트림 핸들 획득 audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType, sampleRate, format, channels, (AudioSystem::output_flags)flags);
  • 6.
    2.트랙 생성 단계(서비스클라이언트) 안드로이드 아나토미 정리 2)트랙 생성 요청 status_t status = createTrack(streamType, sampleRate, format, channelCount,frameCount, flags, sharedBuffer, output, true); status_t AudioTrack::createTrack(){ sp<IAudioTrack> track = audioFlinger->createTrack(getpid(), streamType, sampleRate, format, channelCount, frameCount, ((uint16_t)flags) << 16, sharedBuffer, output, &mSessionId, &status); } 3)트랙 핸들 서비스 프록시 획득 mAudioTrack = track;  mAudioTrack 은 trackhandle 서비스의 proxy를 가리킨다. 즉,이 mAudioTrack 변수를 통해서 trackhandle 서비스로 접근해서 생성된 track을 control한다. 4)오디오 트랙 쓰레드 생성 if (cbf != 0) { mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava); }
  • 7.
    2.트랙 생성 단계(서비스클라이언트) 안드로이드 아나토미 정리 AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava) : Thread(bCanCallJava), mReceiver(receiver) { } bool AudioTrack::AudioTrackThread::threadLoop() { return mReceiver.processAudioBuffer(this); } status_t AudioTrack::AudioTrackThread::readyToRun() { return NO_ERROR; } void AudioTrack::AudioTrackThread::onFirstRef() { } onFirstRef 에 아무 code 도 없기 때문에 readyToRun, threadLoop 이 불리지 않는다. AudioTrack::start() 에서 t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); 이 불리면 readyToRun-> threadLoop이 호출 된다. threadLoop 에서는 AudioTrack::processAudioBuffer를 반복 호출 한다. tonegenerator AudioPlayer Android_media_audiotrack Audiocallback() Audiocallback() Audiocallback() AudioTrackThread EVENT_MORE_DAT A event EVENT_UNDERRU N processAudioBuffer EVENT_NEW_POS
  • 8.
    2.트랙 생성 단계(서비스클라이언트) 안드로이드 아나토미 정리 Ex) EVENT_MORE_DATA 생성 및 처리 1) processAudioBuffer 에서 EVENT_MORE_DATA 생성 -EVENT_MORE_DATA:오디오 버퍼에 PCM 데이터를 쓰도록 요청 status_t err = obtainBuffer(&audioBuffer, 1); 오디오 버퍼를 확보. mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer); 확보된 오디오 버퍼를 인자로 EVENT_MORE_DATA event 전달 Audioplayer.cpp에 AudioCallback이 등록된 경우 void AudioPlayer::AudioCallback(int event, void *info) { if (event != AudioTrack::EVENT_MORE_DATA) { return; } AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size); buffer->size = numBytesWritten; } 오디오 버퍼에 전달된 data를 copy한다. size_t AudioPlayer::fillBuffer(void *data, size_t size) { memcpy((char *)data + size_done, (const char *)mInputBuffer->data() + mInputBuffer->range_offset(), copy); }
  • 9.
    2.트랙 생성 단계(서비스서버) 안드로이드 아나토미 정리 서비스 클라이언트로 부터 요청 받은 track 생성 요구를 서비스 서버에서 처리하는 과정이다. sp<IAudioTrack> AudioFlinger::createTrack(…,output..){ PlaybackThread *thread = checkPlaybackThread_l(output);  1)playbackthread 획득 client = new Client(this, pid);  2) 트랙 공유 메모리 생성 track = thread->createTrack_l(client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);  3) 트랙 생성 trackHandle = new TrackHandle(track);  4) 트랙 핸들 리모트 서비스 생성 후 반환 return trackHandle; 1)playbackthread 획득 인자로 들어온 출력스트림(output)을 이용하여 playbackthread를 획득한다. AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const { PlaybackThread *thread = NULL; if (mPlaybackThreads.indexOfKey(output) >= 0) { thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get(); } return thread; }
  • 10.
    2.트랙 생성 단계(서비스서버) 안드로이드 아나토미 정리 2) 트랙 공유 메모리 생성 서비스 클라이언트와 서비스 서버간의 PCM 데이터를 공유하기 위한 공유 메모리 생성 Client 객체가 생성될 때 공유 메모리 생성 됨. sp<IAudioTrack> AudioFlinger::createTrack{ AudioFlinger::Client::Client() : mMemoryDealer( wclient = mClients.valueFor(pid); new MemoryDealer(1024*1024, "AudioFlinger::Client") Client 생성자는 MemoryDealer를 if (wclient != NULL) { 통해 1Mbytes의 공유 메모리확보 client = wclient.promote(); } else { client = new Client(this, pid); mClients.add(pid, client); } } Singletone pattern으로 하나의 process당 하나의 Client만 존재하게 된다. (즉, application은 audioflinger에 있는 createtrack()함수를 여러 번 호출 할 수 있지만, 하나의 Client만 생성하게 된다.) AudioTrack++ Audioflinger write read write android kernel Track[3 32kbyte 1] AudioFlinger::Client 1M Audio (shared memory) Driver Track[0] buffer
  • 11.
    2.트랙 생성 단계(서비스서버) 안드로이드 아나토미 정리 3) 트랙 생성 sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l( track = new Track(this, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, sessionId); AudioFlinger::PlaybackThread::Track::Track() : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId), { … } Trackbase의 생성자가 먼저 호출됨.(오디오 트랙 컨트롤 블록 생성) AudioFlinger::ThreadBase::TrackBase::TrackBase(){ size_t size = sizeof(audio_track_cblk_t); size_t bufferSize = 0; if ( (format == AudioSystem::PCM_16_BIT) || (format == AudioSystem::PCM_8_BIT)) { bufferSize = frameCount*channelCount*sizeof(int16_t); } size += bufferSize; mCblkMemory = client->heap()->allocate(size);  1)size 만큼 메모리 할당 mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); new(mCblk) audio_track_cblk_t();  2)할당 된 메모리에 64kbyte의 audio_track_cblk_t 구조체 생성 mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); 3)pcm 데이터 공유 버퍼 설정 memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); mBufferEnd = (uint8_t *)mBuffer + bufferSize;
  • 12.
    2.트랙 생성 단계(서비스서버) 안드로이드 아나토미 정리 Track frameCount*ch PCM 데이터 mBufferEnd annelCount* 공유 버퍼 sizeof(int16_t); mBuffer mCblk 64kbytes 오디오 컨트롤 블록 user 출력 대기중인 struct audio_track_cblk_t PCM 데이터 { server User offset volatile uint32_t user; Server volatile uint32_t server; offset uint32_t userBase; uint32_t serverBase; void* buffers; userBase serverBase uint32_t frameCount; … } 오디오 컨트롤 블록
  • 13.
    2.트랙 생성 단계(서비스서버) 안드로이드 아나토미 정리 Useroffset 계산 과정(user-userbase) -512 프레임씩 write한다고 가정. -pcm 데이터 공유 버퍼 framecount 3,072 -pcm 데이터 공유 버퍼가 full 인 상태(user가 3,072)에서 write할려고 할 경우 buffer overflow 발생 userbase를 0에서 framecount 인 3,072로 변경 유저오프셋=user(3,072)-userbase(3,072)=0 즉,buffer의 제일 처음 부터 다시 write함.
  • 14.
    2.트랙 생성 단계(서비스서버) 안드로이드 아나토미 정리 -Track class 생성자 실행 AudioFlinger::PlaybackThread::Track::Track() { mName = playbackThread->getTrackName_l();트랙 이름(0x1000)부터 시작,1씩 증가함. mMainBuffer = playbackThread->mixBuffer(); mixerbuffer를 가리킴. mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t); } Audioflinger Track mBufferEnd mBuffer mCblk mName Mixer mMainBuffer buffer android kernel Audio PCM 데이터 Driver 공유 버퍼 buffer 오디오 컨트롤 블록
  • 15.
    2.트랙 생성 단계(트랙공유 메모리 참조)-서비스 클라이언트 안드로이드 아나토미 정리 서비스 클라이언트가(audiotrack) 트랙 생성을 요청한 이후 서비스 서버측(audioflinger)에 의해 생성된 트랙 공유 메모리를 참조하는 과정 status_t AudioTrack::createTrack() { sp<IAudioTrack> track = audioFlinger->createTrack(); sp<IMemory> cblk = track->getCblk(); 1)trackhandle의 getCblk() 호출 함으로써 트랙 공유 메모리의 공유 메모리 서비스 프락시를 얻어온다. mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); 트랙 공유 메모리의 오디오 컨트롤 블록을 가리킨다. mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); pcm 데이터 공유 버퍼를 가리킨다. } Track AudioTrack PCM 데이터 공유 버퍼 mBufferEnd mBuffer mBuffer mCblk mCblk 오디오 컨트롤 블록