mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-16 01:05:04 +01:00
select audio device (WIP)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
9b889d232f
commit
9c0fa9acc2
@ -32,7 +32,6 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
@ -84,7 +83,6 @@ import com.nextcloud.talk.models.json.signaling.SignalingOverall;
|
|||||||
import com.nextcloud.talk.models.json.signaling.settings.IceServer;
|
import com.nextcloud.talk.models.json.signaling.settings.IceServer;
|
||||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
|
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
|
||||||
import com.nextcloud.talk.ui.dialog.AudioOutputDialog;
|
import com.nextcloud.talk.ui.dialog.AudioOutputDialog;
|
||||||
import com.nextcloud.talk.ui.dialog.ScopeDialog;
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils;
|
import com.nextcloud.talk.utils.ApiUtils;
|
||||||
import com.nextcloud.talk.utils.DisplayUtils;
|
import com.nextcloud.talk.utils.DisplayUtils;
|
||||||
import com.nextcloud.talk.utils.NotificationUtils;
|
import com.nextcloud.talk.utils.NotificationUtils;
|
||||||
@ -145,6 +143,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
import androidx.core.graphics.drawable.DrawableCompat;
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
@ -335,17 +334,6 @@ public class CallActivity extends CallBaseActivity {
|
|||||||
this
|
this
|
||||||
).show());
|
).show());
|
||||||
|
|
||||||
// binding.audioOutputButton.setOnClickListener(l -> {
|
|
||||||
// if (audioManager != null) {
|
|
||||||
// audioManager.toggleUseSpeakerphone();
|
|
||||||
// if (audioManager.isSpeakerphoneAutoOn()) {
|
|
||||||
// binding.audioOutputButton.getHierarchy().setPlaceholderImage(R.drawable.ic_volume_up_white_24dp);
|
|
||||||
// } else {
|
|
||||||
// binding.audioOutputButton.getHierarchy().setPlaceholderImage(R.drawable.ic_volume_mute_white_24dp);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
binding.microphoneButton.setOnClickListener(l -> onMicrophoneClick());
|
binding.microphoneButton.setOnClickListener(l -> onMicrophoneClick());
|
||||||
binding.microphoneButton.setOnLongClickListener(l -> {
|
binding.microphoneButton.setOnLongClickListener(l -> {
|
||||||
if (!microphoneOn) {
|
if (!microphoneOn) {
|
||||||
@ -381,9 +369,31 @@ public class CallActivity extends CallBaseActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAudioOutputIcon(Drawable drawable){
|
public void setAudioOutputChannel(MagicAudioManager.AudioDevice audioDevice) {
|
||||||
binding.audioOutputButton.getHierarchy().setPlaceholderImage(drawable);
|
if (audioManager == null) {
|
||||||
DrawableCompat.setTint(drawable, Color.WHITE);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioManager.selectAudioDevice(audioDevice);
|
||||||
|
|
||||||
|
switch (audioManager.getResultingAudioDevice()) {
|
||||||
|
case BLUETOOTH:
|
||||||
|
binding.audioOutputButton.getHierarchy().setPlaceholderImage(
|
||||||
|
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_bluetooth_audio_24));
|
||||||
|
break;
|
||||||
|
case SPEAKER_PHONE:
|
||||||
|
binding.audioOutputButton.getHierarchy().setPlaceholderImage(
|
||||||
|
AppCompatResources.getDrawable(context, R.drawable.ic_volume_up_white_24dp));
|
||||||
|
break;
|
||||||
|
case EARPIECE:
|
||||||
|
binding.audioOutputButton.getHierarchy().setPlaceholderImage(
|
||||||
|
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_phone_in_talk_24));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Invalid audio device selection");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DrawableCompat.setTint(binding.audioOutputButton.getDrawable(), Color.WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCameraEnumerator() {
|
private void createCameraEnumerator() {
|
||||||
@ -391,7 +401,7 @@ public class CallActivity extends CallBaseActivity {
|
|||||||
try {
|
try {
|
||||||
camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(this);
|
camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(this);
|
||||||
} catch (final Throwable throwable) {
|
} catch (final Throwable throwable) {
|
||||||
Log.w(TAG, "Camera2Enumator threw an error");
|
Log.w(TAG, "Camera2Enumerator threw an error");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (camera2EnumeratorIsSupported) {
|
if (camera2EnumeratorIsSupported) {
|
||||||
@ -726,7 +736,8 @@ public class CallActivity extends CallBaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onAudioManagerDevicesChanged(
|
private void onAudioManagerDevicesChanged(
|
||||||
final MagicAudioManager.AudioDevice device, final Set<MagicAudioManager.AudioDevice> availableDevices) {
|
final MagicAudioManager.AudioDevice device,
|
||||||
|
final Set<MagicAudioManager.AudioDevice> availableDevices) {
|
||||||
Log.d(TAG, "onAudioManagerDevicesChanged: " + availableDevices + ", "
|
Log.d(TAG, "onAudioManagerDevicesChanged: " + availableDevices + ", "
|
||||||
+ "selected: " + device);
|
+ "selected: " + device);
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
package com.nextcloud.talk.ui.dialog
|
package com.nextcloud.talk.ui.dialog
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
@ -31,6 +30,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
|||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
import com.nextcloud.talk.activities.CallActivity
|
import com.nextcloud.talk.activities.CallActivity
|
||||||
import com.nextcloud.talk.databinding.DialogAudioOutputBinding
|
import com.nextcloud.talk.databinding.DialogAudioOutputBinding
|
||||||
|
import com.nextcloud.talk.webrtc.MagicAudioManager
|
||||||
|
|
||||||
class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(callActivity) {
|
class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(callActivity) {
|
||||||
|
|
||||||
@ -44,22 +44,17 @@ class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(call
|
|||||||
|
|
||||||
|
|
||||||
dialogAudioOutputBinding.audioOutputBluetooth.setOnClickListener {
|
dialogAudioOutputBinding.audioOutputBluetooth.setOnClickListener {
|
||||||
Log.d(TAG, "bluetooth button clicked")
|
callActivity.setAudioOutputChannel(MagicAudioManager.AudioDevice.BLUETOOTH)
|
||||||
callActivity.setAudioOutputIcon(dialogAudioOutputBinding.audioOutputBluetoothIcon.drawable)
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogAudioOutputBinding.audioOutputSpeaker.setOnClickListener {
|
dialogAudioOutputBinding.audioOutputSpeaker.setOnClickListener {
|
||||||
Log.d(TAG, "speaker button clicked")
|
callActivity.setAudioOutputChannel(MagicAudioManager.AudioDevice.SPEAKER_PHONE)
|
||||||
callActivity.setAudioOutputIcon(dialogAudioOutputBinding.audioOutputSpeakerIcon.drawable)
|
|
||||||
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogAudioOutputBinding.audioOutputEarspeaker.setOnClickListener {
|
dialogAudioOutputBinding.audioOutputEarspeaker.setOnClickListener {
|
||||||
Log.d(TAG, "earspeaker button clicked")
|
callActivity.setAudioOutputChannel(MagicAudioManager.AudioDevice.EARPIECE)
|
||||||
callActivity.setAudioOutputIcon(dialogAudioOutputBinding.audioOutputEarspeakerIcon.drawable)
|
|
||||||
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,13 +55,9 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class MagicAudioManager {
|
public class MagicAudioManager {
|
||||||
private static final String TAG = "MagicAudioManager";
|
private static final String TAG = "MagicAudioManager";
|
||||||
private static final String SPEAKERPHONE_AUTO = "auto";
|
|
||||||
private static final String SPEAKERPHONE_FALSE = "false";
|
|
||||||
private final Context magicContext;
|
private final Context magicContext;
|
||||||
// Handles all tasks related to Bluetooth headset devices.
|
|
||||||
private final MagicBluetoothManager bluetoothManager;
|
private final MagicBluetoothManager bluetoothManager;
|
||||||
// Contains speakerphone setting: auto, true or false
|
private boolean controlSpeakerByProximitySensor;
|
||||||
private String useSpeakerphone;
|
|
||||||
private AudioManager audioManager;
|
private AudioManager audioManager;
|
||||||
private AudioManagerEvents audioManagerEvents;
|
private AudioManagerEvents audioManagerEvents;
|
||||||
private AudioManagerState amState;
|
private AudioManagerState amState;
|
||||||
@ -69,31 +65,15 @@ public class MagicAudioManager {
|
|||||||
private boolean savedIsSpeakerPhoneOn = false;
|
private boolean savedIsSpeakerPhoneOn = false;
|
||||||
private boolean savedIsMicrophoneMute = false;
|
private boolean savedIsMicrophoneMute = false;
|
||||||
private boolean hasWiredHeadset = false;
|
private boolean hasWiredHeadset = false;
|
||||||
// Default audio device; speaker phone for video calls or earpiece for audio
|
|
||||||
// only calls.
|
|
||||||
private AudioDevice defaultAudioDevice;
|
|
||||||
// Contains the currently selected audio device.
|
|
||||||
// This device is changed automatically using a certain scheme where e.g.
|
|
||||||
// a wired headset "wins" over speaker phone. It is also possible for a
|
|
||||||
// user to explicitly select a device (and overrid any predefined scheme).
|
|
||||||
// See |userSelectedAudioDevice| for details.
|
|
||||||
private AudioDevice selectedAudioDevice;
|
|
||||||
// Contains the user-selected audio device which overrides the predefined
|
|
||||||
// selection scheme.
|
|
||||||
// TODO(henrika): always set to AudioDevice.NONE today. Add support for
|
|
||||||
// explicit selection based on choice by userSelectedAudioDevice.
|
|
||||||
private AudioDevice userSelectedAudioDevice;
|
private AudioDevice userSelectedAudioDevice;
|
||||||
// Proximity sensor object. It measures the proximity of an object in cm
|
private AudioDevice resultingAudioDevice;
|
||||||
// relative to the view screen of a device and can therefore be used to
|
|
||||||
// assist device switching (close to ear <=> use headset earpiece if
|
|
||||||
// available, far from ear <=> use speaker phone).
|
|
||||||
private MagicProximitySensor proximitySensor = null;
|
private MagicProximitySensor proximitySensor = null;
|
||||||
// Contains a list of available audio devices. A Set collection is used to
|
|
||||||
// avoid duplicate elements.
|
|
||||||
private Set<AudioDevice> audioDevices = new HashSet<>();
|
private Set<AudioDevice> audioDevices = new HashSet<>();
|
||||||
// Broadcast receiver for wired headset intent broadcasts.
|
|
||||||
private BroadcastReceiver wiredHeadsetReceiver;
|
private BroadcastReceiver wiredHeadsetReceiver;
|
||||||
// Callback method for changes in audio focus.
|
|
||||||
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener;
|
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener;
|
||||||
|
|
||||||
private PowerManagerUtils powerManagerUtils;
|
private PowerManagerUtils powerManagerUtils;
|
||||||
@ -110,18 +90,8 @@ public class MagicAudioManager {
|
|||||||
powerManagerUtils = new PowerManagerUtils();
|
powerManagerUtils = new PowerManagerUtils();
|
||||||
powerManagerUtils.updatePhoneState(PowerManagerUtils.PhoneState.WITH_PROXIMITY_SENSOR_LOCK);
|
powerManagerUtils.updatePhoneState(PowerManagerUtils.PhoneState.WITH_PROXIMITY_SENSOR_LOCK);
|
||||||
|
|
||||||
if (useProximitySensor) {
|
controlSpeakerByProximitySensor = useProximitySensor;
|
||||||
useSpeakerphone = SPEAKERPHONE_AUTO;
|
updateAudioDeviceState();
|
||||||
} else {
|
|
||||||
useSpeakerphone = SPEAKERPHONE_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (useSpeakerphone.equals(SPEAKERPHONE_FALSE)) {
|
|
||||||
defaultAudioDevice = AudioDevice.EARPIECE;
|
|
||||||
} else {
|
|
||||||
defaultAudioDevice = AudioDevice.SPEAKER_PHONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and initialize the proximity sensor.
|
// Create and initialize the proximity sensor.
|
||||||
// Tablet devices (e.g. Nexus 7) does not support proximity sensors.
|
// Tablet devices (e.g. Nexus 7) does not support proximity sensors.
|
||||||
@ -134,8 +104,6 @@ public class MagicAudioManager {
|
|||||||
onProximitySensorChangedState();
|
onProximitySensorChangedState();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Log.d(TAG, "defaultAudioDevice: " + defaultAudioDevice);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,29 +113,13 @@ public class MagicAudioManager {
|
|||||||
return new MagicAudioManager(context, useProximitySensor);
|
return new MagicAudioManager(context, useProximitySensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleUseSpeakerphone() {
|
|
||||||
if (useSpeakerphone.equals(SPEAKERPHONE_FALSE)) {
|
|
||||||
useSpeakerphone = SPEAKERPHONE_AUTO;
|
|
||||||
setDefaultAudioDevice(AudioDevice.SPEAKER_PHONE);
|
|
||||||
} else {
|
|
||||||
useSpeakerphone = SPEAKERPHONE_FALSE;
|
|
||||||
setDefaultAudioDevice(AudioDevice.EARPIECE);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAudioDeviceState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSpeakerphoneAutoOn() {
|
|
||||||
return (useSpeakerphone.equals(SPEAKERPHONE_AUTO));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called when the proximity sensor reports a state change,
|
* This method is called when the proximity sensor reports a state change,
|
||||||
* e.g. from "NEAR to FAR" or from "FAR to NEAR".
|
* e.g. from "NEAR to FAR" or from "FAR to NEAR".
|
||||||
*/
|
*/
|
||||||
private void onProximitySensorChangedState() {
|
private void onProximitySensorChangedState() {
|
||||||
|
|
||||||
if (!useSpeakerphone.equals(SPEAKERPHONE_AUTO)) {
|
if (!controlSpeakerByProximitySensor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +226,7 @@ public class MagicAudioManager {
|
|||||||
|
|
||||||
// Set initial device states.
|
// Set initial device states.
|
||||||
userSelectedAudioDevice = AudioDevice.NONE;
|
userSelectedAudioDevice = AudioDevice.NONE;
|
||||||
selectedAudioDevice = AudioDevice.NONE;
|
resultingAudioDevice = AudioDevice.NONE;
|
||||||
audioDevices.clear();
|
audioDevices.clear();
|
||||||
|
|
||||||
// Initialize and start Bluetooth if a BT device is available or initiate
|
// Initialize and start Bluetooth if a BT device is available or initiate
|
||||||
@ -355,35 +307,10 @@ public class MagicAudioManager {
|
|||||||
Log.e(TAG, "Invalid audio device selection");
|
Log.e(TAG, "Invalid audio device selection");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
selectedAudioDevice = device;
|
resultingAudioDevice = device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes default audio device.
|
|
||||||
* TODO(henrika): add usage of this method in the AppRTCMobile client.
|
|
||||||
*/
|
|
||||||
public void setDefaultAudioDevice(AudioDevice defaultDevice) {
|
|
||||||
ThreadUtils.checkIsOnMainThread();
|
|
||||||
switch (defaultDevice) {
|
|
||||||
case SPEAKER_PHONE:
|
|
||||||
defaultAudioDevice = defaultDevice;
|
|
||||||
break;
|
|
||||||
case EARPIECE:
|
|
||||||
if (hasEarpiece()) {
|
|
||||||
defaultAudioDevice = defaultDevice;
|
|
||||||
} else {
|
|
||||||
defaultAudioDevice = AudioDevice.SPEAKER_PHONE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.e(TAG, "Invalid default audio device selection");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Log.d(TAG, "setDefaultAudioDevice(device=" + defaultAudioDevice + ")");
|
|
||||||
updateAudioDeviceState();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes selection of the currently active audio device.
|
* Changes selection of the currently active audio device.
|
||||||
*/
|
*/
|
||||||
@ -392,7 +319,15 @@ public class MagicAudioManager {
|
|||||||
if (!audioDevices.contains(device)) {
|
if (!audioDevices.contains(device)) {
|
||||||
Log.e(TAG, "Can not select " + device + " from available " + audioDevices);
|
Log.e(TAG, "Can not select " + device + " from available " + audioDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
userSelectedAudioDevice = device;
|
userSelectedAudioDevice = device;
|
||||||
|
|
||||||
|
if (device == AudioDevice.SPEAKER_PHONE) {
|
||||||
|
controlSpeakerByProximitySensor = true;
|
||||||
|
} else {
|
||||||
|
controlSpeakerByProximitySensor = false;
|
||||||
|
}
|
||||||
|
|
||||||
updateAudioDeviceState();
|
updateAudioDeviceState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,9 +342,9 @@ public class MagicAudioManager {
|
|||||||
/**
|
/**
|
||||||
* Returns the currently selected audio device.
|
* Returns the currently selected audio device.
|
||||||
*/
|
*/
|
||||||
public AudioDevice getSelectedAudioDevice() {
|
public AudioDevice getResultingAudioDevice() {
|
||||||
ThreadUtils.checkIsOnMainThread();
|
ThreadUtils.checkIsOnMainThread();
|
||||||
return selectedAudioDevice;
|
return resultingAudioDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -482,10 +417,6 @@ public class MagicAudioManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates list of possible audio devices and make new device selection.
|
|
||||||
* TODO(henrika): add unit test to verify all state transitions.
|
|
||||||
*/
|
|
||||||
public void updateAudioDeviceState() {
|
public void updateAudioDeviceState() {
|
||||||
ThreadUtils.checkIsOnMainThread();
|
ThreadUtils.checkIsOnMainThread();
|
||||||
Log.d(TAG, "--- updateAudioDeviceState: "
|
Log.d(TAG, "--- updateAudioDeviceState: "
|
||||||
@ -493,19 +424,18 @@ public class MagicAudioManager {
|
|||||||
+ "BT state=" + bluetoothManager.getState());
|
+ "BT state=" + bluetoothManager.getState());
|
||||||
Log.d(TAG, "Device status: "
|
Log.d(TAG, "Device status: "
|
||||||
+ "available=" + audioDevices + ", "
|
+ "available=" + audioDevices + ", "
|
||||||
+ "selected=" + selectedAudioDevice + ", "
|
+ "resulting(current)=" + resultingAudioDevice + ", "
|
||||||
+ "user selected=" + userSelectedAudioDevice);
|
+ "user selected=" + userSelectedAudioDevice);
|
||||||
|
|
||||||
// Check if any Bluetooth headset is connected. The internal BT state will
|
|
||||||
// change accordingly.
|
|
||||||
// TODO(henrika): perhaps wrap required state into BT manager.
|
|
||||||
if (bluetoothManager.getState() == MagicBluetoothManager.State.HEADSET_AVAILABLE
|
if (bluetoothManager.getState() == MagicBluetoothManager.State.HEADSET_AVAILABLE
|
||||||
|| bluetoothManager.getState() == MagicBluetoothManager.State.HEADSET_UNAVAILABLE
|
|| bluetoothManager.getState() == MagicBluetoothManager.State.HEADSET_UNAVAILABLE
|
||||||
|| bluetoothManager.getState() == MagicBluetoothManager.State.SCO_DISCONNECTING) {
|
|| bluetoothManager.getState() == MagicBluetoothManager.State.SCO_DISCONNECTING) {
|
||||||
bluetoothManager.updateDevice();
|
bluetoothManager.updateDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the set of available audio devices.
|
|
||||||
Set<AudioDevice> newAudioDevices = new HashSet<>();
|
Set<AudioDevice> newAudioDevices = new HashSet<>();
|
||||||
|
|
||||||
if (bluetoothManager.getState() == MagicBluetoothManager.State.SCO_CONNECTED
|
if (bluetoothManager.getState() == MagicBluetoothManager.State.SCO_CONNECTED
|
||||||
@ -518,34 +448,32 @@ public class MagicAudioManager {
|
|||||||
// 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);
|
newAudioDevices.add(AudioDevice.WIRED_HEADSET);
|
||||||
} else {
|
} else {
|
||||||
// No wired headset, hence the audio-device list can contain speaker
|
|
||||||
// phone (on a tablet), or speaker phone and earpiece (on mobile phone).
|
|
||||||
newAudioDevices.add(AudioDevice.SPEAKER_PHONE);
|
newAudioDevices.add(AudioDevice.SPEAKER_PHONE);
|
||||||
if (hasEarpiece()) {
|
if (hasEarpiece()) {
|
||||||
newAudioDevices.add(AudioDevice.EARPIECE);
|
newAudioDevices.add(AudioDevice.EARPIECE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Store state which is set to true if the device list has changed.
|
|
||||||
boolean audioDeviceSetUpdated = !audioDevices.equals(newAudioDevices);
|
boolean audioDeviceSetUpdated = !audioDevices.equals(newAudioDevices);
|
||||||
// Update the existing audio device set.
|
|
||||||
audioDevices = newAudioDevices;
|
audioDevices = newAudioDevices;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Correct user selected audio devices if needed.
|
// Correct user selected audio devices if needed.
|
||||||
if (bluetoothManager.getState() == MagicBluetoothManager.State.HEADSET_UNAVAILABLE
|
if (userSelectedAudioDevice == AudioDevice.BLUETOOTH
|
||||||
&& userSelectedAudioDevice == AudioDevice.BLUETOOTH) {
|
&& bluetoothManager.getState() == MagicBluetoothManager.State.HEADSET_UNAVAILABLE) {
|
||||||
// If BT is not available, it can't be the user selection.
|
|
||||||
userSelectedAudioDevice = AudioDevice.NONE;
|
userSelectedAudioDevice = AudioDevice.NONE;
|
||||||
}
|
}
|
||||||
if (hasWiredHeadset && userSelectedAudioDevice == AudioDevice.SPEAKER_PHONE) {
|
if (userSelectedAudioDevice == AudioDevice.SPEAKER_PHONE && hasWiredHeadset) {
|
||||||
// If user selected speaker phone, but then plugged wired headset then make
|
|
||||||
// wired headset as user selected device.
|
|
||||||
userSelectedAudioDevice = AudioDevice.WIRED_HEADSET;
|
userSelectedAudioDevice = AudioDevice.WIRED_HEADSET;
|
||||||
}
|
}
|
||||||
if (!hasWiredHeadset && userSelectedAudioDevice == AudioDevice.WIRED_HEADSET) {
|
if (userSelectedAudioDevice == AudioDevice.WIRED_HEADSET && !hasWiredHeadset) {
|
||||||
// If user selected wired headset, but then unplugged wired headset then make
|
|
||||||
// speaker phone as user selected device.
|
|
||||||
userSelectedAudioDevice = AudioDevice.SPEAKER_PHONE;
|
userSelectedAudioDevice = AudioDevice.SPEAKER_PHONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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 needBluetoothAudioStart =
|
||||||
@ -586,34 +514,34 @@ public class MagicAudioManager {
|
|||||||
|
|
||||||
|
|
||||||
// Update selected audio device.
|
// Update selected audio device.
|
||||||
AudioDevice newAudioDevice = selectedAudioDevice;
|
AudioDevice newResultingAudioDevice;
|
||||||
|
|
||||||
if (bluetoothManager.getState() == MagicBluetoothManager.State.SCO_CONNECTED) {
|
if (bluetoothManager.getState() == MagicBluetoothManager.State.SCO_CONNECTED) {
|
||||||
// If a Bluetooth is connected, then it should be used as output audio
|
// If a Bluetooth is connected, then it should be used as output audio
|
||||||
// device. Note that it is not sufficient that a headset is available;
|
// device. Note that it is not sufficient that a headset is available;
|
||||||
// an active SCO channel must also be up and running.
|
// an active SCO channel must also be up and running.
|
||||||
newAudioDevice = AudioDevice.BLUETOOTH;
|
newResultingAudioDevice = 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 is not, then wired headset is used as
|
||||||
// audio device.
|
// audio device.
|
||||||
newAudioDevice = AudioDevice.WIRED_HEADSET;
|
newResultingAudioDevice = 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, 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
|
// |defaultAudioDevice| contains either AudioDevice.SPEAKER_PHONE or AudioDevice.EARPIECE
|
||||||
// depending on the user's selection.
|
// depending on the user's selection.
|
||||||
newAudioDevice = defaultAudioDevice;
|
newResultingAudioDevice = 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.
|
||||||
if (newAudioDevice != selectedAudioDevice || audioDeviceSetUpdated) {
|
if (newResultingAudioDevice != resultingAudioDevice || audioDeviceSetUpdated) {
|
||||||
// Do the required device switch.
|
// Do the required device switch.
|
||||||
setAudioDeviceInternal(newAudioDevice);
|
setAudioDeviceInternal(newResultingAudioDevice);
|
||||||
Log.d(TAG, "New device status: "
|
Log.d(TAG, "New device status: "
|
||||||
+ "available=" + audioDevices + ", "
|
+ "available=" + audioDevices + ", "
|
||||||
+ "selected=" + newAudioDevice);
|
+ "resulting(new)=" + newResultingAudioDevice);
|
||||||
if (audioManagerEvents != null) {
|
if (audioManagerEvents != null) {
|
||||||
// Notify a listening client that audio device has been changed.
|
// Notify a listening client that audio device has been changed.
|
||||||
audioManagerEvents.onAudioDeviceChanged(selectedAudioDevice, audioDevices);
|
audioManagerEvents.onAudioDeviceChanged(resultingAudioDevice, audioDevices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d(TAG, "--- updateAudioDeviceState done");
|
Log.d(TAG, "--- updateAudioDeviceState done");
|
||||||
|
Loading…
Reference in New Issue
Block a user