add microphone availability check

This commit is contained in:
Daniel Gultsch 2020-04-18 17:51:21 +02:00
parent ebda472c22
commit 934b98d199
5 changed files with 64 additions and 7 deletions

View file

@ -15,7 +15,10 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.media.AudioDeviceInfo; import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Build; import android.os.Build;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
@ -111,6 +114,40 @@ public class AppRTCAudioManager {
return new AppRTCAudioManager(context, speakerPhonePreference); 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, * This method is called when the proximity sensor reports a state change,
* e.g. from "NEAR to FAR" or from "FAR to NEAR". * e.g. from "NEAR to FAR" or from "FAR to NEAR".

View file

@ -82,6 +82,7 @@ import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.http.HttpDownloadConnection; import eu.siacs.conversations.http.HttpDownloadConnection;
import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.AppRTCAudioManager;
import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.QuickConversationsService; import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
@ -1272,12 +1273,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
private void triggerRtpSession(final String action) { private void triggerRtpSession(final String action) {
if (AppRTCAudioManager.isMicrophoneAvailable(getActivity())) {
final Contact contact = conversation.getContact(); final Contact contact = conversation.getContact();
final Intent intent = new Intent(activity, RtpSessionActivity.class); final Intent intent = new Intent(activity, RtpSessionActivity.class);
intent.setAction(action); intent.setAction(action);
intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, contact.getAccount().getJid().toEscapedString()); intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, contact.getAccount().getJid().toEscapedString());
intent.putExtra(RtpSessionActivity.EXTRA_WITH, contact.getJid().asBareJid().toEscapedString()); intent.putExtra(RtpSessionActivity.EXTRA_WITH, contact.getJid().asBareJid().toEscapedString());
startActivity(intent); startActivity(intent);
} else {
Toast.makeText(getActivity(), R.string.microphone_unavailable, Toast.LENGTH_SHORT).show();
}
} }
private void handleAttachmentSelection(MenuItem item) { private void handleAttachmentSelection(MenuItem item) {

View file

@ -9,6 +9,7 @@ import android.databinding.DataBindingUtil;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.SystemClock;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.util.Log; import android.util.Log;
@ -126,7 +127,19 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
} }
if (PermissionUtils.hasPermission(this, permissions, REQUEST_ACCEPT_CALL)) { if (PermissionUtils.hasPermission(this, permissions, REQUEST_ACCEPT_CALL)) {
putScreenInCallMode(); 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(); 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); super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (PermissionUtils.allGranted(grantResults)) { if (PermissionUtils.allGranted(grantResults)) {
if (requestCode == REQUEST_ACCEPT_CALL) { if (requestCode == REQUEST_ACCEPT_CALL) {
requireRtpConnection().acceptCall(); checkRecorderAndAcceptCall();
} }
} else { } else {
@StringRes int res; @StringRes int res;

View file

@ -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); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": not sending session-terminate after connectivity error because session is already in state " + this.state);
return; return;
} }
//we need to call close
sendSessionTerminate(Reason.CONNECTIVITY_ERROR); sendSessionTerminate(Reason.CONNECTIVITY_ERROR);
} else { } else {
updateEndUserState(); updateEndUserState();

View file

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