media.cpp: prevent AudioMediaPlayer destructor from doubly removing port #4
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The
AudioMediaPlayer
destructor has an issue where it effectively destroys the player's conference port twice, in a thread-unsafe way that leaves an opportunity for another thread to see a conference port used by a player as free-for-use, and reserve it for other purposes before ultimately being destroyed again, causing crashes.We see this race condition ~1 in 5 times when attempting to disrupt an ongoing call with a talkdown call, where
StopTransmit()
is interrupted by the PJSIP thread answering the incoming call.Here's an example of how this can happen:
The approach taken in this PR to fix this problem is taken from a pattern used elsewhere in media.cpp presumably to prevent this exact problem - invalidating the
AudioMedia
id
such thatunregisterMediaPort()
does not attempt to remove the port unnecessarily:pjproject/pjsip/src/pjsua2/media.cpp
Lines 665 to 670 in 7eec09d
Relevant segment of
unregisterMediaPort()
:pjproject/pjsip/src/pjsua2/media.cpp
Lines 177 to 182 in 7eec09d
This ensures that the only attempt to remove an
AudioMediaPlayer
's port occurs inpjsua_player_destroy()
, therefore guaranteeing thatpjsua_player_destroy()
does not delete a now-occupied port mistakenly.