make mute and speaker button work

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java           | 94 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java | 12 
src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java       | 26 
src/main/res/drawable-hdpi/ic_bluetooth_audio_black_24dp.png              |  0 
src/main/res/drawable-hdpi/ic_headset_black_24dp.png                      |  0 
src/main/res/drawable-mdpi/ic_bluetooth_audio_black_24dp.png              |  0 
src/main/res/drawable-mdpi/ic_headset_black_24dp.png                      |  0 
src/main/res/drawable-xhdpi/ic_bluetooth_audio_black_24dp.png             |  0 
src/main/res/drawable-xhdpi/ic_headset_black_24dp.png                     |  0 
src/main/res/drawable-xxhdpi/ic_bluetooth_audio_black_24dp.png            |  0 
src/main/res/drawable-xxhdpi/ic_headset_black_24dp.png                    |  0 
src/main/res/drawable-xxxhdpi/ic_bluetooth_audio_black_24dp.png           |  0 
src/main/res/drawable-xxxhdpi/ic_headset_black_24dp.png                   |  0 
13 files changed, 125 insertions(+), 7 deletions(-)

Detailed changes

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

@@ -16,6 +16,7 @@ import android.view.View;
 import android.view.WindowManager;
 import android.widget.Toast;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.ref.WeakReference;
@@ -344,18 +345,91 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
             this.binding.endCall.setVisibility(View.VISIBLE);
             this.binding.acceptCall.setVisibility(View.INVISIBLE);
         }
+        updateInCallButtonConfiguration(state);
+    }
+
+    private void updateInCallButtonConfiguration() {
+        updateInCallButtonConfiguration(requireRtpConnection().getEndUserState());
+    }
 
+    @SuppressLint("RestrictedApi")
+    private void updateInCallButtonConfiguration(final RtpEndUserState state) {
         if (state == RtpEndUserState.CONNECTED) {
-            this.binding.inCallActionLeft.setImageResource(R.drawable.ic_volume_off_black_24dp);
-            this.binding.inCallActionLeft.setVisibility(View.VISIBLE);
-            this.binding.inCallActionRight.setImageResource(R.drawable.ic_mic_black_24dp);
-            this.binding.inCallActionRight.setVisibility(View.VISIBLE);
+            final AppRTCAudioManager audioManager = requireRtpConnection().getAudioManager();
+            updateInCallButtonConfiguration(
+                    audioManager.getSelectedAudioDevice(),
+                    audioManager.getAudioDevices().size(),
+                    requireRtpConnection().isMicrophoneEnabled()
+            );
         } else {
             this.binding.inCallActionLeft.setVisibility(View.GONE);
             this.binding.inCallActionRight.setVisibility(View.GONE);
         }
     }
 
+    @SuppressLint("RestrictedApi")
+    private void updateInCallButtonConfiguration(final AppRTCAudioManager.AudioDevice selectedAudioDevice, final int numberOfChoices, final boolean microphoneEnabled) {
+        switch (selectedAudioDevice) {
+            case EARPIECE:
+                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_volume_off_black_24dp);
+                if (numberOfChoices >= 2) {
+                    this.binding.inCallActionLeft.setOnClickListener(this::switchToSpeaker);
+                } else {
+                    this.binding.inCallActionLeft.setOnClickListener(null);
+                    this.binding.inCallActionLeft.setClickable(false);
+                }
+                break;
+            case WIRED_HEADSET:
+                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_headset_black_24dp);
+                this.binding.inCallActionLeft.setOnClickListener(null);
+                this.binding.inCallActionLeft.setClickable(false);
+                break;
+            case SPEAKER_PHONE:
+                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_volume_up_black_24dp);
+                if (numberOfChoices >= 2) {
+                    this.binding.inCallActionLeft.setOnClickListener(this::switchToEarpiece);
+                } else {
+                    this.binding.inCallActionLeft.setOnClickListener(null);
+                    this.binding.inCallActionLeft.setClickable(false);
+                }
+                break;
+            case BLUETOOTH:
+                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_bluetooth_audio_black_24dp);
+                this.binding.inCallActionLeft.setOnClickListener(null);
+                this.binding.inCallActionLeft.setClickable(false);
+                break;
+        }
+        this.binding.inCallActionLeft.setVisibility(View.VISIBLE);
+        if (microphoneEnabled) {
+            this.binding.inCallActionRight.setImageResource(R.drawable.ic_mic_black_24dp);
+            this.binding.inCallActionRight.setOnClickListener(this::disableMicrophone);
+        } else {
+            this.binding.inCallActionRight.setImageResource(R.drawable.ic_mic_off_black_24dp);
+            this.binding.inCallActionRight.setOnClickListener(this::enableMicrophone);
+        }
+        this.binding.inCallActionRight.setVisibility(View.VISIBLE);
+    }
+
+    private void disableMicrophone(View view) {
+        JingleRtpConnection rtpConnection = requireRtpConnection();
+        rtpConnection.setMicrophoneEnabled(false);
+        updateInCallButtonConfiguration();
+    }
+
+    private void enableMicrophone(View view) {
+        JingleRtpConnection rtpConnection = requireRtpConnection();
+        rtpConnection.setMicrophoneEnabled(true);
+        updateInCallButtonConfiguration();
+    }
+
+    private void switchToEarpiece(View view) {
+        requireRtpConnection().getAudioManager().setDefaultAudioDevice(AppRTCAudioManager.AudioDevice.EARPIECE);
+    }
+
+    private void switchToSpeaker(View view) {
+        requireRtpConnection().getAudioManager().setDefaultAudioDevice(AppRTCAudioManager.AudioDevice.SPEAKER_PHONE);
+    }
+
     private void retry(View view) {
         Log.d(Config.LOGTAG, "attempting retry");
         final Intent intent = getIntent();
@@ -419,6 +493,18 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
     @Override
     public void onAudioDeviceChanged(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set<AppRTCAudioManager.AudioDevice> availableAudioDevices) {
         Log.d(Config.LOGTAG, "onAudioDeviceChanged in activity: selected:" + selectedAudioDevice + ", available:" + availableAudioDevices);
+        try {
+            if (requireRtpConnection().getEndUserState() == RtpEndUserState.CONNECTED) {
+                final AppRTCAudioManager audioManager = requireRtpConnection().getAudioManager();
+                updateInCallButtonConfiguration(
+                        audioManager.getSelectedAudioDevice(),
+                        audioManager.getAudioDevices().size(),
+                        requireRtpConnection().isMicrophoneEnabled()
+                );
+            }
+        } catch (IllegalStateException e) {
+            Log.d(Config.LOGTAG, "RTP connection was not available when audio device changed");
+        }
     }
 
     private void updateRtpSessionProposalState(final Account account, final Jid with, final RtpEndUserState state) {

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java 🔗

@@ -833,6 +833,18 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
         }
     }
 
+    public AppRTCAudioManager getAudioManager() {
+        return webRTCWrapper.getAudioManager();
+    }
+
+    public void setMicrophoneEnabled(final boolean enabled) {
+        webRTCWrapper.setMicrophoneEnabled(enabled);
+    }
+
+    public boolean isMicrophoneEnabled() {
+        return webRTCWrapper.isMicrophoneEnabled();
+    }
+
     @Override
     public void onAudioDeviceChanged(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set<AppRTCAudioManager.AudioDevice> availableAudioDevices) {
         xmppConnectionService.notifyJingleRtpConnectionUpdate(selectedAudioDevice, availableAudioDevices);

src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java 🔗

@@ -131,6 +131,7 @@ public class WebRTCWrapper {
     };
     @Nullable
     private PeerConnection peerConnection = null;
+    private AudioTrack localAudioTrack = null;
     private AppRTCAudioManager appRTCAudioManager = null;
     private final Handler mainHandler = new Handler(Looper.getMainLooper());
 
@@ -201,10 +202,9 @@ public class WebRTCWrapper {
 
         final AudioSource audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
 
-        final AudioTrack audioTrack = peerConnectionFactory.createAudioTrack("my-audio-track", audioSource);
-        Log.d(Config.LOGTAG, "audioTrack enabled:" + audioTrack.enabled() + " state=" + audioTrack.state());
+        this.localAudioTrack = peerConnectionFactory.createAudioTrack("my-audio-track", audioSource);
         final MediaStream stream = peerConnectionFactory.createLocalMediaStream("my-media-stream");
-        stream.addTrack(audioTrack);
+        stream.addTrack(this.localAudioTrack);
         //stream.addTrack(videoTrack);
 
         this.localVideoTrack = videoTrack;
@@ -229,6 +229,22 @@ public class WebRTCWrapper {
         }
     }
 
+    public void setMicrophoneEnabled(final boolean enabled) {
+        final AudioTrack audioTrack = this.localAudioTrack;
+        if (audioTrack == null) {
+            throw new IllegalStateException("Local audio track does not exist (yet)");
+        }
+        audioTrack.setEnabled(enabled);
+    }
+
+    public boolean isMicrophoneEnabled() {
+        final AudioTrack audioTrack = this.localAudioTrack;
+        if (audioTrack == null) {
+            throw new IllegalStateException("Local audio track does not exist (yet)");
+        }
+        return audioTrack.enabled();
+    }
+
 
     public ListenableFuture<SessionDescription> createOffer() {
         return Futures.transformAsync(getPeerConnectionFuture(), peerConnection -> {
@@ -330,6 +346,10 @@ public class WebRTCWrapper {
         return peerConnection;
     }
 
+    public AppRTCAudioManager getAudioManager() {
+        return appRTCAudioManager;
+    }
+
     private static abstract class SetSdpObserver implements SdpObserver {
 
         @Override