| 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" | |
| 12 #include "base/logging.h" | 10 #include "base/logging.h" |
| 13 #include "base/message_loop/message_loop.h" | |
| 14 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 16 #include "base/thread_task_runner_handle.h" | |
| 17 | 13 |
| 18 namespace content { | 14 namespace content { |
| 19 | 15 |
| 20 namespace { | 16 namespace { |
| 21 | 17 |
| 22 enum DataChannelCounters { | 18 enum DataChannelCounters { |
| 23 CHANNEL_CREATED, | 19 CHANNEL_CREATED, |
| 24 CHANNEL_OPENED, | 20 CHANNEL_OPENED, |
| 25 CHANNEL_RELIABLE, | 21 CHANNEL_RELIABLE, |
| 26 CHANNEL_ORDERED, | 22 CHANNEL_ORDERED, |
| 27 CHANNEL_NEGOTIATED, | 23 CHANNEL_NEGOTIATED, |
| 28 CHANNEL_BOUNDARY | 24 CHANNEL_BOUNDARY |
| 29 }; | 25 }; |
| 30 | 26 |
| 31 void IncrementCounter(DataChannelCounters counter) { | 27 void IncrementCounter(DataChannelCounters counter) { |
| 32 UMA_HISTOGRAM_ENUMERATION("WebRTC.DataChannelCounters", | 28 UMA_HISTOGRAM_ENUMERATION("WebRTC.DataChannelCounters", |
| 33 counter, | 29 counter, |
| 34 CHANNEL_BOUNDARY); | 30 CHANNEL_BOUNDARY); |
| 35 } | 31 } |
| 36 | 32 |
| 37 } // namespace | 33 } // namespace |
| 38 | 34 |
| 39 // Implementation of DataChannelObserver that receives events on libjingle's | 35 RtcDataChannelHandler::RtcDataChannelHandler( |
| 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) | 36 webrtc::DataChannelInterface* channel) |
| 49 : handler_(handler), main_thread_(main_thread), channel_(channel) { | 37 : channel_(channel), |
| 38 webkit_client_(NULL) { |
| 39 DVLOG(1) << "::ctor"; |
| 50 channel_->RegisterObserver(this); | 40 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 | |
| 100 RtcDataChannelHandler::RtcDataChannelHandler( | |
| 101 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread, | |
| 102 webrtc::DataChannelInterface* channel) | |
| 103 : observer_(new Observer(this, main_thread, channel)), | |
| 104 webkit_client_(NULL) { | |
| 105 DVLOG(1) << "RtcDataChannelHandler " << channel->label(); | |
| 106 | |
| 107 // Detach from the ctor thread since we can be constructed on either the main | |
| 108 // or signaling threads. | |
| 109 thread_checker_.DetachFromThread(); | |
| 110 | 41 |
| 111 IncrementCounter(CHANNEL_CREATED); | 42 IncrementCounter(CHANNEL_CREATED); |
| 112 if (channel->reliable()) | 43 if (isReliable()) |
| 113 IncrementCounter(CHANNEL_RELIABLE); | 44 IncrementCounter(CHANNEL_RELIABLE); |
| 114 if (channel->ordered()) | 45 if (ordered()) |
| 115 IncrementCounter(CHANNEL_ORDERED); | 46 IncrementCounter(CHANNEL_ORDERED); |
| 116 if (channel->negotiated()) | 47 if (negotiated()) |
| 117 IncrementCounter(CHANNEL_NEGOTIATED); | 48 IncrementCounter(CHANNEL_NEGOTIATED); |
| 118 | 49 |
| 119 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits", | 50 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits", |
| 120 channel->maxRetransmits(), 0, | 51 maxRetransmits(), 0, |
| 121 std::numeric_limits<unsigned short>::max(), 50); | 52 std::numeric_limits<unsigned short>::max(), 50); |
| 122 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime", | 53 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime", |
| 123 channel->maxRetransmitTime(), 0, | 54 maxRetransmitTime(), 0, |
| 124 std::numeric_limits<unsigned short>::max(), 50); | 55 std::numeric_limits<unsigned short>::max(), 50); |
| 125 } | 56 } |
| 126 | 57 |
| 127 RtcDataChannelHandler::~RtcDataChannelHandler() { | 58 RtcDataChannelHandler::~RtcDataChannelHandler() { |
| 128 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 129 DVLOG(1) << "::dtor"; | 59 DVLOG(1) << "::dtor"; |
| 130 observer_->ClearHandler(); | 60 channel_->UnregisterObserver(); |
| 131 } | 61 } |
| 132 | 62 |
| 133 void RtcDataChannelHandler::setClient( | 63 void RtcDataChannelHandler::setClient( |
| 134 blink::WebRTCDataChannelHandlerClient* client) { | 64 blink::WebRTCDataChannelHandlerClient* client) { |
| 135 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 136 webkit_client_ = client; | 65 webkit_client_ = client; |
| 137 } | 66 } |
| 138 | 67 |
| 139 blink::WebString RtcDataChannelHandler::label() { | 68 blink::WebString RtcDataChannelHandler::label() { |
| 140 DCHECK(thread_checker_.CalledOnValidThread()); | 69 return base::UTF8ToUTF16(channel_->label()); |
| 141 return base::UTF8ToUTF16(channel()->label()); | |
| 142 } | 70 } |
| 143 | 71 |
| 144 bool RtcDataChannelHandler::isReliable() { | 72 bool RtcDataChannelHandler::isReliable() { |
| 145 DCHECK(thread_checker_.CalledOnValidThread()); | 73 return channel_->reliable(); |
| 146 return channel()->reliable(); | |
| 147 } | 74 } |
| 148 | 75 |
| 149 bool RtcDataChannelHandler::ordered() const { | 76 bool RtcDataChannelHandler::ordered() const { |
| 150 DCHECK(thread_checker_.CalledOnValidThread()); | 77 return channel_->ordered(); |
| 151 return channel()->ordered(); | |
| 152 } | 78 } |
| 153 | 79 |
| 154 unsigned short RtcDataChannelHandler::maxRetransmitTime() const { | 80 unsigned short RtcDataChannelHandler::maxRetransmitTime() const { |
| 155 DCHECK(thread_checker_.CalledOnValidThread()); | 81 return channel_->maxRetransmitTime(); |
| 156 return channel()->maxRetransmitTime(); | |
| 157 } | 82 } |
| 158 | 83 |
| 159 unsigned short RtcDataChannelHandler::maxRetransmits() const { | 84 unsigned short RtcDataChannelHandler::maxRetransmits() const { |
| 160 DCHECK(thread_checker_.CalledOnValidThread()); | 85 return channel_->maxRetransmits(); |
| 161 return channel()->maxRetransmits(); | |
| 162 } | 86 } |
| 163 | 87 |
| 164 blink::WebString RtcDataChannelHandler::protocol() const { | 88 blink::WebString RtcDataChannelHandler::protocol() const { |
| 165 DCHECK(thread_checker_.CalledOnValidThread()); | 89 return base::UTF8ToUTF16(channel_->protocol()); |
| 166 return base::UTF8ToUTF16(channel()->protocol()); | |
| 167 } | 90 } |
| 168 | 91 |
| 169 bool RtcDataChannelHandler::negotiated() const { | 92 bool RtcDataChannelHandler::negotiated() const { |
| 170 DCHECK(thread_checker_.CalledOnValidThread()); | 93 return channel_->negotiated(); |
| 171 return channel()->negotiated(); | |
| 172 } | 94 } |
| 173 | 95 |
| 174 unsigned short RtcDataChannelHandler::id() const { | 96 unsigned short RtcDataChannelHandler::id() const { |
| 175 DCHECK(thread_checker_.CalledOnValidThread()); | 97 return channel_->id(); |
| 176 return channel()->id(); | |
| 177 } | 98 } |
| 178 | 99 |
| 179 unsigned long RtcDataChannelHandler::bufferedAmount() { | 100 unsigned long RtcDataChannelHandler::bufferedAmount() { |
| 180 DCHECK(thread_checker_.CalledOnValidThread()); | 101 return channel_->buffered_amount(); |
| 181 return channel()->buffered_amount(); | |
| 182 } | 102 } |
| 183 | 103 |
| 184 bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) { | 104 bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) { |
| 185 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 186 std::string utf8_buffer = base::UTF16ToUTF8(data); | 105 std::string utf8_buffer = base::UTF16ToUTF8(data); |
| 187 rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length()); | 106 rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length()); |
| 188 webrtc::DataBuffer data_buffer(buffer, false); | 107 webrtc::DataBuffer data_buffer(buffer, false); |
| 189 RecordMessageSent(data_buffer.size()); | 108 RecordMessageSent(data_buffer.size()); |
| 190 return channel()->Send(data_buffer); | 109 return channel_->Send(data_buffer); |
| 191 } | 110 } |
| 192 | 111 |
| 193 bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) { | 112 bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) { |
| 194 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 195 rtc::Buffer buffer(data, length); | 113 rtc::Buffer buffer(data, length); |
| 196 webrtc::DataBuffer data_buffer(buffer, true); | 114 webrtc::DataBuffer data_buffer(buffer, true); |
| 197 RecordMessageSent(data_buffer.size()); | 115 RecordMessageSent(data_buffer.size()); |
| 198 return channel()->Send(data_buffer); | 116 return channel_->Send(data_buffer); |
| 199 } | 117 } |
| 200 | 118 |
| 201 void RtcDataChannelHandler::close() { | 119 void RtcDataChannelHandler::close() { |
| 202 DCHECK(thread_checker_.CalledOnValidThread()); | 120 channel_->Close(); |
| 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. | |
| 211 } | 121 } |
| 212 | 122 |
| 213 const scoped_refptr<webrtc::DataChannelInterface>& | 123 void RtcDataChannelHandler::OnStateChange() { |
| 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 | |
| 223 if (!webkit_client_) { | 124 if (!webkit_client_) { |
| 224 // If this happens, the web application will not get notified of changes. | 125 LOG(ERROR) << "WebRTCDataChannelHandlerClient not set."; |
| 225 NOTREACHED() << "WebRTCDataChannelHandlerClient not set."; | |
| 226 return; | 126 return; |
| 227 } | 127 } |
| 228 | 128 DVLOG(1) << "OnStateChange " << channel_->state(); |
| 229 switch (state) { | 129 switch (channel_->state()) { |
| 230 case webrtc::DataChannelInterface::kConnecting: | 130 case webrtc::DataChannelInterface::kConnecting: |
| 231 webkit_client_->didChangeReadyState( | 131 webkit_client_->didChangeReadyState( |
| 232 blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting); | 132 blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting); |
| 233 break; | 133 break; |
| 234 case webrtc::DataChannelInterface::kOpen: | 134 case webrtc::DataChannelInterface::kOpen: |
| 235 IncrementCounter(CHANNEL_OPENED); | 135 IncrementCounter(CHANNEL_OPENED); |
| 236 webkit_client_->didChangeReadyState( | 136 webkit_client_->didChangeReadyState( |
| 237 blink::WebRTCDataChannelHandlerClient::ReadyStateOpen); | 137 blink::WebRTCDataChannelHandlerClient::ReadyStateOpen); |
| 238 break; | 138 break; |
| 239 case webrtc::DataChannelInterface::kClosing: | 139 case webrtc::DataChannelInterface::kClosing: |
| 240 webkit_client_->didChangeReadyState( | 140 webkit_client_->didChangeReadyState( |
| 241 blink::WebRTCDataChannelHandlerClient::ReadyStateClosing); | 141 blink::WebRTCDataChannelHandlerClient::ReadyStateClosing); |
| 242 break; | 142 break; |
| 243 case webrtc::DataChannelInterface::kClosed: | 143 case webrtc::DataChannelInterface::kClosed: |
| 244 webkit_client_->didChangeReadyState( | 144 webkit_client_->didChangeReadyState( |
| 245 blink::WebRTCDataChannelHandlerClient::ReadyStateClosed); | 145 blink::WebRTCDataChannelHandlerClient::ReadyStateClosed); |
| 246 break; | 146 break; |
| 247 default: | 147 default: |
| 248 NOTREACHED(); | 148 NOTREACHED(); |
| 249 break; | 149 break; |
| 250 } | 150 } |
| 251 } | 151 } |
| 252 | 152 |
| 253 void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) { | 153 void RtcDataChannelHandler::OnMessage(const webrtc::DataBuffer& buffer) { |
| 254 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 255 if (!webkit_client_) { | 154 if (!webkit_client_) { |
| 256 // If this happens, the web application will not get notified of changes. | 155 LOG(ERROR) << "WebRTCDataChannelHandlerClient not set."; |
| 257 NOTREACHED() << "WebRTCDataChannelHandlerClient not set."; | |
| 258 return; | 156 return; |
| 259 } | 157 } |
| 260 | 158 |
| 261 if (buffer->binary) { | 159 if (buffer.binary) { |
| 262 webkit_client_->didReceiveRawData(buffer->data.data(), | 160 webkit_client_->didReceiveRawData(buffer.data.data(), buffer.data.length()); |
| 263 buffer->data.length()); | |
| 264 } else { | 161 } else { |
| 265 base::string16 utf16; | 162 base::string16 utf16; |
| 266 if (!base::UTF8ToUTF16(buffer->data.data(), buffer->data.length(), | 163 if (!base::UTF8ToUTF16(buffer.data.data(), buffer.data.length(), &utf16)) { |
| 267 &utf16)) { | |
| 268 LOG(ERROR) << "Failed convert received data to UTF16"; | 164 LOG(ERROR) << "Failed convert received data to UTF16"; |
| 269 return; | 165 return; |
| 270 } | 166 } |
| 271 webkit_client_->didReceiveStringData(utf16); | 167 webkit_client_->didReceiveStringData(utf16); |
| 272 } | 168 } |
| 273 } | 169 } |
| 274 | 170 |
| 275 void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) { | 171 void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) { |
| 276 // Currently, messages are capped at some fairly low limit (16 Kb?) | 172 // Currently, messages are capped at some fairly low limit (16 Kb?) |
| 277 // but we may allow unlimited-size messages at some point, so making | 173 // but we may allow unlimited-size messages at some point, so making |
| 278 // the histogram maximum quite large (100 Mb) to have some | 174 // the histogram maximum quite large (100 Mb) to have some |
| 279 // granularity at the higher end in that eventuality. The histogram | 175 // granularity at the higher end in that eventuality. The histogram |
| 280 // buckets are exponentially growing in size, so we'll still have | 176 // buckets are exponentially growing in size, so we'll still have |
| 281 // good granularity at the low end. | 177 // good granularity at the low end. |
| 282 | 178 |
| 283 // This makes the last bucket in the histogram count messages from | 179 // This makes the last bucket in the histogram count messages from |
| 284 // 100 Mb to infinity. | 180 // 100 Mb to infinity. |
| 285 const int kMaxBucketSize = 100 * 1024 * 1024; | 181 const int kMaxBucketSize = 100 * 1024 * 1024; |
| 286 const int kNumBuckets = 50; | 182 const int kNumBuckets = 50; |
| 287 | 183 |
| 288 if (channel()->reliable()) { | 184 if (isReliable()) { |
| 289 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize", | 185 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize", |
| 290 num_bytes, | 186 num_bytes, |
| 291 1, kMaxBucketSize, kNumBuckets); | 187 1, kMaxBucketSize, kNumBuckets); |
| 292 } else { | 188 } else { |
| 293 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize", | 189 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize", |
| 294 num_bytes, | 190 num_bytes, |
| 295 1, kMaxBucketSize, kNumBuckets); | 191 1, kMaxBucketSize, kNumBuckets); |
| 296 } | 192 } |
| 297 } | 193 } |
| 298 | 194 |
| 299 } // namespace content | 195 } // namespace content |
| OLD | NEW |