포럼 회원으로 등록하신분만 다운로드가 가능합니다. 최대 업로드 가능한 용량은 20MB 입니다.
AudioPolicyService와 AudioFlinger 및 HAL의 연결 구조
글쓴이 : 김재훈 (이솝 임베디드 포럼)
안드로이드 AudioPolicyService와 AudioFlinger의 연결 구조에 대한 코드를 트레이스하여 간단하게 정리해 봤습니다. :)
도움되시길 바랍니다.
1. main_mediaserver.cpp => AudioPolicyService::instantiate(); 명령으로 서비스가 초기화 된다.
frameworksbasemediamediaservermain_mediaserver.cpp
2. frameworksbaselibsaudioflingerAudioPolicyService.cpp // 424라인
void AudioPolicyService::instantiate(); 함수에서 서비스가 활성화 된다.
AudioPolicyService의 바인더 구조
1. AudioPolicyService는 AudioSystem에서 Binder를 통해 호출한다.
2. AudioSystem.cpp에서 Binder를 통해 AudioPolicyService를 호출하면,
IAudioPolicyService.cpp의 onTranct(); 함수를 통하여, Binder에 대한 응답이 이루어진다.
- 참고소스 : frameworks/base/media/AudioSystem.cpp : 447라인
// client singleton for AudioPolicyService binder interface
sp<IAudioPolicyService> AudioSystem::gAudioPolicyService
sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient;
// establish binder interface to AudioPolicy service
const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service()
{
gLock.lock();
if (gAudioPolicyService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.audio_policy"));
if (binder != 0)
break;
LOGW("AudioPolicyService not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (gAudioPolicyServiceClient == NULL) {
gAudioPolicyServiceClient = new AudioPolicyServiceClient();
}
binder->linkToDeath(gAudioPolicyServiceClient);
gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
gLock.unlock();
} else {
gLock.unlock();
}
return gAudioPolicyService;
}
3. AudioSystem에서의 Binder에 대한 처리는 다음과 같은 형식으로 이루어진다.
status_t AudioSystem::setDeviceConnectionState(audio_devices device,
device_connection_state state,
const char *device_address)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->setDeviceConnectionState(device, state, device_address);
}
4. 위와 같이 AudioSystem::get_audio_policy_service();에 대한 리턴형을 <IAudioPolicyService>으로 캐스팅하여,
사용하기 때문에, 소스코드 추적이 잘 되지 않는다.
실제적인 AudioPolicyService에 대한 Binder onTranct(); 함수는 frameworks/base/medis/IAudioPolicyService.cpp에
위치하게 된다.
- 참고소스 : frameworks/base/media/libmedia/IAudioPolicyService.cpp : 58라인
5. 결론적으로 AudioSystem.cpp에서 setDeviceConnectionState();를 호출했을 경우, IAudioPolicyService.cpp의
setDeviceConnectionState(); 함수에서 Binder를 이용한 실제 Transaction이 발생하게 되며, 이것을 AudioPolicySerivce에서
받아서 처리하게 된다.
6. AudioPolicyService에서의 Binder Transaction의 처리
AudioPolicyService에서의 Binder Transaction의 처리는 다음의 코드와 같으며,
reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address)));를 호출하며,
이것은 실제로, AudioPolicyService.cpp의 setDeviceConnectionState(); 함수가 호출되는 것이다.
- 참고소스 1 : frameworks/base/medis/libmedia/IAudioPolicyService.cpp : 252라인
- 참고소스 2 : frameworksbaselibsaudioflingerAudioPolicyService.cpp // 107라인
status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices device,
AudioSystem::device_connection_state state,
const char *device_address)
{
if (mpPolicyManager == NULL) {
return NO_INIT;
}
if (!checkPermission()) {
return PERMISSION_DENIED;
}
if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) {
return BAD_VALUE;
}
if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
return BAD_VALUE;
}
LOGV("setDeviceConnectionState() tid %d", gettid());
Mutex::Autolock _l(mLock);
return mpPolicyManager->setDeviceConnectionState(device, state, device_address);
}
7. 위의 참고소스 2에서 유의해야 할 점은 시스템의 퍼미션을 검사하는 부분이며, 접근 퍼미션이 거부될 경우
시스템 부팅이 다운되게 된다. 오디오에 대한 퍼미션 설정은 system/core/init/devices.cpp 에서 설정을 해줘야 한다.
8. 위의 참고소스 2에서 return mpPolicyManager->setDeviceConnectionState(device, state, device_address);의 경우,
HAL 부분을 호출하는 부분이며, Audio Device의 종류에 따라 mpPolicyManager에 붙는 HAL의 종류를 선택하여 할당한다.
mpPolicyManager를 할당하는 부분은 다음과 같으며, AudioPolicyService 클래스를 생성할 때 초기화된다.
- 참고소스 : frameworksbaselibsaudioflingerAudioPolicyService.cpp // 64라인
AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService() , mpPolicyManager(NULL)
{
char value[PROPERTY_VALUE_MAX];
// start tone playback thread
mTonePlaybackThread = new AudioCommandThread();
// start audio commands thread
mAudioCommandThread = new AudioCommandThread();
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST) // BoardConfig.mk에서 GENERIC_AUDIO를 선택했을 경우
mpPolicyManager = new AudioPolicyManagerGeneric(this);
LOGV("build for GENERIC_AUDIO - using generic audio policy");
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGV("Running in emulation - using generic audio policy");
mpPolicyManager = new AudioPolicyManagerGeneric(this); // System Property에서 qemu가 선택되었을 경우
}
else {
LOGV("Using hardware specific audio policy"); // Audio 관련 HAL을 사용하는 경우
mpPolicyManager = createAudioPolicyManager(this);
}
#endif
// load properties
property_get("ro.camera.sound.forced", value, "0");
mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
}
9. mpPolicyManager = createAudioPolicyManager(this); 에서 createAudioPolicyManager();는 ALSA HAL에 위치해 있으며,
다음의 소스코드를 참조한다.
- 참고소스 : hardware/alsa_sound/AudioPolicyManager // 1207라인
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManagerALSA(clientInterface); // AudioPolicyClientInterface 클래스를 상속 받아서, ALSA에서
AudioPolicyManagerALSA 클래스 초기에, 각종 오디오 인터페이스에 대한
설정사항을 등록한다.
}
AudioPolicyManagerALSA::AudioPolicyManagerALSA(AudioPolicyClientInterface *clientInterface)
: mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0)
{
mpClientInterface = clientInterface;
for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
mForceUse[i] = AudioSystem::FORCE_NONE;
}
// devices available by default are speaker, ear piece and microphone
mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
AudioSystem::DEVICE_OUT_SPEAKER;
mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
mA2dpDeviceAddress = String8("");
mScoDeviceAddress = String8("");
// open hardware output
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);
if (mHardwareOutput == 0) {
LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
} else {
mOutputs.add(mHardwareOutput, outputDesc);
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
}
mA2dpOutput = 0;
mDuplicatedOutput = 0;
}
10. AudioPolicyManager와 AudioPolicySerivce 사이의 함수 매핑
다음 AudioPolicyServe는 참고소스1 에서 mpPolicyManager 클래스 포인터를 할당받아, 사용하며,
AudioPolicyManagerALSA.h와 1:1 매핑이 된다.
- 참고소스1 : frameworksbaselibsaudioflingerAudioPolicyService.cpp // 64라인
AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService() , mpPolicyManager(NULL)
{
char value[PROPERTY_VALUE_MAX];
// start tone playback thread
mTonePlaybackThread = new AudioCommandThread();
// start audio commands thread
mAudioCommandThread = new AudioCommandThread();
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST) // BoardConfig.mk에서 GENERIC_AUDIO를 선택했을 경우
mpPolicyManager = new AudioPolicyManagerGeneric(this);
LOGV("build for GENERIC_AUDIO - using generic audio policy");
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGV("Running in emulation - using generic audio policy");
mpPolicyManager = new AudioPolicyManagerGeneric(this); // System Property에서 qemu가 선택되었을 경우
}
else {
LOGV("Using hardware specific audio policy"); // Audio 관련 HAL을 사용하는 경우
mpPolicyManager = createAudioPolicyManager(this);
}
#endif
// load properties
property_get("ro.camera.sound.forced", value, "0");
mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
}
참고소스2 : hardware/alsa_sound/AudioPolicyManagerALSA.h // 45라인
// AudioPolicyInterface
virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
AudioSystem::device_connection_state state,
const char *device_address);
virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
const char *device_address);
virtual void setPhoneState(int state);
virtual void setRingerMode(uint32_t mode, uint32_t mask);
virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
virtual void setSystemProperty(const char* property, const char* value);
virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
uint32_t samplingRate,
uint32_t format,
uint32_t channels,
AudioSystem::output_flags flags);
virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
virtual void releaseOutput(audio_io_handle_t output);
virtual audio_io_handle_t getInput(int inputSource,
uint32_t samplingRate,
uint32_t format,
uint32_t channels,
AudioSystem::audio_in_acoustics acoustics);
// indicates to the audio policy manager that the input starts being used.
virtual status_t startInput(audio_io_handle_t input);
// indicates to the audio policy manager that the input stops being used.
virtual status_t stopInput(audio_io_handle_t input);
virtual void releaseInput(audio_io_handle_t input);
virtual void initStreamVolume(AudioSystem::stream_type stream,
int indexMin,
int indexMax);
virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
virtual status_t dump(int fd);
11. hardware/alsa_sound/AudioPolicyManagerALSA.h에서 AudioPolicyClientInterface 클래스에 대한 각종 함수들은
AudioPolicyInterface에서 AudioPolicyService의 요청사항을 대응할 때 내부적으로 이용하게 된다.
따라서, 실제 Android쪽의 인터페이스는 AudioPolicyClientInterface 클래스이며, AudioPolicyClientInterface
부분 부터는 H/W에 의존적인 완전한 ALSA HAL단이 된다.
따라서, H/W를 디버깅하려면 이 부분을 수정하면 된다.
- 참고소스 : hardware/alsa_sound/AudioPolicyManagerALSA.cpp
1) 내부적으로 사용되는 AudioPolicyClientInterface 클래스의 getOutputForDevice(uint32_t device) 함수의 경우 다음과 같다.
audio_io_handle_t AudioPolicyManagerALSA::getOutputForDevice(uint32_t device)
{
audio_io_handle_t output = 0;
uint32_t lDevice;
for (size_t i = 0; i < mOutputs.size(); i++) {
lDevice = mOutputs.valueAt(i)->device();
LOGV("getOutputForDevice() output %d devices %x", mOutputs.keyAt(i), lDevice);
// We are only considering outputs connected to a mixer here => exclude direct outputs
if ((lDevice == device) &&
!(mOutputs.valueAt(i)->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
output = mOutputs.keyAt(i);
LOGV("getOutputForDevice() found output %d for device %x", output, device);
break;
}
}
return output;
}
2) 이것은 AudioPolicyInterface 클래스의 setDeviceConnectionState(); 함수에서, 다음과 같이 사용하는 것을 볼 수있다.
status_t AudioPolicyManagerALSA::setDeviceConnectionState(AudioSystem::audio_devices device,
AudioSystem::device_connection_state state,
const char *device_address)
{
LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
// connect/disconnect only 1 device at a time
if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
LOGE("setDeviceConnectionState() invalid address: %s", device_address);
return BAD_VALUE;
}
// handle output devices
if (AudioSystem::isOutputDevice(device)) {
#ifndef WITH_A2DP
if (AudioSystem::isA2dpDevice(device)) {
LOGE("setDeviceConnectionState() invalid device: %x", device);
return BAD_VALUE;
}
#endif
switch (state)
{
// handle output device connection
case AudioSystem::DEVICE_STATE_AVAILABLE:
if (mAvailableOutputDevices & device) {
LOGW("setDeviceConnectionState() device already connected: %x", device);
return INVALID_OPERATION;
}
LOGW_IF((getOutputForDevice((uint32_t)device) != 0), "setDeviceConnectionState(): output using unconnected device %x", device);
LOGV("setDeviceConnectionState() connecting device %x", device);
.
.
.
.
.
12. 따라서 AudioPolicyInterface에 대한 호출 구조는 다음과 같다.
AudioPolicyManagerALSA => AudioPolicyInterface => AudioPolicyService => AudioSystem.cpp
AudioPolicyManagerALSA의 경우, ALSA 오디오에 대한 라우팅 경로를 설정하는데 사용되며,
실제 소리의 출력등은 AudioFlinger에서 수행한다.
13. AudioPolicyService와 AudioFlingerService의 연관성
다음은 HAL을 연동하는 AudioPolicyServiceManagerALSA에서, 샘플링 레이트와, 포멧, 체널, 주기 및 플래그를 사용할 때,
AudioFlinger와 연동되는 예이다.
참고소스1에서과 같이 mpClientInterface->openOutput을 사용하고 있으며,
이것은 AudioPolicyService.cpp에서 참고소스2에서와 같이 사용된다.
- 참고소스1 : hardware/alsa_sound/AudioPolicyManagerALSA.cpp // 1217라인
AudioPolicyManagerALSA::AudioPolicyManagerALSA(AudioPolicyClientInterface *clientInterface)
: mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0)
{
mpClientInterface = clientInterface;
for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
mForceUse[i] = AudioSystem::FORCE_NONE;
}
// devices available by default are speaker, ear piece and microphone
mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
AudioSystem::DEVICE_OUT_SPEAKER;
mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
mA2dpDeviceAddress = String8("");
mScoDeviceAddress = String8("");
// open hardware output
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);
if (mHardwareOutput == 0) {
LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
} else {
mOutputs.add(mHardwareOutput, outputDesc);
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
}
mA2dpOutput = 0;
mDuplicatedOutput = 0;
}
- 참고소스2 : frameworks/base/libs/audioflinger/AudioPolicyService.cpp // 435라인
# 아래 부분에서와 같이 AudioSystem::get_audio_flinger();를 할당하여 audioFlinger 측으로 Binder를 이용해
함수를 호출하게 된다.
audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
uint32_t *pFormat,
uint32_t *pChannels,
uint32_t *pLatencyMs,
AudioSystem::output_flags flags)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
LOGW("openOutput() could not get AudioFlinger");
return 0;
}
return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
}
14. 결론적으로 AudioPolicyManager에서의 ALSA H/W에 대한 접근은 AudioFlinger를 이용하게 된다.