Android Audio系列 AudioPatch的bug
来源:互联网 发布:淘宝澳洲站 编辑:程序博客网 时间:2024/05/22 16:45
最近发现一个奇怪的bug,注册OnAudioPortUpdateListener后,却没有收到onAudioPatchListUpdate callback
debug后发现android在这一块有个bug
可以看下OnAudioPortUpdateListener的注册过程
AudioManager.java: public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) { sAudioPortEventHandler.init(); sAudioPortEventHandler.registerListener(l); }
sAudioPortEventHandler是一个event handle,它接受来自native层的event,并调用OnAudioPortUpdateListener中的call,在它的Init函数中和native层联系起来
void init() { synchronized (this) { if (mHandler != null) { return; } // find the looper for our new event handler Looper looper = Looper.getMainLooper(); if (looper != null) { mHandler = new Handler(looper) { }; native_setup(new WeakReference<AudioPortEventHandler>(this)); } else { mHandler = null; } } }
native_setup会通过jni调到native层:
static voidandroid_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this){ ALOGV("eventHandlerSetup"); sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this); if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) { setJniCallback(env, thiz, callback); }}
这里象调用了AudioSystem的addAudioPortCallback, JNIAudioPortCallback在收到natvie层的callback后,向java层的AudioPortEventHandler发送消息
status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callback){ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; Mutex::Autolock _l(gLockAPS); if (gAudioPolicyServiceClient == 0) { return NO_INIT; } int ret = gAudioPolicyServiceClient->addAudioPortCallback(callback); if (ret == 1) { aps->setAudioPortCallbacksEnabled(true); } return (ret < 0) ? INVALID_OPERATION : NO_ERROR;}
每个AudioSystem都是AudioPolicyService的一个client,在get_audio_policy_service()里会生成两个全局的binder,一个BpBinder,用于AudioSystem向AudioPolicyService发生消息,一个BnBinder,用于AudioPolicyService向AudioSystem发生消息,BnBinder就是AudioPolicyServiceClient. 然后把callback加到AudioPolicyServiceClient中去.
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback( const sp<AudioPortCallback>& callback){ Mutex::Autolock _l(mLock); for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) { if (mAudioPortCallbacks[i] == callback) { return -1; } } mAudioPortCallbacks.add(callback); return mAudioPortCallbacks.size();}
bug马上要出现了,接下来看看 get_audio_policy_service()
// establish binder interface to AudioPolicy serviceconst sp<IAudioPolicyService> AudioSystem::get_audio_policy_service(){ sp<IAudioPolicyService> ap; sp<AudioPolicyServiceClient> apc; { Mutex::Autolock _l(gLockAPS); if (gAudioPolicyService == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { binder = sm->getService(String16("media.audio_policy")); if (binder != 0) break; ALOGW("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); LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0); apc = gAudioPolicyServiceClient; } ap = gAudioPolicyService; } if (apc != 0) { ap->registerClient(apc); } return ap;}
按照前面的解释,很好理解,为当前进程生成全局的BpBInder( gAudioPolicyService) 和BnBinder(gAudioPolicyServiceClient), 然后调用gAudioPolicyService->registerClient
// A notification client is always registered by AudioSystem when the client process// connects to AudioPolicyService.void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& client){ Mutex::Autolock _l(mNotificationClientsLock); uid_t uid = IPCThreadState::self()->getCallingUid(); if (mNotificationClients.indexOfKey(uid) < 0) { sp<NotificationClient> notificationClient = new NotificationClient(this, client, uid); ALOGV("registerClient() client %p, uid %d", client.get(), uid); mNotificationClients.add(uid, notificationClient); sp<IBinder> binder = IInterface::asBinder(client); binder->linkToDeath(notificationClient); }}
问题就出在这里了,这里通过检查uid来查看client是否已经注册了,如果几个进程共享uid的话,这里的client就没有加mNotificationClients里去,也就不会收到callback,
可以看一下,这IAudioPolicyServiceClient目前只有三个callback,几乎也没有app使用,所以还没有什么问题.如果用进程号的话,应该能解决这个问题.
class IAudioPolicyServiceClient : public IInterface{public: DECLARE_META_INTERFACE(AudioPolicyServiceClient); // Notifies a change of audio port configuration. virtual void onAudioPortListUpdate() = 0; // Notifies a change of audio patch configuration. virtual void onAudioPatchListUpdate() = 0; // Notifies a change in the mixing state of a specific mix in a dynamic audio policy virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;};
至于callack的过程,就是一个相反的过程,event的源头都是AudioPolicyManager中的openOutput, closeOutput, startOutput, openInput, closeInput, startInput
下一遍打算详细介绍下audioPatch...
- Android Audio系列 AudioPatch的bug
- Android 5.0中AudioPatch概念简单探索
- ANDROID Porting系列十、Audio
- android 系统级 bug audio latency
- Android的Audio系统
- Android的Audio系统
- Android的Audio系统
- Android的Audio 系统
- android的audio系统
- Android的Audio系统
- Android的Audio系统
- Android的Audio系统
- Android的Audio系统
- Android的Audio系统
- Android的Audio系统
- Android的Audio子系统
- Android Audio 的播放
- Android Audio 3: Audio的实现
- 从mongo得到数据分页
- JQueryUI Chosen插件
- 四元数、欧拉角及方向余弦矩阵的相互转换公式
- ApplicationContextAware 获取Spring 上下文
- RS232&TTL
- Android Audio系列 AudioPatch的bug
- CSUOJ 1256 天朝的单行道(最短路)
- angularjs·的使用:指令(3)
- 【e医疗原创】如何做好以数字签名为基础的医疗信息安全性管理
- web前端入坑:web前端到底怎么学?干货资料!
- Grid表中 组合框显示 displayField
- c语言,fclose()带来的内存错误(求解)
- java exception 和 runtimeException的区别
- EL表达式