react-native-webrtc / react-native-webrtc/react-native-incall-manager
Audio is not routed to speaker on incoming call on Android
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 597
- Forks
- 201
- Avg merge
- 2h 42m
- Merged PRs (30d)
- 1
Description
My scenario is the following:
I am using react-native-incall-manager with react-native-callkeep.
When initiating an outgoing video call i am calling InCallManager.start({
media: 'video',
auto: true,
ringback: '_BUNDLE_',
}); in CallKeep's didActivateAudioSession event, which plays a ringback sound, then when the video call is connected the audio is playing through the speakers, at is should.
But on incoming calls, when the call is answered the video call is playing through the earpiece. On CallKeep's showIncomingCallUi event i am calling InCallManager.start({ media: 'video' });, to have all the events around the video call be handled automatically by IncallManager.
I think the issue might happen because IncallManager is used with CallKeep and maybe there are some overriding issues.
These are my logs, starting from when the incoming call is first registered to when the video call was answered and connected:
RNCallKeep D [RNCallKeepModule] displayIncomingCall, uuid: 2dbb2069-6dfb-4745-a1bf-ffb8ed676220, number: 909c6991-96c6-4844-a925-accd3a0fdd94, callerName: Io, hasVideo: true, payload: null
RNCallKeep D [RNCallKeepModule] listenToNativeCallsState
RNCallKeep D [VoiceConnectionService] Constructor
RNCallKeep D [VoiceConnectionService] onCreateIncomingConnection, name: Io, numbertel: 909c6991-96c6-4844-a925-accd3a0fdd94, isForeground: true, isReachable: false, timeout: null
RNCallKeep D [VoiceConnectionService] createConnection, callerNumber: tel:909c6991-96c6-4844-a925-accd3a0fdd94
RNCallKeep D [VoiceConnectionService] PhoneAccount is SELF_MANAGED, so connection will be too
RNCallKeep D [VoiceConnection] onStateChanged called, state : 0
RNCallKeep D [VoiceConnection] onStateChanged called, state : 2
RNCallKeep D [VoiceConnection] onStateChanged called, state : 1
RNCallKeep D [VoiceConnectionService] startForegroundService
RNCallKeep D [VoiceConnectionService] Starting foreground service
RNCallKeep D [VoiceConnection] onShowIncomingCallUi
RNCallKeep D [RNCallKeepModule][onReceive] ACTION_SHOW_INCOMING_CALL_UI
RNCallKeep V [RNCallKeepModule] sendEventToJS, eventName: RNCallKeepShowIncomingCallUi, bound: true, hasListeners: true args : {"hasVideo":"true","name":"Io","callUUID":"2dbb2069-6dfb-4745-a1bf-ffb8ed676220","handle":"909c6991-96c6-4844-a925-accd3a0fdd94"}
RNCallKeep D [VoiceConnection] onCallAudioStateChanged muted :false
RNCallKeep D [RNCallKeepModule][onReceive] ACTION_DID_CHANGE_AUDIO_ROUTE
RNCallKeep V [RNCallKeepModule] sendEventToJS, eventName: RNCallKeepDidChangeAudioRoute, bound: true, hasListeners: true args : {"output":"EARPIECE","callUUID":"2dbb2069-6dfb-4745-a1bf-ffb8ed676220","handle":"909c6991-96c6-4844-a925-accd3a0fdd94"}
RNCallKeep D [VoiceConnection] onCallAudioStateChanged muted :false
RNCallKeep D [RNCallKeepModule][onReceive] ACTION_DID_CHANGE_AUDIO_ROUTE
RNCallKeep V [RNCallKeepModule] sendEventToJS, eventName: RNCallKeepDidChangeAudioRoute, bound: true, hasListeners: true args : {"output":"EARPIECE","callUUID":"2dbb2069-6dfb-4745-a1bf-ffb8ed676220","handle":"909c6991-96c6-4844-a925-accd3a0fdd94"}
InCallManager D start audioRouteManager
InCallManager D storeOriginalAudioSetup()
InCallManager D requestAudioFocus(): res = AUDIOFOCUS_REQUEST_FAILED
InCallManager D startWiredHeadsetEvent()
InCallManager D startNoisyAudioEvent()
InCallManager D startMediaButtonEvent()
InCallManager D startProximitySensor()
InCallManager D setKeepScreenOn() true
InCallManager D --- updateAudioDeviceState: wired headset=false, BT state=HEADSET_UNAVAILABLE
InCallManager D Device status: available=[SPEAKER_PHONE], selected=SPEAKER_PHONE, user selected=NONE
InCallManager D --hasEarpiece: NO
InCallManager D --- updateAudioDeviceState done | isSpeakerPhoneOn: false
InCallManager D setSpeakerphoneOn(): true
RNCallKeep D [VoiceConnection] onCallAudioStateChanged muted :false
RNCallKeep D [RNCallKeepModule][onReceive] ACTION_DID_CHANGE_AUDIO_ROUTE
RNCallKeep V [RNCallKeepModule] sendEventToJS, eventName: RNCallKeepDidChangeAudioRoute, bound: true, hasListeners: true args : {"output":"SPEAKER","callUUID":"2dbb2069-6dfb-4745-a1bf-ffb8ed676220","handle":"909c6991-96c6-4844-a925-accd3a0fdd94"}
InCallManager D --- updateAudioDeviceState: wired headset=false, BT state=HEADSET_UNAVAILABLE
InCallManager D Device status: available=[], selected=NONE, user selected=NONE
InCallManager D --hasEarpiece: NO
InCallManager D setAudioDeviceInternal(device=SPEAKER_PHONE)
InCallManager D New device status: available=[SPEAKER_PHONE], selected=SPEAKER_PHONE
InCallManager D --- updateAudioDeviceState done | isSpeakerPhoneOn: true
InCallManager D onPause()
InCallManager D onResume()
RNCallKeep D [VoiceConnection] onCallAudioStateChanged muted :false
RNCallKeep D [RNCallKeepModule][onReceive] ACTION_DID_CHANGE_AUDIO_ROUTE
RNCallKeep V [RNCallKeepModule] sendEventToJS, eventName: RNCallKeepDidChangeAudioRoute, bound: true, hasListeners: true args : {"output":"EARPIECE","callUUID":"2dbb2069-6dfb-4745-a1bf-ffb8ed676220","handle":"909c6991-96c6-4844-a925-accd3a0fdd94"}
RNCallKeep D [RNCallKeepModule] setCurrentCallActive, uuid: 2dbb2069-6dfb-4745-a1bf-ffb8ed676220
RNCallKeep D [VoiceConnection] onStateChanged called, state : 4
As you can see in
InCallManager D Device status: available=[], selected=NONE, user selected=NONE
InCallManager D --hasEarpiece: NO
InCallManager D setAudioDeviceInternal(device=SPEAKER_PHONE)
InCallManager D New device status: available=[SPEAKER_PHONE], selected=SPEAKER_PHONE
InCallManager D --- updateAudioDeviceState done | isSpeakerPhoneOn: true
the speaker is selected and the audio device is updated, but the audio is still not routed to the speakers, despite the logs.
p.s. --hasEarpiece: NO is because i hardcoded hasEarpiece() return value to false, to make it impossible to route it to the earpiece
I tried calling IncallManager.setForceSpeakerPhoneOn right after IncallManager.start({ media: 'video' }), that gave me
Device status: available=[], selected=NONE, user selected=NONE
D setForceSpeakerphoneOn() flag: 1
E selectAudioDevice() Can not select SPEAKER_PHONE from available []
so for some reason, on incoming call the SPEAKER_PHONE is not available.
I event tried calling CallKeep's toggleAudioRouteSpeaker, but that didn't help either.
I would take any advice happily.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the incoming-call showIncomingCallUi path that calls InCallManager.start({ media: 'video' }), and compare it with the outgoing didActivateAudioSession path. Trace the interactions with setForceSpeakerPhoneOn and CallKeep's toggleAudioRouteSpeaker, using the supplied route logs to reproduce the unavailable SPEAKER_PHONE state. Done means an answered incoming video call stays routed to the speaker.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, java, react-native
- Domain
- audio-video-rtc, mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100