Maintain a cache of previously attached audio ports used to create lists of added and removed devices following a port list update callback. Change-Id: Iad1c95b85c8ae9bdbed79eb0cdc46aeedeafccea
177 lines
6.5 KiB
Java
177 lines
6.5 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.media;
|
|
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.os.Message;
|
|
import java.util.ArrayList;
|
|
import java.lang.ref.WeakReference;
|
|
|
|
/**
|
|
* The AudioPortEventHandler handles AudioManager.OnAudioPortUpdateListener callbacks
|
|
* posted from JNI
|
|
* @hide
|
|
*/
|
|
|
|
class AudioPortEventHandler {
|
|
private Handler mHandler;
|
|
private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners =
|
|
new ArrayList<AudioManager.OnAudioPortUpdateListener>();
|
|
|
|
private static final String TAG = "AudioPortEventHandler";
|
|
|
|
private static final int AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1;
|
|
private static final int AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2;
|
|
private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
|
|
private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
|
|
|
|
/**
|
|
* Accessed by native methods: JNI Callback context.
|
|
*/
|
|
@SuppressWarnings("unused")
|
|
private long mJniCallback;
|
|
|
|
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) {
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
ArrayList<AudioManager.OnAudioPortUpdateListener> listeners;
|
|
synchronized (this) {
|
|
if (msg.what == AUDIOPORT_EVENT_NEW_LISTENER) {
|
|
listeners = new ArrayList<AudioManager.OnAudioPortUpdateListener>();
|
|
if (mListeners.contains(msg.obj)) {
|
|
listeners.add((AudioManager.OnAudioPortUpdateListener)msg.obj);
|
|
}
|
|
} else {
|
|
listeners = mListeners;
|
|
}
|
|
}
|
|
// reset audio port cache if the event corresponds to a change coming
|
|
// from audio policy service or if mediaserver process died.
|
|
if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED ||
|
|
msg.what == AUDIOPORT_EVENT_PATCH_LIST_UPDATED ||
|
|
msg.what == AUDIOPORT_EVENT_SERVICE_DIED) {
|
|
AudioManager.resetAudioPortGeneration();
|
|
}
|
|
|
|
if (listeners.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
|
|
ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
|
|
if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
|
|
int status = AudioManager.updateAudioPortCache(ports, patches, null);
|
|
if (status != AudioManager.SUCCESS) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (msg.what) {
|
|
case AUDIOPORT_EVENT_NEW_LISTENER:
|
|
case AUDIOPORT_EVENT_PORT_LIST_UPDATED:
|
|
AudioPort[] portList = ports.toArray(new AudioPort[0]);
|
|
for (int i = 0; i < listeners.size(); i++) {
|
|
listeners.get(i).onAudioPortListUpdate(portList);
|
|
}
|
|
if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED) {
|
|
break;
|
|
}
|
|
// FALL THROUGH
|
|
|
|
case AUDIOPORT_EVENT_PATCH_LIST_UPDATED:
|
|
AudioPatch[] patchList = patches.toArray(new AudioPatch[0]);
|
|
for (int i = 0; i < listeners.size(); i++) {
|
|
listeners.get(i).onAudioPatchListUpdate(patchList);
|
|
}
|
|
break;
|
|
|
|
case AUDIOPORT_EVENT_SERVICE_DIED:
|
|
for (int i = 0; i < listeners.size(); i++) {
|
|
listeners.get(i).onServiceDied();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
native_setup(new WeakReference<AudioPortEventHandler>(this));
|
|
} else {
|
|
mHandler = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private native void native_setup(Object module_this);
|
|
|
|
@Override
|
|
protected void finalize() {
|
|
native_finalize();
|
|
}
|
|
private native void native_finalize();
|
|
|
|
void registerListener(AudioManager.OnAudioPortUpdateListener l) {
|
|
synchronized (this) {
|
|
mListeners.add(l);
|
|
}
|
|
if (mHandler != null) {
|
|
Message m = mHandler.obtainMessage(AUDIOPORT_EVENT_NEW_LISTENER, 0, 0, l);
|
|
mHandler.sendMessage(m);
|
|
}
|
|
}
|
|
|
|
void unregisterListener(AudioManager.OnAudioPortUpdateListener l) {
|
|
synchronized (this) {
|
|
mListeners.remove(l);
|
|
}
|
|
}
|
|
|
|
Handler handler() {
|
|
return mHandler;
|
|
}
|
|
|
|
@SuppressWarnings("unused")
|
|
private static void postEventFromNative(Object module_ref,
|
|
int what, int arg1, int arg2, Object obj) {
|
|
AudioPortEventHandler eventHandler =
|
|
(AudioPortEventHandler)((WeakReference)module_ref).get();
|
|
if (eventHandler == null) {
|
|
return;
|
|
}
|
|
|
|
if (eventHandler != null) {
|
|
Handler handler = eventHandler.handler();
|
|
if (handler != null) {
|
|
Message m = handler.obtainMessage(what, arg1, arg2, obj);
|
|
handler.sendMessage(m);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|