@@ -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