Skip to content

Commit 9176d67

Browse files
authored
Merge pull request #2117 from tappress/fix/le-audio-call-routing
Route call audio to LE Audio headsets via communication devices on Android 12+
2 parents f2908b1 + f636634 commit 9176d67

2 files changed

Lines changed: 142 additions & 38 deletions

File tree

‎TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java‎

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,14 @@ public void run() {
394394
if (audioDeviceCallback != null) {
395395
am.unregisterAudioDeviceCallback(audioDeviceCallback);
396396
}
397+
if (communicationDeviceListener != null) {
398+
am.removeOnCommunicationDeviceChangedListener(communicationDeviceListener);
399+
communicationDeviceListener = null;
400+
}
397401
if (!USE_CONNECTION_SERVICE && sharedInstance == null) {
398402
if (isBtHeadsetConnected) {
399-
am.stopBluetoothSco();
400-
am.setBluetoothScoOn(false);
403+
vam.stopBluetooth();
404+
vam.setBluetoothOn(false);
401405
bluetoothScoActive = false;
402406
bluetoothScoConnecting = false;
403407
}
@@ -451,6 +455,7 @@ public void onServiceConnected(int profile, BluetoothProfile proxy) {
451455
};
452456

453457
private AudioDeviceCallback audioDeviceCallback;
458+
private AudioManager.OnCommunicationDeviceChangedListener communicationDeviceListener;
454459

455460
private BroadcastReceiver receiver = new BroadcastReceiver() {
456461

@@ -462,11 +467,10 @@ public void onReceive(Context context, Intent intent) {
462467
proximityWakelock.release();
463468
}
464469
if (isHeadsetPlugged) {
465-
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
466470
VoipAudioManager vam = VoipAudioManager.get();
467471
if (vam.isSpeakerphoneOn()) {
468472
previousAudioOutput = 0;
469-
} else if (am.isBluetoothScoOn()) {
473+
} else if (vam.isBluetoothOn()) {
470474
previousAudioOutput = 2;
471475
} else {
472476
previousAudioOutput = 1;
@@ -493,7 +497,7 @@ public void onReceive(Context context, Intent intent) {
493497
FileLog.e("Bluetooth SCO state updated: " + state);
494498
}
495499
if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED && isBtHeadsetConnected) {
496-
if (!btAdapter.isEnabled() || !PermissionRequest.hasPermission(Manifest.permission.BLUETOOTH_CONNECT) || btAdapter.getProfileConnectionState(BluetoothProfile.HEADSET) != BluetoothProfile.STATE_CONNECTED) {
500+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? VoipAudioManager.get().findBluetoothDevice() == null : (!btAdapter.isEnabled() || !PermissionRequest.hasPermission(Manifest.permission.BLUETOOTH_CONNECT) || btAdapter.getProfileConnectionState(BluetoothProfile.HEADSET) != BluetoothProfile.STATE_CONNECTED)) {
497501
updateBluetoothHeadsetState(false);
498502
return;
499503
}
@@ -504,10 +508,9 @@ public void onReceive(Context context, Intent intent) {
504508
fetchBluetoothDeviceName();
505509
if (needSwitchToBluetoothAfterScoActivates) {
506510
needSwitchToBluetoothAfterScoActivates = false;
507-
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
508511
VoipAudioManager vam = VoipAudioManager.get();
509512
vam.setSpeakerphoneOn(false);
510-
am.setBluetoothScoOn(true);
513+
vam.setBluetoothOn(true);
511514
}
512515
}
513516
for (VoIPService.StateListener l : stateListeners) {
@@ -3808,12 +3811,11 @@ public void toggleSpeakerphoneOrShowRouteSheet(Context context, boolean fromOver
38083811
systemCallConnection.setAudioRoute(systemCallConnection.getCallAudioState().getRoute() == CallAudioState.ROUTE_BLUETOOTH ? CallAudioState.ROUTE_WIRED_OR_EARPIECE : CallAudioState.ROUTE_BLUETOOTH);
38093812
}
38103813
} else if (audioConfigured && !USE_CONNECTION_SERVICE) {
3811-
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
38123814
VoipAudioManager vam = VoipAudioManager.get();
38133815
if (hasEarpiece()) {
38143816
vam.setSpeakerphoneOn(!vam.isSpeakerphoneOn());
38153817
} else {
3816-
am.setBluetoothScoOn(!am.isBluetoothScoOn());
3818+
vam.setBluetoothOn(!vam.isBluetoothOn());
38173819
}
38183820
vam.isBluetoothAndSpeakerOnAsync((isBluetoothOn, isSpeakerOn) -> {
38193821
updateOutputGainControlState();
@@ -3834,7 +3836,6 @@ public void setAudioOutput(int which) {
38343836
if (BuildVars.LOGS_ENABLED) {
38353837
FileLog.d("setAudioOutput " + which);
38363838
}
3837-
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
38383839
VoipAudioManager vam = VoipAudioManager.get();
38393840
if (USE_CONNECTION_SERVICE && systemCallConnection != null) {
38403841
switch (which) {
@@ -3854,35 +3855,35 @@ public void setAudioOutput(int which) {
38543855
if (!bluetoothScoActive) {
38553856
needSwitchToBluetoothAfterScoActivates = true;
38563857
try {
3857-
am.startBluetoothSco();
3858+
vam.startBluetooth();
38583859
} catch (Throwable e) {
38593860
FileLog.e(e);
38603861
}
38613862
} else {
3862-
am.setBluetoothScoOn(true);
3863+
vam.setBluetoothOn(true);
38633864
vam.setSpeakerphoneOn(false);
38643865
}
38653866
audioRouteToSet = AUDIO_ROUTE_BLUETOOTH;
38663867
break;
38673868
case 1:
38683869
needSwitchToBluetoothAfterScoActivates = false;
38693870
if (bluetoothScoActive || bluetoothScoConnecting) {
3870-
am.stopBluetoothSco();
3871+
vam.stopBluetooth();
38713872
bluetoothScoActive = false;
38723873
bluetoothScoConnecting = false;
38733874
}
38743875
vam.setSpeakerphoneOn(false);
3875-
am.setBluetoothScoOn(false);
3876+
vam.setBluetoothOn(false);
38763877
audioRouteToSet = AUDIO_ROUTE_EARPIECE;
38773878
break;
38783879
case 0:
38793880
needSwitchToBluetoothAfterScoActivates = false;
38803881
if (bluetoothScoActive || bluetoothScoConnecting) {
3881-
am.stopBluetoothSco();
3882+
vam.stopBluetooth();
38823883
bluetoothScoActive = false;
38833884
bluetoothScoConnecting = false;
38843885
}
3885-
am.setBluetoothScoOn(false);
3886+
vam.setBluetoothOn(false);
38863887
vam.setSpeakerphoneOn(true);
38873888
audioRouteToSet = AUDIO_ROUTE_SPEAKER;
38883889
break;
@@ -3914,9 +3915,8 @@ public boolean isSpeakerphoneOn() {
39143915
int route = systemCallConnection.getCallAudioState().getRoute();
39153916
return hasEarpiece() ? route == CallAudioState.ROUTE_SPEAKER : route == CallAudioState.ROUTE_BLUETOOTH;
39163917
} else if (audioConfigured && !USE_CONNECTION_SERVICE) {
3917-
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
39183918
VoipAudioManager vam = VoipAudioManager.get();
3919-
return hasEarpiece() ? vam.isSpeakerphoneOn() : am.isBluetoothScoOn();
3919+
return hasEarpiece() ? vam.isSpeakerphoneOn() : vam.isBluetoothOn();
39203920
}
39213921
return speakerphoneStateToSet;
39223922
}
@@ -3937,9 +3937,8 @@ public int getCurrentAudioRoute() {
39373937
return audioRouteToSet;
39383938
}
39393939
if (audioConfigured) {
3940-
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
39413940
VoipAudioManager vam = VoipAudioManager.get();
3942-
if (am.isBluetoothScoOn()) {
3941+
if (vam.isBluetoothOn()) {
39433942
return AUDIO_ROUTE_BLUETOOTH;
39443943
} else if (vam.isSpeakerphoneOn()) {
39453944
return AUDIO_ROUTE_SPEAKER;
@@ -4207,8 +4206,8 @@ public void onDestroy() {
42074206
VoipAudioManager vam = VoipAudioManager.get();
42084207
if (!USE_CONNECTION_SERVICE) {
42094208
if (isBtHeadsetConnected || bluetoothScoActive || bluetoothScoConnecting) {
4210-
am.stopBluetoothSco();
4211-
am.setBluetoothScoOn(false);
4209+
vam.stopBluetooth();
4210+
vam.setBluetoothOn(false);
42124211
vam.setSpeakerphoneOn(false);
42134212
bluetoothScoActive = false;
42144213
bluetoothScoConnecting = false;
@@ -4240,6 +4239,10 @@ public void onDestroy() {
42404239
if (audioDeviceCallback != null) {
42414240
am.unregisterAudioDeviceCallback(audioDeviceCallback);
42424241
}
4242+
if (communicationDeviceListener != null) {
4243+
am.removeOnCommunicationDeviceChangedListener(communicationDeviceListener);
4244+
communicationDeviceListener = null;
4245+
}
42434246

42444247
Utilities.globalQueue.postRunnable(() -> {
42454248
if (soundPool != null) {
@@ -4677,6 +4680,20 @@ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
46774680
if (audioDeviceCallback != null) {
46784681
am.registerAudioDeviceCallback(audioDeviceCallback, new Handler(Looper.getMainLooper()));
46794682
}
4683+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && communicationDeviceListener == null) {
4684+
communicationDeviceListener = device -> {
4685+
bluetoothScoConnecting = false;
4686+
bluetoothScoActive = VoipAudioManager.isBluetoothDevice(device);
4687+
if (bluetoothScoActive) {
4688+
needSwitchToBluetoothAfterScoActivates = false;
4689+
currentBluetoothDeviceName = device.getProductName().toString();
4690+
}
4691+
for (StateListener l : stateListeners) {
4692+
l.onAudioSettingsChanged();
4693+
}
4694+
};
4695+
am.addOnCommunicationDeviceChangedListener(AndroidUtilities::runOnUIThread, communicationDeviceListener);
4696+
}
46804697
am.registerMediaButtonEventReceiver(new ComponentName(this, VoIPMediaButtonReceiver.class));
46814698

46824699
checkUpdateBluetoothHeadset();
@@ -4724,7 +4741,16 @@ private void checkUpdateBluetoothHeadset() {
47244741
try {
47254742
MediaRouter mr = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);
47264743
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
4727-
if (Build.VERSION.SDK_INT < 24) {
4744+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
4745+
AudioDeviceInfo device = VoipAudioManager.get().findBluetoothDevice();
4746+
if (device != null) {
4747+
currentBluetoothDeviceName = device.getProductName().toString();
4748+
}
4749+
updateBluetoothHeadsetState(device != null);
4750+
for (StateListener l : stateListeners) {
4751+
l.onAudioSettingsChanged();
4752+
}
4753+
} else if (Build.VERSION.SDK_INT < 24) {
47284754
int headsetState = btAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
47294755
updateBluetoothHeadsetState(headsetState == BluetoothProfile.STATE_CONNECTED);
47304756
for (StateListener l : stateListeners) {
@@ -4827,7 +4853,7 @@ private void configureDeviceForCall() {
48274853
try {
48284854
if (hasRtmpStream()) {
48294855
am.setMode(AudioManager.MODE_NORMAL);
4830-
am.setBluetoothScoOn(false);
4856+
VoipAudioManager.get().setBluetoothOn(false);
48314857
AndroidUtilities.runOnUIThread(() -> {
48324858
if (!MediaController.getInstance().isMessagePaused()) {
48334859
MediaController.getInstance().pauseMessage(MediaController.getInstance().getPlayingMessageObject());
@@ -4850,26 +4876,26 @@ private void configureDeviceForCall() {
48504876
if (!bluetoothScoActive) {
48514877
needSwitchToBluetoothAfterScoActivates = true;
48524878
try {
4853-
am.startBluetoothSco();
4879+
vam.startBluetooth();
48544880
} catch (Throwable e) {
48554881
FileLog.e(e);
48564882
}
48574883
} else {
4858-
am.setBluetoothScoOn(true);
4884+
vam.setBluetoothOn(true);
48594885
vam.setSpeakerphoneOn(false);
48604886
}
48614887
break;
48624888
case AUDIO_ROUTE_EARPIECE:
4863-
am.setBluetoothScoOn(false);
4889+
vam.setBluetoothOn(false);
48644890
vam.setSpeakerphoneOn(false);
48654891
break;
48664892
case AUDIO_ROUTE_SPEAKER:
4867-
am.setBluetoothScoOn(false);
4893+
vam.setBluetoothOn(false);
48684894
vam.setSpeakerphoneOn(true);
48694895
break;
48704896
}
48714897
} else if (isBluetoothHeadsetConnected()) {
4872-
am.setBluetoothScoOn(speakerphoneStateToSet);
4898+
vam.setBluetoothOn(speakerphoneStateToSet);
48734899
} else {
48744900
vam.setSpeakerphoneOn(speakerphoneStateToSet);
48754901
if (speakerphoneStateToSet) {
@@ -4925,9 +4951,8 @@ public void onSensorChanged(SensorEvent event) {
49254951
return;
49264952
}
49274953
if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
4928-
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
49294954
VoipAudioManager vam = VoipAudioManager.get();
4930-
if (audioRouteToSet != AUDIO_ROUTE_EARPIECE || isHeadsetPlugged || vam.isSpeakerphoneOn() || (isBluetoothHeadsetConnected() && am.isBluetoothScoOn())) {
4955+
if (audioRouteToSet != AUDIO_ROUTE_EARPIECE || isHeadsetPlugged || vam.isSpeakerphoneOn() || (isBluetoothHeadsetConnected() && vam.isBluetoothOn())) {
49314956
return;
49324957
}
49334958
boolean newIsNear = event.values[0] < Math.min(event.sensor.getMaximumRange(), 3);
@@ -4989,14 +5014,15 @@ private void updateBluetoothHeadsetState(boolean connected) {
49895014
}
49905015
isBtHeadsetConnected = connected;
49915016
final AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
5017+
final VoipAudioManager vam = VoipAudioManager.get();
49925018
if (connected && !isRinging() && currentState != 0) {
49935019
if (bluetoothScoActive) {
49945020
if (BuildVars.LOGS_ENABLED) {
49955021
FileLog.d("SCO already active, setting audio routing");
49965022
}
49975023
if (!hasRtmpStream()) {
49985024
am.setSpeakerphoneOn(false);
4999-
am.setBluetoothScoOn(true);
5025+
vam.setBluetoothOn(true);
50005026
}
50015027
} else {
50025028
if (BuildVars.LOGS_ENABLED) {
@@ -5006,7 +5032,7 @@ private void updateBluetoothHeadsetState(boolean connected) {
50065032
needSwitchToBluetoothAfterScoActivates = true;
50075033
AndroidUtilities.runOnUIThread(() -> {
50085034
try {
5009-
am.startBluetoothSco();
5035+
vam.startBluetooth();
50105036
} catch (Throwable ignore) {
50115037

50125038
}
@@ -5017,7 +5043,7 @@ private void updateBluetoothHeadsetState(boolean connected) {
50175043
bluetoothScoActive = false;
50185044
bluetoothScoConnecting = false;
50195045

5020-
am.setBluetoothScoOn(false);
5046+
vam.setBluetoothOn(false);
50215047
}
50225048
for (StateListener l : stateListeners) {
50235049
l.onAudioSettingsChanged();
@@ -5489,8 +5515,7 @@ public void onSignalBarCountChanged(int newCount) {
54895515
}
54905516

54915517
public boolean isBluetoothOn() {
5492-
final AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
5493-
return am.isBluetoothScoOn();
5518+
return VoipAudioManager.get().isBluetoothOn();
54945519
}
54955520

54965521
public boolean isBluetoothWillOn() {

0 commit comments

Comments
 (0)