mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 05:48:34 +00:00
Fix bluetooth behavior.
This commit is contained in:
parent
6b47618351
commit
cd1bad0718
@ -55,7 +55,7 @@ public class WebRtcAudioOutputToggleButton extends AppCompatImageView {
|
|||||||
List<WebRtcAudioOutput> availableModes = buildOutputModeList(isHeadsetAvailable, isHandsetAvailable);
|
List<WebRtcAudioOutput> availableModes = buildOutputModeList(isHeadsetAvailable, isHandsetAvailable);
|
||||||
|
|
||||||
if (availableModes.size() > 2 || !isHandsetAvailable) showPicker(availableModes);
|
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;
|
this.isHeadsetAvailable = isHeadsetAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAudioOutput(@NonNull WebRtcAudioOutput audioOutput) {
|
public void setAudioOutput(@NonNull WebRtcAudioOutput audioOutput, boolean notifyListener) {
|
||||||
int oldIndex = outputIndex;
|
int oldIndex = outputIndex;
|
||||||
outputIndex = resolveAudioOutputIndex(OUTPUT_MODES.lastIndexOf(audioOutput));
|
outputIndex = resolveAudioOutputIndex(OUTPUT_MODES.lastIndexOf(audioOutput));
|
||||||
|
|
||||||
if (oldIndex != outputIndex) {
|
if (oldIndex != outputIndex) {
|
||||||
refreshDrawableState();
|
refreshDrawableState();
|
||||||
notifyListener();
|
|
||||||
|
if (notifyListener) {
|
||||||
|
notifyListener();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ public class WebRtcAudioOutputToggleButton extends AppCompatImageView {
|
|||||||
private void showPicker(@NonNull List<WebRtcAudioOutput> availableModes) {
|
private void showPicker(@NonNull List<WebRtcAudioOutput> availableModes) {
|
||||||
RecyclerView rv = new RecyclerView(getContext());
|
RecyclerView rv = new RecyclerView(getContext());
|
||||||
AudioOutputAdapter adapter = new AudioOutputAdapter(audioOutput -> {
|
AudioOutputAdapter adapter = new AudioOutputAdapter(audioOutput -> {
|
||||||
setAudioOutput(audioOutput);
|
setAudioOutput(audioOutput, true);
|
||||||
hidePicker();
|
hidePicker();
|
||||||
},
|
},
|
||||||
availableModes);
|
availableModes);
|
||||||
@ -138,7 +141,8 @@ public class WebRtcAudioOutputToggleButton extends AppCompatImageView {
|
|||||||
isHandsetAvailable = savedState.getBoolean(STATE_HANDSET_ENABLED);
|
isHandsetAvailable = savedState.getBoolean(STATE_HANDSET_ENABLED);
|
||||||
|
|
||||||
setAudioOutput(OUTPUT_MODES.get(
|
setAudioOutput(OUTPUT_MODES.get(
|
||||||
resolveAudioOutputIndex(savedState.getInt(STATE_OUTPUT_INDEX)))
|
resolveAudioOutputIndex(savedState.getInt(STATE_OUTPUT_INDEX))),
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
super.onRestoreInstanceState(savedState.getParcelable(STATE_PARENT));
|
super.onRestoreInstanceState(savedState.getParcelable(STATE_PARENT));
|
||||||
|
@ -196,10 +196,6 @@ public class WebRtcCallView extends FrameLayout {
|
|||||||
micToggle.setChecked(isMicEnabled, false);
|
micToggle.setChecked(isMicEnabled, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAudioOutput(WebRtcAudioOutput output) {
|
|
||||||
audioToggle.setAudioOutput(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRemoteVideoEnabled(boolean isRemoteVideoEnabled) {
|
public void setRemoteVideoEnabled(boolean isRemoteVideoEnabled) {
|
||||||
if (isRemoteVideoEnabled) {
|
if (isRemoteVideoEnabled) {
|
||||||
remoteRenderContainer.setVisibility(View.VISIBLE);
|
remoteRenderContainer.setVisibility(View.VISIBLE);
|
||||||
@ -333,7 +329,7 @@ public class WebRtcCallView extends FrameLayout {
|
|||||||
audioToggle.setControlAvailability(webRtcControls.enableHandsetInAudioToggle(),
|
audioToggle.setControlAvailability(webRtcControls.enableHandsetInAudioToggle(),
|
||||||
webRtcControls.enableHeadsetInAudioToggle());
|
webRtcControls.enableHeadsetInAudioToggle());
|
||||||
|
|
||||||
audioToggle.setAudioOutput(webRtcControls.getAudioOutput());
|
audioToggle.setAudioOutput(webRtcControls.getAudioOutput(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webRtcControls.displayCameraToggle()) {
|
if (webRtcControls.displayCameraToggle()) {
|
||||||
|
@ -482,10 +482,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
|
|||||||
boolean isSpeaker = intent.getBooleanExtra(EXTRA_SPEAKER, false);
|
boolean isSpeaker = intent.getBooleanExtra(EXTRA_SPEAKER, false);
|
||||||
AudioManager audioManager = ServiceUtil.getAudioManager(this);
|
AudioManager audioManager = ServiceUtil.getAudioManager(this);
|
||||||
|
|
||||||
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
bluetoothStateManager.setWantsConnection(false);
|
||||||
audioManager.stopBluetoothSco();
|
|
||||||
audioManager.setBluetoothScoOn(false);
|
|
||||||
audioManager.setSpeakerphoneOn(true);
|
|
||||||
audioManager.setSpeakerphoneOn(isSpeaker);
|
audioManager.setSpeakerphoneOn(isSpeaker);
|
||||||
|
|
||||||
if (!localCameraState.isEnabled()) {
|
if (!localCameraState.isEnabled()) {
|
||||||
@ -499,15 +496,8 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
|
|||||||
|
|
||||||
private void handleSetBluetoothAudio(Intent intent) {
|
private void handleSetBluetoothAudio(Intent intent) {
|
||||||
boolean isBluetooth = intent.getBooleanExtra(EXTRA_BLUETOOTH, false);
|
boolean isBluetooth = intent.getBooleanExtra(EXTRA_BLUETOOTH, false);
|
||||||
AudioManager audioManager = ServiceUtil.getAudioManager(this);
|
|
||||||
|
|
||||||
if (isBluetooth) {
|
bluetoothStateManager.setWantsConnection(isBluetooth);
|
||||||
audioManager.startBluetoothSco();
|
|
||||||
audioManager.setBluetoothScoOn(true);
|
|
||||||
} else {
|
|
||||||
audioManager.stopBluetoothSco();
|
|
||||||
audioManager.setBluetoothScoOn(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!localCameraState.isEnabled()) {
|
if (!localCameraState.isEnabled()) {
|
||||||
lockManager.updatePhoneState(getInCallPhoneState());
|
lockManager.updatePhoneState(getInCallPhoneState());
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
public class BluetoothStateManager {
|
public class BluetoothStateManager {
|
||||||
|
|
||||||
private static final String TAG = BluetoothStateManager.class.getSimpleName();
|
private static final String TAG = Log.tag(BluetoothStateManager.class);
|
||||||
|
|
||||||
private enum ScoConnection {
|
private enum ScoConnection {
|
||||||
DISCONNECTED,
|
DISCONNECTED,
|
||||||
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.webrtc.audio;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -109,7 +110,15 @@ public class IncomingRinger {
|
|||||||
mediaPlayer.setOnErrorListener(new MediaPlayerErrorListener());
|
mediaPlayer.setOnErrorListener(new MediaPlayerErrorListener());
|
||||||
mediaPlayer.setDataSource(context, ringtoneUri);
|
mediaPlayer.setDataSource(context, ringtoneUri);
|
||||||
mediaPlayer.setLooping(true);
|
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;
|
return mediaPlayer;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package org.thoughtcrime.securesms.webrtc.audio;
|
package org.thoughtcrime.securesms.webrtc.audio;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
|
||||||
@ -40,7 +43,15 @@ public class OutgoingRinger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mediaPlayer = new MediaPlayer();
|
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);
|
mediaPlayer.setLooping(true);
|
||||||
|
|
||||||
String packageName = context.getPackageName();
|
String packageName = context.getPackageName();
|
||||||
|
@ -25,19 +25,21 @@ public class SignalAudioManager {
|
|||||||
private final int connectedSoundId;
|
private final int connectedSoundId;
|
||||||
private final int disconnectedSoundId;
|
private final int disconnectedSoundId;
|
||||||
|
|
||||||
|
private final AudioManagerCompat audioManagerCompat;
|
||||||
|
|
||||||
public SignalAudioManager(@NonNull Context context) {
|
public SignalAudioManager(@NonNull Context context) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.incomingRinger = new IncomingRinger(context);
|
this.incomingRinger = new IncomingRinger(context);
|
||||||
this.outgoingRinger = new OutgoingRinger(context);
|
this.outgoingRinger = new OutgoingRinger(context);
|
||||||
this.soundPool = new SoundPool(1, AudioManager.STREAM_VOICE_CALL, 0);
|
this.audioManagerCompat = AudioManagerCompat.create(context);
|
||||||
|
this.soundPool = audioManagerCompat.createSoundPool();
|
||||||
|
|
||||||
this.connectedSoundId = this.soundPool.load(context, R.raw.webrtc_completed, 1);
|
this.connectedSoundId = this.soundPool.load(context, R.raw.webrtc_completed, 1);
|
||||||
this.disconnectedSoundId = this.soundPool.load(context, R.raw.webrtc_disconnected, 1);
|
this.disconnectedSoundId = this.soundPool.load(context, R.raw.webrtc_disconnected, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeAudioForCall() {
|
public void initializeAudioForCall() {
|
||||||
AudioManager audioManager = ServiceUtil.getAudioManager(context);
|
audioManagerCompat.requestCallAudioFocus();
|
||||||
audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startIncomingRinger(@Nullable Uri ringtoneUri, boolean vibrate) {
|
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);
|
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.setMode(AudioManager.MODE_NORMAL);
|
||||||
audioManager.abandonAudioFocus(null);
|
|
||||||
|
audioManagerCompat.abandonCallAudioFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user