From a2a7256682198e03a3e66cb61eedc35bc2019d86 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 21 May 2020 11:13:46 +0200 Subject: [PATCH] disable hardware AEC on some devices. fixes #3734 --- .../xmpp/jingle/WebRTCWrapper.java | 73 ++++++++++++------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java index 96c98181a..d5f009dba 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java @@ -8,7 +8,6 @@ import android.util.Log; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.Futures; @@ -41,6 +40,8 @@ import org.webrtc.SessionDescription; import org.webrtc.SurfaceTextureHelper; import org.webrtc.VideoSource; import org.webrtc.VideoTrack; +import org.webrtc.audio.JavaAudioDeviceModule; +import org.webrtc.voiceengine.WebRtcAudioEffects; import java.util.ArrayList; import java.util.Collections; @@ -57,6 +58,22 @@ public class WebRTCWrapper { private static final String EXTENDED_LOGGING_TAG = WebRTCWrapper.class.getSimpleName(); + //we should probably keep this in sync with: https://github.com/signalapp/Signal-Android/blob/master/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java#L296 + private static final Set HARDWARE_AEC_BLACKLIST = new ImmutableSet.Builder() + .add("Pixel") + .add("Pixel XL") + .add("Moto G5") + .add("Moto G (5S) Plus") + .add("Moto G4") + .add("TA-1053") + .add("Mi A1") + .add("Mi A2") + .add("E5823") // Sony z5 compact + .add("Redmi Note 5") + .add("FP2") // Fairphone FP2 + .add("MI 5") + .build(); + private static final int CAPTURING_RESOLUTION = 1920; private static final int CAPTURING_MAX_FRAME_RATE = 30; @@ -165,6 +182,30 @@ public class WebRTCWrapper { this.eventCallback = eventCallback; } + private static void dispose(final PeerConnection peerConnection) { + try { + peerConnection.dispose(); + } catch (final IllegalStateException e) { + Log.e(Config.LOGTAG, "unable to dispose of peer connection", e); + } + } + + @Nullable + private static CapturerChoice of(CameraEnumerator enumerator, final String deviceName, Set availableCameras) { + final CameraVideoCapturer capturer = enumerator.createCapturer(deviceName, null); + if (capturer == null) { + return null; + } + final ArrayList choices = new ArrayList<>(enumerator.getSupportedFormats(deviceName)); + Collections.sort(choices, (a, b) -> b.width - a.width); + for (final CameraEnumerationAndroid.CaptureFormat captureFormat : choices) { + if (captureFormat.width <= CAPTURING_RESOLUTION) { + return new CapturerChoice(capturer, captureFormat, availableCameras); + } + } + return null; + } + public void setup(final Context context, final AppRTCAudioManager.SpeakerPhonePreference speakerPhonePreference) throws InitializationException { try { PeerConnectionFactory.initialize( @@ -186,9 +227,15 @@ public class WebRTCWrapper { Preconditions.checkState(this.eglBase != null); Preconditions.checkNotNull(media); Preconditions.checkArgument(media.size() > 0, "media can not be empty when initializing peer connection"); + final boolean setUseHardwareAcousticEchoCanceler = WebRtcAudioEffects.canUseAcousticEchoCanceler() && !HARDWARE_AEC_BLACKLIST.contains(Build.MODEL); + Log.d(Config.LOGTAG, String.format("setUseHardwareAcousticEchoCanceler(%s) model=%s", setUseHardwareAcousticEchoCanceler, Build.MODEL)); PeerConnectionFactory peerConnectionFactory = PeerConnectionFactory.builder() .setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglBase.getEglBaseContext())) .setVideoEncoderFactory(new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), true, true)) + .setAudioDeviceModule(JavaAudioDeviceModule.builder(context) + .setUseHardwareAcousticEchoCanceler(setUseHardwareAcousticEchoCanceler) + .createAudioDeviceModule() + ) .createPeerConnectionFactory(); @@ -258,14 +305,6 @@ public class WebRTCWrapper { } } - private static void dispose(final PeerConnection peerConnection) { - try { - peerConnection.dispose(); - } catch (final IllegalStateException e) { - Log.e(Config.LOGTAG, "unable to dispose of peer connection", e); - } - } - synchronized void verifyClosed() { if (this.peerConnection != null || this.eglBase != null @@ -469,22 +508,6 @@ public class WebRTCWrapper { } } - @Nullable - private static CapturerChoice of(CameraEnumerator enumerator, final String deviceName, Set availableCameras) { - final CameraVideoCapturer capturer = enumerator.createCapturer(deviceName, null); - if (capturer == null) { - return null; - } - final ArrayList choices = new ArrayList<>(enumerator.getSupportedFormats(deviceName)); - Collections.sort(choices, (a, b) -> b.width - a.width); - for (final CameraEnumerationAndroid.CaptureFormat captureFormat : choices) { - if (captureFormat.width <= CAPTURING_RESOLUTION) { - return new CapturerChoice(capturer, captureFormat, availableCameras); - } - } - return null; - } - public PeerConnection.PeerConnectionState getState() { return requirePeerConnection().connectionState(); }