Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 22 additions & 17 deletions rtc-datachannel/src/data_channel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,28 @@ impl DataChannel {
) -> Result<Self> {
let mut data_channel = DataChannel::new(config.clone(), association_handle, stream_id);

if !config.negotiated {
let msg = Message::DataChannelOpen(DataChannelOpen {
channel_type: config.channel_type,
priority: config.priority,
reliability_parameter: config.reliability_parameter,
label: config.label.bytes().collect(),
protocol: config.protocol.bytes().collect(),
})
.marshal()?;

data_channel.write_outs.push_back(DataChannelMessage {
association_handle,
stream_id,
ppi: PayloadProtocolIdentifier::Dcep,
payload: msg,
});
}
// Send DataChannelOpen for all channels — including out-of-band negotiated ones.
//
// For non-negotiated channels this initiates the DCEP handshake per RFC 8832 §3.
// For pre-negotiated channels (negotiated=true) the DCEP exchange also opens the
// underlying SCTP stream on both sides. Without it the SCTP association never
// registers the stream, causing every subsequent write to fail with
// "Stream not existed" (issue webrtc-rs/rtc#61).
let msg = Message::DataChannelOpen(DataChannelOpen {
channel_type: config.channel_type,
priority: config.priority,
reliability_parameter: config.reliability_parameter,
label: config.label.bytes().collect(),
protocol: config.protocol.bytes().collect(),
})
.marshal()?;

data_channel.write_outs.push_back(DataChannelMessage {
association_handle,
stream_id,
ppi: PayloadProtocolIdentifier::Dcep,
payload: msg,
});

Ok(data_channel)
}
Expand Down
15 changes: 14 additions & 1 deletion rtc/src/peer_connection/handler/sctp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,20 @@ impl<'a> sansio::Protocol<TaggedRTCMessageInternal, TaggedRTCMessageInternal, RT
::datachannel::data_channel::DataChannel::get_reliability_params(
data_channel_open.channel_type,
);
let mut stream = conn.open_stream(message.stream_id, message.ppi)?;
// For pre-negotiated (out-of-band) channels both peers send
// DataChannelOpen simultaneously. The remote's message may arrive
// before we process our own outbound one, causing get_or_create_stream
// to auto-create the stream first. Treat ErrStreamAlreadyExist as
// non-fatal: the stream is open, just update its reliability params.
let mut stream = match conn
.open_stream(message.stream_id, message.ppi)
{
Ok(s) => s,
Err(Error::ErrStreamAlreadyExist) => {
conn.stream(message.stream_id)?
}
Err(e) => return Err(e),
};
stream.set_reliability_params(
unordered,
reliability_type,
Expand Down