| 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 |