1 /*
2  * Copyright 2023 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 androidx.camera.core.impl.utils.executor;
18 
19 import android.os.Process;
20 
21 import androidx.camera.core.CameraXThreads;
22 
23 import org.jspecify.annotations.NonNull;
24 
25 import java.util.Locale;
26 import java.util.concurrent.Executor;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.atomic.AtomicInteger;
31 
32 /**
33  * A singleton executor which is suitable for audio I/O tasks.
34  */
35 public class AudioExecutor implements Executor {
36     private static volatile Executor sExecutor;
37 
38     private final ExecutorService mAudioService =
39             Executors.newFixedThreadPool(
40                     2,
41                     new ThreadFactory() {
42                         private static final String THREAD_NAME_STEM =
43                                 CameraXThreads.TAG + "camerax_audio_%d";
44 
45                         private final AtomicInteger mThreadId = new AtomicInteger(0);
46 
47                         @Override
48                         public Thread newThread(final Runnable r) {
49                             Runnable wrapper = () -> {
50                                 Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
51                                 r.run();
52                             };
53                             Thread t = new Thread(wrapper);
54                             t.setName(
55                                     String.format(
56                                             Locale.US,
57                                             THREAD_NAME_STEM,
58                                             mThreadId.getAndIncrement()));
59                             return t;
60                         }
61                     });
62 
getInstance()63     static Executor getInstance() {
64         if (sExecutor != null) {
65             return sExecutor;
66         }
67         synchronized (AudioExecutor.class) {
68             if (sExecutor == null) {
69                 sExecutor = new AudioExecutor();
70             }
71         }
72 
73         return sExecutor;
74     }
75 
76     @Override
execute(@onNull Runnable command)77     public void execute(@NonNull Runnable command) {
78         mAudioService.execute(command);
79     }
80 }
81