@@ -15,9 +15,12 @@ const platform = isIOS ? 'iOS' : 'Android';
1515const TAG = `[MediaCallEvents][${ platform } ]` ;
1616
1717const EVENT_VOIP_ACCEPT_FAILED = 'VoipAcceptFailed' ;
18+ const EVENT_VOIP_ACCEPT_SUCCEEDED = 'VoipAcceptSucceeded' ;
1819
1920/** Dedupe native emit + stash replay for the same failed accept. */
2021let lastHandledVoipAcceptFailureCallId : string | null = null ;
22+ /** Idempotent warm delivery of native accept success. */
23+ let lastHandledVoipAcceptSucceededCallId : string | null = null ;
2124
2225function dispatchVoipAcceptFailureFromNative ( raw : VoipPayload & { voipAcceptFailed ?: boolean } ) {
2326 if ( ! raw . voipAcceptFailed ) {
@@ -38,6 +41,29 @@ function dispatchVoipAcceptFailureFromNative(raw: VoipPayload & { voipAcceptFail
3841 ) ;
3942}
4043
44+ function handleVoipAcceptSucceededFromNative ( data : VoipPayload ) {
45+ const { callId } = data ;
46+ if ( callId && lastHandledVoipAcceptSucceededCallId === callId ) {
47+ return ;
48+ }
49+ if ( callId ) {
50+ lastHandledVoipAcceptSucceededCallId = callId ;
51+ }
52+ if ( data . type !== 'incoming_call' ) {
53+ console . log ( `${ TAG } VoipAcceptSucceeded: not an incoming call` ) ;
54+ return ;
55+ }
56+ console . log ( `${ TAG } VoipAcceptSucceeded:` , data ) ;
57+ NativeVoipModule . clearInitialEvents ( ) ;
58+ useCallStore . getState ( ) . setNativeAcceptedCallId ( data . callId ) ;
59+ store . dispatch (
60+ deepLinkingOpen ( {
61+ callId : data . callId ,
62+ host : data . host
63+ } )
64+ ) ;
65+ }
66+
4167/**
4268 * Sets up listeners for media call events.
4369 * @returns Cleanup function to remove listeners
@@ -66,39 +92,19 @@ export const setupMediaCallEvents = (): (() => void) => {
6692 // Note: there is intentionally no 'answerCall' listener here.
6793 // VoipService.swift handles accept natively: handleObservedCallChanged detects
6894 // hasConnected = true and calls handleNativeAccept(), which sends the DDP accept
69- // signal before JS runs. JS only reads the stored initialEventsData payload after the fact.
70- } else {
71- // Android listens for media call events from VoipModule
72- subscriptions . push (
73- Emitter . addListener ( 'VoipPushInitialEvents' , async ( data : VoipPayload & { voipAcceptFailed ?: boolean } ) => {
74- try {
75- if ( data . voipAcceptFailed ) {
76- console . log ( `${ TAG } Accept failed initial event` ) ;
77- dispatchVoipAcceptFailureFromNative ( data ) ;
78- NativeVoipModule . clearInitialEvents ( ) ;
79- return ;
80- }
81- if ( data . type !== 'incoming_call' ) {
82- console . log ( `${ TAG } Not an incoming call` ) ;
83- return ;
84- }
85- console . log ( `${ TAG } Initial events event:` , data ) ;
86- NativeVoipModule . clearInitialEvents ( ) ;
87- useCallStore . getState ( ) . setCallId ( data . callId ) ;
88- store . dispatch (
89- deepLinkingOpen ( {
90- callId : data . callId ,
91- host : data . host
92- } )
93- ) ;
94- await mediaSessionInstance . answerCall ( data . callId ) ;
95- } catch ( error ) {
96- console . error ( `${ TAG } Error handling initial events event:` , error ) ;
97- }
98- } )
99- ) ;
95+ // signal before JS runs. JS receives VoipAcceptSucceeded after success.
10096 }
10197
98+ subscriptions . push (
99+ Emitter . addListener ( EVENT_VOIP_ACCEPT_SUCCEEDED , ( data : VoipPayload ) => {
100+ try {
101+ handleVoipAcceptSucceededFromNative ( data ) ;
102+ } catch ( error ) {
103+ console . error ( `${ TAG } Error handling VoipAcceptSucceeded:` , error ) ;
104+ }
105+ } )
106+ ) ;
107+
102108 subscriptions . push (
103109 Emitter . addListener ( EVENT_VOIP_ACCEPT_FAILED , ( data : VoipPayload & { voipAcceptFailed ?: boolean } ) => {
104110 console . log ( `${ TAG } VoipAcceptFailed event:` , data ) ;
@@ -165,7 +171,7 @@ export const getInitialMediaCallEvents = async (): Promise<boolean> => {
165171 }
166172
167173 if ( wasAnswered ) {
168- useCallStore . getState ( ) . setCallId ( initialEvents . callId ) ;
174+ useCallStore . getState ( ) . setNativeAcceptedCallId ( initialEvents . callId ) ;
169175
170176 store . dispatch (
171177 deepLinkingOpen ( {
0 commit comments