mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-14 23:18:43 +00:00
Add more AudioManager logging
This commit is contained in:
@@ -34,7 +34,15 @@ public abstract class AudioManagerCompat {
|
||||
|
||||
@SuppressWarnings("CodeBlock2Expr")
|
||||
protected final AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = focusChange -> {
|
||||
Log.i(TAG, "onAudioFocusChangeListener: " + focusChange);
|
||||
String focusName;
|
||||
switch (focusChange) {
|
||||
case AudioManager.AUDIOFOCUS_GAIN: focusName = "GAIN"; break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS: focusName = "LOSS"; break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: focusName = "LOSS_TRANSIENT"; break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: focusName = "LOSS_TRANSIENT_CAN_DUCK"; break;
|
||||
default: focusName = "UNKNOWN(" + focusChange + ")"; break;
|
||||
}
|
||||
Log.i(TAG, "onAudioFocusChangeListener: " + focusName);
|
||||
hasFocus = focusChange == AudioManager.AUDIOFOCUS_GAIN;
|
||||
};
|
||||
|
||||
@@ -180,6 +188,16 @@ public abstract class AudioManagerCompat {
|
||||
audioManager.unregisterAudioDeviceCallback(deviceCallback);
|
||||
}
|
||||
|
||||
@RequiresApi(24)
|
||||
public void registerAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback callback, @NonNull Handler handler) {
|
||||
audioManager.registerAudioRecordingCallback(callback, handler);
|
||||
}
|
||||
|
||||
@RequiresApi(24)
|
||||
public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback callback) {
|
||||
audioManager.unregisterAudioRecordingCallback(callback);
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
public boolean isWiredHeadsetOn() {
|
||||
AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
|
||||
@@ -220,13 +238,40 @@ public abstract class AudioManagerCompat {
|
||||
abstract public void abandonCallAudioFocus();
|
||||
|
||||
public static AudioManagerCompat create(@NonNull Context context) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
if (Build.VERSION.SDK_INT >= 31) {
|
||||
return new Api31AudioManagerCompat(context);
|
||||
} else if (Build.VERSION.SDK_INT >= 26) {
|
||||
return new Api26AudioManagerCompat(context);
|
||||
} else {
|
||||
return new Api21AudioManagerCompat(context);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(31)
|
||||
static class Api31AudioManagerCompat extends Api26AudioManagerCompat {
|
||||
|
||||
private Api31AudioManagerCompat(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void addOnModeChangedListener(@NonNull java.util.concurrent.Executor executor, @NonNull AudioManager.OnModeChangedListener listener) {
|
||||
audioManager.addOnModeChangedListener(executor, listener);
|
||||
}
|
||||
|
||||
public void removeOnModeChangedListener(@NonNull AudioManager.OnModeChangedListener listener) {
|
||||
audioManager.removeOnModeChangedListener(listener);
|
||||
}
|
||||
|
||||
public void addOnCommunicationDeviceChangedListener(@NonNull java.util.concurrent.Executor executor, @NonNull AudioManager.OnCommunicationDeviceChangedListener listener) {
|
||||
audioManager.addOnCommunicationDeviceChangedListener(executor, listener);
|
||||
}
|
||||
|
||||
public void removeOnCommunicationDeviceChangedListener(@NonNull AudioManager.OnCommunicationDeviceChangedListener listener) {
|
||||
audioManager.removeOnCommunicationDeviceChangedListener(listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RequiresApi(26)
|
||||
private static class Api26AudioManagerCompat extends AudioManagerCompat {
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import android.content.Context
|
||||
import android.media.AudioDeviceCallback
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import android.media.AudioRecordingConfiguration
|
||||
import android.media.MediaRecorder
|
||||
import android.net.Uri
|
||||
import androidx.annotation.RequiresApi
|
||||
import org.signal.core.util.logging.Log
|
||||
@@ -38,6 +40,34 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
}
|
||||
}
|
||||
|
||||
private val communicationDeviceChangedListener = AudioManager.OnCommunicationDeviceChangedListener { device ->
|
||||
if (device != null) {
|
||||
Log.i(TAG, "OnCommunicationDeviceChangedListener: id: ${device.id} type: ${getDeviceTypeName(device.type)}")
|
||||
} else {
|
||||
Log.w(TAG, "OnCommunicationDeviceChangedListener: null")
|
||||
}
|
||||
}
|
||||
|
||||
private val modeChangedListener = AudioManager.OnModeChangedListener { mode ->
|
||||
Log.i(TAG, "OnModeChangedListener: ${getModeName(mode)}")
|
||||
if (state == State.RUNNING && mode != AudioManager.MODE_IN_COMMUNICATION) {
|
||||
Log.w(TAG, "OnModeChangedListener: Not MODE_IN_COMMUNICATION during a call. state: $state")
|
||||
}
|
||||
}
|
||||
|
||||
private val audioRecordingCallback = object : AudioManager.AudioRecordingCallback() {
|
||||
override fun onRecordingConfigChanged(configs: List<AudioRecordingConfiguration>) {
|
||||
if (configs.isEmpty()) {
|
||||
Log.i(TAG, "AudioRecordingCallback: no active recordings")
|
||||
} else {
|
||||
for (config in configs) {
|
||||
val deviceName = config.audioDevice?.let { getDeviceTypeName(it.type) } ?: "null"
|
||||
Log.i(TAG, "AudioRecordingCallback: silenced: ${config.isClientSilenced} source: ${getAudioSourceName(config.audioSource)} device: $deviceName")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setDefaultAudioDevice(recipientId: RecipientId?, newDefaultDevice: AudioDevice, clearUserEarpieceSelection: Boolean) {
|
||||
Log.d(TAG, "setDefaultAudioDevice(): currentDefault: $defaultAudioDevice device: $newDefaultDevice clearUser: $clearUserEarpieceSelection")
|
||||
defaultAudioDevice = when (newDefaultDevice) {
|
||||
@@ -69,15 +99,27 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute
|
||||
hasWiredHeadset = androidAudioManager.isWiredHeadsetOn
|
||||
|
||||
val focusedGained = androidAudioManager.requestCallAudioFocus()
|
||||
if (!focusedGained) {
|
||||
handler.postDelayed({ androidAudioManager.requestCallAudioFocus() }, 500)
|
||||
Log.i(TAG, "initialize: savedMode: ${getModeName(savedAudioMode)} savedSpeaker: $savedIsSpeakerPhoneOn savedMicMute: $savedIsMicrophoneMute wiredHeadset: $hasWiredHeadset")
|
||||
|
||||
val focusGained = androidAudioManager.requestCallAudioFocus()
|
||||
if (!focusGained) {
|
||||
Log.w(TAG, "initialize: audio focus request failed, scheduling retry")
|
||||
handler.postDelayed({
|
||||
val retryGained = androidAudioManager.requestCallAudioFocus()
|
||||
Log.i(TAG, "initialize: audio focus retry result: $retryGained")
|
||||
}, 500)
|
||||
}
|
||||
|
||||
setMicrophoneMute(false)
|
||||
|
||||
updateAudioDeviceState()
|
||||
|
||||
androidAudioManager.registerAudioDeviceCallback(deviceCallback, handler)
|
||||
androidAudioManager.registerAudioRecordingCallback(audioRecordingCallback, handler)
|
||||
val api31AudioManager = androidAudioManager as AudioManagerCompat.Api31AudioManagerCompat
|
||||
api31AudioManager.addOnModeChangedListener(handler::post, modeChangedListener)
|
||||
api31AudioManager.addOnCommunicationDeviceChangedListener(handler::post, communicationDeviceChangedListener)
|
||||
|
||||
state = State.PREINITIALIZED
|
||||
|
||||
Log.d(TAG, "Initialized")
|
||||
@@ -85,15 +127,22 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
Log.i(TAG, "start: currentState: $state currentMode: ${getModeName(androidAudioManager.mode)}")
|
||||
|
||||
incomingRinger.stop()
|
||||
outgoingRinger.stop()
|
||||
|
||||
val focusedGained = androidAudioManager.requestCallAudioFocus()
|
||||
if (!focusedGained) {
|
||||
handler.postDelayed({ androidAudioManager.requestCallAudioFocus() }, 500)
|
||||
val focusGained = androidAudioManager.requestCallAudioFocus()
|
||||
if (!focusGained) {
|
||||
Log.w(TAG, "start: audio focus request failed, scheduling retry")
|
||||
handler.postDelayed({
|
||||
val retryGained = androidAudioManager.requestCallAudioFocus()
|
||||
Log.i(TAG, "start: audio focus retry result: $retryGained")
|
||||
}, 500)
|
||||
}
|
||||
|
||||
state = State.RUNNING
|
||||
Log.i(TAG, "start: setting mode to MODE_IN_COMMUNICATION")
|
||||
androidAudioManager.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
val volume: Float = androidAudioManager.ringVolumeWithMinimum()
|
||||
soundPool.play(connectedSoundId, volume, volume, 0, 0, 1.0f)
|
||||
@@ -102,6 +151,8 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
}
|
||||
|
||||
override fun stop(playDisconnect: Boolean) {
|
||||
Log.i(TAG, "stop: playDisconnect: $playDisconnect currentState: $state")
|
||||
|
||||
incomingRinger.stop()
|
||||
outgoingRinger.stop()
|
||||
|
||||
@@ -109,7 +160,14 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
val volume: Float = androidAudioManager.ringVolumeWithMinimum()
|
||||
soundPool.play(disconnectedSoundId, volume, volume, 0, 0, 1.0f)
|
||||
}
|
||||
androidAudioManager.unregisterAudioDeviceCallback(deviceCallback)
|
||||
if (state != State.UNINITIALIZED) {
|
||||
androidAudioManager.unregisterAudioDeviceCallback(deviceCallback)
|
||||
androidAudioManager.unregisterAudioRecordingCallback(audioRecordingCallback)
|
||||
val api31AudioManager = androidAudioManager as AudioManagerCompat.Api31AudioManagerCompat
|
||||
api31AudioManager.removeOnModeChangedListener(modeChangedListener)
|
||||
api31AudioManager.removeOnCommunicationDeviceChangedListener(communicationDeviceChangedListener)
|
||||
}
|
||||
|
||||
if (state == State.UNINITIALIZED && userSelectedAudioDevice != null) {
|
||||
Log.d(
|
||||
TAG,
|
||||
@@ -118,6 +176,7 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
"Therefore skipping audio device reset."
|
||||
)
|
||||
} else {
|
||||
Log.i(TAG, "stop: restoring mode to ${getModeName(savedAudioMode)}")
|
||||
androidAudioManager.clearCommunicationDevice()
|
||||
setSpeakerphoneOn(savedIsSpeakerPhoneOn)
|
||||
setMicrophoneMute(savedIsMicrophoneMute)
|
||||
@@ -143,7 +202,7 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
}
|
||||
|
||||
override fun startIncomingRinger(ringtoneUri: Uri?, vibrate: Boolean) {
|
||||
Log.i(TAG, "startIncomingRinger(): uri: ${if (ringtoneUri != null) "present" else "null"} vibrate: $vibrate")
|
||||
Log.i(TAG, "startIncomingRinger: uri: ${if (ringtoneUri != null) "present" else "null"} vibrate: $vibrate currentMode: ${getModeName(androidAudioManager.mode)}")
|
||||
androidAudioManager.mode = AudioManager.MODE_RINGTONE
|
||||
setMicrophoneMute(false)
|
||||
setDefaultAudioDevice(recipientId = null, newDefaultDevice = AudioDevice.SPEAKER_PHONE, clearUserEarpieceSelection = false)
|
||||
@@ -151,7 +210,7 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
}
|
||||
|
||||
override fun startOutgoingRinger() {
|
||||
Log.i(TAG, "startOutgoingRinger(): currentDevice: $selectedAudioDevice")
|
||||
Log.i(TAG, "startOutgoingRinger: currentDevice: $selectedAudioDevice currentMode: ${getModeName(androidAudioManager.mode)}")
|
||||
androidAudioManager.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
setMicrophoneMute(false)
|
||||
outgoingRinger.start(OutgoingRinger.Type.RINGING)
|
||||
@@ -181,7 +240,7 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
if (result) {
|
||||
eventListener?.onAudioDeviceChanged(AudioDeviceMapping.fromPlatformType(candidate.type), availableCommunicationDevices.map { AudioDeviceMapping.fromPlatformType(it.type) }.toSet())
|
||||
} else {
|
||||
Log.w(TAG, "Failed to set ${candidate.id} of type ${candidate.type}as communication device.")
|
||||
Log.w(TAG, "Failed to set ${candidate.id} of type ${getDeviceTypeName(candidate.type)} as communication device.")
|
||||
}
|
||||
} else {
|
||||
val searchOrder: List<AudioDevice> = listOf(AudioDevice.BLUETOOTH, AudioDevice.WIRED_HEADSET, defaultAudioDevice, AudioDevice.EARPIECE, AudioDevice.SPEAKER_PHONE, AudioDevice.NONE).distinct()
|
||||
@@ -194,14 +253,14 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
|
||||
when (candidate) {
|
||||
null -> {
|
||||
Log.e(TAG, "Tried to switch audio devices but could not find suitable device in list of types: ${availableCommunicationDevices.map { it.type }.joinToString()}")
|
||||
Log.e(TAG, "Tried to switch audio devices but could not find suitable device in list of types: ${availableCommunicationDevices.map { getDeviceTypeName(it.type) }.joinToString()}")
|
||||
androidAudioManager.clearCommunicationDevice()
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "Switching to new device of type ${candidate.type} from ${currentAudioDevice?.type}")
|
||||
Log.d(TAG, "Switching to new device of type ${getDeviceTypeName(candidate.type)} from ${currentAudioDevice?.type?.let { getDeviceTypeName(it) }}")
|
||||
val result = androidAudioManager.setCommunicationDevice(candidate)
|
||||
if (result) {
|
||||
Log.w(TAG, "Succeeded in setting ${candidate.id} (type: ${candidate.type}) as communication device.")
|
||||
Log.w(TAG, "Succeeded in setting ${candidate.id} (type: ${getDeviceTypeName(candidate.type)}) as communication device.")
|
||||
eventListener?.onAudioDeviceChanged(AudioDeviceMapping.fromPlatformType(candidate.type), availableCommunicationDevices.map { AudioDeviceMapping.fromPlatformType(it.type) }.toSet())
|
||||
} else {
|
||||
Log.w(TAG, "Failed to set ${candidate.id} as communication device.")
|
||||
@@ -210,4 +269,52 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getModeName(mode: Int): String {
|
||||
return when (mode) {
|
||||
AudioManager.MODE_NORMAL -> "MODE_NORMAL"
|
||||
AudioManager.MODE_RINGTONE -> "MODE_RINGTONE"
|
||||
AudioManager.MODE_IN_CALL -> "MODE_IN_CALL"
|
||||
AudioManager.MODE_IN_COMMUNICATION -> "MODE_IN_COMMUNICATION"
|
||||
AudioManager.MODE_CALL_SCREENING -> "MODE_CALL_SCREENING"
|
||||
else -> "UNKNOWN($mode)"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDeviceTypeName(type: Int): String {
|
||||
return when (type) {
|
||||
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> "BUILTIN_EARPIECE"
|
||||
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> "BUILTIN_SPEAKER"
|
||||
AudioDeviceInfo.TYPE_BUILTIN_MIC -> "BUILTIN_MIC"
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADSET -> "WIRED_HEADSET"
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> "WIRED_HEADPHONES"
|
||||
AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> "BLUETOOTH_SCO"
|
||||
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP -> "BLUETOOTH_A2DP"
|
||||
AudioDeviceInfo.TYPE_USB_DEVICE -> "USB_DEVICE"
|
||||
AudioDeviceInfo.TYPE_USB_ACCESSORY -> "USB_ACCESSORY"
|
||||
AudioDeviceInfo.TYPE_USB_HEADSET -> "USB_HEADSET"
|
||||
AudioDeviceInfo.TYPE_TELEPHONY -> "TELEPHONY"
|
||||
AudioDeviceInfo.TYPE_HEARING_AID -> "HEARING_AID"
|
||||
AudioDeviceInfo.TYPE_BLE_HEADSET -> "BLE_HEADSET"
|
||||
AudioDeviceInfo.TYPE_BLE_SPEAKER -> "BLE_SPEAKER"
|
||||
AudioDeviceInfo.TYPE_BLE_BROADCAST -> "BLE_BROADCAST"
|
||||
else -> "UNKNOWN($type)"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAudioSourceName(source: Int): String {
|
||||
return when (source) {
|
||||
MediaRecorder.AudioSource.DEFAULT -> "DEFAULT"
|
||||
MediaRecorder.AudioSource.MIC -> "MIC"
|
||||
MediaRecorder.AudioSource.VOICE_UPLINK -> "VOICE_UPLINK"
|
||||
MediaRecorder.AudioSource.VOICE_DOWNLINK -> "VOICE_DOWNLINK"
|
||||
MediaRecorder.AudioSource.VOICE_CALL -> "VOICE_CALL"
|
||||
MediaRecorder.AudioSource.CAMCORDER -> "CAMCORDER"
|
||||
MediaRecorder.AudioSource.VOICE_RECOGNITION -> "VOICE_RECOGNITION"
|
||||
MediaRecorder.AudioSource.VOICE_COMMUNICATION -> "VOICE_COMMUNICATION"
|
||||
MediaRecorder.AudioSource.UNPROCESSED -> "UNPROCESSED"
|
||||
MediaRecorder.AudioSource.VOICE_PERFORMANCE -> "VOICE_PERFORMANCE"
|
||||
else -> "UNKNOWN($source)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user