Fix bluetooth behavior.

This commit is contained in:
Alex Hart 2020-05-28 17:36:40 -03:00 committed by GitHub
parent 6b47618351
commit cd1bad0718
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 188 additions and 39 deletions

View File

@ -55,7 +55,7 @@ public class WebRtcAudioOutputToggleButton extends AppCompatImageView {
List<WebRtcAudioOutput> availableModes = buildOutputModeList(isHeadsetAvailable, isHandsetAvailable);
if (availableModes.size() > 2 || !isHandsetAvailable) showPicker(availableModes);
else setAudioOutput(OUTPUT_MODES.get((outputIndex + 1) % OUTPUT_MODES.size()));
else setAudioOutput(OUTPUT_MODES.get((outputIndex + 1) % OUTPUT_MODES.size()), true);
});
}
@ -83,13 +83,16 @@ public class WebRtcAudioOutputToggleButton extends AppCompatImageView {
this.isHeadsetAvailable = isHeadsetAvailable;
}
public void setAudioOutput(@NonNull WebRtcAudioOutput audioOutput) {
public void setAudioOutput(@NonNull WebRtcAudioOutput audioOutput, boolean notifyListener) {
int oldIndex = outputIndex;
outputIndex = resolveAudioOutputIndex(OUTPUT_MODES.lastIndexOf(audioOutput));
if (oldIndex != outputIndex) {
refreshDrawableState();
notifyListener();
if (notifyListener) {
notifyListener();
}
}
}
@ -100,7 +103,7 @@ public class WebRtcAudioOutputToggleButton extends AppCompatImageView {
private void showPicker(@NonNull List<WebRtcAudioOutput> availableModes) {
RecyclerView rv = new RecyclerView(getContext());
AudioOutputAdapter adapter = new AudioOutputAdapter(audioOutput -> {
setAudioOutput(audioOutput);
setAudioOutput(audioOutput, true);
hidePicker();
},
availableModes);
@ -138,7 +141,8 @@ public class WebRtcAudioOutputToggleButton extends AppCompatImageView {
isHandsetAvailable = savedState.getBoolean(STATE_HANDSET_ENABLED);
setAudioOutput(OUTPUT_MODES.get(
resolveAudioOutputIndex(savedState.getInt(STATE_OUTPUT_INDEX)))
resolveAudioOutputIndex(savedState.getInt(STATE_OUTPUT_INDEX))),
false
);
super.onRestoreInstanceState(savedState.getParcelable(STATE_PARENT));

View File

@ -196,10 +196,6 @@ public class WebRtcCallView extends FrameLayout {
micToggle.setChecked(isMicEnabled, false);
}
public void setAudioOutput(WebRtcAudioOutput output) {
audioToggle.setAudioOutput(output);
}
public void setRemoteVideoEnabled(boolean isRemoteVideoEnabled) {
if (isRemoteVideoEnabled) {
remoteRenderContainer.setVisibility(View.VISIBLE);
@ -333,7 +329,7 @@ public class WebRtcCallView extends FrameLayout {
audioToggle.setControlAvailability(webRtcControls.enableHandsetInAudioToggle(),
webRtcControls.enableHeadsetInAudioToggle());
audioToggle.setAudioOutput(webRtcControls.getAudioOutput());
audioToggle.setAudioOutput(webRtcControls.getAudioOutput(), false);
}
if (webRtcControls.displayCameraToggle()) {

View File

@ -482,10 +482,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
boolean isSpeaker = intent.getBooleanExtra(EXTRA_SPEAKER, false);
AudioManager audioManager = ServiceUtil.getAudioManager(this);
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.stopBluetoothSco();
audioManager.setBluetoothScoOn(false);
audioManager.setSpeakerphoneOn(true);
bluetoothStateManager.setWantsConnection(false);
audioManager.setSpeakerphoneOn(isSpeaker);
if (!localCameraState.isEnabled()) {
@ -499,15 +496,8 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
private void handleSetBluetoothAudio(Intent intent) {
boolean isBluetooth = intent.getBooleanExtra(EXTRA_BLUETOOTH, false);
AudioManager audioManager = ServiceUtil.getAudioManager(this);
if (isBluetooth) {
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
} else {
audioManager.stopBluetoothSco();
audioManager.setBluetoothScoOn(false);
}
bluetoothStateManager.setWantsConnection(isBluetooth);
if (!localCameraState.isEnabled()) {
lockManager.updatePhoneState(getInCallPhoneState());

View File

@ -0,0 +1,143 @@
package org.thoughtcrime.securesms.webrtc.audio;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import org.thoughtcrime.securesms.util.ServiceUtil;
public abstract class AudioManagerCompat {
protected final AudioManager audioManager;
private AudioManagerCompat(@NonNull Context context) {
audioManager = ServiceUtil.getAudioManager(context);
}
abstract public SoundPool createSoundPool();
abstract public void requestCallAudioFocus();
abstract public void abandonCallAudioFocus();
public static AudioManagerCompat create(@NonNull Context context) {
if (Build.VERSION.SDK_INT >= 26) {
return new Api26AudioManagerCompat(context);
} else if (Build.VERSION.SDK_INT >= 21) {
return new Api21AudioManagerCompat(context);
} else {
return new Api19AudioManagerCompat(context);
}
}
@RequiresApi(26)
private static class Api26AudioManagerCompat extends AudioManagerCompat {
private static AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build();
private AudioFocusRequest audioFocusRequest;
private Api26AudioManagerCompat(@NonNull Context context) {
super(context);
}
@Override
public SoundPool createSoundPool() {
return new SoundPool.Builder()
.setAudioAttributes(AUDIO_ATTRIBUTES)
.setMaxStreams(1)
.build();
}
@Override
public void requestCallAudioFocus() {
if (audioFocusRequest != null) {
throw new IllegalStateException("Already focused.");
}
audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
.setAudioAttributes(AUDIO_ATTRIBUTES)
.build();
int result = audioManager.requestAudioFocus(audioFocusRequest);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
throw new IllegalStateException("Got " + result);
}
}
@Override
public void abandonCallAudioFocus() {
if (audioFocusRequest == null) {
throw new IllegalStateException("Not focused.");
}
int result = audioManager.abandonAudioFocusRequest(audioFocusRequest);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
throw new IllegalStateException("Got " + result);
}
audioFocusRequest = null;
}
}
@RequiresApi(21)
private static class Api21AudioManagerCompat extends Api19AudioManagerCompat {
private static AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setLegacyStreamType(AudioManager.STREAM_VOICE_CALL)
.build();
private Api21AudioManagerCompat(@NonNull Context context) {
super(context);
}
@Override
public SoundPool createSoundPool() {
return new SoundPool.Builder()
.setAudioAttributes(AUDIO_ATTRIBUTES)
.setMaxStreams(1)
.build();
}
}
private static class Api19AudioManagerCompat extends AudioManagerCompat {
private Api19AudioManagerCompat(@NonNull Context context) {
super(context);
}
@Override
public SoundPool createSoundPool() {
return new SoundPool(1, AudioManager.STREAM_VOICE_CALL, 0);
}
@Override
public void requestCallAudioFocus() {
int result = audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
throw new IllegalStateException("Got " + result);
}
}
@Override
public void abandonCallAudioFocus() {
int result = audioManager.abandonAudioFocus(null);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
throw new IllegalStateException("Got " + result);
}
}
}
}

View File

@ -23,7 +23,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class BluetoothStateManager {
private static final String TAG = BluetoothStateManager.class.getSimpleName();
private static final String TAG = Log.tag(BluetoothStateManager.class);
private enum ScoConnection {
DISCONNECTED,

View File

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.webrtc.audio;
import android.annotation.TargetApi;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
@ -109,7 +110,15 @@ public class IncomingRinger {
mediaPlayer.setOnErrorListener(new MediaPlayerErrorListener());
mediaPlayer.setDataSource(context, ringtoneUri);
mediaPlayer.setLooping(true);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
if (Build.VERSION.SDK_INT <= 21) {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
} else {
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
.build());
}
return mediaPlayer;
} catch (IOException e) {

View File

@ -1,9 +1,12 @@
package org.thoughtcrime.securesms.webrtc.audio;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.logging.Log;
@ -40,7 +43,15 @@ public class OutgoingRinger {
}
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
if (Build.VERSION.SDK_INT <= 21) {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
} else {
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build());
}
mediaPlayer.setLooping(true);
String packageName = context.getPackageName();

View File

@ -25,19 +25,21 @@ public class SignalAudioManager {
private final int connectedSoundId;
private final int disconnectedSoundId;
private final AudioManagerCompat audioManagerCompat;
public SignalAudioManager(@NonNull Context context) {
this.context = context.getApplicationContext();
this.incomingRinger = new IncomingRinger(context);
this.outgoingRinger = new OutgoingRinger(context);
this.soundPool = new SoundPool(1, AudioManager.STREAM_VOICE_CALL, 0);
this.context = context.getApplicationContext();
this.incomingRinger = new IncomingRinger(context);
this.outgoingRinger = new OutgoingRinger(context);
this.audioManagerCompat = AudioManagerCompat.create(context);
this.soundPool = audioManagerCompat.createSoundPool();
this.connectedSoundId = this.soundPool.load(context, R.raw.webrtc_completed, 1);
this.disconnectedSoundId = this.soundPool.load(context, R.raw.webrtc_disconnected, 1);
}
public void initializeAudioForCall() {
AudioManager audioManager = ServiceUtil.getAudioManager(context);
audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);
audioManagerCompat.requestCallAudioFocus();
}
public void startIncomingRinger(@Nullable Uri ringtoneUri, boolean vibrate) {
@ -89,14 +91,8 @@ public class SignalAudioManager {
soundPool.play(disconnectedSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
}
if (audioManager.isBluetoothScoOn()) {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
}
audioManager.setSpeakerphoneOn(false);
audioManager.setMicrophoneMute(false);
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.abandonAudioFocus(null);
audioManagerCompat.abandonCallAudioFocus();
}
}