| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2019 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 11 | #include "pc/data_channel_controller.h" |
| 12 | |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 13 | #include <cstddef> |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 14 | #include <cstdint> |
| 15 | #include <memory> |
| Florent Castelli | 8037fc6 | 2024-08-29 13:00:40 | [diff] [blame] | 16 | #include <optional> |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 17 | #include <string> |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 18 | #include <utility> |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 19 | #include <vector> |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 20 | |
| Tommi | 51edb56 | 2023-03-14 08:23:51 | [diff] [blame] | 21 | #include "absl/algorithm/container.h" |
| Jonas Oreland | 90ea141 | 2025-07-04 11:54:36 | [diff] [blame] | 22 | #include "absl/functional/any_invocable.h" |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 23 | #include "api/array_view.h" |
| 24 | #include "api/data_channel_event_observer_interface.h" |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 25 | #include "api/data_channel_interface.h" |
| Florent Castelli | 0012bfa | 2024-07-26 16:16:41 | [diff] [blame] | 26 | #include "api/priority.h" |
| Harald Alvestrand | 5761e7b | 2021-01-29 14:45:08 | [diff] [blame] | 27 | #include "api/rtc_error.h" |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 28 | #include "api/scoped_refptr.h" |
| 29 | #include "api/sequence_checker.h" |
| 30 | #include "api/task_queue/pending_task_safety_flag.h" |
| 31 | #include "api/transport/data_channel_transport_interface.h" |
| 32 | #include "media/sctp/sctp_transport_internal.h" |
| 33 | #include "pc/data_channel_utils.h" |
| Harald Alvestrand | 5b84f38 | 2022-02-08 10:49:09 | [diff] [blame] | 34 | #include "pc/peer_connection_internal.h" |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 35 | #include "pc/sctp_data_channel.h" |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 36 | #include "pc/sctp_utils.h" |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 37 | #include "rtc_base/checks.h" |
| 38 | #include "rtc_base/copy_on_write_buffer.h" |
| Harald Alvestrand | 5761e7b | 2021-01-29 14:45:08 | [diff] [blame] | 39 | #include "rtc_base/logging.h" |
| Harald Alvestrand | f0d5caf | 2025-04-07 09:08:51 | [diff] [blame] | 40 | #include "rtc_base/ssl_stream_adapter.h" |
| 41 | #include "rtc_base/thread.h" |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 42 | #include "rtc_base/time_utils.h" |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 43 | |
| 44 | namespace webrtc { |
| 45 | |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 46 | using Message = DataChannelEventObserverInterface::Message; |
| 47 | using Direction = DataChannelEventObserverInterface::Message::Direction; |
| 48 | |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 49 | DataChannelController::~DataChannelController() { |
| Tommi | 5271965 | 2023-04-04 09:59:55 | [diff] [blame] | 50 | RTC_DCHECK(sctp_data_channels_n_.empty()) |
| 51 | << "Missing call to TeardownDataChannelTransport_n?"; |
| 52 | RTC_DCHECK(!signaling_safety_.flag()->alive()) |
| 53 | << "Missing call to PrepareForShutdown?"; |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 54 | } |
| Harald Alvestrand | 9e5aeb9 | 2022-05-11 09:35:36 | [diff] [blame] | 55 | |
| Philipp Hancke | 522380f | 2023-05-09 07:41:03 | [diff] [blame] | 56 | bool DataChannelController::HasDataChannels() const { |
| Tommi | 44ebe2a | 2023-05-15 13:14:10 | [diff] [blame] | 57 | RTC_DCHECK_RUN_ON(signaling_thread()); |
| 58 | return channel_usage_ == DataChannelUsage::kInUse; |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 59 | } |
| 60 | |
| Harald Alvestrand | 5da3eb0 | 2023-03-15 20:39:42 | [diff] [blame] | 61 | bool DataChannelController::HasUsedDataChannels() const { |
| 62 | RTC_DCHECK_RUN_ON(signaling_thread()); |
| Tommi | 44ebe2a | 2023-05-15 13:14:10 | [diff] [blame] | 63 | return channel_usage_ != DataChannelUsage::kNeverUsed; |
| Harald Alvestrand | 5da3eb0 | 2023-03-15 20:39:42 | [diff] [blame] | 64 | } |
| 65 | |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 66 | void DataChannelController::SetEventObserver( |
| 67 | std::unique_ptr<DataChannelEventObserverInterface> observer) { |
| 68 | RTC_DCHECK_RUN_ON(network_thread()); |
| 69 | event_observer_ = std::move(observer); |
| 70 | } |
| 71 | |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 72 | RTCError DataChannelController::SendData(StreamId sid, |
| 73 | const SendDataParams& params, |
| 74 | const CopyOnWriteBuffer& payload) { |
| Tommi | add7ac0 | 2023-04-12 10:01:10 | [diff] [blame] | 75 | RTC_DCHECK_RUN_ON(network_thread()); |
| 76 | if (!data_channel_transport_) { |
| 77 | RTC_LOG(LS_ERROR) << "SendData called before transport is ready"; |
| 78 | return RTCError(RTCErrorType::INVALID_STATE); |
| 79 | } |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 80 | RTCError result = |
| 81 | data_channel_transport_->SendData(sid.stream_id_int(), params, payload); |
| 82 | |
| 83 | if (event_observer_ && result.ok()) { |
| 84 | if (std::optional<Message> message = |
| 85 | BuildObserverMessage(sid, params.type, payload, Direction::kSend)) { |
| 86 | event_observer_->OnMessage(*message); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | return result; |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 91 | } |
| 92 | |
| Florent Castelli | 0012bfa | 2024-07-26 16:16:41 | [diff] [blame] | 93 | void DataChannelController::AddSctpDataStream(StreamId sid, |
| 94 | PriorityValue priority) { |
| Tommi | 55f7280 | 2023-03-27 10:39:33 | [diff] [blame] | 95 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | add7ac0 | 2023-04-12 10:01:10 | [diff] [blame] | 96 | if (data_channel_transport_) { |
| Florent Castelli | 0012bfa | 2024-07-26 16:16:41 | [diff] [blame] | 97 | data_channel_transport_->OpenChannel(sid.stream_id_int(), priority); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 98 | } |
| 99 | } |
| 100 | |
| Tommi | 4c84222 | 2023-03-21 10:35:24 | [diff] [blame] | 101 | void DataChannelController::RemoveSctpDataStream(StreamId sid) { |
| Tommi | 55f7280 | 2023-03-27 10:39:33 | [diff] [blame] | 102 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | add7ac0 | 2023-04-12 10:01:10 | [diff] [blame] | 103 | if (data_channel_transport_) { |
| 104 | data_channel_transport_->CloseChannel(sid.stream_id_int()); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 105 | } |
| 106 | } |
| 107 | |
| Tommi | d2afbaf | 2023-03-02 09:51:16 | [diff] [blame] | 108 | void DataChannelController::OnChannelStateChanged( |
| 109 | SctpDataChannel* channel, |
| 110 | DataChannelInterface::DataState state) { |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 111 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | eec1810 | 2023-06-22 08:13:52 | [diff] [blame] | 112 | |
| 113 | // Stash away the internal id here in case `OnSctpDataChannelClosed` ends up |
| 114 | // releasing the last reference to the channel. |
| 115 | const int channel_id = channel->internal_id(); |
| 116 | |
| Tommi | d2afbaf | 2023-03-02 09:51:16 | [diff] [blame] | 117 | if (state == DataChannelInterface::DataState::kClosed) |
| 118 | OnSctpDataChannelClosed(channel); |
| 119 | |
| Tommi | 44ebe2a | 2023-05-15 13:14:10 | [diff] [blame] | 120 | DataChannelUsage channel_usage = sctp_data_channels_n_.empty() |
| 121 | ? DataChannelUsage::kHaveBeenUsed |
| 122 | : DataChannelUsage::kInUse; |
| 123 | signaling_thread()->PostTask(SafeTask( |
| Tommi | eec1810 | 2023-06-22 08:13:52 | [diff] [blame] | 124 | signaling_safety_.flag(), [this, channel_id, state, channel_usage] { |
| Tommi | 44ebe2a | 2023-05-15 13:14:10 | [diff] [blame] | 125 | RTC_DCHECK_RUN_ON(signaling_thread()); |
| 126 | channel_usage_ = channel_usage; |
| 127 | pc_->OnSctpDataChannelStateChanged(channel_id, state); |
| 128 | })); |
| Tommi | d2afbaf | 2023-03-02 09:51:16 | [diff] [blame] | 129 | } |
| 130 | |
| Victor Boivie | fea41f5 | 2024-03-11 15:43:31 | [diff] [blame] | 131 | size_t DataChannelController::buffered_amount(StreamId sid) const { |
| 132 | RTC_DCHECK_RUN_ON(network_thread()); |
| 133 | if (!data_channel_transport_) { |
| 134 | return 0; |
| 135 | } |
| 136 | return data_channel_transport_->buffered_amount(sid.stream_id_int()); |
| 137 | } |
| 138 | |
| Victor Boivie | cdecc4e | 2024-03-18 12:47:34 | [diff] [blame] | 139 | size_t DataChannelController::buffered_amount_low_threshold( |
| 140 | StreamId sid) const { |
| 141 | RTC_DCHECK_RUN_ON(network_thread()); |
| 142 | if (!data_channel_transport_) { |
| 143 | return 0; |
| 144 | } |
| 145 | return data_channel_transport_->buffered_amount_low_threshold( |
| 146 | sid.stream_id_int()); |
| 147 | } |
| 148 | |
| 149 | void DataChannelController::SetBufferedAmountLowThreshold(StreamId sid, |
| 150 | size_t bytes) { |
| 151 | RTC_DCHECK_RUN_ON(network_thread()); |
| 152 | if (!data_channel_transport_) { |
| 153 | return; |
| 154 | } |
| 155 | data_channel_transport_->SetBufferedAmountLowThreshold(sid.stream_id_int(), |
| 156 | bytes); |
| 157 | } |
| 158 | |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 159 | void DataChannelController::OnDataReceived(int channel_id, |
| 160 | DataMessageType type, |
| 161 | const CopyOnWriteBuffer& buffer) { |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 162 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | 5bbfb00 | 2023-03-04 15:47:53 | [diff] [blame] | 163 | |
| Tommi | 4e1c957 | 2023-03-15 11:36:20 | [diff] [blame] | 164 | if (HandleOpenMessage_n(channel_id, type, buffer)) |
| Tommi | 5bbfb00 | 2023-03-04 15:47:53 | [diff] [blame] | 165 | return; |
| 166 | |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 167 | auto it = absl::c_find_if(sctp_data_channels_n_, [&](const auto& c) { |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 168 | return c->sid_n().has_value() && c->sid_n()->stream_id_int() == channel_id; |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 169 | }); |
| 170 | |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 171 | if (it != sctp_data_channels_n_.end()) { |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 172 | (*it)->OnDataReceived(type, buffer); |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 173 | |
| 174 | if (event_observer_) { |
| 175 | if (std::optional<Message> message = BuildObserverMessage( |
| 176 | StreamId(channel_id), type, buffer, Direction::kReceive)) { |
| 177 | event_observer_->OnMessage(*message); |
| 178 | } |
| 179 | } |
| 180 | } |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 181 | } |
| 182 | |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 183 | void DataChannelController::OnChannelClosing(int channel_id) { |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 184 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 185 | auto it = absl::c_find_if(sctp_data_channels_n_, [&](const auto& c) { |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 186 | return c->sid_n().has_value() && c->sid_n()->stream_id_int() == channel_id; |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 187 | }); |
| 188 | |
| 189 | if (it != sctp_data_channels_n_.end()) |
| 190 | (*it)->OnClosingProcedureStartedRemotely(); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 191 | } |
| 192 | |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 193 | void DataChannelController::OnChannelClosed(int channel_id) { |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 194 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 195 | StreamId sid(channel_id); |
| 196 | sid_allocator_.ReleaseSid(sid); |
| 197 | auto it = absl::c_find_if(sctp_data_channels_n_, |
| Tommi | 1158bde | 2023-03-30 10:01:56 | [diff] [blame] | 198 | [&](const auto& c) { return c->sid_n() == sid; }); |
| Tommi | 51edb56 | 2023-03-14 08:23:51 | [diff] [blame] | 199 | |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 200 | if (it != sctp_data_channels_n_.end()) { |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 201 | scoped_refptr<SctpDataChannel> channel = std::move(*it); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 202 | sctp_data_channels_n_.erase(it); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 203 | channel->OnClosingProcedureComplete(); |
| 204 | } |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 205 | } |
| 206 | |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 207 | void DataChannelController::OnReadyToSend() { |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 208 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 209 | auto copy = sctp_data_channels_n_; |
| 210 | for (const auto& channel : copy) { |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 211 | if (channel->sid_n().has_value()) { |
| Tommi | e9aa867 | 2023-03-20 13:43:09 | [diff] [blame] | 212 | channel->OnTransportReady(); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 213 | } else { |
| 214 | // This happens for role==SSL_SERVER channels when we get notified by |
| 215 | // the transport *before* the SDP code calls `AllocateSctpSids` to |
| 216 | // trigger assignment of sids. In this case OnTransportReady() will be |
| 217 | // called from within `AllocateSctpSids` below. |
| 218 | RTC_LOG(LS_INFO) << "OnReadyToSend: Still waiting for an id for channel."; |
| 219 | } |
| 220 | } |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 221 | } |
| 222 | |
| Florent Castelli | dcb9ffc | 2021-06-29 12:58:23 | [diff] [blame] | 223 | void DataChannelController::OnTransportClosed(RTCError error) { |
| Harald Alvestrand | 2697ac1 | 2019-12-16 09:37:04 | [diff] [blame] | 224 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | b00d63c | 2023-04-12 17:49:53 | [diff] [blame] | 225 | |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 226 | // This loop will close all data channels and trigger a callback to |
| Tommi | b00d63c | 2023-04-12 17:49:53 | [diff] [blame] | 227 | // `OnSctpDataChannelClosed`. We'll empty `sctp_data_channels_n_`, first |
| 228 | // and `OnSctpDataChannelClosed` will become a noop but we'll release the |
| 229 | // StreamId here. |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 230 | std::vector<scoped_refptr<SctpDataChannel>> temp_sctp_dcs; |
| Tommi | b00d63c | 2023-04-12 17:49:53 | [diff] [blame] | 231 | temp_sctp_dcs.swap(sctp_data_channels_n_); |
| 232 | for (const auto& channel : temp_sctp_dcs) { |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 233 | channel->OnTransportChannelClosed(error); |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 234 | if (channel->sid_n().has_value()) { |
| 235 | sid_allocator_.ReleaseSid(*channel->sid_n()); |
| 236 | } |
| Tommi | b00d63c | 2023-04-12 17:49:53 | [diff] [blame] | 237 | } |
| Harald Alvestrand | 2697ac1 | 2019-12-16 09:37:04 | [diff] [blame] | 238 | } |
| 239 | |
| Victor Boivie | cdecc4e | 2024-03-18 12:47:34 | [diff] [blame] | 240 | void DataChannelController::OnBufferedAmountLow(int channel_id) { |
| 241 | RTC_DCHECK_RUN_ON(network_thread()); |
| 242 | auto it = absl::c_find_if(sctp_data_channels_n_, [&](const auto& c) { |
| 243 | return c->sid_n().has_value() && c->sid_n()->stream_id_int() == channel_id; |
| 244 | }); |
| 245 | |
| 246 | if (it != sctp_data_channels_n_.end()) |
| 247 | (*it)->OnBufferedAmountLow(); |
| 248 | } |
| 249 | |
| Tommi | aa3c9f2 | 2023-04-18 10:19:19 | [diff] [blame] | 250 | void DataChannelController::SetupDataChannelTransport_n( |
| 251 | DataChannelTransportInterface* transport) { |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 252 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | aa3c9f2 | 2023-04-18 10:19:19 | [diff] [blame] | 253 | RTC_DCHECK(transport); |
| 254 | set_data_channel_transport(transport); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 255 | } |
| 256 | |
| Tommi | 1f708ef | 2023-03-31 16:40:50 | [diff] [blame] | 257 | void DataChannelController::PrepareForShutdown() { |
| 258 | RTC_DCHECK_RUN_ON(signaling_thread()); |
| Tommi | 5271965 | 2023-04-04 09:59:55 | [diff] [blame] | 259 | signaling_safety_.reset(PendingTaskSafetyFlag::CreateDetachedInactive()); |
| Tommi | 44ebe2a | 2023-05-15 13:14:10 | [diff] [blame] | 260 | if (channel_usage_ != DataChannelUsage::kNeverUsed) |
| 261 | channel_usage_ = DataChannelUsage::kHaveBeenUsed; |
| Tommi | 1f708ef | 2023-03-31 16:40:50 | [diff] [blame] | 262 | } |
| 263 | |
| Tommi | b00d63c | 2023-04-12 17:49:53 | [diff] [blame] | 264 | void DataChannelController::TeardownDataChannelTransport_n(RTCError error) { |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 265 | RTC_DCHECK_RUN_ON(network_thread()); |
| Mirko Bonadei | 2983135 | 2023-04-14 17:03:47 | [diff] [blame] | 266 | OnTransportClosed(error); |
| Tommi | aa3c9f2 | 2023-04-18 10:19:19 | [diff] [blame] | 267 | set_data_channel_transport(nullptr); |
| Tommi | b00d63c | 2023-04-12 17:49:53 | [diff] [blame] | 268 | RTC_DCHECK(sctp_data_channels_n_.empty()); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 269 | weak_factory_.InvalidateWeakPtrs(); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 270 | } |
| 271 | |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 272 | void DataChannelController::OnTransportChanged( |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 273 | DataChannelTransportInterface* new_data_channel_transport) { |
| 274 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | add7ac0 | 2023-04-12 10:01:10 | [diff] [blame] | 275 | if (data_channel_transport_ && |
| 276 | data_channel_transport_ != new_data_channel_transport) { |
| Artem Titov | 880fa81 | 2021-07-30 20:30:23 | [diff] [blame] | 277 | // Changed which data channel transport is used for `sctp_mid_` (eg. now |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 278 | // it's bundled). |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 279 | set_data_channel_transport(new_data_channel_transport); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 280 | } |
| 281 | } |
| 282 | |
| Taylor Brandstetter | 3a034e1 | 2020-07-09 22:32:34 | [diff] [blame] | 283 | std::vector<DataChannelStats> DataChannelController::GetDataChannelStats() |
| Tomas Gunnarsson | 2e94de5 | 2020-06-16 14:54:10 | [diff] [blame] | 284 | const { |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 285 | RTC_DCHECK_RUN_ON(network_thread()); |
| Taylor Brandstetter | 3a034e1 | 2020-07-09 22:32:34 | [diff] [blame] | 286 | std::vector<DataChannelStats> stats; |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 287 | stats.reserve(sctp_data_channels_n_.size()); |
| 288 | for (const auto& channel : sctp_data_channels_n_) |
| Tomas Gunnarsson | 2e94de5 | 2020-06-16 14:54:10 | [diff] [blame] | 289 | stats.push_back(channel->GetStats()); |
| 290 | return stats; |
| 291 | } |
| 292 | |
| Tommi | 5bbfb00 | 2023-03-04 15:47:53 | [diff] [blame] | 293 | bool DataChannelController::HandleOpenMessage_n( |
| Tommi | 4e1c957 | 2023-03-15 11:36:20 | [diff] [blame] | 294 | int channel_id, |
| 295 | DataMessageType type, |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 296 | const CopyOnWriteBuffer& buffer) { |
| Tommi | 4e1c957 | 2023-03-15 11:36:20 | [diff] [blame] | 297 | if (type != DataMessageType::kControl || !IsOpenMessage(buffer)) |
| Tommi | 5bbfb00 | 2023-03-04 15:47:53 | [diff] [blame] | 298 | return false; |
| 299 | |
| 300 | // Received OPEN message; parse and signal that a new data channel should |
| 301 | // be created. |
| 302 | std::string label; |
| 303 | InternalDataChannelInit config; |
| Tommi | 4e1c957 | 2023-03-15 11:36:20 | [diff] [blame] | 304 | config.id = channel_id; |
| Tommi | 5bbfb00 | 2023-03-04 15:47:53 | [diff] [blame] | 305 | if (!ParseDataChannelOpenMessage(buffer, &label, &config)) { |
| 306 | RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid " |
| Tommi | 4e1c957 | 2023-03-15 11:36:20 | [diff] [blame] | 307 | << channel_id; |
| Tommi | 5bbfb00 | 2023-03-04 15:47:53 | [diff] [blame] | 308 | } else { |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 309 | config.open_handshake_role = InternalDataChannelInit::kAcker; |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 310 | auto channel_or_error = CreateDataChannel(label, config); |
| 311 | if (channel_or_error.ok()) { |
| 312 | signaling_thread()->PostTask(SafeTask( |
| 313 | signaling_safety_.flag(), |
| 314 | [this, channel = channel_or_error.MoveValue(), |
| 315 | ready_to_send = data_channel_transport_->IsReadyToSend()] { |
| 316 | RTC_DCHECK_RUN_ON(signaling_thread()); |
| 317 | OnDataChannelOpenMessage(std::move(channel), ready_to_send); |
| 318 | })); |
| 319 | } else { |
| 320 | RTC_LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message." |
| 321 | << ToString(channel_or_error.error().type()); |
| 322 | } |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 323 | } |
| Tommi | 5bbfb00 | 2023-03-04 15:47:53 | [diff] [blame] | 324 | return true; |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 325 | } |
| 326 | |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 327 | void DataChannelController::OnDataChannelOpenMessage( |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 328 | scoped_refptr<SctpDataChannel> channel, |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 329 | bool ready_to_send) { |
| Tommi | 44ebe2a | 2023-05-15 13:14:10 | [diff] [blame] | 330 | channel_usage_ = DataChannelUsage::kInUse; |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 331 | auto proxy = SctpDataChannel::CreateProxy(channel, signaling_safety_.flag()); |
| Andrey Logvin | 7f16fcd | 2023-04-05 08:53:13 | [diff] [blame] | 332 | |
| Jonas Oreland | 90ea141 | 2025-07-04 11:54:36 | [diff] [blame] | 333 | pc_->RunWithObserver([&](auto observer) { observer->OnDataChannel(proxy); }); |
| Andrey Logvin | 7f16fcd | 2023-04-05 08:53:13 | [diff] [blame] | 334 | pc_->NoteDataAddedEvent(); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 335 | |
| 336 | if (ready_to_send) { |
| 337 | network_thread()->PostTask([channel = std::move(channel)] { |
| 338 | if (channel->state() != DataChannelInterface::DataState::kClosed) |
| 339 | channel->OnTransportReady(); |
| 340 | }); |
| 341 | } |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 342 | } |
| 343 | |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 344 | // RTC_RUN_ON(network_thread()) |
| 345 | RTCError DataChannelController::ReserveOrAllocateSid( |
| Florent Castelli | 8037fc6 | 2024-08-29 13:00:40 | [diff] [blame] | 346 | std::optional<StreamId>& sid, |
| Evan Shrubsole | eb835d0 | 2025-03-12 09:41:06 | [diff] [blame] | 347 | std::optional<SSLRole> fallback_ssl_role) { |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 348 | if (sid.has_value()) { |
| 349 | return sid_allocator_.ReserveSid(*sid) |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 350 | ? RTCError::OK() |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 351 | : RTCError(RTCErrorType::INVALID_RANGE, "StreamId reserved."); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 352 | } |
| 353 | |
| 354 | // Attempt to allocate an ID based on the negotiated role. |
| Evan Shrubsole | eb835d0 | 2025-03-12 09:41:06 | [diff] [blame] | 355 | std::optional<SSLRole> role = pc_->GetSctpSslRole_n(); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 356 | if (!role) |
| 357 | role = fallback_ssl_role; |
| 358 | if (role) { |
| 359 | sid = sid_allocator_.AllocateSid(*role); |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 360 | if (!sid.has_value()) |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 361 | return RTCError(RTCErrorType::RESOURCE_EXHAUSTED); |
| 362 | } |
| 363 | // When we get here, we may still not have an ID, but that's a supported case |
| 364 | // whereby an id will be assigned later. |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 365 | RTC_DCHECK(sid.has_value() || !role); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 366 | return RTCError::OK(); |
| 367 | } |
| 368 | |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 369 | // RTC_RUN_ON(network_thread()) |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 370 | RTCErrorOr<scoped_refptr<SctpDataChannel>> |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 371 | DataChannelController::CreateDataChannel(const std::string& label, |
| 372 | InternalDataChannelInit& config) { |
| Florent Castelli | 8037fc6 | 2024-08-29 13:00:40 | [diff] [blame] | 373 | std::optional<StreamId> sid = std::nullopt; |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 374 | if (config.id != -1) { |
| Evan Shrubsole | 945e517 | 2025-04-08 14:11:45 | [diff] [blame] | 375 | if (config.id < 0 || config.id > kMaxSctpSid) { |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 376 | return RTCError(RTCErrorType::INVALID_RANGE, "StreamId out of range."); |
| 377 | } |
| 378 | sid = StreamId(config.id); |
| 379 | } |
| 380 | |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 381 | RTCError err = ReserveOrAllocateSid(sid, config.fallback_ssl_role); |
| 382 | if (!err.ok()) |
| 383 | return err; |
| 384 | |
| 385 | // In case `sid` has changed. Update `config` accordingly. |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 386 | if (sid.has_value()) { |
| 387 | config.id = sid->stream_id_int(); |
| 388 | } |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 389 | |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 390 | scoped_refptr<SctpDataChannel> channel = SctpDataChannel::Create( |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 391 | weak_factory_.GetWeakPtr(), label, data_channel_transport_ != nullptr, |
| 392 | config, signaling_thread(), network_thread()); |
| 393 | RTC_DCHECK(channel); |
| 394 | sctp_data_channels_n_.push_back(channel); |
| 395 | |
| 396 | // If we have an id already, notify the transport. |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 397 | if (sid.has_value()) |
| Florent Castelli | 0012bfa | 2024-07-26 16:16:41 | [diff] [blame] | 398 | AddSctpDataStream(*sid, |
| 399 | config.priority.value_or(PriorityValue(Priority::kLow))); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 400 | |
| 401 | return channel; |
| 402 | } |
| 403 | |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 404 | RTCErrorOr<scoped_refptr<DataChannelInterface>> |
| Taylor Brandstetter | 3a034e1 | 2020-07-09 22:32:34 | [diff] [blame] | 405 | DataChannelController::InternalCreateDataChannelWithProxy( |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 406 | const std::string& label, |
| Tommi | 335d084 | 2023-03-25 09:56:18 | [diff] [blame] | 407 | const InternalDataChannelInit& config) { |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 408 | RTC_DCHECK_RUN_ON(signaling_thread()); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 409 | RTC_DCHECK(!pc_->IsClosed()); |
| Tommi | 335d084 | 2023-03-25 09:56:18 | [diff] [blame] | 410 | if (!config.IsValid()) { |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 411 | LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, |
| 412 | "Invalid DataChannelInit"); |
| Tommi | 9296a16 | 2023-03-21 15:28:52 | [diff] [blame] | 413 | } |
| 414 | |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 415 | bool ready_to_send = false; |
| Tommi | 335d084 | 2023-03-25 09:56:18 | [diff] [blame] | 416 | InternalDataChannelInit new_config = config; |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 417 | auto ret = network_thread()->BlockingCall( |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 418 | [&]() -> RTCErrorOr<scoped_refptr<SctpDataChannel>> { |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 419 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 420 | auto channel = CreateDataChannel(label, new_config); |
| 421 | if (!channel.ok()) |
| 422 | return channel; |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 423 | ready_to_send = |
| 424 | data_channel_transport_ && data_channel_transport_->IsReadyToSend(); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 425 | if (ready_to_send) { |
| 426 | // If the transport is ready to send because the initial channel |
| 427 | // ready signal may have been sent before the DataChannel creation. |
| 428 | // This has to be done async because the upper layer objects (e.g. |
| 429 | // Chrome glue and WebKit) are not wired up properly until after |
| 430 | // `InternalCreateDataChannelWithProxy` returns. |
| 431 | network_thread()->PostTask([channel = channel.value()] { |
| 432 | if (channel->state() != DataChannelInterface::DataState::kClosed) |
| 433 | channel->OnTransportReady(); |
| 434 | }); |
| 435 | } |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 436 | |
| 437 | return channel; |
| 438 | }); |
| 439 | |
| 440 | if (!ret.ok()) |
| 441 | return ret.MoveError(); |
| 442 | |
| Tommi | 44ebe2a | 2023-05-15 13:14:10 | [diff] [blame] | 443 | channel_usage_ = DataChannelUsage::kInUse; |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 444 | return SctpDataChannel::CreateProxy(ret.MoveValue(), |
| 445 | signaling_safety_.flag()); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 446 | } |
| 447 | |
| Evan Shrubsole | eb835d0 | 2025-03-12 09:41:06 | [diff] [blame] | 448 | void DataChannelController::AllocateSctpSids(SSLRole role) { |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 449 | RTC_DCHECK_RUN_ON(network_thread()); |
| 450 | |
| 451 | const bool ready_to_send = |
| 452 | data_channel_transport_ && data_channel_transport_->IsReadyToSend(); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 453 | |
| 454 | std::vector<std::pair<SctpDataChannel*, StreamId>> channels_to_update; |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 455 | std::vector<scoped_refptr<SctpDataChannel>> channels_to_close; |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 456 | for (auto it = sctp_data_channels_n_.begin(); |
| 457 | it != sctp_data_channels_n_.end();) { |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 458 | if (!(*it)->sid_n().has_value()) { |
| Florent Castelli | 8037fc6 | 2024-08-29 13:00:40 | [diff] [blame] | 459 | std::optional<StreamId> sid = sid_allocator_.AllocateSid(role); |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 460 | if (sid.has_value()) { |
| 461 | (*it)->SetSctpSid_n(*sid); |
| Florent Castelli | 0012bfa | 2024-07-26 16:16:41 | [diff] [blame] | 462 | AddSctpDataStream(*sid, (*it)->priority()); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 463 | if (ready_to_send) { |
| 464 | RTC_LOG(LS_INFO) << "AllocateSctpSids: Id assigned, ready to send."; |
| 465 | (*it)->OnTransportReady(); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 466 | } |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 467 | channels_to_update.push_back(std::make_pair((*it).get(), *sid)); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 468 | } else { |
| 469 | channels_to_close.push_back(std::move(*it)); |
| 470 | it = sctp_data_channels_n_.erase(it); |
| 471 | continue; |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 472 | } |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 473 | } |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 474 | ++it; |
| 475 | } |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 476 | |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 477 | // Since closing modifies the list of channels, we have to do the actual |
| 478 | // closing outside the loop. |
| 479 | for (const auto& channel : channels_to_close) { |
| Harald Alvestrand | dfbfb46 | 2019-12-08 04:55:43 | [diff] [blame] | 480 | channel->CloseAbruptlyWithDataChannelFailure("Failed to allocate SCTP SID"); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 481 | } |
| 482 | } |
| 483 | |
| Taylor Brandstetter | 3a034e1 | 2020-07-09 22:32:34 | [diff] [blame] | 484 | void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) { |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 485 | RTC_DCHECK_RUN_ON(network_thread()); |
| 486 | // After the closing procedure is done, it's safe to use this ID for |
| 487 | // another data channel. |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 488 | if (channel->sid_n().has_value()) { |
| 489 | sid_allocator_.ReleaseSid(*channel->sid_n()); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 490 | } |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 491 | auto it = absl::c_find_if(sctp_data_channels_n_, |
| 492 | [&](const auto& c) { return c.get() == channel; }); |
| 493 | if (it != sctp_data_channels_n_.end()) |
| 494 | sctp_data_channels_n_.erase(it); |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 495 | } |
| 496 | |
| Tomas Gunnarsson | 7d3cfbf | 2020-06-15 11:47:42 | [diff] [blame] | 497 | void DataChannelController::set_data_channel_transport( |
| 498 | DataChannelTransportInterface* transport) { |
| 499 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | aa3c9f2 | 2023-04-18 10:19:19 | [diff] [blame] | 500 | |
| 501 | if (data_channel_transport_) |
| 502 | data_channel_transport_->SetDataSink(nullptr); |
| 503 | |
| Tomas Gunnarsson | 7d3cfbf | 2020-06-15 11:47:42 | [diff] [blame] | 504 | data_channel_transport_ = transport; |
| Tommi | aa3c9f2 | 2023-04-18 10:19:19 | [diff] [blame] | 505 | |
| 506 | if (data_channel_transport_) { |
| 507 | // There's a new data channel transport. This needs to be signaled to the |
| 508 | // `sctp_data_channels_n_` so that they can reopen and reconnect. This is |
| 509 | // necessary when bundling is applied. |
| 510 | NotifyDataChannelsOfTransportCreated(); |
| 511 | data_channel_transport_->SetDataSink(this); |
| 512 | } |
| Tomas Gunnarsson | 7d3cfbf | 2020-06-15 11:47:42 | [diff] [blame] | 513 | } |
| 514 | |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 515 | std::optional<Message> DataChannelController::BuildObserverMessage( |
| 516 | StreamId sid, |
| 517 | DataMessageType type, |
| 518 | ArrayView<const uint8_t> payload, |
| 519 | Message::Direction direction) const { |
| 520 | RTC_DCHECK_RUN_ON(network_thread()); |
| 521 | |
| 522 | if (type != DataMessageType::kText && type != DataMessageType::kBinary) { |
| 523 | return std::nullopt; |
| 524 | } |
| 525 | |
| 526 | auto it = absl::c_find_if(sctp_data_channels_n_, [sid](const auto& channel) { |
| 527 | return channel->sid_n() == sid; |
| 528 | }); |
| 529 | |
| 530 | if (it == sctp_data_channels_n_.end()) { |
| 531 | return std::nullopt; |
| 532 | } |
| 533 | |
| 534 | Message message; |
| 535 | Message::DataType data_type = type == DataMessageType::kBinary |
| 536 | ? Message::DataType::kBinary |
| 537 | : Message::DataType::kString; |
| 538 | message.set_data_type(data_type); |
| Evan Shrubsole | e6a1f70 | 2025-04-15 14:55:42 | [diff] [blame] | 539 | message.set_unix_timestamp_ms(TimeUTCMillis()); |
| Philip Eliasson | 17ddd31 | 2025-04-08 08:33:49 | [diff] [blame] | 540 | message.set_datachannel_id(sid.stream_id_int()); |
| 541 | message.set_label((*it)->label()); |
| 542 | message.set_direction(direction); |
| 543 | message.set_data(payload); |
| 544 | |
| 545 | return message; |
| 546 | } |
| 547 | |
| Tomas Gunnarsson | 2e94de5 | 2020-06-16 14:54:10 | [diff] [blame] | 548 | void DataChannelController::NotifyDataChannelsOfTransportCreated() { |
| 549 | RTC_DCHECK_RUN_ON(network_thread()); |
| Tommi | add7ac0 | 2023-04-12 10:01:10 | [diff] [blame] | 550 | RTC_DCHECK(data_channel_transport_); |
| Tommi | 4f7ade5 | 2023-03-29 18:46:59 | [diff] [blame] | 551 | |
| Tommi | 1158bde | 2023-03-30 10:01:56 | [diff] [blame] | 552 | for (const auto& channel : sctp_data_channels_n_) { |
| Victor Boivie | cd3d29b | 2024-03-09 20:50:42 | [diff] [blame] | 553 | if (channel->sid_n().has_value()) |
| Florent Castelli | 0012bfa | 2024-07-26 16:16:41 | [diff] [blame] | 554 | AddSctpDataStream(*channel->sid_n(), channel->priority()); |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 555 | channel->OnTransportChannelCreated(); |
| Tommi | 1158bde | 2023-03-30 10:01:56 | [diff] [blame] | 556 | } |
| Tommi | dc90a9c | 2023-03-20 09:26:19 | [diff] [blame] | 557 | } |
| 558 | |
| Evan Shrubsole | 6a9a1ae | 2025-03-21 12:54:15 | [diff] [blame] | 559 | Thread* DataChannelController::network_thread() const { |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 560 | return pc_->network_thread(); |
| 561 | } |
| Tommi | f9e13f8 | 2023-04-06 19:21:45 | [diff] [blame] | 562 | |
| Evan Shrubsole | 6a9a1ae | 2025-03-21 12:54:15 | [diff] [blame] | 563 | Thread* DataChannelController::signaling_thread() const { |
| Harald Alvestrand | 05e4d08 | 2019-12-03 13:04:21 | [diff] [blame] | 564 | return pc_->signaling_thread(); |
| 565 | } |
| 566 | |
| Harald Alvestrand | 00cf34c | 2019-12-02 08:56:02 | [diff] [blame] | 567 | } // namespace webrtc |