check microphone availability on background thread

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/AppRTCAudioManager.java | 21 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java     | 16 
src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java       | 24 
src/main/res/values/strings.xml                                       |  2 
4 files changed, 43 insertions(+), 20 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/AppRTCAudioManager.java 🔗

@@ -28,6 +28,7 @@ import org.webrtc.ThreadUtils;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.utils.AppRTCUtils;
@@ -36,6 +37,9 @@ import eu.siacs.conversations.utils.AppRTCUtils;
  * AppRTCAudioManager manages all audio related parts of the AppRTC demo.
  */
 public class AppRTCAudioManager {
+
+    private static CountDownLatch microphoneLatch;
+
     private final Context apprtcContext;
     // Contains speakerphone setting: auto, true or false
     @Nullable
@@ -114,7 +118,8 @@ public class AppRTCAudioManager {
         return new AppRTCAudioManager(context, speakerPhonePreference);
     }
 
-    public static boolean isMicrophoneAvailable(final Context context) {
+    public static boolean isMicrophoneAvailable() {
+        microphoneLatch = new CountDownLatch(1);
         AudioRecord audioRecord = null;
         boolean available = true;
         try {
@@ -134,6 +139,7 @@ public class AppRTCAudioManager {
             release(audioRecord);
 
         }
+        microphoneLatch.countDown();
         return available;
     }
 
@@ -181,6 +187,7 @@ public class AppRTCAudioManager {
             Log.e(Config.LOGTAG, "AudioManager is already active");
             return;
         }
+        awaitMicrophoneLatch();
         // TODO(henrika): perhaps call new method called preInitAudio() here if UNINITIALIZED.
         Log.d(Config.LOGTAG, "AudioManager starts...");
         this.audioManagerEvents = audioManagerEvents;
@@ -261,6 +268,18 @@ public class AppRTCAudioManager {
         Log.d(Config.LOGTAG, "AudioManager started");
     }
 
+    private void awaitMicrophoneLatch() {
+        final CountDownLatch latch = microphoneLatch;
+        if (latch == null) {
+            return;
+        }
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+            //ignore
+        }
+    }
+
     @SuppressWarnings("deprecation")
     // TODO(henrika): audioManager.abandonAudioFocus() is deprecated.
     public void stop() {

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -1273,16 +1273,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
 
 
     private void triggerRtpSession(final String action) {
-        if (AppRTCAudioManager.isMicrophoneAvailable(getActivity())) {
-            final Contact contact = conversation.getContact();
-            final Intent intent = new Intent(activity, RtpSessionActivity.class);
-            intent.setAction(action);
-            intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, contact.getAccount().getJid().toEscapedString());
-            intent.putExtra(RtpSessionActivity.EXTRA_WITH, contact.getJid().asBareJid().toEscapedString());
-            startActivity(intent);
-        } else {
-            Toast.makeText(getActivity(), R.string.microphone_unavailable, Toast.LENGTH_SHORT).show();
-        }
+        final Contact contact = conversation.getContact();
+        final Intent intent = new Intent(activity, RtpSessionActivity.class);
+        intent.setAction(action);
+        intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, contact.getAccount().getJid().toEscapedString());
+        intent.putExtra(RtpSessionActivity.EXTRA_WITH, contact.getJid().asBareJid().toEscapedString());
+        startActivity(intent);
     }
 
     private void handleAttachmentSelection(MenuItem item) {

src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java 🔗

@@ -132,15 +132,22 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
     }
 
     private void checkRecorderAndAcceptCall() {
-        final long start = SystemClock.elapsedRealtime();
-        final boolean isMicrophoneAvailable = AppRTCAudioManager.isMicrophoneAvailable(this);
-        final long stop = SystemClock.elapsedRealtime();
-        Log.d(Config.LOGTAG, "checking microphone availability took " + (stop - start) + "ms");
-        if (isMicrophoneAvailable) {
-            requireRtpConnection().acceptCall();
-        } else {
-            Toast.makeText(this, R.string.microphone_unavailable, Toast.LENGTH_SHORT).show();
+        checkMicrophoneAvailability();
+        requireRtpConnection().acceptCall();
+    }
+
+    private void checkMicrophoneAvailability() {
+        new Thread(() -> {
+            final long start = SystemClock.elapsedRealtime();
+            final boolean isMicrophoneAvailable = AppRTCAudioManager.isMicrophoneAvailable();
+            final long stop = SystemClock.elapsedRealtime();
+            Log.d(Config.LOGTAG, "checking microphone availability took " + (stop - start) + "ms");
+            if (isMicrophoneAvailable) {
+                return;
+            }
+            runOnUiThread(() -> Toast.makeText(this, R.string.microphone_unavailable, Toast.LENGTH_SHORT).show());
         }
+        ).start();
     }
 
     private void putScreenInCallMode() {
@@ -251,6 +258,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
     }
 
     private void proposeJingleRtpSession(final Account account, final Jid with, final Set<Media> media) {
+        checkMicrophoneAvailability();
         xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(account, with, media);
         putScreenInCallMode(media);
     }

src/main/res/values/strings.xml 🔗

@@ -914,7 +914,7 @@
     <string name="missed_call">Missed call</string>
     <string name="audio_call">Audio call</string>
     <string name="video_call">Video call</string>
-    <string name="microphone_unavailable">Microphone unavailable</string>
+    <string name="microphone_unavailable">Your microphone is unavailable</string>
     <plurals name="view_users">
         <item quantity="one">View %1$d Participant</item>
         <item quantity="other">View %1$d Participants</item>