포럼 회원으로 등록하신분만 다운로드가 가능합니다. 최대 업로드 가능한 용량은 20MB 입니다.

AudioFlingerService의 동작 구조

 

글쓴이 : 김재훈 (이솝 임베디드 포럼)

 

안드로이드 AudioFlinger에서, HAL단까지의 접근 구조에 대한 코드를 트레이스하여 간단하게 정리해 봤습니다. :)

도움되시길 바랍니다.

 

1. main_mediaserver.cpp => AudioFlinger::instantiate(); 명령으로 서비스가 초기화 된다.
   frameworksbasemediamediaservermain_mediaserver.cpp //     41 라인


2. frameworksbaselibsaudioflingerAudioFlinger.cpp            // 3715 라인
   void AudioFlinger::instantiate(); 함수에서 서비스가 활성화 된다.

 

AudioFlingerService의 바인더 구조

 

1. AudioFlingerService는 AudioSystem에서 Binder를 통해 호출한다.


2. AudioSystem.cpp에서 Binder를 통해 AudioFlingerService를 호출하면, 

     IAudioFlinger.cpp의 onTranct(); 함수를 통하여, Binder에 대한 응답이 이루어진다.

 

- 참고소스 : frameworks/base/media/AudioSystem.cpp : 37라인

 

// client singleton for AudioFlinger binder interface
Mutex AudioSystem::gLock;
sp<IAudioFlinger> AudioSystem::gAudioFlinger;
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;

// establish binder interface to AudioFlinger service
const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
{
    Mutex::Autolock _l(gLock);
    if (gAudioFlinger.get() == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16("media.audio_flinger"));
            if (binder != 0)
                break;
            LOGW("AudioFlinger not published, waiting...");
            usleep(500000); // 0.5 s
        } while(true);
        if (gAudioFlingerClient == NULL) {
            gAudioFlingerClient = new AudioFlingerClient();
        } else {
            if (gAudioErrorCallback) {
                gAudioErrorCallback(NO_ERROR);
            }
         }
        binder->linkToDeath(gAudioFlingerClient);
        gAudioFlinger = interface_cast<IAudioFlinger>(binder);
        gAudioFlinger->registerClient(gAudioFlingerClient);
    }
    LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");

    return gAudioFlinger;
}


 3. AudioSystem에서의 Binder에 대한 처리는 다음과 같은 형식으로 이루어진다.

 

- 참고소스 : frameworks/base/media/AudioSystem.cpp : 96라인

 

status_t AudioSystem::setMasterVolume(float value)
{
    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
    if (af == 0) return PERMISSION_DENIED;
    af->setMasterVolume(value);
    return NO_ERROR;
}

 4. 위와 같이 AudioSystem::get_audio_flinger();에 대한 리턴형을 <IAudioPolicyService>으로 캐스팅하여, 

     사용하기 때문에, 소스코드 추적이 잘 되지 않는다. 

     실제적인 AudioFlinerService에 대한 Binder onTranct(); 함수는 frameworks/base/medis/IAudioFlinger.cpp에 위치하게 된다.
  
- 참고소스 : frameworks/base/media/libmedia/AudioFlinger.cpp : 189라인

 

    virtual status_t setMasterVolume(float value)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
        data.writeFloat(value);
        remote()->transact(SET_MASTER_VOLUME, data, &reply);
        return reply.readInt32();
    } 

5. 결론적으로 AudioSystem.cpp에서 setMasterVolume();를 호출했을 경우, IAudioFlinger.cpp의 setMasterVolume();

    함수에서 Binder를 이용한 실제 Transaction이 발생하게 되며, 이것을 AudioFlinger에서 받아서 처리하게 된다.

 

6. AudioFlinger에서의 Binder Transaction의 처리 부분

   AudioFlinger에서의 Binder Transaction의 처리는 다음의 코드와 같으며, 

   reply->writeInt32( setMasterVolume(data.readFloat()) );를 호출한다.

  이것은 실제로, AudioFlinger.cpp의 setMasterVolume(); 함수가 호출되는 것이다. 
   
- 참고소스 1 : frameworks/base/media/IAudioFlinger.cpp : 539라인

 

         case SET_MASTER_VOLUME: {
            CHECK_INTERFACE(IAudioFlinger, data, reply);
            reply->writeInt32( setMasterVolume(data.readFloat()) );
            return NO_ERROR;
   
- 참고소스 2 : frameworks/base/media/libmedia/AudioFlinger.cpp : 378라인

 

status_t AudioFlinger::setMasterVolume(float value)
{
    // check calling permissions
    if (!settingsAllowed()) {
        return PERMISSION_DENIED;
    }

    // when hw supports master volume, don't scale in sw mixer
    AutoMutex lock(mHardwareLock);
    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
    if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
        value = 1.0f;
    }
    mHardwareStatus = AUDIO_HW_IDLE;

    mMasterVolume = value;
    for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
       mPlaybackThreads.valueAt(i)->setMasterVolume(value);

    return NO_ERROR;
}


 7. 위의 참고소스 2에서 유의해야 할 점은 시스템의 퍼미션을 검사하는 부분이며, 접근 퍼미션이 거부될 경우
    시스템 부팅이 다운될 수 있다. 오디오에 대한 퍼미션 설정은 system/core/init/devices.cpp 에서 설정을 해줘야 한다.

 

static struct perms_ devperms[] = {
    { "/dev/null",          0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/zero",          0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/full",          0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/ptmx",          0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/tty",           0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/random",        0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/urandom",       0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/ashmem",        0666,   AID_ROOT,       AID_ROOT,       0 },
    { "/dev/binder",        0666,   AID_ROOT,       AID_ROOT,       0 },
     .
     .
     .
    { "/dev/snd/pcmC0D0c",  0660,   AID_SYSTEM,     AID_AUDIO,      0 }, // ghcstop fix for ALSA
    { "/dev/snd/pcmC0D0p",  0660,   AID_SYSTEM,     AID_AUDIO,      0 },
    { "/dev/snd/controlC0", 0660,   AID_SYSTEM,     AID_AUDIO,      0 },
    { "/dev/snd/timer",     0660,   AID_SYSTEM,     AID_AUDIO,      0 },
    { NULL, 0, 0, 0, 0 },
};

 

8. 위의 참고소스 2에서 mAudioHardware->setMasterVolume(value); 의 경우, HAL 부분을 호출하는 부분이며,

    Audio Device의 종류에 따라 mAudioHardware에 붙는 HAL의 종류를 선택하여 할당한다.
     mAudioHardware를 할당하는 부분은 다음과 같으며, AudioFlinger 클래스를 생성할 때 초기화된다.

 

- 참고소스 : frameworksbaselibsaudioflingerAudioFliner.cpp // 64라인

 

AudioFlinger::AudioFlinger()
    : BnAudioFlinger(),
        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
{
    mHardwareStatus = AUDIO_HW_IDLE;

    mAudioHardware = AudioHardwareInterface::create(); 
// AudioHardwareInterface 클래스를 호출하여, 하드웨어의 접근 핸들을 생성한다.

    mHardwareStatus = AUDIO_HW_INIT;
// mHardwareStatus는 현재 오디오의 상태를 업데이트 하는 것이다.
    if (mAudioHardware->initCheck() == NO_ERROR) {
        // open 16-bit output stream for s/w mixer

        setMode(AudioSystem::MODE_NORMAL);

        setMasterVolume(1.0f);
        setMasterMute(false);
    } else {
        LOGE("Couldn't even initialize the stubbed audio hardware!");
    }

}

 

9. AudioHardware = AudioHardwareInterface::create(); 에서 AudioHardwareInterface::create();는
   AudioHardwareInterface.cpp에 위치해 있으며, 이 클래스는 AudioFlinger와 ALSA H/W를 연결해준다.
  
- 참고소스 : frameworksbaselibsaudioflingerAudioHardwareInterface.cpp // 66라인

 

AudioHardwareInterface* AudioHardwareInterface::create()
{
    /*
     * FIXME: This code needs to instantiate the correct audio device
     * interface. For now - we use compile-time switches.
     */
    AudioHardwareInterface* hw = 0;
    char value[PROPERTY_VALUE_MAX];

#ifdef GENERIC_AUDIO
    hw = new AudioHardwareGeneric();
#else
    // if running in emulation - use the emulator driver
    if (property_get("ro.kernel.qemu", value, 0)) {           // Emulation Driver를 사용할 때
        LOGD("Running in emulation - using generic audio driver");
        hw = new AudioHardwareGeneric();
    }
    else {
        LOGV("Creating Vendor Specific AudioHardware");
        hw = createAudioHardware();                                   // H/W 오디오를 사용할 때
    }
#endif
    if (hw->initCheck() != NO_ERROR) {
        LOGW("Using stubbed audio hardware. No sound will be produced.");
        delete hw;
        hw = new AudioHardwareStub();                              // 더미드라이버
    }


10. AudioHardwareInterface와 AudioHardwareALSA 사이의 함수 매핑 부분

 

다음 AudioFlinger는 mAudioHardware 포인터를 할당받아 사용하며, AudioHardwareALSA에 포함된 함수와 1:1 매핑된다. 이외의 AudioFlinger에서 H/W 접근에 사용되는 것들은 모두 위와 같이 1:1 매핑하여 사용하며, HAL의 경우 매핑이 되는 함수의 인/아웃 구조를 고려하여 작성해 주면 된다.

 

- 참고소스 : hardware/alsa_sound/AudioHardwareALSA.cpp // 135라인

 

status_t AudioHardwareALSA::setMasterVolume(float volume)
{
    if (mMixer)
        return mMixer->setMasterVolume(volume);
    else
        return INVALID_OPERATION;
}

11. 10번에서 보면 mMixer의 setMasterVolume를 호출하고 있는 것이 보이는데,

      기본적으로 ALSA의 오디오 스트림은 Mixer를 통해 믹싱 후 출력된다.

       mMixer는 AudioHardwareALSA 클래스 생성시에 다음과 같이 생성된다.

 

- 참고소스 : hardware/alsa_sound/AudioHardwareALSA.cpp // 74라인
 

AudioHardwareALSA::AudioHardwareALSA() :
    mALSADevice(0),
    mAcousticDevice(0)
{
    snd_lib_error_set_handler(&ALSAErrorHandler);
    mMixer = new ALSAMixer;

    hw_module_t *module;
    int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,
            (hw_module_t const**)&module);

    if (err == 0) {
        hw_device_t* device;
        err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);
        if (err == 0) {
            mALSADevice = (alsa_device_t *)device;
            mALSADevice->init(mALSADevice, mDeviceList);
        } else
            LOGE("ALSA Module could not be opened!!!");
    } else
        LOGE("ALSA Module not found!!!");

    err = hw_get_module(ACOUSTICS_HARDWARE_MODULE_ID,
            (hw_module_t const**)&module);

    if (err == 0) {
        hw_device_t* device;
        err = module->methods->open(module, ACOUSTICS_HARDWARE_NAME, &device);
        if (err == 0)
            mAcousticDevice = (acoustic_device_t *)device;
        else
            LOGE("Acoustics Module not found.");
    }

}


12. 위의 ALSAMixer의 생성자가 들어간 클래스는 ALSAMixer.cpp이며, Mixer에 관련된 각종 설정을 위한 함수들이 모여있다. setMasterVolume();의 경우 Mixser에서 담당하고 있기 때문에, 이 소스코드에서 다음의 함수를 발견할 수 있다.

 

status_t ALSAMixer::setMasterVolume(float volume)
{
    mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_PLAYBACK].mInfo;
    if (!info || !info->elem) return INVALID_OPERATION;

    long minVol = info->min;
    long maxVol = info->max;

    // Make sure volume is between bounds.
    long vol = minVol + volume * (maxVol - minVol);
    if (vol > maxVol) vol = maxVol;
    if (vol < minVol) vol = minVol;

    info->volume = vol;
    snd_mixer_selem_set_playback_volume_all (info->elem, vol);

    return NO_ERROR;
}


 13. 위와 같이 ALSAMixer에서 실제 ALSA 라이브러리를 이용하여 snd_mixer_selem_set_playback_volume_all 함수를 호출하여, 믹싱을 하고 있는 것을 알 수 있다.
   
이와 같은 형식으로 AudioStreamOut과, AudioStreamIn이 구현되어 있다. 따라서, Android Audio System을 접근하기 위해서는 하위 단에서와 상위 단에서의 동시 접근이 필요하다.
       
99. 즉, Android의 Audio System의 경우 결론적으로 다음 구조를 띄게 된다.

 

AudioTrack,  AudioSystem => AudioPolicySerivce  -> AudioPolicyManager  -> AudioPoricyManagerALSA
AudioRecord                            AudioFlingerService -> AudioFlinger                -> AudioHardwareALSA
              
              

profile

인생은 연극이고 세상은 무대이다!

이솝 임베디드 포럼 운영 및 비즈니스와 관련된 것 이외에 E-Mail이나 메신저 및 휴대폰 등을 통한 개인적인 질문 및 답변은 받지 않습니다. 문의 사항은 이솝 임베디드 포럼 게시판을 이용해 주시면 감사하겠습니다.

엮인글 :
http://www.aesop.or.kr/index.php?mid=Board_Documents_Android_Frameworks&document_srl=34862&act=trackback&key=97d

profile

뻔뻔강사

2010.04.08 19:39:26
*.206.33.196

역시나 재훈 님.. 강의는 재훈 님이 하셔야 할 듯..

존경합니다. (_._)

 

tezboy

2010.11.30 02:05:07
*.50.21.22

좋은 정보 감사드립니다.

 

List of Articles
번호 제목 글쓴이 날짜 조회 수
64 Google 의 새로운 코덱 VP8 Video Codec 규격자료를 올려 봅니다... file [1] 장석원 2010-05-24 14955
63 [실습-03] android source compile시 battery 부분 patch하기 [7] 고도리 2010-05-24 15896
62 [실습-02] android에서 new product 만들고 compile하기 file [7] 고도리 2010-05-18 13223
61 [이론-00] Android의 개요와 구성 part0 [2] 고도리 2010-05-17 12471
60 [실습-01] android 개발환경 세팅과 source download [2] 고도리 2010-05-17 13781
59 [실습-00] android eclair porting을 위한 ubuntu 설치하기 file [6] 고도리 2010-05-17 12321
58 AudioSystem과 AudioSystem.java를 이용한 JNI 단에서의 연결 [1] JhoonKim 2010-04-14 10871
57 AudioPolicyService와 AudioFlinger 및 HAL의 연결 구조 JhoonKim 2010-04-08 11291
» Android 2.x AudioFlinger와 HAL의 연결 구조 분석 [2] JhoonKim 2010-04-08 19341
55 busybox에 대한 질문 [3] 득드로이드 2010-03-24 8881
54 누가 Android 에 tslib를 포팅해 놓은듯 합니다. file 최종환 2009-11-11 11061
53 Android Battery 부분 조금 정리해 놓은것 file [2] 최종환 2009-11-04 10726
52 Power Management from Linux Kernel to Android file [10] 최종환 2009-11-01 14996
51 이솝 임베디드 포럼 - 10월 31일 Google Android Seminar 발표 ... file [16] 관리자 2009-10-28 10898
50 Dummy Battery 드라이버 입니다. file [3] 관리자 2009-10-10 10262
49 [참고] Android wifi howto - 아직 테스트는 다 못했습니다. file [10] 고도리 2009-09-22 21723
48 [번역] Android Camera Framework 번역 file [7] 고도리 2009-09-10 19665
47 Android home key is not working(home key 동작 안 할경우 ) [1] 고현철 2009-09-10 10597
46 S3C6410 프로세서용 Andoird Kernel 2.6.29 이식 방법 #1 [2] 김재훈 2009-09-04 15823
45 삼성 안드로이드폰(갤럭시) 리눅스 커널 소스코드 file [3] 유형목 2009-09-01 15909

사용자 로그인