Skip to content

Commit a771228

Browse files
committed
android: refactor audio route logic to fix some bluetooth bug
1 parent 63e0456 commit a771228

File tree

1 file changed

+63
-72
lines changed

1 file changed

+63
-72
lines changed

android/src/main/java/com/zxcpoiu/incallmanager/InCallManagerModule.java

Lines changed: 63 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,107 +1775,71 @@ public void updateAudioDeviceState() {
17751775
// Update the set of available audio devices.
17761776
Set<AudioDevice> newAudioDevices = new HashSet<>();
17771777

1778+
// always assume device has speaker phone
1779+
newAudioDevices.add(AudioDevice.SPEAKER_PHONE);
1780+
17781781
if (bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTED
17791782
|| bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTING
17801783
|| bluetoothManager.getState() == AppRTCBluetoothManager.State.HEADSET_AVAILABLE) {
17811784
newAudioDevices.add(AudioDevice.BLUETOOTH);
17821785
}
17831786

17841787
if (hasWiredHeadset) {
1785-
// If a wired headset is connected, then it is the only possible option.
17861788
newAudioDevices.add(AudioDevice.WIRED_HEADSET);
1787-
} else {
1788-
// No wired headset, hence the audio-device list can contain speaker
1789-
// phone (on a tablet), or speaker phone and earpiece (on mobile phone).
1790-
newAudioDevices.add(AudioDevice.SPEAKER_PHONE);
1791-
if (hasEarpiece()) {
1792-
newAudioDevices.add(AudioDevice.EARPIECE);
1793-
}
17941789
}
1790+
1791+
if (hasEarpiece()) {
1792+
newAudioDevices.add(AudioDevice.EARPIECE);
1793+
}
1794+
1795+
// --- check whether user selected audio device is available
1796+
if (userSelectedAudioDevice != null
1797+
&& userSelectedAudioDevice != AudioDevice.NONE
1798+
&& !newAudioDevices.contains(userSelectedAudioDevice)) {
1799+
userSelectedAudioDevice = AudioDevice.NONE;
1800+
}
1801+
17951802
// Store state which is set to true if the device list has changed.
17961803
boolean audioDeviceSetUpdated = !audioDevices.equals(newAudioDevices);
17971804
// Update the existing audio device set.
17981805
audioDevices = newAudioDevices;
1799-
// Correct user selected audio devices if needed.
1800-
if (bluetoothManager.getState() == AppRTCBluetoothManager.State.HEADSET_UNAVAILABLE
1801-
&& userSelectedAudioDevice == AudioDevice.BLUETOOTH) {
1802-
// If BT is not available, it can't be the user selection.
1803-
userSelectedAudioDevice = AudioDevice.NONE;
1804-
}
1805-
if (hasWiredHeadset && userSelectedAudioDevice == AudioDevice.SPEAKER_PHONE) {
1806-
// If user selected speaker phone, but then plugged wired headset then make
1807-
// wired headset as user selected device.
1808-
userSelectedAudioDevice = AudioDevice.WIRED_HEADSET;
1809-
}
1810-
if (!hasWiredHeadset && userSelectedAudioDevice == AudioDevice.WIRED_HEADSET) {
1811-
// If user selected wired headset, but then unplugged wired headset then make
1812-
// speaker phone as user selected device.
1813-
userSelectedAudioDevice = AudioDevice.SPEAKER_PHONE;
1814-
}
18151806

1816-
// Need to start Bluetooth if it is available and user either selected it explicitly or
1817-
// user did not select any output device.
1818-
boolean needBluetoothAudioStart =
1819-
bluetoothManager.getState() == AppRTCBluetoothManager.State.HEADSET_AVAILABLE
1820-
&& (userSelectedAudioDevice == AudioDevice.NONE
1821-
|| userSelectedAudioDevice == AudioDevice.BLUETOOTH);
1807+
AudioDevice newAudioDevice = getPreferredAudioDevice();
18221808

1823-
// Need to stop Bluetooth audio if user selected different device and
1824-
// Bluetooth SCO connection is established or in the process.
1825-
boolean needBluetoothAudioStop =
1826-
(bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTED
1827-
|| bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTING)
1828-
&& (userSelectedAudioDevice != AudioDevice.NONE
1829-
&& userSelectedAudioDevice != AudioDevice.BLUETOOTH);
1830-
1831-
if (bluetoothManager.getState() == AppRTCBluetoothManager.State.HEADSET_AVAILABLE
1832-
|| bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTING
1833-
|| bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTED) {
1834-
Log.d(TAG, "Need BT audio: start=" + needBluetoothAudioStart + ", "
1835-
+ "stop=" + needBluetoothAudioStop + ", "
1836-
+ "BT state=" + bluetoothManager.getState());
1837-
}
1838-
1839-
// Start or stop Bluetooth SCO connection given states set earlier.
1840-
if (needBluetoothAudioStop) {
1809+
// --- stop bluetooth if needed
1810+
if (selectedAudioDevice == AudioDevice.BLUETOOTH
1811+
&& newAudioDevice != AudioDevice.BLUETOOTH
1812+
&& (bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTED
1813+
|| bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTING)
1814+
) {
18411815
bluetoothManager.stopScoAudio();
18421816
bluetoothManager.updateDevice();
18431817
}
18441818

1845-
if (needBluetoothAudioStart && !needBluetoothAudioStop) {
1819+
// --- start bluetooth if needed
1820+
if (selectedAudioDevice != AudioDevice.BLUETOOTH
1821+
&& newAudioDevice == AudioDevice.BLUETOOTH
1822+
&& bluetoothManager.getState() == AppRTCBluetoothManager.State.HEADSET_AVAILABLE) {
18461823
// Attempt to start Bluetooth SCO audio (takes a few second to start).
18471824
if (!bluetoothManager.startScoAudio()) {
18481825
// Remove BLUETOOTH from list of available devices since SCO failed.
18491826
audioDevices.remove(AudioDevice.BLUETOOTH);
18501827
audioDeviceSetUpdated = true;
1828+
if (userSelectedAudioDevice == AudioDevice.BLUETOOTH) {
1829+
userSelectedAudioDevice = AudioDevice.NONE;
1830+
}
1831+
newAudioDevice = getPreferredAudioDevice();
18511832
}
18521833
}
1853-
1854-
// Update selected audio device.
1855-
final AudioDevice newAudioDevice;
1856-
1857-
if (bluetoothManager.getState() == AppRTCBluetoothManager.State.SCO_CONNECTED) {
1858-
// If a Bluetooth is connected, then it should be used as output audio
1859-
// device. Note that it is not sufficient that a headset is available;
1860-
// an active SCO channel must also be up and running.
1861-
newAudioDevice = AudioDevice.BLUETOOTH;
1862-
} else if (hasWiredHeadset) {
1863-
// If a wired headset is connected, but Bluetooth is not, then wired headset is used as
1864-
// audio device.
1865-
newAudioDevice = AudioDevice.WIRED_HEADSET;
1866-
} else if (userSelectedAudioDevice != null
1867-
&& userSelectedAudioDevice != AudioDevice.NONE
1868-
&& userSelectedAudioDevice != defaultAudioDevice) {
1869-
newAudioDevice = userSelectedAudioDevice;
1870-
} else {
1871-
// No wired headset and no Bluetooth, hence the audio-device list can contain speaker
1872-
// phone (on a tablet), or speaker phone and earpiece (on mobile phone).
1873-
// |defaultAudioDevice| contains either AudioDevice.SPEAKER_PHONE or AudioDevice.EARPIECE
1874-
// depending on the user's selgection.
1875-
newAudioDevice = defaultAudioDevice;
1834+
1835+
if (newAudioDevice == AudioDevice.BLUETOOTH
1836+
&& bluetoothManager.getState() != AppRTCBluetoothManager.State.SCO_CONNECTED) {
1837+
newAudioDevice = getPreferredAudioDevice(true); // --- skip bluetooth
18761838
}
1839+
18771840
// Switch to new device but only if there has been any changes.
18781841
if (newAudioDevice != selectedAudioDevice || audioDeviceSetUpdated) {
1842+
18791843
// Do the required device switch.
18801844
setAudioDeviceInternal(newAudioDevice);
18811845
Log.d(TAG, "New device status: "
@@ -1910,4 +1874,31 @@ private WritableMap getAudioDeviceStatusMap() {
19101874

19111875
return data;
19121876
}
1877+
1878+
private AudioDevice getPreferredAudioDevice() {
1879+
return getPreferredAudioDevice(false);
1880+
}
1881+
1882+
private AudioDevice getPreferredAudioDevice(boolean skipBluetooth) {
1883+
final AudioDevice newAudioDevice;
1884+
1885+
if (userSelectedAudioDevice != null && userSelectedAudioDevice != AudioDevice.NONE) {
1886+
newAudioDevice = userSelectedAudioDevice;
1887+
} else if (!skipBluetooth && audioDevices.contains(AudioDevice.BLUETOOTH)) {
1888+
// If a Bluetooth is connected, then it should be used as output audio
1889+
// device. Note that it is not sufficient that a headset is available;
1890+
// an active SCO channel must also be up and running.
1891+
newAudioDevice = AudioDevice.BLUETOOTH;
1892+
} else if (audioDevices.contains(AudioDevice.WIRED_HEADSET)) {
1893+
// If a wired headset is connected, but Bluetooth is not, then wired headset is used as
1894+
// audio device.
1895+
newAudioDevice = AudioDevice.WIRED_HEADSET;
1896+
} else if (audioDevices.contains(defaultAudioDevice)) {
1897+
newAudioDevice = defaultAudioDevice;
1898+
} else {
1899+
newAudioDevice = AudioDevice.SPEAKER_PHONE;
1900+
}
1901+
1902+
return newAudioDevice;
1903+
}
19131904
}

0 commit comments

Comments
 (0)