Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add on_rejected_incoming_call() callback #3683

Merged
merged 10 commits into from
Oct 3, 2023
Merged

Conversation

trengginas
Copy link
Member

Consider the scenario: (on iOS)

  • User agent received push notification of a new call
  • the call is registered to iOS CallKit, and show to user notification about incoming call. wait for SIP INVITE
  • SIP INVITE is received, however is rejected by the library due to invalid message
  • Notification to the incoming call still shown since the application is not aware of the call rejection

This PR will add a new callback on_rejected_incoming_call() to notifiy the application in case incoming call is rejected.

@wosrediinanatour
Copy link
Contributor

Does this handle INVITE crossover, i.e. SIP 491?

Having the SIP message, that has been rejected, would/could be useful. Maybe by using sip_event.

Isn't it implemented intentionally in PJSUA2?

pjsip/include/pjsua-lib/pjsua.h Outdated Show resolved Hide resolved
pjsip/src/pjsua-lib/pjsua_call.c Outdated Show resolved Hide resolved
- save incoming rdata to be passed as callback parameter
@sauwming
Copy link
Member

This approach seems to be more complicated than expected.

Some alternative ideas:
a. Add on_incoming_invite(). We simply call this new callback in the beginning of pjsua_call_on_incoming().
Pro: very simple. Con: Even though app can know if an incoming INVITE is eventually rejected by the library, it will not know the exact reason why.
b. Invoke on_rejected_incoming_call() from pjsua_call_on_incoming() instead.
Pro: allow more customization (app can change the status code/reason, perhaps even override the rejection, etc).

Personally, I like option b.

@sauwming
Copy link
Member

A couple of spec questions to consider:

  • Is there any need for the user to get the actual rejection message in the form of tdata? So far, pjsua callback usually only provides the status code (and st_text) of the answer. If we don't need the tdata, it will be much simpler, you don't need to copy the implementation of pjsip_endpt_respond/respond_stateless() into pjsua_call.
  • Do we want to call the callback before, or after, rejecting the call?
    If before, the callback will allow room for customisation, such as permitting user to modify the status code and text. But we may need to change the callback name since the call has not actually been rejected yet.
    If after, the callback will serve as informational purpose only.

@trengginas
Copy link
Member Author

trengginas commented Sep 15, 2023

A couple of spec questions to consider:

  • Is there any need for the user to get the actual rejection message in the form of tdata? So far, pjsua callback usually only provides the status code (and st_text) of the answer. If we don't need the tdata, it will be much simpler, you don't need to copy the implementation of pjsip_endpt_respond/respond_stateless() into pjsua_call.
  • Do we want to call the callback before, or after, rejecting the call?
    If before, the callback will allow room for customisation, such as permitting user to modify the status code and text. But we may need to change the callback name since the call has not actually been rejected yet.
    If after, the callback will serve as informational purpose only.
  • I agree to not include tdata on the callback param. It will simplify the solution. Adding st_text as parameter should also be useful.
  • I think we should not allow application to override the/change the status code and it should be informational only.

@wosrediinanatour
Copy link
Contributor

A couple of spec questions to consider:

  • Is there any need for the user to get the actual rejection message in the form of tdata? So far, pjsua callback usually only provides the status code (and st_text) of the answer. If we don't need the tdata, it will be much simpler, you don't need to copy the implementation of pjsip_endpt_respond/respond_stateless() into pjsua_call.
  • Do we want to call the callback before, or after, rejecting the call?
    If before, the callback will allow room for customisation, such as permitting user to modify the status code and text. But we may need to change the callback name since the call has not actually been rejected yet.
    If after, the callback will serve as informational purpose only.
* I agree to not include `tdata` on the callback param. It will simplify the solution. Adding `st_text` as parameter should also be useful.

* I think we should not allow application to override the/change the status code and it should be informational only.

The transmitted message is very useful for tracing, when onCallTsxState(...) is not called.

@@ -1967,6 +2016,20 @@ typedef struct pjsua_callback
*/
void (*on_media_event)(pjmedia_event *event);

/**
* This callback is called when an incoming call is rejected.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the doc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callback is now called only when it's internally rejected by the library, right? Will using pjsua_call_answer() also trigger the callback?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor:
make it clear in the doc that the callback is only called for calls that are internally rejected by the library. And the callback won't be called if user rejects the call using pjsua_call_answer/answer2().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the callback will not trigger when pjsua_call_answer() is used to reject the call

pjsip/include/pjsua2/endpoint.hpp Show resolved Hide resolved
pjsip/include/pjsua2/endpoint.hpp Outdated Show resolved Hide resolved
pjsip/src/pjsua-lib/pjsua_call.c Outdated Show resolved Hide resolved
pjsip/src/pjsua-lib/pjsua_call.c Outdated Show resolved Hide resolved
@sauwming
Copy link
Member

The transmitted message is very useful for tracing, when onCallTsxState(...) is not called.

By "tracing", you mean for info only, correct?
Since it doesn't have any practical purpose, it's not strong enough reason to include tdata within the callback, considering the complexity to do so.

@wosrediinanatour
Copy link
Contributor

The transmitted message is very useful for tracing, when onCallTsxState(...) is not called.

By "tracing", you mean for info only, correct? Since it doesn't have any practical purpose, it's not strong enough reason to include tdata within the callback, considering the complexity to do so.

Yes.

@@ -1475,6 +1516,8 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
pjmedia_sdp_session *offer=NULL;
pj_bool_t should_dec_dlg = PJ_FALSE;
pjsip_tpselector tp_sel;
pj_str_t st_reason = pj_str("");
int st_code = 200;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not initialize st_code with zero?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's following the original code on

int st_code = 200;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's following the original code on

int st_code = 200;

Oh, "the original code" is actually the default answer code for replaced dialog (may be overriden by app from the replaced dlg callback). IMO better not share the same var with the replaced dialog, it serves different purpose, it may cause confusion in the future.

@@ -1965,6 +2023,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
pjsua_perror(THIS_FILE, "Error initializing media channel", status);

pjsip_dlg_inc_lock(dlg);
st_code = sip_err_code;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When pjsua_media_channel_init() is done async-ly or returning EPENDING, e.g: due to waiting for TURN allocations, the library may reject the call if the media init fails, should we invoke the callback too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting scenario indeed. And note that on_incoming_call() has been called for such case, whereas for other cases, it hasn't.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the on_incoming_call() has been called, the new callback (on_rejected_incoming_call()) should not be called again. Another case would be if the called is answered with 200OK, however there's an issue (e.g: media init) and the call is rejected. The callback would not be called, however app still be informed from on_call_state().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure the behavior is consistent on pjsua2 as well, since on pjsua2 onIncomingCall() is called earlier.

Copy link
Member

@nanangizz nanangizz Sep 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it is async, I guess there can be race between on_incoming_call() and on_incoming_call_med_tp_complete(), in other word, we cannot be sure whether on_incoming_call() has been called?

Moreover, the purpose of the callback is to notify app about the call rejection by lib (e.g: so app can stop the incoming call UI), I guess it is better to still call the callback even when on_incoming_call() has been called. Btw, if rx_data is the problem (add complexity for example), IMHO we can set it to NULL for now for this scenario (notifying app is the priority).

…ode to using defined/enum error for uniformity
@sauwming
Copy link
Member

sauwming commented Sep 27, 2023

Sorry for rather late comment. But maybe we should consider adding call_id to the callback? So app can easily tell: - which call is getting internally rejected by the library, and - whether on_incoming_call() has ever been called (I suppose if call_id == PJSUA_INVALID_ID it means that app has not been notified of such call before).

@sauwming
Copy link
Member

sauwming commented Oct 3, 2023

looks okay.

@sauwming
Copy link
Member

sauwming commented Oct 3, 2023

Just a few additional notes:
The last commit won't be able to help app know if the callback on_incoming_call() has been called.
And I still have some reservations about whether there can be any issue caused by the overlap between on_call_state(DISCONNECTED) and on_rejected_incoming_call().

But I think the PR can be merged first for now.

If there's any feedback @anikitin-intermedia, please feel free to inform us.

@trengginas trengginas merged commit be0c6c4 into master Oct 3, 2023
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants