1 /*
2  * Copyright (C) 2020 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 com.android.effectstest;
18 
19 import android.os.Handler;
20 import android.os.Looper;
21 import android.util.Log;
22 
23 import com.android.internal.annotations.GuardedBy;
24 
25 class VisualizerInstanceMT implements VisualizerInstance {
26 
27     private static final String TAG = "VisualizerInstanceMT";
28 
29     private final Object mLock = new Object();
30     private final int mThreadCount;
31     @GuardedBy("mLock")
32     private Handler mVisualizerHandler;
33     @GuardedBy("mLock")
34     private VisualizerInstanceSync mVisualizer;
35 
VisualizerInstanceMT(int session, Handler uiHandler, int extraThreadCount)36     VisualizerInstanceMT(int session, Handler uiHandler, int extraThreadCount) {
37         Log.d(TAG, "Multi-threaded constructor");
38         mThreadCount = 1 + extraThreadCount;
39         Thread t = new Thread() {
40             @Override public void run() {
41                 Looper.prepare();
42                 VisualizerInstanceSync v = new VisualizerInstanceSync(session, uiHandler);
43                 synchronized (mLock) {
44                     mVisualizerHandler = new Handler();
45                     mVisualizer = v;
46                 }
47                 Looper.loop();
48             }
49         };
50         t.start();
51     }
52 
getVisualizer()53     private VisualizerInstance getVisualizer() {
54         synchronized (mLock) {
55             return mVisualizer != null ? new VisualizerInstanceSync(mVisualizer) : null;
56         }
57     }
58 
59     private interface VisualizerOperation {
run(VisualizerInstance v)60         void run(VisualizerInstance v);
61     }
62 
runOperationMt(VisualizerOperation op)63     private void runOperationMt(VisualizerOperation op) {
64         final VisualizerInstance v = getVisualizer();
65         if (v == null) return;
66         for (int i = 0; i < mThreadCount; ++i) {
67             Thread t = new Thread() {
68                 @Override
69                 public void run() {
70                     op.run(v);
71                 }
72             };
73             t.start();
74         }
75     }
76 
77     @Override
enableDataCaptureListener(boolean enable)78     public void enableDataCaptureListener(boolean enable) {
79         runOperationMt(v -> v.enableDataCaptureListener(enable));
80     }
81 
82     @Override
getEnabled()83     public boolean getEnabled() {
84         final VisualizerInstance v = getVisualizer();
85         return v != null ? v.getEnabled() : false;
86     }
87 
88     @Override
release()89     public void release() {
90         runOperationMt(v -> v.release());
91         synchronized (mLock) {
92             if (mVisualizerHandler == null) return;
93             mVisualizerHandler.post(() -> {
94                 synchronized (mLock) {
95                     mVisualizerHandler = null;
96                     mVisualizer = null;
97                     Looper.myLooper().quitSafely();
98                 }
99                 Log.d(TAG, "Exiting looper");
100             });
101         }
102     }
103 
104     @Override
setEnabled(boolean enabled)105     public void setEnabled(boolean enabled) {
106         runOperationMt(v -> v.setEnabled(enabled));
107     }
108 
109     @Override
startStopCapture(boolean start)110     public void startStopCapture(boolean start) {
111         runOperationMt(v -> v.startStopCapture(start));
112     }
113 }
114