support mute via call integration

This commit is contained in:
Daniel Gultsch 2024-05-04 15:49:05 +02:00
parent 069b02004f
commit d904b5e303
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
6 changed files with 57 additions and 18 deletions

View file

@ -39,7 +39,7 @@ public class CallIntegration extends Connection {
private static final List<String> BROKEN_DEVICE_MODELS = private static final List<String> BROKEN_DEVICE_MODELS =
Arrays.asList( Arrays.asList(
"OnePlus6" // OnePlus 6 (Android 8.1-11) Device is buggy and always starts the "OnePlus6" // OnePlus 6 (Android 8.1-11) Device is buggy and always starts the
// OS call screen even though we want to be self managed // OS call screen even though we want to be self managed
); );
public static final int DEFAULT_TONE_VOLUME = 60; public static final int DEFAULT_TONE_VOLUME = 60;
@ -56,6 +56,7 @@ public class CallIntegration extends Connection {
private final AtomicBoolean isDestroyed = new AtomicBoolean(false); private final AtomicBoolean isDestroyed = new AtomicBoolean(false);
private List<CallEndpoint> availableEndpoints = Collections.emptyList(); private List<CallEndpoint> availableEndpoints = Collections.emptyList();
private boolean isMicrophoneEnabled = true;
private Callback callback = null; private Callback callback = null;
@ -74,6 +75,7 @@ public class CallIntegration extends Connection {
this.appRTCAudioManager.setAudioManagerEvents(this::onAudioDeviceChanged); this.appRTCAudioManager.setAudioManagerEvents(this::onAudioDeviceChanged);
} }
setRingbackRequested(true); setRingbackRequested(true);
setConnectionCapabilities(CAPABILITY_MUTE | CAPABILITY_RESPOND_VIA_TEXT);
} }
public void setCallback(final Callback callback) { public void setCallback(final Callback callback) {
@ -139,10 +141,26 @@ public class CallIntegration extends Connection {
Log.d(Config.LOGTAG, "ignoring onCallAudioStateChange() on Upside Down Cake"); Log.d(Config.LOGTAG, "ignoring onCallAudioStateChange() on Upside Down Cake");
return; return;
} }
setMicrophoneEnabled(!state.isMuted());
Log.d(Config.LOGTAG, "onCallAudioStateChange(" + state + ")"); Log.d(Config.LOGTAG, "onCallAudioStateChange(" + state + ")");
this.onAudioDeviceChanged(getAudioDeviceOreo(state), getAudioDevicesOreo(state)); this.onAudioDeviceChanged(getAudioDeviceOreo(state), getAudioDevicesOreo(state));
} }
@Override
public void onMuteStateChanged(final boolean isMuted) {
Log.d(Config.LOGTAG, "onMuteStateChanged(" + isMuted + ")");
setMicrophoneEnabled(!isMuted);
}
private void setMicrophoneEnabled(final boolean enabled) {
this.isMicrophoneEnabled = enabled;
this.callback.onCallIntegrationMicrophoneEnabled(enabled);
}
public boolean isMicrophoneEnabled() {
return this.isMicrophoneEnabled;
}
public Set<AudioDevice> getAudioDevices() { public Set<AudioDevice> getAudioDevices() {
if (notSelfManaged(context)) { if (notSelfManaged(context)) {
return getAudioDevicesFallback(); return getAudioDevicesFallback();
@ -578,5 +596,7 @@ public class CallIntegration extends Connection {
void onCallIntegrationAnswer(); void onCallIntegrationAnswer();
void onCallIntegrationSilence(); void onCallIntegrationSilence();
void onCallIntegrationMicrophoneEnabled(boolean enabled);
} }
} }

View file

@ -117,7 +117,7 @@ public class NotificationsSettingsFragment extends XmppPreferenceFragment {
try { try {
startActivity(intent); startActivity(intent);
} catch (final ActivityNotFoundException e) { } catch (final ActivityNotFoundException e) {
Toast.makeText(requireContext(), R.string.no_application_found, Toast.LENGTH_SHORT) Toast.makeText(requireContext(), R.string.unsupported_operation, Toast.LENGTH_SHORT)
.show(); .show();
return false; return false;
} }

View file

@ -649,7 +649,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
} }
public JingleRtpConnection getOngoingRtpConnection() { public JingleRtpConnection getOngoingRtpConnection() {
for(final AbstractJingleConnection jingleConnection : this.connections.values()) { for (final AbstractJingleConnection jingleConnection : this.connections.values()) {
if (jingleConnection instanceof JingleRtpConnection jingleRtpConnection) { if (jingleConnection instanceof JingleRtpConnection jingleRtpConnection) {
if (jingleRtpConnection.isTerminated()) { if (jingleRtpConnection.isTerminated()) {
continue; continue;
@ -986,10 +986,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
this.rtpSessionProposals.remove(sessionProposal); this.rtpSessionProposals.remove(sessionProposal);
sessionProposal.getCallIntegration().error(); sessionProposal.getCallIntegration().error();
mXmppConnectionService.notifyJingleRtpConnectionUpdate( mXmppConnectionService.notifyJingleRtpConnectionUpdate(
account, account, sessionProposal.with, sessionProposal.sessionId, endUserState);
sessionProposal.with,
sessionProposal.sessionId,
endUserState);
return; return;
} }
@ -1226,5 +1223,8 @@ public class JingleConnectionManager extends AbstractConnectionManager {
@Override @Override
public void onCallIntegrationSilence() {} public void onCallIntegrationSilence() {}
@Override
public void onCallIntegrationMicrophoneEnabled(boolean enabled) {}
} }
} }

View file

@ -2324,6 +2324,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
this.jingleConnectionManager.ensureConnectionIsRegistered(this); this.jingleConnectionManager.ensureConnectionIsRegistered(this);
this.webRTCWrapper.setup(this.xmppConnectionService); this.webRTCWrapper.setup(this.xmppConnectionService);
this.webRTCWrapper.initializePeerConnection(media, iceServers, trickle); this.webRTCWrapper.initializePeerConnection(media, iceServers, trickle);
this.webRTCWrapper.setMicrophoneEnabledOrThrow(callIntegration.isMicrophoneEnabled());
} }
private void acceptCallFromProposed() { private void acceptCallFromProposed() {
@ -2686,7 +2687,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
} }
public boolean setMicrophoneEnabled(final boolean enabled) { public boolean setMicrophoneEnabled(final boolean enabled) {
return webRTCWrapper.setMicrophoneEnabled(enabled); return webRTCWrapper.setMicrophoneEnabledOrThrow(enabled);
} }
public boolean isVideoEnabled() { public boolean isVideoEnabled() {
@ -2762,6 +2763,11 @@ public class JingleRtpConnection extends AbstractJingleConnection
xmppConnectionService.getNotificationService().stopSoundAndVibration(); xmppConnectionService.getNotificationService().stopSoundAndVibration();
} }
@Override
public void onCallIntegrationMicrophoneEnabled(final boolean enabled) {
this.webRTCWrapper.setMicrophoneEnabled(enabled);
}
@Override @Override
public void onAudioDeviceChanged( public void onAudioDeviceChanged(
final CallIntegration.AudioDevice selectedAudioDevice, final CallIntegration.AudioDevice selectedAudioDevice,

View file

@ -506,23 +506,36 @@ public class WebRTCWrapper {
} }
} }
boolean setMicrophoneEnabled(final boolean enabled) { boolean setMicrophoneEnabledOrThrow(final boolean enabled) {
final Optional<AudioTrack> audioTrack = final Optional<AudioTrack> audioTrack =
TrackWrapper.get(peerConnection, this.localAudioTrack); TrackWrapper.get(peerConnection, this.localAudioTrack);
if (audioTrack.isPresent()) { if (audioTrack.isPresent()) {
try { return setEnabled(audioTrack.get(), enabled);
audioTrack.get().setEnabled(enabled);
return true;
} catch (final IllegalStateException e) {
Log.d(Config.LOGTAG, "unable to toggle microphone", e);
// ignoring race condition in case MediaStreamTrack has been disposed
return false;
}
} else { } else {
throw new IllegalStateException("Local audio track does not exist (yet)"); throw new IllegalStateException("Local audio track does not exist (yet)");
} }
} }
private static boolean setEnabled(final AudioTrack audioTrack, final boolean enabled) {
try {
audioTrack.setEnabled(enabled);
return true;
} catch (final IllegalStateException e) {
Log.d(Config.LOGTAG, "unable to toggle audio track", e);
// ignoring race condition in case MediaStreamTrack has been disposed
return false;
}
}
void setMicrophoneEnabled(final boolean enabled) {
final Optional<AudioTrack> audioTrack =
TrackWrapper.get(peerConnection, this.localAudioTrack);
if (audioTrack.isPresent()) {
setEnabled(audioTrack.get(), enabled);
}
}
boolean isVideoEnabled() { boolean isVideoEnabled() {
final Optional<VideoTrack> videoTrack = final Optional<VideoTrack> videoTrack =
TrackWrapper.get(peerConnection, this.localVideoTrack); TrackWrapper.get(peerConnection, this.localVideoTrack);

View file

@ -1064,5 +1064,5 @@
<string name="pref_backup_recurring">Recurring backup</string> <string name="pref_backup_recurring">Recurring backup</string>
<string name="pref_fullscreen_notification">Full screen notifications</string> <string name="pref_fullscreen_notification">Full screen notifications</string>
<string name="pref_fullscreen_notification_summary">Allow this app to show incoming call notifications that take up the full screen when the device is locked.</string> <string name="pref_fullscreen_notification_summary">Allow this app to show incoming call notifications that take up the full screen when the device is locked.</string>
<string name="unsupported_operation">Unsupported operation</string>
</resources> </resources>