mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
Update and open WebRtcAudioUtils
Opening the visibility of a few methods from this utils class to allow it to be used by other implementations of `AudioDeviceModule`. Also updating a few methods, like adding new audio device types from recent Android SDKs, and updating the definition of an emulator. Bug: b/287409066 Change-Id: I1473fa0342252347ce92ee2319380ebb14e9885b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/339905 Commit-Queue: Zoé Lepaul <xalep@webrtc.org> Reviewed-by: Ranveer Aggarwal <ranvr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41778}
This commit is contained in:
parent
56d3cf0c6d
commit
dc6a001b6b
1 changed files with 109 additions and 90 deletions
|
@ -23,106 +23,124 @@ import android.media.AudioFormat;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaRecorder.AudioSource;
|
import android.media.MediaRecorder.AudioSource;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import java.lang.Thread;
|
import android.os.Build.VERSION_CODES;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.webrtc.Logging;
|
import org.webrtc.Logging;
|
||||||
|
|
||||||
final class WebRtcAudioUtils {
|
/** Utilities for implementations of {@code AudioDeviceModule}, mostly for logging. */
|
||||||
|
public final class WebRtcAudioUtils {
|
||||||
private static final String TAG = "WebRtcAudioUtilsExternal";
|
private static final String TAG = "WebRtcAudioUtilsExternal";
|
||||||
|
|
||||||
// Helper method for building a string of thread information.
|
/** Helper method for building a string of thread information. */
|
||||||
public static String getThreadInfo() {
|
public static String getThreadInfo() {
|
||||||
return "@[name=" + Thread.currentThread().getName() + ", id=" + Thread.currentThread().getId()
|
Thread current = Thread.currentThread();
|
||||||
+ "]";
|
return "@[name=" + current.getName() + ", id=" + current.getId() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if we're running on emulator.
|
/** Returns true if we're running on emulator. */
|
||||||
public static boolean runningOnEmulator() {
|
public static boolean runningOnEmulator() {
|
||||||
return Build.HARDWARE.equals("goldfish") && Build.BRAND.startsWith("generic_");
|
// Hardware type of qemu1 is goldfish and qemu2 is ranchu.
|
||||||
|
return Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("ranchu");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information about the current build, taken from system properties.
|
/** Information about the current build, taken from system properties. */
|
||||||
static void logDeviceInfo(String tag) {
|
private static void logDeviceInfo(String tag) {
|
||||||
Logging.d(tag,
|
Logging.d(
|
||||||
"Android SDK: " + Build.VERSION.SDK_INT + ", "
|
tag,
|
||||||
+ "Release: " + Build.VERSION.RELEASE + ", "
|
("Android SDK: " + Build.VERSION.SDK_INT)
|
||||||
+ "Brand: " + Build.BRAND + ", "
|
+ (", Release: " + Build.VERSION.RELEASE)
|
||||||
+ "Device: " + Build.DEVICE + ", "
|
+ (", Brand: " + Build.BRAND)
|
||||||
+ "Id: " + Build.ID + ", "
|
+ (", Device: " + Build.DEVICE)
|
||||||
+ "Hardware: " + Build.HARDWARE + ", "
|
+ (", Id: " + Build.ID)
|
||||||
+ "Manufacturer: " + Build.MANUFACTURER + ", "
|
+ (", Hardware: " + Build.HARDWARE)
|
||||||
+ "Model: " + Build.MODEL + ", "
|
+ (", Manufacturer: " + Build.MANUFACTURER)
|
||||||
+ "Product: " + Build.PRODUCT);
|
+ (", Model: " + Build.MODEL)
|
||||||
|
+ (", Product: " + Build.PRODUCT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logs information about the current audio state. The idea is to call this
|
/**
|
||||||
// method when errors are detected to log under what conditions the error
|
* Logs information about the current audio state. The idea is to call this method when errors are
|
||||||
// occurred. Hopefully it will provide clues to what might be the root cause.
|
* detected to log under what conditions the error occurred. Hopefully it will provide clues to
|
||||||
static void logAudioState(String tag, Context context, AudioManager audioManager) {
|
* what might be the root cause.
|
||||||
|
*/
|
||||||
|
public static void logAudioState(String tag, Context context, AudioManager audioManager) {
|
||||||
logDeviceInfo(tag);
|
logDeviceInfo(tag);
|
||||||
logAudioStateBasic(tag, context, audioManager);
|
logAudioStateBasic(tag, context, audioManager);
|
||||||
logAudioStateVolume(tag, audioManager);
|
logAudioStateVolume(tag, audioManager);
|
||||||
logAudioDeviceInfo(tag, audioManager);
|
logAudioDeviceInfo(tag, audioManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts AudioDeviceInfo types to local string representation.
|
/** Converts AudioDeviceInfo types to local string representation. */
|
||||||
static String deviceTypeToString(int type) {
|
public static String deviceTypeToString(int type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AudioDeviceInfo.TYPE_UNKNOWN:
|
case AudioDeviceInfo.TYPE_AUX_LINE:
|
||||||
return "TYPE_UNKNOWN";
|
return "TYPE_AUX_LINE";
|
||||||
case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
|
case AudioDeviceInfo.TYPE_BLE_BROADCAST:
|
||||||
return "TYPE_BUILTIN_EARPIECE";
|
return "TYPE_BLE_BROADCAST";
|
||||||
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
|
case AudioDeviceInfo.TYPE_BLE_HEADSET:
|
||||||
return "TYPE_BUILTIN_SPEAKER";
|
return "TYPE_BLE_HEADSET";
|
||||||
case AudioDeviceInfo.TYPE_WIRED_HEADSET:
|
case AudioDeviceInfo.TYPE_BLE_SPEAKER:
|
||||||
return "TYPE_WIRED_HEADSET";
|
return "TYPE_BLE_SPEAKER";
|
||||||
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
|
|
||||||
return "TYPE_WIRED_HEADPHONES";
|
|
||||||
case AudioDeviceInfo.TYPE_LINE_ANALOG:
|
|
||||||
return "TYPE_LINE_ANALOG";
|
|
||||||
case AudioDeviceInfo.TYPE_LINE_DIGITAL:
|
|
||||||
return "TYPE_LINE_DIGITAL";
|
|
||||||
case AudioDeviceInfo.TYPE_BLUETOOTH_SCO:
|
|
||||||
return "TYPE_BLUETOOTH_SCO";
|
|
||||||
case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
|
case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
|
||||||
return "TYPE_BLUETOOTH_A2DP";
|
return "TYPE_BLUETOOTH_A2DP";
|
||||||
|
case AudioDeviceInfo.TYPE_BLUETOOTH_SCO:
|
||||||
|
return "TYPE_BLUETOOTH_SCO";
|
||||||
|
case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
|
||||||
|
return "TYPE_BUILTIN_EARPIECE";
|
||||||
|
case AudioDeviceInfo.TYPE_BUILTIN_MIC:
|
||||||
|
return "TYPE_BUILTIN_MIC";
|
||||||
|
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
|
||||||
|
return "TYPE_BUILTIN_SPEAKER";
|
||||||
|
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE:
|
||||||
|
return "TYPE_BUILTIN_SPEAKER_SAFE";
|
||||||
|
case AudioDeviceInfo.TYPE_BUS:
|
||||||
|
return "TYPE_BUS";
|
||||||
|
case AudioDeviceInfo.TYPE_DOCK:
|
||||||
|
return "TYPE_DOCK";
|
||||||
|
case AudioDeviceInfo.TYPE_DOCK_ANALOG:
|
||||||
|
return "TYPE_DOCK_ANALOG";
|
||||||
|
case AudioDeviceInfo.TYPE_FM:
|
||||||
|
return "TYPE_FM";
|
||||||
|
case AudioDeviceInfo.TYPE_FM_TUNER:
|
||||||
|
return "TYPE_FM_TUNER";
|
||||||
case AudioDeviceInfo.TYPE_HDMI:
|
case AudioDeviceInfo.TYPE_HDMI:
|
||||||
return "TYPE_HDMI";
|
return "TYPE_HDMI";
|
||||||
case AudioDeviceInfo.TYPE_HDMI_ARC:
|
case AudioDeviceInfo.TYPE_HDMI_ARC:
|
||||||
return "TYPE_HDMI_ARC";
|
return "TYPE_HDMI_ARC";
|
||||||
case AudioDeviceInfo.TYPE_USB_DEVICE:
|
case AudioDeviceInfo.TYPE_HDMI_EARC:
|
||||||
return "TYPE_USB_DEVICE";
|
return "TYPE_HDMI_EARC";
|
||||||
case AudioDeviceInfo.TYPE_USB_ACCESSORY:
|
case AudioDeviceInfo.TYPE_HEARING_AID:
|
||||||
return "TYPE_USB_ACCESSORY";
|
return "TYPE_HEARING_AID";
|
||||||
case AudioDeviceInfo.TYPE_DOCK:
|
|
||||||
return "TYPE_DOCK";
|
|
||||||
case AudioDeviceInfo.TYPE_FM:
|
|
||||||
return "TYPE_FM";
|
|
||||||
case AudioDeviceInfo.TYPE_BUILTIN_MIC:
|
|
||||||
return "TYPE_BUILTIN_MIC";
|
|
||||||
case AudioDeviceInfo.TYPE_FM_TUNER:
|
|
||||||
return "TYPE_FM_TUNER";
|
|
||||||
case AudioDeviceInfo.TYPE_TV_TUNER:
|
|
||||||
return "TYPE_TV_TUNER";
|
|
||||||
case AudioDeviceInfo.TYPE_TELEPHONY:
|
|
||||||
return "TYPE_TELEPHONY";
|
|
||||||
case AudioDeviceInfo.TYPE_AUX_LINE:
|
|
||||||
return "TYPE_AUX_LINE";
|
|
||||||
case AudioDeviceInfo.TYPE_IP:
|
case AudioDeviceInfo.TYPE_IP:
|
||||||
return "TYPE_IP";
|
return "TYPE_IP";
|
||||||
case AudioDeviceInfo.TYPE_BUS:
|
case AudioDeviceInfo.TYPE_LINE_ANALOG:
|
||||||
return "TYPE_BUS";
|
return "TYPE_LINE_ANALOG";
|
||||||
|
case AudioDeviceInfo.TYPE_LINE_DIGITAL:
|
||||||
|
return "TYPE_LINE_DIGITAL";
|
||||||
|
case AudioDeviceInfo.TYPE_REMOTE_SUBMIX:
|
||||||
|
return "TYPE_REMOTE_SUBMIX";
|
||||||
|
case AudioDeviceInfo.TYPE_TELEPHONY:
|
||||||
|
return "TYPE_TELEPHONY";
|
||||||
|
case AudioDeviceInfo.TYPE_TV_TUNER:
|
||||||
|
return "TYPE_TV_TUNER";
|
||||||
|
case AudioDeviceInfo.TYPE_UNKNOWN:
|
||||||
|
return "TYPE_UNKNOWN";
|
||||||
|
case AudioDeviceInfo.TYPE_USB_ACCESSORY:
|
||||||
|
return "TYPE_USB_ACCESSORY";
|
||||||
|
case AudioDeviceInfo.TYPE_USB_DEVICE:
|
||||||
|
return "TYPE_USB_DEVICE";
|
||||||
case AudioDeviceInfo.TYPE_USB_HEADSET:
|
case AudioDeviceInfo.TYPE_USB_HEADSET:
|
||||||
return "TYPE_USB_HEADSET";
|
return "TYPE_USB_HEADSET";
|
||||||
|
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
|
||||||
|
return "TYPE_WIRED_HEADPHONES";
|
||||||
|
case AudioDeviceInfo.TYPE_WIRED_HEADSET:
|
||||||
|
return "TYPE_WIRED_HEADSET";
|
||||||
default:
|
default:
|
||||||
return "TYPE_UNKNOWN";
|
return "TYPE_UNKNOWN(" + type + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.N)
|
|
||||||
public static String audioSourceToString(int source) {
|
public static String audioSourceToString(int source) {
|
||||||
// AudioSource.UNPROCESSED requires API level 29. Use local define instead.
|
|
||||||
final int VOICE_PERFORMANCE = 10;
|
|
||||||
switch (source) {
|
switch (source) {
|
||||||
case AudioSource.DEFAULT:
|
case AudioSource.DEFAULT:
|
||||||
return "DEFAULT";
|
return "DEFAULT";
|
||||||
|
@ -142,7 +160,7 @@ final class WebRtcAudioUtils {
|
||||||
return "VOICE_COMMUNICATION";
|
return "VOICE_COMMUNICATION";
|
||||||
case AudioSource.UNPROCESSED:
|
case AudioSource.UNPROCESSED:
|
||||||
return "UNPROCESSED";
|
return "UNPROCESSED";
|
||||||
case VOICE_PERFORMANCE:
|
case AudioSource.VOICE_PERFORMANCE:
|
||||||
return "VOICE_PERFORMANCE";
|
return "VOICE_PERFORMANCE";
|
||||||
default:
|
default:
|
||||||
return "INVALID";
|
return "INVALID";
|
||||||
|
@ -163,7 +181,7 @@ final class WebRtcAudioUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.N)
|
@TargetApi(VERSION_CODES.N)
|
||||||
public static String audioEncodingToString(int enc) {
|
public static String audioEncodingToString(int enc) {
|
||||||
switch (enc) {
|
switch (enc) {
|
||||||
case AudioFormat.ENCODING_INVALID:
|
case AudioFormat.ENCODING_INVALID:
|
||||||
|
@ -189,23 +207,29 @@ final class WebRtcAudioUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reports basic audio statistics.
|
/** Reports basic audio statistics. */
|
||||||
private static void logAudioStateBasic(String tag, Context context, AudioManager audioManager) {
|
private static void logAudioStateBasic(String tag, Context context, AudioManager audioManager) {
|
||||||
Logging.d(tag,
|
Logging.d(
|
||||||
|
tag,
|
||||||
"Audio State: "
|
"Audio State: "
|
||||||
+ "audio mode: " + modeToString(audioManager.getMode()) + ", "
|
+ ("audio mode: " + modeToString(audioManager.getMode()))
|
||||||
+ "has mic: " + hasMicrophone(context) + ", "
|
+ (", has mic: " + hasMicrophone(context))
|
||||||
+ "mic muted: " + audioManager.isMicrophoneMute() + ", "
|
+ (", mic muted: " + audioManager.isMicrophoneMute())
|
||||||
+ "music active: " + audioManager.isMusicActive() + ", "
|
+ (", music active: " + audioManager.isMusicActive())
|
||||||
+ "speakerphone: " + audioManager.isSpeakerphoneOn() + ", "
|
+ (", speakerphone: " + audioManager.isSpeakerphoneOn())
|
||||||
+ "BT SCO: " + audioManager.isBluetoothScoOn());
|
+ (", BT SCO: " + audioManager.isBluetoothScoOn()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds volume information for all possible stream types.
|
/** Adds volume information for all possible stream types. */
|
||||||
private static void logAudioStateVolume(String tag, AudioManager audioManager) {
|
private static void logAudioStateVolume(String tag, AudioManager audioManager) {
|
||||||
final int[] streams = {AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_MUSIC,
|
final int[] streams = {
|
||||||
AudioManager.STREAM_RING, AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
|
AudioManager.STREAM_VOICE_CALL,
|
||||||
AudioManager.STREAM_SYSTEM};
|
AudioManager.STREAM_MUSIC,
|
||||||
|
AudioManager.STREAM_RING,
|
||||||
|
AudioManager.STREAM_ALARM,
|
||||||
|
AudioManager.STREAM_NOTIFICATION,
|
||||||
|
AudioManager.STREAM_SYSTEM
|
||||||
|
};
|
||||||
Logging.d(tag, "Audio State: ");
|
Logging.d(tag, "Audio State: ");
|
||||||
// Some devices may not have volume controls and might use a fixed volume.
|
// Some devices may not have volume controls and might use a fixed volume.
|
||||||
boolean fixedVolume = audioManager.isVolumeFixed();
|
boolean fixedVolume = audioManager.isVolumeFixed();
|
||||||
|
@ -216,21 +240,16 @@ final class WebRtcAudioUtils {
|
||||||
info.append(" " + streamTypeToString(stream) + ": ");
|
info.append(" " + streamTypeToString(stream) + ": ");
|
||||||
info.append("volume=").append(audioManager.getStreamVolume(stream));
|
info.append("volume=").append(audioManager.getStreamVolume(stream));
|
||||||
info.append(", max=").append(audioManager.getStreamMaxVolume(stream));
|
info.append(", max=").append(audioManager.getStreamMaxVolume(stream));
|
||||||
logIsStreamMute(tag, audioManager, stream, info);
|
if (Build.VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||||
|
info.append(", muted=").append(audioManager.isStreamMute(stream));
|
||||||
|
}
|
||||||
Logging.d(tag, info.toString());
|
Logging.d(tag, info.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void logIsStreamMute(
|
|
||||||
String tag, AudioManager audioManager, int stream, StringBuilder info) {
|
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
|
||||||
info.append(", muted=").append(audioManager.isStreamMute(stream));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logAudioDeviceInfo(String tag, AudioManager audioManager) {
|
private static void logAudioDeviceInfo(String tag, AudioManager audioManager) {
|
||||||
if (Build.VERSION.SDK_INT < 23) {
|
if (Build.VERSION.SDK_INT < VERSION_CODES.M) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
|
final AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
|
||||||
|
@ -261,7 +280,7 @@ final class WebRtcAudioUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts media.AudioManager modes into local string representation.
|
/** Converts media.AudioManager modes into local string representation. */
|
||||||
static String modeToString(int mode) {
|
static String modeToString(int mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case MODE_IN_CALL:
|
case MODE_IN_CALL:
|
||||||
|
@ -296,7 +315,7 @@ final class WebRtcAudioUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the device can record audio via a microphone.
|
/** Returns true if the device can record audio via a microphone. */
|
||||||
private static boolean hasMicrophone(Context context) {
|
private static boolean hasMicrophone(Context context) {
|
||||||
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
|
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue