Skip to content

fix: skip RTCP sends when connection is closed or failed#246

Open
kingdomcoding wants to merge 1 commit intoelixir-webrtc:masterfrom
kingdomcoding:fix/rtcp-timers-after-close
Open

fix: skip RTCP sends when connection is closed or failed#246
kingdomcoding wants to merge 1 commit intoelixir-webrtc:masterfrom
kingdomcoding:fix/rtcp-timers-after-close

Conversation

@kingdomcoding
Copy link
Copy Markdown

Problem

After calling PeerConnection.close/1, the TWCC feedback, sender/receiver report, and NACK timers continue to fire because they are self-rescheduling and their already-queued mailbox messages cannot be cancelled. Each fired message attempts to call DTLSTransport.send_rtcp/2, which logs a debug warning since DTLS is no longer connected:

Attempted to send RTCP in wrong DTLS state: closed. Ignoring.

This is a race condition between the DTLS/ICE teardown completing and in-flight timer messages being processed. Fixes #232.

Solution

Add guard clauses before each of the three affected handle_info handlers to short-circuit when conn_state is :closed or :failed. This matches the existing pattern already used by the send_rtp cast handler:

def handle_cast({:send_rtp, track_id, packet, opts}, %{conn_state: conn_state} = state)
    when conn_state not in [:failed, :closed] do

The three new guard clauses follow the same convention:

def handle_info(:send_twcc_feedback, %{conn_state: conn_state} = state)
    when conn_state in [:failed, :closed],
    do: {:noreply, state}

def handle_info({:send_reports, _transceiver_id}, %{conn_state: conn_state} = state)
    when conn_state in [:failed, :closed],
    do: {:noreply, state}

def handle_info({:send_nacks, _transceiver_id}, %{conn_state: conn_state} = state)
    when conn_state in [:failed, :closed],
    do: {:noreply, state}

Testing

Manually verified by starting a WebRTC stream, stopping it, and confirming the debug message no longer appears in logs.

TWCC feedback, sender/receiver reports, and NACK timers are
self-rescheduling and cannot be cancelled. When PeerConnection.close/1
is called, messages already queued in the mailbox for these timers
still fire and attempt to send RTCP via DTLSTransport, which logs
a debug warning because DTLS is no longer connected.

Add guard clauses (matching the existing pattern used by send_rtp)
to short-circuit these three handle_info handlers when conn_state
is :closed or :failed, preventing spurious RTCP sends and the
resulting "Attempted to send RTCP in wrong DTLS state" warning.

Fixes elixir-webrtc#232
Copy link
Copy Markdown
Member

@sgfn sgfn left a comment

Choose a reason for hiding this comment

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

Thanks for the fix!

Comment on lines +1682 to +1685
@impl true
def handle_info(:send_twcc_feedback, %{conn_state: conn_state} = state)
when conn_state in [:failed, :closed],
do: {:noreply, state}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's keep the clause order consistent for all of the :send_ handlers -- the happy path with when conn_state not in [:failed, :closed] should be first


@impl true
def handle_info(:send_twcc_feedback, %{twcc_recorder: twcc_recorder} = state) do
Process.send_after(self(), :send_twcc_feedback, @twcc_interval)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please add a comment in the new fallback clause that we're not scheduling any more TWCC feedback sends.

At this point, it shouldn't be an issue since conn_states :closed and :failed are permanent, but this seems like something that can easily be overlooked in the future were this to change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

keep getting Attempted to send RTCP in wrong DTLS state: closed in console

2 participants