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.media.audiofx.AcousticEchoCanceler;
16 import android.media.audiofx.AudioEffect;
17 import android.media.audiofx.AudioEffect.Descriptor;
18 import android.media.AudioManager;
19 import android.os.Build;
20 import android.os.Process;
21 
22 import org.webrtc.Logging;
23 
24 import java.lang.Thread;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28 
29 public final class WebRtcAudioUtils {
30   private static final String TAG = "WebRtcAudioUtils";
31 
32   // List of devices where we have seen issues (e.g. bad audio quality) using
33   // the low latency output mode in combination with OpenSL ES.
34   // The device name is given by Build.MODEL.
35   private static final String[] BLACKLISTED_OPEN_SL_ES_MODELS = new String[] {
36     // This list is currently empty ;-)
37   };
38 
39   // List of devices where it has been verified that the built-in effect
40   // bad and where it makes sense to avoid using it and instead rely on the
41   // native WebRTC version instead. The device name is given by Build.MODEL.
42   private static final String[] BLACKLISTED_AEC_MODELS = new String[] {
43       "Nexus 5",
44       "D6503",      // Sony Xperia Z2 D6503
45       "ONE A2005",  // OnePlus 2
46   };
47   private static final String[] BLACKLISTED_AGC_MODELS = new String[] {
48       "Nexus 10",
49       "Nexus 9",
50   };
51   private static final String[] BLACKLISTED_NS_MODELS = new String[] {
52       "Nexus 10",
53       "Nexus 9",
54       "Nexus 5",
55       "ONE A2005",  // OnePlus 2
56   };
57 
58   // Use 16kHz as the default sample rate. A higher sample rate might prevent
59   // us from supporting communication mode on some older (e.g. ICS) devices.
60   private static final int DEFAULT_SAMPLE_RATE_HZ = 16000;
61   private static int defaultSampleRateHz = DEFAULT_SAMPLE_RATE_HZ;
62   // Set to true if setDefaultSampleRateHz() has been called.
63   private static boolean isDefaultSampleRateOverridden = false;
64 
65   // By default, utilize hardware based audio effects when available.
66   private static boolean useWebRtcBasedAcousticEchoCanceler = false;
67   private static boolean useWebRtcBasedAutomaticGainControl = false;
68   private static boolean useWebRtcBasedNoiseSuppressor = false;
69 
70   // Call these methods if any hardware based effect shall be replaced by a
71   // software based version provided by the WebRTC stack instead.
setWebRtcBasedAcousticEchoCanceler( boolean enable)72   public static synchronized void setWebRtcBasedAcousticEchoCanceler(
73       boolean enable) {
74     useWebRtcBasedAcousticEchoCanceler = enable;
75   }
setWebRtcBasedAutomaticGainControl( boolean enable)76   public static synchronized void setWebRtcBasedAutomaticGainControl(
77       boolean enable) {
78     useWebRtcBasedAutomaticGainControl = enable;
79   }
setWebRtcBasedNoiseSuppressor( boolean enable)80   public static synchronized void setWebRtcBasedNoiseSuppressor(
81       boolean enable) {
82     useWebRtcBasedNoiseSuppressor = enable;
83   }
84 
useWebRtcBasedAcousticEchoCanceler()85   public static synchronized boolean useWebRtcBasedAcousticEchoCanceler() {
86     if (useWebRtcBasedAcousticEchoCanceler) {
87       Logging.w(TAG, "Overriding default behavior; now using WebRTC AEC!");
88     }
89     return useWebRtcBasedAcousticEchoCanceler;
90   }
useWebRtcBasedAutomaticGainControl()91   public static synchronized boolean useWebRtcBasedAutomaticGainControl() {
92     if (useWebRtcBasedAutomaticGainControl) {
93       Logging.w(TAG, "Overriding default behavior; now using WebRTC AGC!");
94     }
95     return useWebRtcBasedAutomaticGainControl;
96   }
useWebRtcBasedNoiseSuppressor()97   public static synchronized boolean useWebRtcBasedNoiseSuppressor() {
98     if (useWebRtcBasedNoiseSuppressor) {
99       Logging.w(TAG, "Overriding default behavior; now using WebRTC NS!");
100     }
101     return useWebRtcBasedNoiseSuppressor;
102   }
103 
104   // Call this method if the default handling of querying the native sample
105   // rate shall be overridden. Can be useful on some devices where the
106   // available Android APIs are known to return invalid results.
setDefaultSampleRateHz(int sampleRateHz)107   public static synchronized void setDefaultSampleRateHz(int sampleRateHz) {
108     isDefaultSampleRateOverridden = true;
109     defaultSampleRateHz = sampleRateHz;
110   }
111 
isDefaultSampleRateOverridden()112   public static synchronized boolean isDefaultSampleRateOverridden() {
113     return isDefaultSampleRateOverridden;
114   }
115 
getDefaultSampleRateHz()116   public static synchronized int getDefaultSampleRateHz() {
117     return defaultSampleRateHz;
118   }
119 
getBlackListedModelsForAecUsage()120   public static List<String> getBlackListedModelsForAecUsage() {
121     return Arrays.asList(WebRtcAudioUtils.BLACKLISTED_AEC_MODELS);
122   }
123 
getBlackListedModelsForAgcUsage()124   public static List<String> getBlackListedModelsForAgcUsage() {
125     return Arrays.asList(WebRtcAudioUtils.BLACKLISTED_AGC_MODELS);
126   }
127 
getBlackListedModelsForNsUsage()128   public static List<String> getBlackListedModelsForNsUsage() {
129     return Arrays.asList(WebRtcAudioUtils.BLACKLISTED_NS_MODELS);
130   }
131 
runningOnGingerBreadOrHigher()132   public static boolean runningOnGingerBreadOrHigher() {
133     // November 2010: Android 2.3, API Level 9.
134     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
135   }
136 
runningOnJellyBeanOrHigher()137   public static boolean runningOnJellyBeanOrHigher() {
138     // June 2012: Android 4.1. API Level 16.
139     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
140   }
141 
runningOnJellyBeanMR1OrHigher()142   public static boolean runningOnJellyBeanMR1OrHigher() {
143     // November 2012: Android 4.2. API Level 17.
144     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
145   }
146 
runningOnJellyBeanMR2OrHigher()147   public static boolean runningOnJellyBeanMR2OrHigher() {
148     // July 24, 2013: Android 4.3. API Level 18.
149     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
150   }
151 
runningOnLollipopOrHigher()152   public static boolean runningOnLollipopOrHigher() {
153     // API Level 21.
154     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
155   }
156 
157   // TODO(phoglund): enable when all downstream users use M.
158   // public static boolean runningOnMOrHigher() {
159     // API Level 23.
160     // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
161   //}
162 
163   // Helper method for building a string of thread information.
getThreadInfo()164   public static String getThreadInfo() {
165     return "@[name=" + Thread.currentThread().getName()
166         + ", id=" + Thread.currentThread().getId() + "]";
167   }
168 
169   // Returns true if we're running on emulator.
runningOnEmulator()170   public static boolean runningOnEmulator() {
171     return Build.HARDWARE.equals("goldfish") &&
172         Build.BRAND.startsWith("generic_");
173   }
174 
175   // Returns true if the device is blacklisted for OpenSL ES usage.
deviceIsBlacklistedForOpenSLESUsage()176   public static boolean deviceIsBlacklistedForOpenSLESUsage() {
177     List<String> blackListedModels =
178         Arrays.asList(BLACKLISTED_OPEN_SL_ES_MODELS);
179     return blackListedModels.contains(Build.MODEL);
180   }
181 
182   // Information about the current build, taken from system properties.
logDeviceInfo(String tag)183   public static void logDeviceInfo(String tag) {
184     Logging.d(tag, "Android SDK: " + Build.VERSION.SDK_INT + ", "
185         + "Release: " + Build.VERSION.RELEASE + ", "
186         + "Brand: " + Build.BRAND + ", "
187         + "Device: " + Build.DEVICE + ", "
188         + "Id: " + Build.ID + ", "
189         + "Hardware: " + Build.HARDWARE + ", "
190         + "Manufacturer: " + Build.MANUFACTURER + ", "
191         + "Model: " + Build.MODEL + ", "
192         + "Product: " + Build.PRODUCT);
193   }
194 
195   // Checks if the process has as specified permission or not.
hasPermission(Context context, String permission)196   public static boolean hasPermission(Context context, String permission) {
197     return context.checkPermission(
198         permission,
199         Process.myPid(),
200         Process.myUid()) == PackageManager.PERMISSION_GRANTED;
201     }
202 }
203