diff --git a/rtc-datachannel/src/data_channel/mod.rs b/rtc-datachannel/src/data_channel/mod.rs index 1411abd1..85a19587 100644 --- a/rtc-datachannel/src/data_channel/mod.rs +++ b/rtc-datachannel/src/data_channel/mod.rs @@ -71,23 +71,28 @@ impl DataChannel { ) -> Result { 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) } diff --git a/rtc/src/peer_connection/handler/sctp.rs b/rtc/src/peer_connection/handler/sctp.rs index 8f1d4f41..6bfd0ca2 100644 --- a/rtc/src/peer_connection/handler/sctp.rs +++ b/rtc/src/peer_connection/handler/sctp.rs @@ -281,7 +281,20 @@ impl<'a> sansio::Protocol s, + Err(Error::ErrStreamAlreadyExist) => { + conn.stream(message.stream_id)? + } + Err(e) => return Err(e), + }; stream.set_reliability_params( unordered, reliability_type,