• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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