1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.os.Build; 21 import android.os.Handler; 22 import android.os.HandlerThread; 23 import android.os.Message; 24 25 import com.android.internal.annotations.GuardedBy; 26 27 import java.lang.ref.WeakReference; 28 import java.util.ArrayList; 29 30 /** 31 * The AudioPortEventHandler handles AudioManager.OnAudioPortUpdateListener callbacks 32 * posted from JNI 33 * @hide 34 */ 35 36 class AudioPortEventHandler { 37 private Handler mHandler; 38 private HandlerThread mHandlerThread; 39 private final Object mLock = new Object(); 40 41 @GuardedBy("mLock") 42 private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners = 43 new ArrayList<AudioManager.OnAudioPortUpdateListener>(); 44 45 private static final String TAG = "AudioPortEventHandler"; 46 47 private static final int AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1; 48 private static final int AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2; 49 private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3; 50 private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4; 51 52 private static final long RESCHEDULE_MESSAGE_DELAY_MS = 100; 53 54 /** 55 * Accessed by native methods: JNI Callback context. 56 */ 57 @SuppressWarnings("unused") 58 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 59 private long mJniCallback; 60 init()61 void init() { 62 synchronized (mLock) { 63 if (mHandler != null) { 64 return; 65 } 66 // create a new thread for our new event handler 67 mHandlerThread = new HandlerThread(TAG); 68 mHandlerThread.start(); 69 70 if (mHandlerThread.getLooper() != null) { 71 mHandler = new Handler(mHandlerThread.getLooper()) { 72 @Override 73 public void handleMessage(Message msg) { 74 ArrayList<AudioManager.OnAudioPortUpdateListener> listeners; 75 synchronized (mLock) { 76 if (msg.what == AUDIOPORT_EVENT_NEW_LISTENER) { 77 listeners = new ArrayList<AudioManager.OnAudioPortUpdateListener>(); 78 if (mListeners.contains(msg.obj)) { 79 listeners.add((AudioManager.OnAudioPortUpdateListener)msg.obj); 80 } 81 } else { 82 listeners = (ArrayList<AudioManager.OnAudioPortUpdateListener>) 83 mListeners.clone(); 84 } 85 } 86 // reset audio port cache if the event corresponds to a change coming 87 // from audio policy service or if mediaserver process died. 88 if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED || 89 msg.what == AUDIOPORT_EVENT_PATCH_LIST_UPDATED || 90 msg.what == AUDIOPORT_EVENT_SERVICE_DIED) { 91 AudioManager.resetAudioPortGeneration(); 92 } 93 94 if (listeners.isEmpty()) { 95 return; 96 } 97 98 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 99 ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>(); 100 if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) { 101 int status = AudioManager.updateAudioPortCache(ports, patches, null); 102 if (status != AudioManager.SUCCESS) { 103 // Since audio ports and audio patches are not null, the return 104 // value could be ERROR due to inconsistency between port generation 105 // and patch generation. In this case, we need to reschedule the 106 // message to make sure the native callback is done. 107 sendMessageDelayed(obtainMessage(msg.what, msg.obj), 108 RESCHEDULE_MESSAGE_DELAY_MS); 109 return; 110 } 111 } 112 113 switch (msg.what) { 114 case AUDIOPORT_EVENT_NEW_LISTENER: 115 case AUDIOPORT_EVENT_PORT_LIST_UPDATED: 116 AudioPort[] portList = ports.toArray(new AudioPort[0]); 117 for (int i = 0; i < listeners.size(); i++) { 118 listeners.get(i).onAudioPortListUpdate(portList); 119 } 120 if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED) { 121 break; 122 } 123 // FALL THROUGH 124 125 case AUDIOPORT_EVENT_PATCH_LIST_UPDATED: 126 AudioPatch[] patchList = patches.toArray(new AudioPatch[0]); 127 for (int i = 0; i < listeners.size(); i++) { 128 listeners.get(i).onAudioPatchListUpdate(patchList); 129 } 130 break; 131 132 case AUDIOPORT_EVENT_SERVICE_DIED: 133 for (int i = 0; i < listeners.size(); i++) { 134 listeners.get(i).onServiceDied(); 135 } 136 break; 137 138 default: 139 break; 140 } 141 } 142 }; 143 native_setup(new WeakReference<AudioPortEventHandler>(this)); 144 } else { 145 mHandler = null; 146 } 147 } 148 } 149 native_setup(Object module_this)150 private native void native_setup(Object module_this); 151 152 @Override finalize()153 protected void finalize() { 154 native_finalize(); 155 if (mHandlerThread.isAlive()) { 156 mHandlerThread.quit(); 157 } 158 } native_finalize()159 private native void native_finalize(); 160 registerListener(AudioManager.OnAudioPortUpdateListener l)161 void registerListener(AudioManager.OnAudioPortUpdateListener l) { 162 synchronized (mLock) { 163 mListeners.add(l); 164 } 165 if (mHandler != null) { 166 Message m = mHandler.obtainMessage(AUDIOPORT_EVENT_NEW_LISTENER, 0, 0, l); 167 mHandler.sendMessage(m); 168 } 169 } 170 unregisterListener(AudioManager.OnAudioPortUpdateListener l)171 void unregisterListener(AudioManager.OnAudioPortUpdateListener l) { 172 synchronized (mLock) { 173 mListeners.remove(l); 174 } 175 } 176 handler()177 Handler handler() { 178 return mHandler; 179 } 180 181 @SuppressWarnings("unused") 182 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) postEventFromNative(Object module_ref, int what, int arg1, int arg2, Object obj)183 private static void postEventFromNative(Object module_ref, 184 int what, int arg1, int arg2, Object obj) { 185 AudioPortEventHandler eventHandler = 186 (AudioPortEventHandler)((WeakReference)module_ref).get(); 187 if (eventHandler == null) { 188 return; 189 } 190 191 if (eventHandler != null) { 192 Handler handler = eventHandler.handler(); 193 if (handler != null) { 194 Message m = handler.obtainMessage(what, arg1, arg2, obj); 195 if (what != AUDIOPORT_EVENT_NEW_LISTENER) { 196 // Except AUDIOPORT_EVENT_NEW_LISTENER, we can only respect the last message. 197 handler.removeMessages(what); 198 } 199 handler.sendMessage(m); 200 } 201 } 202 } 203 204 } 205