Skip to content

Commit 8134487

Browse files
committed
fix: avoid double RegisterObserver on DataChannel to prevent message loss
In M114, SctpDataChannel uses an ObserverAdapter that relays callbacks through the signaling thread via SafeTask. When RegisterObserver was called twice (first from DataChannelObserver's constructor, then from RTCDataChannel's constructor), the adapter's SetDelegate call could race with in-flight message delivery tasks on the signaling thread, causing messages sent immediately after dc.onopen to be silently lost. The fix removes the initial RegisterObserver from DataChannelObserver, so registration only happens once in RTCDataChannel's constructor. The SCTP layer queues any messages that arrive before an observer is registered, and DeliverQueuedReceivedData() delivers them when RegisterObserver is called. Also dispatches the "open" state change event if the channel has already transitioned to kOpen before the RTCDataChannel wrapper is constructed, ensuring JS onopen handlers fire.
1 parent 861d763 commit 8134487

1 file changed

Lines changed: 15 additions & 2 deletions

File tree

src/interfaces/rtc_data_channel.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ DataChannelObserver::DataChannelObserver(
3030
PeerConnectionFactory *factory,
3131
rtc::scoped_refptr<webrtc::DataChannelInterface> jingleDataChannel)
3232
: _factory(factory), _jingleDataChannel(std::move(jingleDataChannel)) {
33-
_jingleDataChannel->RegisterObserver(this);
33+
// Don't register here. Registration happens in RTCDataChannel's constructor,
34+
// which avoids a double RegisterObserver that causes message loss through
35+
// M114's ObserverAdapter signaling thread relay.
3436
}
3537

3638
void DataChannelObserver::OnStateChange() {
@@ -72,9 +74,20 @@ RTCDataChannel::RTCDataChannel(const Napi::CallbackInfo &info)
7274
_jingleDataChannel = observer->_jingleDataChannel;
7375
_jingleDataChannel->RegisterObserver(this);
7476

75-
// Re-queue cached observer events
77+
// Re-queue any cached observer events (from the window between
78+
// OnDataChannel and this constructor).
7679
requeue(*observer, *this);
7780

81+
// If the channel already transitioned to open before we registered,
82+
// dispatch the open event so JS onopen handlers fire.
83+
auto state = _jingleDataChannel->state();
84+
if (state == webrtc::DataChannelInterface::kOpen) {
85+
Dispatch(
86+
Callback1<RTCDataChannel>::Create([state](RTCDataChannel &channel) {
87+
RTCDataChannel::HandleStateChange(channel, state);
88+
}));
89+
}
90+
7891
delete observer;
7992

8093
// NOTE(mroberts): These doesn't actually matter yet.

0 commit comments

Comments
 (0)