diff --git a/src/main/java/eu/siacs/conversations/services/AppRTCAudioManager.java b/src/main/java/eu/siacs/conversations/services/AppRTCAudioManager.java
index db1b8e1e1..07d52891b 100644
--- a/src/main/java/eu/siacs/conversations/services/AppRTCAudioManager.java
+++ b/src/main/java/eu/siacs/conversations/services/AppRTCAudioManager.java
@@ -15,7 +15,10 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.Log;
@@ -111,6 +114,40 @@ public class AppRTCAudioManager {
return new AppRTCAudioManager(context, speakerPhonePreference);
}
+ public static boolean isMicrophoneAvailable(final Context context) {
+ AudioRecord audioRecord = null;
+ boolean available = true;
+ try {
+ final int sampleRate = 44100;
+ final int channel = AudioFormat.CHANNEL_IN_MONO;
+ final int format = AudioFormat.ENCODING_PCM_16BIT;
+ final int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channel, format);
+ audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channel, format, bufferSize);
+ audioRecord.startRecording();
+ final short[] buffer = new short[bufferSize];
+ final int audioStatus = audioRecord.read(buffer, 0, bufferSize);
+ if (audioStatus == AudioRecord.ERROR_INVALID_OPERATION || audioStatus == AudioRecord.STATE_UNINITIALIZED)
+ available = false;
+ } catch (Exception e) {
+ available = false;
+ } finally {
+ release(audioRecord);
+
+ }
+ return available;
+ }
+
+ private static void release(final AudioRecord audioRecord) {
+ if (audioRecord == null) {
+ return;
+ }
+ try {
+ audioRecord.release();
+ } catch (Exception e) {
+ //ignore
+ }
+ }
+
/**
* This method is called when the proximity sensor reports a state change,
* e.g. from "NEAR to FAR" or from "FAR to NEAR".
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 03c90320f..8d1a0f1ab 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -82,6 +82,7 @@ import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.http.HttpDownloadConnection;
import eu.siacs.conversations.persistance.FileBackend;
+import eu.siacs.conversations.services.AppRTCAudioManager;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -1272,12 +1273,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
private void triggerRtpSession(final String action) {
- 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);
+ 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();
+ }
}
private void handleAttachmentSelection(MenuItem item) {
diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
index 7a3545166..7b6c1fefe 100644
--- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
@@ -9,6 +9,7 @@ import android.databinding.DataBindingUtil;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.util.Log;
@@ -126,7 +127,19 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
}
if (PermissionUtils.hasPermission(this, permissions, REQUEST_ACCEPT_CALL)) {
putScreenInCallMode();
+ checkRecorderAndAcceptCall();
+ }
+ }
+
+ 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();
}
}
@@ -247,7 +260,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (PermissionUtils.allGranted(grantResults)) {
if (requestCode == REQUEST_ACCEPT_CALL) {
- requireRtpConnection().acceptCall();
+ checkRecorderAndAcceptCall();
}
} else {
@StringRes int res;
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
index f47eb8f4f..3067f18f0 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
@@ -950,6 +950,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": not sending session-terminate after connectivity error because session is already in state " + this.state);
return;
}
+ //we need to call close
sendSessionTerminate(Reason.CONNECTIVITY_ERROR);
} else {
updateEndUserState();
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 1ac409fdc..9b05af9e3 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -914,6 +914,7 @@
Missed call
Audio call
Video call
+ Microphone unavailable
- View %1$d Participant
- View %1$d Participants