1 /*
2  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.webrtc.voiceengine;
12 
13 import android.content.Context;
14 import android.content.pm.PackageManager;
15 import android.os.Build;
16 import android.os.Process;
17 import java.lang.Thread;
18 import java.util.Arrays;
19 import java.util.List;
20 import org.webrtc.Logging;
21 
22 public final class WebRtcAudioUtils {
23   private static final String TAG = "WebRtcAudioUtils";
24 
25   // List of devices where we have seen issues (e.g. bad audio quality) using
26   // the low latency output mode in combination with OpenSL ES.
27   // The device name is given by Build.MODEL.
28   private static final String[] BLACKLISTED_OPEN_SL_ES_MODELS = new String[] {
29       // It is recommended to maintain a list of blacklisted models outside
30       // this package and instead call
31       // WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true)
32       // from the client for devices where OpenSL ES shall be disabled.
33   };
34 
35   // List of devices where it has been verified that the built-in effect
36   // bad and where it makes sense to avoid using it and instead rely on the
37   // native WebRTC version instead. The device name is given by Build.MODEL.
38   private static final String[] BLACKLISTED_AEC_MODELS = new String[] {
39       // It is recommended to maintain a list of blacklisted models outside
40       // this package and instead call setWebRtcBasedAcousticEchoCanceler(true)
41       // from the client for devices where the built-in AEC shall be disabled.
42   };
43   private static final String[] BLACKLISTED_NS_MODELS = new String[] {
44     // It is recommended to maintain a list of blacklisted models outside
45     // this package and instead call setWebRtcBasedNoiseSuppressor(true)
46     // from the client for devices where the built-in NS shall be disabled.
47   };
48 
49   // Use 16kHz as the default sample rate. A higher sample rate might prevent
50   // us from supporting communication mode on some older (e.g. ICS) devices.
51   private static final int DEFAULT_SAMPLE_RATE_HZ = 16000;
52   private static int defaultSampleRateHz = DEFAULT_SAMPLE_RATE_HZ;
53   // Set to true if setDefaultSampleRateHz() has been called.
54   private static boolean isDefaultSampleRateOverridden = false;
55 
56   // By default, utilize hardware based audio effects for AEC and NS when
57   // available.
58   private static boolean useWebRtcBasedAcousticEchoCanceler = false;
59   private static boolean useWebRtcBasedNoiseSuppressor = false;
60 
61   // Call these methods if any hardware based effect shall be replaced by a
62   // software based version provided by the WebRTC stack instead.
63   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
64   @SuppressWarnings("NoSynchronizedMethodCheck")
setWebRtcBasedAcousticEchoCanceler(boolean enable)65   public static synchronized void setWebRtcBasedAcousticEchoCanceler(boolean enable) {
66     useWebRtcBasedAcousticEchoCanceler = enable;
67   }
68 
69     // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
70   @SuppressWarnings("NoSynchronizedMethodCheck")
setWebRtcBasedNoiseSuppressor(boolean enable)71   public static synchronized void setWebRtcBasedNoiseSuppressor(boolean enable) {
72     useWebRtcBasedNoiseSuppressor = enable;
73   }
74 
75   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
76   @SuppressWarnings("NoSynchronizedMethodCheck")
setWebRtcBasedAutomaticGainControl(boolean enable)77   public static synchronized void setWebRtcBasedAutomaticGainControl(boolean enable) {
78     // TODO(henrika): deprecated; remove when no longer used by any client.
79     Logging.w(TAG, "setWebRtcBasedAutomaticGainControl() is deprecated");
80   }
81 
82   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
83   @SuppressWarnings("NoSynchronizedMethodCheck")
useWebRtcBasedAcousticEchoCanceler()84   public static synchronized boolean useWebRtcBasedAcousticEchoCanceler() {
85     if (useWebRtcBasedAcousticEchoCanceler) {
86       Logging.w(TAG, "Overriding default behavior; now using WebRTC AEC!");
87     }
88     return useWebRtcBasedAcousticEchoCanceler;
89   }
90 
91   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
92   @SuppressWarnings("NoSynchronizedMethodCheck")
useWebRtcBasedNoiseSuppressor()93   public static synchronized boolean useWebRtcBasedNoiseSuppressor() {
94     if (useWebRtcBasedNoiseSuppressor) {
95       Logging.w(TAG, "Overriding default behavior; now using WebRTC NS!");
96     }
97     return useWebRtcBasedNoiseSuppressor;
98   }
99 
100   // TODO(henrika): deprecated; remove when no longer used by any client.
101   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
102   @SuppressWarnings("NoSynchronizedMethodCheck")
useWebRtcBasedAutomaticGainControl()103   public static synchronized boolean useWebRtcBasedAutomaticGainControl() {
104     // Always return true here to avoid trying to use any built-in AGC.
105     return true;
106   }
107 
108   // Returns true if the device supports an audio effect (AEC or NS).
109   // Four conditions must be fulfilled if functions are to return true:
110   // 1) the platform must support the built-in (HW) effect,
111   // 2) explicit use (override) of a WebRTC based version must not be set,
112   // 3) the device must not be blacklisted for use of the effect, and
113   // 4) the UUID of the effect must be approved (some UUIDs can be excluded).
isAcousticEchoCancelerSupported()114   public static boolean isAcousticEchoCancelerSupported() {
115     return WebRtcAudioEffects.canUseAcousticEchoCanceler();
116   }
isNoiseSuppressorSupported()117   public static boolean isNoiseSuppressorSupported() {
118     return WebRtcAudioEffects.canUseNoiseSuppressor();
119   }
120   // TODO(henrika): deprecated; remove when no longer used by any client.
isAutomaticGainControlSupported()121   public static boolean isAutomaticGainControlSupported() {
122     // Always return false here to avoid trying to use any built-in AGC.
123     return false;
124   }
125 
126   // Call this method if the default handling of querying the native sample
127   // rate shall be overridden. Can be useful on some devices where the
128   // available Android APIs are known to return invalid results.
129   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
130   @SuppressWarnings("NoSynchronizedMethodCheck")
setDefaultSampleRateHz(int sampleRateHz)131   public static synchronized void setDefaultSampleRateHz(int sampleRateHz) {
132     isDefaultSampleRateOverridden = true;
133     defaultSampleRateHz = sampleRateHz;
134   }
135 
136   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
137   @SuppressWarnings("NoSynchronizedMethodCheck")
isDefaultSampleRateOverridden()138   public static synchronized boolean isDefaultSampleRateOverridden() {
139     return isDefaultSampleRateOverridden;
140   }
141 
142   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
143   @SuppressWarnings("NoSynchronizedMethodCheck")
getDefaultSampleRateHz()144   public static synchronized int getDefaultSampleRateHz() {
145     return defaultSampleRateHz;
146   }
147 
getBlackListedModelsForAecUsage()148   public static List<String> getBlackListedModelsForAecUsage() {
149     return Arrays.asList(WebRtcAudioUtils.BLACKLISTED_AEC_MODELS);
150   }
151 
getBlackListedModelsForNsUsage()152   public static List<String> getBlackListedModelsForNsUsage() {
153     return Arrays.asList(WebRtcAudioUtils.BLACKLISTED_NS_MODELS);
154   }
155 
runningOnJellyBeanMR1OrHigher()156   public static boolean runningOnJellyBeanMR1OrHigher() {
157     // November 2012: Android 4.2. API Level 17.
158     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
159   }
160 
runningOnJellyBeanMR2OrHigher()161   public static boolean runningOnJellyBeanMR2OrHigher() {
162     // July 24, 2013: Android 4.3. API Level 18.
163     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
164   }
165 
runningOnLollipopOrHigher()166   public static boolean runningOnLollipopOrHigher() {
167     // API Level 21.
168     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
169   }
170 
runningOnMarshmallowOrHigher()171   public static boolean runningOnMarshmallowOrHigher() {
172     // API Level 23.
173     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
174   }
175 
runningOnNougatOrHigher()176   public static boolean runningOnNougatOrHigher() {
177     // API Level 24.
178     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
179   }
180 
181   // Helper method for building a string of thread information.
getThreadInfo()182   public static String getThreadInfo() {
183     return "@[name=" + Thread.currentThread().getName() + ", id=" + Thread.currentThread().getId()
184         + "]";
185   }
186 
187   // Returns true if we're running on emulator.
runningOnEmulator()188   public static boolean runningOnEmulator() {
189     return Build.HARDWARE.equals("goldfish") && Build.BRAND.startsWith("generic_");
190   }
191 
192   // Returns true if the device is blacklisted for OpenSL ES usage.
deviceIsBlacklistedForOpenSLESUsage()193   public static boolean deviceIsBlacklistedForOpenSLESUsage() {
194     List<String> blackListedModels = Arrays.asList(BLACKLISTED_OPEN_SL_ES_MODELS);
195     return blackListedModels.contains(Build.MODEL);
196   }
197 
198   // Information about the current build, taken from system properties.
logDeviceInfo(String tag)199   public static void logDeviceInfo(String tag) {
200     Logging.d(tag, "Android SDK: " + Build.VERSION.SDK_INT + ", "
201             + "Release: " + Build.VERSION.RELEASE + ", "
202             + "Brand: " + Build.BRAND + ", "
203             + "Device: " + Build.DEVICE + ", "
204             + "Id: " + Build.ID + ", "
205             + "Hardware: " + Build.HARDWARE + ", "
206             + "Manufacturer: " + Build.MANUFACTURER + ", "
207             + "Model: " + Build.MODEL + ", "
208             + "Product: " + Build.PRODUCT);
209   }
210 }
211