From 981aeaf264c90b4a4d645040c816e2b175e76c72 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 13 Apr 2020 12:53:23 +0200 Subject: [PATCH] make mute and speaker button work --- .../conversations/ui/RtpSessionActivity.java | 94 +++++++++++++++++- .../xmpp/jingle/JingleRtpConnection.java | 12 +++ .../xmpp/jingle/WebRTCWrapper.java | 26 ++++- .../ic_bluetooth_audio_black_24dp.png | Bin 0 -> 420 bytes .../drawable-hdpi/ic_headset_black_24dp.png | Bin 0 -> 349 bytes .../ic_bluetooth_audio_black_24dp.png | Bin 0 -> 283 bytes .../drawable-mdpi/ic_headset_black_24dp.png | Bin 0 -> 230 bytes .../ic_bluetooth_audio_black_24dp.png | Bin 0 -> 479 bytes .../drawable-xhdpi/ic_headset_black_24dp.png | Bin 0 -> 412 bytes .../ic_bluetooth_audio_black_24dp.png | Bin 0 -> 724 bytes .../drawable-xxhdpi/ic_headset_black_24dp.png | Bin 0 -> 586 bytes .../ic_bluetooth_audio_black_24dp.png | Bin 0 -> 867 bytes .../ic_headset_black_24dp.png | Bin 0 -> 786 bytes 13 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 src/main/res/drawable-hdpi/ic_bluetooth_audio_black_24dp.png create mode 100644 src/main/res/drawable-hdpi/ic_headset_black_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_bluetooth_audio_black_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_headset_black_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_bluetooth_audio_black_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_headset_black_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_bluetooth_audio_black_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_headset_black_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_bluetooth_audio_black_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_headset_black_24dp.png diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index bdef662bd..7e1b3592e 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/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 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) { 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 d3dba70a9..b8a67cb0e 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/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 availableAudioDevices) { xmppConnectionService.notifyJingleRtpConnectionUpdate(selectedAudioDevice, availableAudioDevices); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java index 0b776e431..e21a65f19 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java +++ b/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 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 diff --git a/src/main/res/drawable-hdpi/ic_bluetooth_audio_black_24dp.png b/src/main/res/drawable-hdpi/ic_bluetooth_audio_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..14a5a5584a2a102a8862f1166bdfe6582989212f GIT binary patch literal 420 zcmV;V0bBlwP)I|gBTHP1$*&QS$G4HU@ur|DPY}(`MxSAm4S5Ph8(+d#5D{WbrGk(V z4u{MjF_{h1>3?CfGsFHC&Yqp{H&ez?4g>|D6jCY-Gz66+>ItQ!PUsLTWucF>RE`b? zV=0BMxJgGvRP}}`5$;>da@&JiB|n&|5jhZy^Q)-& z<8v5HB~;}1lDdOy7~uuOBlM#Zz42Aftsj+}L81?w@}u-{m_=Gj9mxD9{bH-4N9-_$ zJpk5ZRoG$H3h(L(nC O00009xqKhbqYg4a7Y6r1bpj4a$C&?w)P)eYfU2qLf;vGmc6!8M;2i}O(OeVF$ z%R2;44n55v1o}H$-ltDFAN-FUI`{+x_#CrM1?zN4$e0&a#)wnaa7UX@=9cwA3rBrs z`lA^WVj?19UisCpIXxWQX?)5MkD?|weCza<1^OBs)1ZvUvnH;=uC1GTU;~>?9(98U z)|=8J9&3%g>P2#Iwj1o~*)&+BNh;YBN+mKJ;v$mlQ~4{-R$3!7y=nYD92OkVF+aq;!5-NDJrheHBufm*CJ;oC8=@+t!@p>$f}a hK5f7SZNQ}^?i-8UfZfY2g-`$h002ovPDHLkV1nmwdAk4r literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_headset_black_24dp.png b/src/main/res/drawable-mdpi/ic_headset_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d872b05d5c54f5bab40e21c182bd41f2124e4dac GIT binary patch literal 230 zcmVt!WO>|nVbGP2b+NB*j8_^s1Z)hggMwA+J(Q8m@%)~RL zu~-_|<;;h;R_Mh<&7F8uScp!|g?LriidN03_*RIhBXVf)x5|Hn!PnkkrSPyfm@2gH geO7~&sS`)z7w37E&qCDKX8-^I07*qoM6N<$f~VSMG5`Po literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_bluetooth_audio_black_24dp.png b/src/main/res/drawable-xhdpi/ic_bluetooth_audio_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..c1d6b931dc0c7f2a629e528f44e6def0eddd546d GIT binary patch literal 479 zcmV<50U-W~P)k

O;i9j5G`(4h@l3OM2iK-U?da(uVgN`LkKrn;P^|M zjTu&mkpjk)QvU!6_rmrq*a-n*^^!}!|H&0IAwadh%X%J$+kO5kBZLqjR^Q|n_*@Iu z8CVGYE9h0~zcH2Ri@%>k4MNpB-phRIpZJU+<29mG^^WhddF|&Fn2AKaqmbRq&wuIw zec9h;sR5bo^$B7rn>T*`VXsdU7c!suCqCNi)5Jukul{~$trvzOO0>Y|dbmEe*7pVI z#t6xyaBExZ5deA#;)CCRve#DtPn1!j6Shx`^$LKOGMDOw^NXv-dIfY?$^1;cGN0P& z6%enNG&vxdchPzQRJ}P3j*=f&aX%zzcFk>UT2x`~!8& V1Rl8!)*k=>002ovPDHLkV1m0l*M|TA literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_headset_black_24dp.png b/src/main/res/drawable-xhdpi/ic_headset_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f2664dcde2705ebf36252d28c5a116286b9fca14 GIT binary patch literal 412 zcmV;N0b~A&P)8G96VOKO`}$sT|iMQYZrlc5P1WUNP$7ul0~cV4uVz{K@nmDz8WG9OUE?D!|N9(K&C9!(MXRhL7nrzG+goVWRiuiEeYJgpR!2n&m{?WY zcWCugB!h`5wf&CPKt)_kB-QpOTAmtHvTqB_3p8V%w*|Jq7W{p|M=S+>v|6zgG|<|O zrJ#aVlE;w?+PL_b;bEkLHq!)1vO|-8O=2U-Y;$%Z=o6 zBe~p2E;o|PjpVkTbb$#fHYhzwa~5$lOp;4a3OP=ZEYQc4B;m+t3dsT;PEC5IK3s&61BNrMV{Cdbbmuj5!8QkzNuD(I@Nj>qw{ zmtWE|2JuM#&mpHRoG=s8^&U1#YU^L9o<_*AbJgoS5RIgVdVYQi9^+>p%hG!pl9Dt> zcGn5~e30%3ke1X^oWa$zH-euh(%)cHDgHrfYL5J6dWxS>S@9OqkwVUt)ZXFerp$kZ zRHOzr$FYE)i!%Qk(vUQ#N*}-e2S2C0%Fe9;4e<&abXw+@lW=4Q*`#myxg_&HQf}&2 zK$Rnmy@PsDgKj*Lz~dX3{aerBcnc0!Jft|qDH zaM0^L8H>|UCoCk{xgmYu8HmJD7qsvS*JBVX9qD==kE5@!A!*Ve?Pp1PuEgVL&|0La zHA!`;FHnufQ6PO^vPrx7BGpGRISM2z`f5dAZQF_*hb3yUI5y}gpVXSWs0e917RLq+ z+nj*(lS6Si3S@H((izs37Y4@$4Kp8bBIYcMHYWs8OU99$Th~iZ&8d?h=QsRXxSrRG z^E%rUo0Adf9^07AION75GmZj{l0h=#kQ)b!lYh#TDf1UPWQQxijuDvv0000veM1>mHdB7GiIw6lxcre07Lit-38RazRxWl`IQ!PfwNF~hKr;d#| z-X}~_WMW>{FIE`B)-X+eV_sYa4WsNMlen7VlhJaMl&Z#?^@=iSjPV97@{@5=*)isv zA+59Q8UL43STHWDOcrCt#WiqL;v4c&o+PV_$jAFL5l)uTA}jcCA1!hh2MYN`-)9IP zhWQ{`4^dc~MT^w&*n&_zwp|Z_C3shpdd)D#)zUZY9RzW1%-%Buro~* zG%ARljY85`*}Qvm6(mS9HbMMmcm3|L_hT}!XSnmwJLrJ;9}(;8IU;sVBJ96I|*EZl@*;utcqNK(vGb-r#7VC%A|SioWY8 z!Np6^^|J|jz>7!;QePbF)B*zfVka!&aD@qa0I?HltSbpxK>36o+XOwJT*5V`z%)S* zD3Nd-$5#$oC5-CuJAuY=W_= z>a=t9htb&W{hZTuje22%cTUmQcqmpq2J3{jeg;RgK)(;4f5f`aV3?pEivBdS`0Qs( ztUVq-p~*;rzGICn@5Sl~h?Jn{U)ml&fzN%heg?Xq&<@Za{jI)Z5}z~T3JVY~p;e$i z^UIvO`1~!du>y7p<@FuU@i`^NSHUtNT>r8+Zw;SA-u;6Z2`$Dt(sz8pr&o+`fN4TW zea9v~Jz{)oCk5Q;DBuq<{@q-^WI`LCJ#svPeo(@y@<;qBf__lKva&CG7ePNLVP3hB zJ&B;N-3>&-f6Al8?Fjlo3CHlcC)Q8K)z=a}s*lqnk@b~?tICGv8@sIaTiM-jz+?43 zWlQw~#|VE~Ni3F@oG zhP{4q0F2TKOc?Z@Q;(SHs{!E&3u4})wZ0wzV?hZw#jHQg^-KJV=`8u&lAC>7eLbL$ zm$~{=_+)`i4AJ^p$|v`mmSR0s7g1 zeqQD3Hvl3egnsZ8Utc7Ie{vR6UnF$#qrXPlpItWC;i&p42V5Wl64xhneNxvab$t~5 t1OqOT7>VnXx<0Av6GOkEqN1Xr;s*_K4zEGH2DShI002ovPDHLkV1gV_nlAtV literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_headset_black_24dp.png b/src/main/res/drawable-xxxhdpi/ic_headset_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..974457ee1dc25f4c8e68fb4908cd1d5eb4639e0c GIT binary patch literal 786 zcmV+t1MU2YP)*g2?U|Ie)Zs)xOsK$73 zW@#q~9V{8TXNVIN>Smzv`cLUlcrtJ8 z{E_4vHH`-`a-vNSwj33cH~0_NI+1Vmo!C-GQB2>DYeS;N0ye$!fBVmf7Sq^tLrlMk zYiZG90GkHI^vAfC5iPo~>42F28rN1tixf7=OLQ66Y6;rV%StArWbI{ z5oMd4uK{e+02)98XaHAbr@sc!02)98XaEhM0W^RH&;S}h184vZU?IR}qypq|Z7EU# zvbgpnQUTJqb}3Q;MsY1gF){%PG~>bj$OM?hlV;W<5nzo*JUSkM03~|y;T)xk1}HI% zPsjLCu>foI5`ZS|QLrAMz$}dfCdmcTWXXpfAWxPwqco$GQc5YMlu~8=1ygWd*VB(W Qz5oCK07*qoM6N<$g5iW