mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 03:29:28 +01:00
Merge pull request #4878 from gavine99/automagic-bluetooth-on-off
automatic switch to and away from bluetooth audio if no audio actively selected by user
This commit is contained in:
commit
44fc106575
@ -805,9 +805,9 @@ class CallActivity : CallBaseActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (isVoiceOnlyCall) {
|
if (isVoiceOnlyCall) {
|
||||||
setAudioOutputChannel(AudioDevice.EARPIECE)
|
setDefaultAudioOutputChannel(AudioDevice.EARPIECE)
|
||||||
} else {
|
} else {
|
||||||
setAudioOutputChannel(AudioDevice.SPEAKER_PHONE)
|
setDefaultAudioOutputChannel(AudioDevice.SPEAKER_PHONE)
|
||||||
}
|
}
|
||||||
iceServers = ArrayList()
|
iceServers = ArrayList()
|
||||||
|
|
||||||
@ -834,6 +834,13 @@ class CallActivity : CallBaseActivity() {
|
|||||||
microphoneInitialization()
|
microphoneInitialization()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setDefaultAudioOutputChannel(selectedAudioDevice: AudioDevice?) {
|
||||||
|
if (audioManager != null) {
|
||||||
|
audioManager!!.setDefaultAudioDevice(selectedAudioDevice)
|
||||||
|
updateAudioOutputButton(audioManager!!.currentAudioDevice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun setAudioOutputChannel(selectedAudioDevice: AudioDevice?) {
|
fun setAudioOutputChannel(selectedAudioDevice: AudioDevice?) {
|
||||||
if (audioManager != null) {
|
if (audioManager != null) {
|
||||||
audioManager!!.selectAudioDevice(selectedAudioDevice)
|
audioManager!!.selectAudioDevice(selectedAudioDevice)
|
||||||
|
@ -55,11 +55,14 @@ public class WebRtcAudioManager {
|
|||||||
|
|
||||||
private AudioDevice userSelectedAudioDevice;
|
private AudioDevice userSelectedAudioDevice;
|
||||||
private AudioDevice currentAudioDevice;
|
private AudioDevice currentAudioDevice;
|
||||||
|
private AudioDevice defaultAudioDevice;
|
||||||
|
|
||||||
private ProximitySensor proximitySensor = null;
|
private ProximitySensor proximitySensor = null;
|
||||||
|
|
||||||
private Set<AudioDevice> audioDevices = new HashSet<>();
|
private Set<AudioDevice> audioDevices = new HashSet<>();
|
||||||
|
|
||||||
|
private Set<AudioDevice> internalAudioDevices = new HashSet<>();
|
||||||
|
|
||||||
private final BroadcastReceiver wiredHeadsetReceiver;
|
private final BroadcastReceiver wiredHeadsetReceiver;
|
||||||
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener;
|
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener;
|
||||||
|
|
||||||
@ -215,7 +218,9 @@ public class WebRtcAudioManager {
|
|||||||
// Set initial device states.
|
// Set initial device states.
|
||||||
userSelectedAudioDevice = AudioDevice.NONE;
|
userSelectedAudioDevice = AudioDevice.NONE;
|
||||||
currentAudioDevice = AudioDevice.NONE;
|
currentAudioDevice = AudioDevice.NONE;
|
||||||
|
defaultAudioDevice = AudioDevice.NONE;
|
||||||
audioDevices.clear();
|
audioDevices.clear();
|
||||||
|
internalAudioDevices.clear();
|
||||||
|
|
||||||
startBluetoothManager();
|
startBluetoothManager();
|
||||||
|
|
||||||
@ -294,6 +299,18 @@ public class WebRtcAudioManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default audio device to use if selection algo has no other option
|
||||||
|
*/
|
||||||
|
public void setDefaultAudioDevice(AudioDevice device) {
|
||||||
|
ThreadUtils.checkIsOnMainThread();
|
||||||
|
if (!audioDevices.contains(device)) {
|
||||||
|
Log.e(TAG, "Can not select default " + device + " from available " + audioDevices);
|
||||||
|
}
|
||||||
|
defaultAudioDevice = device;
|
||||||
|
updateAudioDeviceState();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes selection of the currently active audio device.
|
* Changes selection of the currently active audio device.
|
||||||
*/
|
*/
|
||||||
@ -392,7 +409,9 @@ public class WebRtcAudioManager {
|
|||||||
+ "wired headset=" + hasWiredHeadset + ", "
|
+ "wired headset=" + hasWiredHeadset + ", "
|
||||||
+ "BT state=" + bluetoothManager.getState());
|
+ "BT state=" + bluetoothManager.getState());
|
||||||
Log.d(TAG, "Device status: "
|
Log.d(TAG, "Device status: "
|
||||||
+ "available=" + audioDevices + ", "
|
+ "internally available=" + internalAudioDevices + ", "
|
||||||
|
+ "externally available=" + audioDevices + ", "
|
||||||
|
+ "default=" + defaultAudioDevice + ", "
|
||||||
+ "current=" + currentAudioDevice + ", "
|
+ "current=" + currentAudioDevice + ", "
|
||||||
+ "user selected=" + userSelectedAudioDevice);
|
+ "user selected=" + userSelectedAudioDevice);
|
||||||
|
|
||||||
@ -402,28 +421,28 @@ public class WebRtcAudioManager {
|
|||||||
bluetoothManager.updateDevice();
|
bluetoothManager.updateDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<AudioDevice> newAudioDevices = new HashSet<>();
|
Set<AudioDevice> newInternalAudioDevices = new HashSet<>();
|
||||||
|
|
||||||
if (bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED
|
if (bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED
|
||||||
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTING
|
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTING
|
||||||
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_AVAILABLE) {
|
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_AVAILABLE) {
|
||||||
newAudioDevices.add(AudioDevice.BLUETOOTH);
|
newInternalAudioDevices.add(AudioDevice.BLUETOOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED) {
|
||||||
|
newInternalAudioDevices.add(AudioDevice.BLUETOOTH_SCO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasWiredHeadset) {
|
if (hasWiredHeadset) {
|
||||||
// If a wired headset is connected, then it is the only possible option.
|
// If a wired headset is connected, then it is the only possible option.
|
||||||
newAudioDevices.add(AudioDevice.WIRED_HEADSET);
|
newInternalAudioDevices.add(AudioDevice.WIRED_HEADSET);
|
||||||
} else {
|
} else {
|
||||||
newAudioDevices.add(AudioDevice.SPEAKER_PHONE);
|
newInternalAudioDevices.add(AudioDevice.SPEAKER_PHONE);
|
||||||
if (hasEarpiece()) {
|
if (hasEarpiece()) {
|
||||||
newAudioDevices.add(AudioDevice.EARPIECE);
|
newInternalAudioDevices.add(AudioDevice.EARPIECE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean audioDeviceSetUpdated = !audioDevices.equals(newAudioDevices);
|
|
||||||
audioDevices = newAudioDevices;
|
|
||||||
|
|
||||||
|
|
||||||
// Correct user selected audio devices if needed.
|
// Correct user selected audio devices if needed.
|
||||||
if (userSelectedAudioDevice == AudioDevice.BLUETOOTH
|
if (userSelectedAudioDevice == AudioDevice.BLUETOOTH
|
||||||
&& bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_UNAVAILABLE) {
|
&& bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_UNAVAILABLE) {
|
||||||
@ -439,14 +458,14 @@ public class WebRtcAudioManager {
|
|||||||
|
|
||||||
// Need to start Bluetooth if it is available and user either selected it explicitly or
|
// Need to start Bluetooth if it is available and user either selected it explicitly or
|
||||||
// user did not select any output device.
|
// user did not select any output device.
|
||||||
boolean needBluetoothAudioStart =
|
boolean needBluetoothScoStart =
|
||||||
bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_AVAILABLE
|
bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_AVAILABLE
|
||||||
&& (userSelectedAudioDevice == AudioDevice.NONE
|
&& (userSelectedAudioDevice == AudioDevice.NONE
|
||||||
|| userSelectedAudioDevice == AudioDevice.BLUETOOTH);
|
|| userSelectedAudioDevice == AudioDevice.BLUETOOTH);
|
||||||
|
|
||||||
// Need to stop Bluetooth audio if user selected different device and
|
// Need to stop Bluetooth audio if user selected different device and
|
||||||
// Bluetooth SCO connection is established or in the process.
|
// Bluetooth SCO connection is established or in the process.
|
||||||
boolean needBluetoothAudioStop =
|
boolean needBluetoothScoStop =
|
||||||
(bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED
|
(bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED
|
||||||
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTING)
|
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTING)
|
||||||
&& (userSelectedAudioDevice != AudioDevice.NONE
|
&& (userSelectedAudioDevice != AudioDevice.NONE
|
||||||
@ -455,44 +474,51 @@ public class WebRtcAudioManager {
|
|||||||
if (bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_AVAILABLE
|
if (bluetoothManager.getState() == WebRtcBluetoothManager.State.HEADSET_AVAILABLE
|
||||||
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTING
|
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTING
|
||||||
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED) {
|
|| bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED) {
|
||||||
Log.d(TAG, "Need BT audio: start=" + needBluetoothAudioStart + ", "
|
Log.d(TAG, "Need BT audio: start=" + needBluetoothScoStart + ", "
|
||||||
+ "stop=" + needBluetoothAudioStop + ", "
|
+ "stop=" + needBluetoothScoStop + ", "
|
||||||
+ "BT state=" + bluetoothManager.getState());
|
+ "BT state=" + bluetoothManager.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start or stop Bluetooth SCO connection given states set earlier.
|
// Start or stop Bluetooth SCO connection given states set earlier.
|
||||||
if (needBluetoothAudioStop) {
|
if (needBluetoothScoStop) {
|
||||||
bluetoothManager.stopScoAudio();
|
bluetoothManager.stopScoAudio();
|
||||||
bluetoothManager.updateDevice();
|
bluetoothManager.updateDevice();
|
||||||
|
} else if (needBluetoothScoStart && !bluetoothManager.startScoAudio()) {
|
||||||
|
// Remove BLUETOOTH and BLUETOOTH_SCO from list of available devices since SCO start has
|
||||||
|
// reported no longer available or too many failed attempts.
|
||||||
|
newInternalAudioDevices.remove(AudioDevice.BLUETOOTH);
|
||||||
|
newInternalAudioDevices.remove(AudioDevice.BLUETOOTH_SCO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to start Bluetooth SCO audio (takes a few second to start).
|
boolean audioDeviceSetUpdated = !internalAudioDevices.equals(newInternalAudioDevices);
|
||||||
if (needBluetoothAudioStart &&
|
internalAudioDevices = newInternalAudioDevices;
|
||||||
!needBluetoothAudioStop &&
|
// BLUETOOTH_SCO isn't allowed to be in the externally accessible list of devices
|
||||||
!bluetoothManager.startScoAudio()) {
|
audioDevices = new HashSet<>(internalAudioDevices);
|
||||||
// Remove BLUETOOTH from list of available devices since SCO failed.
|
audioDevices.remove(AudioDevice.BLUETOOTH_SCO);
|
||||||
audioDevices.remove(AudioDevice.BLUETOOTH);
|
|
||||||
audioDeviceSetUpdated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Update selected audio device.
|
// Update selected audio device.
|
||||||
AudioDevice newCurrentAudioDevice;
|
AudioDevice newCurrentAudioDevice;
|
||||||
|
|
||||||
if (bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED) {
|
if ((bluetoothManager.getState() == WebRtcBluetoothManager.State.SCO_CONNECTED)
|
||||||
// If a Bluetooth is connected, then it should be used as output audio
|
&& newInternalAudioDevices.contains(AudioDevice.BLUETOOTH_SCO))
|
||||||
// device. Note that it is not sufficient that a headset is available;
|
{
|
||||||
// an active SCO channel must also be up and running.
|
// If Bluetooth SCO is connected and available to use, then it has been selected by user or
|
||||||
|
// auto-selected and it should be used as output audio device.
|
||||||
newCurrentAudioDevice = AudioDevice.BLUETOOTH;
|
newCurrentAudioDevice = AudioDevice.BLUETOOTH;
|
||||||
} else if (hasWiredHeadset) {
|
} else if (hasWiredHeadset) {
|
||||||
// If a wired headset is connected, but Bluetooth is not, then wired headset is used as
|
// If a wired headset is connected, but Bluetooth SCO is not, then wired headset is used as
|
||||||
// audio device.
|
// audio device.
|
||||||
newCurrentAudioDevice = AudioDevice.WIRED_HEADSET;
|
newCurrentAudioDevice = AudioDevice.WIRED_HEADSET;
|
||||||
} else {
|
} else {
|
||||||
// No wired headset and no Bluetooth, hence the audio-device list can contain speaker
|
// No wired headset and no Bluetooth SCO, hence the audio-device list can contain speaker
|
||||||
// phone (on a tablet), or speaker phone and earpiece (on mobile phone).
|
// phone (on a tablet), or speaker phone and earpiece (on mobile phone).
|
||||||
// |defaultAudioDevice| contains either AudioDevice.SPEAKER_PHONE or AudioDevice.EARPIECE
|
// |userSelectedAudioDevice| may contain either AudioDevice.SPEAKER_PHONE or AudioDevice.EARPIECE
|
||||||
// depending on the user's selection.
|
// depending on the user's selection. |defaultAudioDevice|, which is set in code depending on
|
||||||
|
// call is audio only or video, to be used if user hasn't made an explicit selection
|
||||||
|
if ((userSelectedAudioDevice == AudioDevice.NONE) && (defaultAudioDevice != AudioDevice.NONE))
|
||||||
|
newCurrentAudioDevice = defaultAudioDevice;
|
||||||
|
else
|
||||||
newCurrentAudioDevice = userSelectedAudioDevice;
|
newCurrentAudioDevice = userSelectedAudioDevice;
|
||||||
}
|
}
|
||||||
// Switch to new device but only if there has been any changes.
|
// Switch to new device but only if there has been any changes.
|
||||||
@ -500,7 +526,8 @@ public class WebRtcAudioManager {
|
|||||||
// Do the required device switch.
|
// Do the required device switch.
|
||||||
setAudioDeviceInternal(newCurrentAudioDevice);
|
setAudioDeviceInternal(newCurrentAudioDevice);
|
||||||
Log.d(TAG, "New device status: "
|
Log.d(TAG, "New device status: "
|
||||||
+ "available=" + audioDevices + ", "
|
+ "internally available=" + internalAudioDevices + ", "
|
||||||
|
+ "externally available=" + audioDevices + ", "
|
||||||
+ "current(new)=" + newCurrentAudioDevice);
|
+ "current(new)=" + newCurrentAudioDevice);
|
||||||
if (audioManagerListener != null) {
|
if (audioManagerListener != null) {
|
||||||
// Notify a listening client that audio device has been changed.
|
// Notify a listening client that audio device has been changed.
|
||||||
@ -514,7 +541,8 @@ public class WebRtcAudioManager {
|
|||||||
* AudioDevice is the names of possible audio devices that we currently support.
|
* AudioDevice is the names of possible audio devices that we currently support.
|
||||||
*/
|
*/
|
||||||
public enum AudioDevice {
|
public enum AudioDevice {
|
||||||
SPEAKER_PHONE, WIRED_HEADSET, EARPIECE, BLUETOOTH, NONE
|
SPEAKER_PHONE, WIRED_HEADSET, EARPIECE, BLUETOOTH, NONE,
|
||||||
|
BLUETOOTH_SCO // BLUETOOTH_SCO is only valid internal to this class
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user