2323import android .content .BroadcastReceiver ;
2424import android .content .pm .PackageManager ;
2525import android .media .AudioAttributes ;
26- import android .media .AudioManager ;
27- import androidx .media .AudioAttributesCompat ;
28- import androidx .media .AudioManagerCompat ;
29- import androidx .media .AudioFocusRequestCompat ;
3026import android .media .AudioDeviceInfo ;
27+ import android .media .AudioFocusRequest ;
28+ import android .media .AudioManager ;
3129import android .media .MediaPlayer ;
3230import android .media .ToneGenerator ;
3331import android .net .Uri ;
3735import android .os .Looper ;
3836import android .provider .Settings ;
3937import androidx .annotation .Nullable ;
40- import androidx .core .app .ActivityCompat ;
41- import androidx .core .content .ContextCompat ;
4238import android .util .Log ;
4339import android .util .SparseArray ;
4440import android .view .Display ;
@@ -83,6 +79,7 @@ public class InCallManagerModule extends ReactContextBaseJavaModule implements L
8379 private AudioManager audioManager ;
8480 private boolean audioManagerActivated = false ;
8581 private boolean isAudioFocused = false ;
82+ //private final Object mAudioFocusLock = new Object();
8683 private boolean isOrigAudioSetupStored = false ;
8784 private boolean origIsSpeakerPhoneOn = false ;
8885 private boolean origIsMicrophoneMute = false ;
@@ -98,6 +95,8 @@ public class InCallManagerModule extends ReactContextBaseJavaModule implements L
9895 private BroadcastReceiver noisyAudioReceiver ;
9996 private BroadcastReceiver mediaButtonReceiver ;
10097 private OnFocusChangeListener mOnFocusChangeListener ;
98+ private AudioAttributes mAudioAttributes ;
99+ private AudioFocusRequest mAudioFocusRequest ;
101100
102101 // --- same as: RingtoneManager.getActualDefaultRingtoneUri(reactContext, RingtoneManager.TYPE_RINGTONE);
103102 private Uri defaultRingtoneUri = Settings .System .DEFAULT_RINGTONE_URI ;
@@ -454,6 +453,7 @@ public void stopProximitySensor() {
454453 }
455454
456455 private class OnFocusChangeListener implements AudioManager .OnAudioFocusChangeListener {
456+ // --- see: https://developer.android.com/reference/android/media/AudioManager
457457
458458 @ Override
459459 public void onAudioFocusChange (final int focusChange ) {
@@ -480,6 +480,9 @@ public void onAudioFocusChange(final int focusChange) {
480480 case AudioManager .AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK :
481481 focusChangeStr = "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK" ;
482482 break ;
483+ case AudioManager .AUDIOFOCUS_NONE :
484+ focusChangeStr = "AUDIOFOCUS_NONE" ;
485+ break ;
483486 default :
484487 focusChangeStr = "AUDIOFOCUS_UNKNOW" ;
485488 break ;
@@ -612,7 +615,7 @@ public void stop(final String busytoneUriType) {
612615 forceSpeakerOn = 0 ;
613616 bluetoothManager .stop ();
614617 restoreOriginalAudioSetup ();
615- releaseAudioFocus ();
618+ abandonAudioFocus ();
616619 audioManagerActivated = false ;
617620 }
618621 wakeLockUtils .releasePartialWakeLock ();
@@ -637,23 +640,66 @@ private void stopEvents() {
637640 }
638641
639642 private void requestAudioFocus () {
640- if (!isAudioFocused ) {
641- int result = audioManager .requestAudioFocus (mOnFocusChangeListener , AudioManager .STREAM_VOICE_CALL , AudioManager .AUDIOFOCUS_GAIN );
642- if (result == AudioManager .AUDIOFOCUS_REQUEST_GRANTED ) {
643- Log .d (TAG , "AudioFocus granted" );
643+ if (isAudioFocused ) {
644+ return ;
645+ }
646+
647+ if (mAudioAttributes == null ) {
648+ mAudioAttributes = new AudioAttributes .Builder ()
649+ .setUsage (AudioAttributes .USAGE_VOICE_COMMUNICATION )
650+ .setContentType (AudioAttributes .CONTENT_TYPE_SPEECH )
651+ .build ();
652+ }
653+
654+ if (mAudioFocusRequest == null ) {
655+ mAudioFocusRequest = new AudioFocusRequest .Builder (AudioManager .AUDIOFOCUS_GAIN_TRANSIENT )
656+ .setAudioAttributes (mAudioAttributes )
657+ .setAcceptsDelayedFocusGain (false )
658+ .setWillPauseWhenDucked (false )
659+ .setOnAudioFocusChangeListener (mOnFocusChangeListener )
660+ .build ();
661+ }
662+
663+ int requestAudioFocusRes = audioManager .requestAudioFocus (mAudioFocusRequest );
664+ String requestAudioFocusResStr ;
665+ switch (requestAudioFocusRes ) {
666+ case AudioManager .AUDIOFOCUS_REQUEST_FAILED :
667+ requestAudioFocusResStr = "AUDIOFOCUS_REQUEST_FAILED" ;
668+ break ;
669+ case AudioManager .AUDIOFOCUS_REQUEST_GRANTED :
644670 isAudioFocused = true ;
645- } else if (result == AudioManager .AUDIOFOCUS_REQUEST_FAILED ) {
646- Log .d (TAG , "AudioFocus failed" );
647- isAudioFocused = false ;
648- }
671+ requestAudioFocusResStr = "AUDIOFOCUS_REQUEST_GRANTED" ;
672+ break ;
673+ case AudioManager .AUDIOFOCUS_REQUEST_DELAYED :
674+ requestAudioFocusResStr = "AUDIOFOCUS_REQUEST_DELAYED" ;
675+ break ;
676+ default :
677+ requestAudioFocusResStr = "AUDIOFOCUS_REQUEST_UNKNOWN" ;
678+ break ;
649679 }
680+ Log .d (TAG , "requestAudioFocus(): res = " + requestAudioFocusRes + " - " + requestAudioFocusResStr );
650681 }
651682
652- private void releaseAudioFocus () {
653- if (isAudioFocused ) {
654- audioManager .abandonAudioFocus (null );
655- isAudioFocused = false ;
683+ private void abandonAudioFocus () {
684+ if (!isAudioFocused || mAudioFocusRequest == null ) {
685+ return ;
686+ }
687+
688+ int abandonAudioFocusRes = audioManager .abandonAudioFocusRequest (mAudioFocusRequest );
689+ String abandonAudioFocusResStr ;
690+ switch (abandonAudioFocusRes ) {
691+ case AudioManager .AUDIOFOCUS_REQUEST_FAILED :
692+ abandonAudioFocusResStr = "AUDIOFOCUS_REQUEST_FAILED" ;
693+ break ;
694+ case AudioManager .AUDIOFOCUS_REQUEST_GRANTED :
695+ isAudioFocused = false ;
696+ abandonAudioFocusResStr = "AUDIOFOCUS_REQUEST_GRANTED" ;
697+ break ;
698+ default :
699+ abandonAudioFocusResStr = "AUDIOFOCUS_REQUEST_UNKNOWN" ;
700+ break ;
656701 }
702+ Log .d (TAG , "abandonAudioFocus(): res = " + abandonAudioFocusRes + " - " + abandonAudioFocusResStr );
657703 }
658704
659705 @ ReactMethod
@@ -832,8 +878,8 @@ public void startRingback(final String ringbackUriType) {
832878 //data.put("audioStream", AudioManager.STREAM_VOICE_CALL); // --- lagacy
833879 // --- The ringback doesn't have to be a DTMF.
834880 // --- Should use VOICE_COMMUNICATION for sound during call or it may be silenced.
835- data .put ("audioUsage" , AudioAttributesCompat .USAGE_VOICE_COMMUNICATION );
836- data .put ("audioContentType" , AudioAttributesCompat .CONTENT_TYPE_MUSIC );
881+ data .put ("audioUsage" , AudioAttributes .USAGE_VOICE_COMMUNICATION );
882+ data .put ("audioContentType" , AudioAttributes .CONTENT_TYPE_MUSIC );
837883
838884 setMediaPlayerEvents ((MediaPlayer )mRingback , "mRingback" );
839885
@@ -899,8 +945,8 @@ public boolean startBusytone(final String busytoneUriType) {
899945 data .put ("setLooping" , false );
900946 //data.put("audioStream", AudioManager.STREAM_VOICE_CALL); // --- lagacy
901947 // --- Should use VOICE_COMMUNICATION for sound during a call or it may be silenced.
902- data .put ("audioUsage" , AudioAttributesCompat .USAGE_VOICE_COMMUNICATION );
903- data .put ("audioContentType" , AudioAttributesCompat .CONTENT_TYPE_SONIFICATION ); // --- CONTENT_TYPE_MUSIC?
948+ data .put ("audioUsage" , AudioAttributes .USAGE_VOICE_COMMUNICATION );
949+ data .put ("audioContentType" , AudioAttributes .CONTENT_TYPE_SONIFICATION ); // --- CONTENT_TYPE_MUSIC?
904950
905951 setMediaPlayerEvents ((MediaPlayer )mBusytone , "mBusytone" );
906952 mBusytone .startPlay (data );
@@ -969,8 +1015,8 @@ public void run() {
9691015 data .put ("setLooping" , true );
9701016
9711017 //data.put("audioStream", AudioManager.STREAM_RING); // --- lagacy
972- data .put ("audioUsage" , AudioAttributesCompat .USAGE_NOTIFICATION_RINGTONE ); // --- USAGE_NOTIFICATION_COMMUNICATION_REQUEST?
973- data .put ("audioContentType" , AudioAttributesCompat .CONTENT_TYPE_MUSIC );
1018+ data .put ("audioUsage" , AudioAttributes .USAGE_NOTIFICATION_RINGTONE ); // --- USAGE_NOTIFICATION_COMMUNICATION_REQUEST?
1019+ data .put ("audioContentType" , AudioAttributes .CONTENT_TYPE_MUSIC );
9741020
9751021 setMediaPlayerEvents ((MediaPlayer ) mRingtone , "mRingtone" );
9761022
0 commit comments