OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/rtc_data_channel_handler.h" | 5 #include "content/renderer/media/rtc_data_channel_handler.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <string> | 8 #include <string> |
9 | 9 |
| 10 #include "base/bind.h" |
| 11 #include "base/location.h" |
10 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/message_loop/message_loop.h" |
11 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
12 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "base/thread_task_runner_handle.h" |
13 | 17 |
14 namespace content { | 18 namespace content { |
15 | 19 |
16 namespace { | 20 namespace { |
17 | 21 |
18 enum DataChannelCounters { | 22 enum DataChannelCounters { |
19 CHANNEL_CREATED, | 23 CHANNEL_CREATED, |
20 CHANNEL_OPENED, | 24 CHANNEL_OPENED, |
21 CHANNEL_RELIABLE, | 25 CHANNEL_RELIABLE, |
22 CHANNEL_ORDERED, | 26 CHANNEL_ORDERED, |
23 CHANNEL_NEGOTIATED, | 27 CHANNEL_NEGOTIATED, |
24 CHANNEL_BOUNDARY | 28 CHANNEL_BOUNDARY |
25 }; | 29 }; |
26 | 30 |
27 void IncrementCounter(DataChannelCounters counter) { | 31 void IncrementCounter(DataChannelCounters counter) { |
28 UMA_HISTOGRAM_ENUMERATION("WebRTC.DataChannelCounters", | 32 UMA_HISTOGRAM_ENUMERATION("WebRTC.DataChannelCounters", |
29 counter, | 33 counter, |
30 CHANNEL_BOUNDARY); | 34 CHANNEL_BOUNDARY); |
31 } | 35 } |
32 | 36 |
33 } // namespace | 37 } // namespace |
34 | 38 |
| 39 // Implementation of DataChannelObserver that receives events on libjingle's |
| 40 // signaling thread and forwards them over to the main thread for handling. |
| 41 // Since the handler's lifetime is scoped potentially narrower than what |
| 42 // the callbacks allow for, we use reference counting here to make sure |
| 43 // all callbacks have a valid pointer but won't do anything if the handler |
| 44 // has gone away. |
| 45 RtcDataChannelHandler::Observer::Observer( |
| 46 RtcDataChannelHandler* handler, |
| 47 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread, |
| 48 webrtc::DataChannelInterface* channel) |
| 49 : handler_(handler), main_thread_(main_thread), channel_(channel) { |
| 50 channel_->RegisterObserver(this); |
| 51 } |
| 52 |
| 53 RtcDataChannelHandler::Observer::~Observer() {} |
| 54 |
| 55 const scoped_refptr<base::SingleThreadTaskRunner>& |
| 56 RtcDataChannelHandler::Observer::main_thread() const { |
| 57 return main_thread_; |
| 58 } |
| 59 |
| 60 const scoped_refptr<webrtc::DataChannelInterface>& |
| 61 RtcDataChannelHandler::Observer::channel() const { |
| 62 return channel_; |
| 63 } |
| 64 |
| 65 void RtcDataChannelHandler::Observer::ClearHandler() { |
| 66 DCHECK(main_thread_->BelongsToCurrentThread()); |
| 67 handler_ = nullptr; |
| 68 } |
| 69 |
| 70 void RtcDataChannelHandler::Observer::OnStateChange() { |
| 71 main_thread_->PostTask(FROM_HERE, base::Bind( |
| 72 &RtcDataChannelHandler::Observer::OnStateChangeImpl, this, |
| 73 channel_->state())); |
| 74 } |
| 75 |
| 76 void RtcDataChannelHandler::Observer::OnMessage( |
| 77 const webrtc::DataBuffer& buffer) { |
| 78 // TODO(tommi): Figure out a way to transfer ownership of the buffer without |
| 79 // having to create a copy. See webrtc bug 3967. |
| 80 scoped_ptr<webrtc::DataBuffer> new_buffer(new webrtc::DataBuffer(buffer)); |
| 81 main_thread_->PostTask(FROM_HERE, |
| 82 base::Bind(&RtcDataChannelHandler::Observer::OnMessageImpl, this, |
| 83 base::Passed(&new_buffer))); |
| 84 } |
| 85 |
| 86 void RtcDataChannelHandler::Observer::OnStateChangeImpl( |
| 87 webrtc::DataChannelInterface::DataState state) { |
| 88 DCHECK(main_thread_->BelongsToCurrentThread()); |
| 89 if (handler_) |
| 90 handler_->OnStateChange(state); |
| 91 } |
| 92 |
| 93 void RtcDataChannelHandler::Observer::OnMessageImpl( |
| 94 scoped_ptr<webrtc::DataBuffer> buffer) { |
| 95 DCHECK(main_thread_->BelongsToCurrentThread()); |
| 96 if (handler_) |
| 97 handler_->OnMessage(buffer.Pass()); |
| 98 } |
| 99 |
35 RtcDataChannelHandler::RtcDataChannelHandler( | 100 RtcDataChannelHandler::RtcDataChannelHandler( |
| 101 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread, |
36 webrtc::DataChannelInterface* channel) | 102 webrtc::DataChannelInterface* channel) |
37 : channel_(channel), | 103 : observer_(new Observer(this, main_thread, channel)), |
38 webkit_client_(NULL) { | 104 webkit_client_(NULL) { |
39 DVLOG(1) << "::ctor"; | 105 DVLOG(1) << "RtcDataChannelHandler " << channel->label(); |
40 channel_->RegisterObserver(this); | 106 |
| 107 // Detach from the ctor thread since we can be constructed on either the main |
| 108 // or signaling threads. |
| 109 thread_checker_.DetachFromThread(); |
41 | 110 |
42 IncrementCounter(CHANNEL_CREATED); | 111 IncrementCounter(CHANNEL_CREATED); |
43 if (isReliable()) | 112 if (channel->reliable()) |
44 IncrementCounter(CHANNEL_RELIABLE); | 113 IncrementCounter(CHANNEL_RELIABLE); |
45 if (ordered()) | 114 if (channel->ordered()) |
46 IncrementCounter(CHANNEL_ORDERED); | 115 IncrementCounter(CHANNEL_ORDERED); |
47 if (negotiated()) | 116 if (channel->negotiated()) |
48 IncrementCounter(CHANNEL_NEGOTIATED); | 117 IncrementCounter(CHANNEL_NEGOTIATED); |
49 | 118 |
50 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits", | 119 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits", |
51 maxRetransmits(), 0, | 120 channel->maxRetransmits(), 0, |
52 std::numeric_limits<unsigned short>::max(), 50); | 121 std::numeric_limits<unsigned short>::max(), 50); |
53 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime", | 122 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime", |
54 maxRetransmitTime(), 0, | 123 channel->maxRetransmitTime(), 0, |
55 std::numeric_limits<unsigned short>::max(), 50); | 124 std::numeric_limits<unsigned short>::max(), 50); |
56 } | 125 } |
57 | 126 |
58 RtcDataChannelHandler::~RtcDataChannelHandler() { | 127 RtcDataChannelHandler::~RtcDataChannelHandler() { |
| 128 DCHECK(thread_checker_.CalledOnValidThread()); |
59 DVLOG(1) << "::dtor"; | 129 DVLOG(1) << "::dtor"; |
60 channel_->UnregisterObserver(); | 130 observer_->ClearHandler(); |
61 } | 131 } |
62 | 132 |
63 void RtcDataChannelHandler::setClient( | 133 void RtcDataChannelHandler::setClient( |
64 blink::WebRTCDataChannelHandlerClient* client) { | 134 blink::WebRTCDataChannelHandlerClient* client) { |
| 135 DCHECK(thread_checker_.CalledOnValidThread()); |
65 webkit_client_ = client; | 136 webkit_client_ = client; |
66 } | 137 } |
67 | 138 |
68 blink::WebString RtcDataChannelHandler::label() { | 139 blink::WebString RtcDataChannelHandler::label() { |
69 return base::UTF8ToUTF16(channel_->label()); | 140 DCHECK(thread_checker_.CalledOnValidThread()); |
| 141 return base::UTF8ToUTF16(channel()->label()); |
70 } | 142 } |
71 | 143 |
72 bool RtcDataChannelHandler::isReliable() { | 144 bool RtcDataChannelHandler::isReliable() { |
73 return channel_->reliable(); | 145 DCHECK(thread_checker_.CalledOnValidThread()); |
| 146 return channel()->reliable(); |
74 } | 147 } |
75 | 148 |
76 bool RtcDataChannelHandler::ordered() const { | 149 bool RtcDataChannelHandler::ordered() const { |
77 return channel_->ordered(); | 150 DCHECK(thread_checker_.CalledOnValidThread()); |
| 151 return channel()->ordered(); |
78 } | 152 } |
79 | 153 |
80 unsigned short RtcDataChannelHandler::maxRetransmitTime() const { | 154 unsigned short RtcDataChannelHandler::maxRetransmitTime() const { |
81 return channel_->maxRetransmitTime(); | 155 DCHECK(thread_checker_.CalledOnValidThread()); |
| 156 return channel()->maxRetransmitTime(); |
82 } | 157 } |
83 | 158 |
84 unsigned short RtcDataChannelHandler::maxRetransmits() const { | 159 unsigned short RtcDataChannelHandler::maxRetransmits() const { |
85 return channel_->maxRetransmits(); | 160 DCHECK(thread_checker_.CalledOnValidThread()); |
| 161 return channel()->maxRetransmits(); |
86 } | 162 } |
87 | 163 |
88 blink::WebString RtcDataChannelHandler::protocol() const { | 164 blink::WebString RtcDataChannelHandler::protocol() const { |
89 return base::UTF8ToUTF16(channel_->protocol()); | 165 DCHECK(thread_checker_.CalledOnValidThread()); |
| 166 return base::UTF8ToUTF16(channel()->protocol()); |
90 } | 167 } |
91 | 168 |
92 bool RtcDataChannelHandler::negotiated() const { | 169 bool RtcDataChannelHandler::negotiated() const { |
93 return channel_->negotiated(); | 170 DCHECK(thread_checker_.CalledOnValidThread()); |
| 171 return channel()->negotiated(); |
94 } | 172 } |
95 | 173 |
96 unsigned short RtcDataChannelHandler::id() const { | 174 unsigned short RtcDataChannelHandler::id() const { |
97 return channel_->id(); | 175 DCHECK(thread_checker_.CalledOnValidThread()); |
| 176 return channel()->id(); |
98 } | 177 } |
99 | 178 |
100 unsigned long RtcDataChannelHandler::bufferedAmount() { | 179 unsigned long RtcDataChannelHandler::bufferedAmount() { |
101 return channel_->buffered_amount(); | 180 DCHECK(thread_checker_.CalledOnValidThread()); |
| 181 return channel()->buffered_amount(); |
102 } | 182 } |
103 | 183 |
104 bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) { | 184 bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) { |
| 185 DCHECK(thread_checker_.CalledOnValidThread()); |
105 std::string utf8_buffer = base::UTF16ToUTF8(data); | 186 std::string utf8_buffer = base::UTF16ToUTF8(data); |
106 rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length()); | 187 rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length()); |
107 webrtc::DataBuffer data_buffer(buffer, false); | 188 webrtc::DataBuffer data_buffer(buffer, false); |
108 RecordMessageSent(data_buffer.size()); | 189 RecordMessageSent(data_buffer.size()); |
109 return channel_->Send(data_buffer); | 190 return channel()->Send(data_buffer); |
110 } | 191 } |
111 | 192 |
112 bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) { | 193 bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) { |
| 194 DCHECK(thread_checker_.CalledOnValidThread()); |
113 rtc::Buffer buffer(data, length); | 195 rtc::Buffer buffer(data, length); |
114 webrtc::DataBuffer data_buffer(buffer, true); | 196 webrtc::DataBuffer data_buffer(buffer, true); |
115 RecordMessageSent(data_buffer.size()); | 197 RecordMessageSent(data_buffer.size()); |
116 return channel_->Send(data_buffer); | 198 return channel()->Send(data_buffer); |
117 } | 199 } |
118 | 200 |
119 void RtcDataChannelHandler::close() { | 201 void RtcDataChannelHandler::close() { |
120 channel_->Close(); | 202 DCHECK(thread_checker_.CalledOnValidThread()); |
| 203 channel()->Close(); |
| 204 // Note that even though Close() will run synchronously, the readyState has |
| 205 // not changed yet since the state changes that occured on the signaling |
| 206 // thread have been posted to this thread and will be delivered later. |
| 207 // To work around this, we could have a nested loop here and deliver the |
| 208 // callbacks before running from this function, but doing so can cause |
| 209 // undesired side effects in webkit, so we don't, and instead rely on the |
| 210 // user of the API handling readyState notifications. |
121 } | 211 } |
122 | 212 |
123 void RtcDataChannelHandler::OnStateChange() { | 213 const scoped_refptr<webrtc::DataChannelInterface>& |
| 214 RtcDataChannelHandler::channel() const { |
| 215 return observer_->channel(); |
| 216 } |
| 217 |
| 218 void RtcDataChannelHandler::OnStateChange( |
| 219 webrtc::DataChannelInterface::DataState state) { |
| 220 DCHECK(thread_checker_.CalledOnValidThread()); |
| 221 DVLOG(1) << "OnStateChange " << state; |
| 222 |
124 if (!webkit_client_) { | 223 if (!webkit_client_) { |
125 LOG(ERROR) << "WebRTCDataChannelHandlerClient not set."; | 224 // If this happens, the web application will not get notified of changes. |
| 225 NOTREACHED() << "WebRTCDataChannelHandlerClient not set."; |
126 return; | 226 return; |
127 } | 227 } |
128 DVLOG(1) << "OnStateChange " << channel_->state(); | 228 |
129 switch (channel_->state()) { | 229 switch (state) { |
130 case webrtc::DataChannelInterface::kConnecting: | 230 case webrtc::DataChannelInterface::kConnecting: |
131 webkit_client_->didChangeReadyState( | 231 webkit_client_->didChangeReadyState( |
132 blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting); | 232 blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting); |
133 break; | 233 break; |
134 case webrtc::DataChannelInterface::kOpen: | 234 case webrtc::DataChannelInterface::kOpen: |
135 IncrementCounter(CHANNEL_OPENED); | 235 IncrementCounter(CHANNEL_OPENED); |
136 webkit_client_->didChangeReadyState( | 236 webkit_client_->didChangeReadyState( |
137 blink::WebRTCDataChannelHandlerClient::ReadyStateOpen); | 237 blink::WebRTCDataChannelHandlerClient::ReadyStateOpen); |
138 break; | 238 break; |
139 case webrtc::DataChannelInterface::kClosing: | 239 case webrtc::DataChannelInterface::kClosing: |
140 webkit_client_->didChangeReadyState( | 240 webkit_client_->didChangeReadyState( |
141 blink::WebRTCDataChannelHandlerClient::ReadyStateClosing); | 241 blink::WebRTCDataChannelHandlerClient::ReadyStateClosing); |
142 break; | 242 break; |
143 case webrtc::DataChannelInterface::kClosed: | 243 case webrtc::DataChannelInterface::kClosed: |
144 webkit_client_->didChangeReadyState( | 244 webkit_client_->didChangeReadyState( |
145 blink::WebRTCDataChannelHandlerClient::ReadyStateClosed); | 245 blink::WebRTCDataChannelHandlerClient::ReadyStateClosed); |
146 break; | 246 break; |
147 default: | 247 default: |
148 NOTREACHED(); | 248 NOTREACHED(); |
149 break; | 249 break; |
150 } | 250 } |
151 } | 251 } |
152 | 252 |
153 void RtcDataChannelHandler::OnMessage(const webrtc::DataBuffer& buffer) { | 253 void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) { |
| 254 DCHECK(thread_checker_.CalledOnValidThread()); |
154 if (!webkit_client_) { | 255 if (!webkit_client_) { |
155 LOG(ERROR) << "WebRTCDataChannelHandlerClient not set."; | 256 // If this happens, the web application will not get notified of changes. |
| 257 NOTREACHED() << "WebRTCDataChannelHandlerClient not set."; |
156 return; | 258 return; |
157 } | 259 } |
158 | 260 |
159 if (buffer.binary) { | 261 if (buffer->binary) { |
160 webkit_client_->didReceiveRawData(buffer.data.data(), buffer.data.length()); | 262 webkit_client_->didReceiveRawData(buffer->data.data(), |
| 263 buffer->data.length()); |
161 } else { | 264 } else { |
162 base::string16 utf16; | 265 base::string16 utf16; |
163 if (!base::UTF8ToUTF16(buffer.data.data(), buffer.data.length(), &utf16)) { | 266 if (!base::UTF8ToUTF16(buffer->data.data(), buffer->data.length(), |
| 267 &utf16)) { |
164 LOG(ERROR) << "Failed convert received data to UTF16"; | 268 LOG(ERROR) << "Failed convert received data to UTF16"; |
165 return; | 269 return; |
166 } | 270 } |
167 webkit_client_->didReceiveStringData(utf16); | 271 webkit_client_->didReceiveStringData(utf16); |
168 } | 272 } |
169 } | 273 } |
170 | 274 |
171 void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) { | 275 void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) { |
172 // Currently, messages are capped at some fairly low limit (16 Kb?) | 276 // Currently, messages are capped at some fairly low limit (16 Kb?) |
173 // but we may allow unlimited-size messages at some point, so making | 277 // but we may allow unlimited-size messages at some point, so making |
174 // the histogram maximum quite large (100 Mb) to have some | 278 // the histogram maximum quite large (100 Mb) to have some |
175 // granularity at the higher end in that eventuality. The histogram | 279 // granularity at the higher end in that eventuality. The histogram |
176 // buckets are exponentially growing in size, so we'll still have | 280 // buckets are exponentially growing in size, so we'll still have |
177 // good granularity at the low end. | 281 // good granularity at the low end. |
178 | 282 |
179 // This makes the last bucket in the histogram count messages from | 283 // This makes the last bucket in the histogram count messages from |
180 // 100 Mb to infinity. | 284 // 100 Mb to infinity. |
181 const int kMaxBucketSize = 100 * 1024 * 1024; | 285 const int kMaxBucketSize = 100 * 1024 * 1024; |
182 const int kNumBuckets = 50; | 286 const int kNumBuckets = 50; |
183 | 287 |
184 if (isReliable()) { | 288 if (channel()->reliable()) { |
185 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize", | 289 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize", |
186 num_bytes, | 290 num_bytes, |
187 1, kMaxBucketSize, kNumBuckets); | 291 1, kMaxBucketSize, kNumBuckets); |
188 } else { | 292 } else { |
189 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize", | 293 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize", |
190 num_bytes, | 294 num_bytes, |
191 1, kMaxBucketSize, kNumBuckets); | 295 1, kMaxBucketSize, kNumBuckets); |
192 } | 296 } |
193 } | 297 } |
194 | 298 |
195 } // namespace content | 299 } // namespace content |
OLD | NEW |