Make USB permissions work in the new permission message system
[chromium-blink-merge.git] / content / renderer / media / rtc_data_channel_handler.cc
blob51fe9e64b974e8ed92c157d7503d2a2e72003ba7
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
3 // found in the LICENSE file.
5 #include "content/renderer/media/rtc_data_channel_handler.h"
7 #include <limits>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/thread_task_runner_handle.h"
18 namespace content {
20 namespace {
22 enum DataChannelCounters {
23 CHANNEL_CREATED,
24 CHANNEL_OPENED,
25 CHANNEL_RELIABLE,
26 CHANNEL_ORDERED,
27 CHANNEL_NEGOTIATED,
28 CHANNEL_BOUNDARY
31 void IncrementCounter(DataChannelCounters counter) {
32 UMA_HISTOGRAM_ENUMERATION("WebRTC.DataChannelCounters",
33 counter,
34 CHANNEL_BOUNDARY);
37 } // namespace
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);
53 RtcDataChannelHandler::Observer::~Observer() {
54 DVLOG(3) << "dtor";
55 DCHECK(!channel_.get()) << "Unregister hasn't been called.";
58 const scoped_refptr<base::SingleThreadTaskRunner>&
59 RtcDataChannelHandler::Observer::main_thread() const {
60 return main_thread_;
63 const scoped_refptr<webrtc::DataChannelInterface>&
64 RtcDataChannelHandler::Observer::channel() const {
65 DCHECK(main_thread_->BelongsToCurrentThread());
66 return channel_;
69 void RtcDataChannelHandler::Observer::Unregister() {
70 DCHECK(main_thread_->BelongsToCurrentThread());
71 handler_ = nullptr;
72 if (channel_.get()) {
73 channel_->UnregisterObserver();
74 // Now that we're guaranteed to not get further OnStateChange callbacks,
75 // it's safe to release our reference to the channel.
76 channel_ = nullptr;
80 void RtcDataChannelHandler::Observer::OnStateChange() {
81 main_thread_->PostTask(FROM_HERE, base::Bind(
82 &RtcDataChannelHandler::Observer::OnStateChangeImpl, this,
83 channel_->state()));
86 void RtcDataChannelHandler::Observer::OnBufferedAmountChange(
87 uint64 previous_amount) {
88 // Optimization: Only post a task if the change is a decrease, because the web
89 // interface does not perform any action when there is an increase.
90 if (previous_amount > channel_->buffered_amount()) {
91 main_thread_->PostTask(FROM_HERE, base::Bind(
92 &RtcDataChannelHandler::Observer::OnBufferedAmountDecreaseImpl, this,
93 previous_amount));
97 void RtcDataChannelHandler::Observer::OnMessage(
98 const webrtc::DataBuffer& buffer) {
99 // TODO(tommi): Figure out a way to transfer ownership of the buffer without
100 // having to create a copy. See webrtc bug 3967.
101 scoped_ptr<webrtc::DataBuffer> new_buffer(new webrtc::DataBuffer(buffer));
102 main_thread_->PostTask(FROM_HERE,
103 base::Bind(&RtcDataChannelHandler::Observer::OnMessageImpl, this,
104 base::Passed(&new_buffer)));
107 void RtcDataChannelHandler::Observer::OnStateChangeImpl(
108 webrtc::DataChannelInterface::DataState state) {
109 DCHECK(main_thread_->BelongsToCurrentThread());
110 if (handler_)
111 handler_->OnStateChange(state);
114 void RtcDataChannelHandler::Observer::OnBufferedAmountDecreaseImpl(
115 unsigned previous_amount) {
116 DCHECK(main_thread_->BelongsToCurrentThread());
117 if (handler_)
118 handler_->OnBufferedAmountDecrease(previous_amount);
121 void RtcDataChannelHandler::Observer::OnMessageImpl(
122 scoped_ptr<webrtc::DataBuffer> buffer) {
123 DCHECK(main_thread_->BelongsToCurrentThread());
124 if (handler_)
125 handler_->OnMessage(buffer.Pass());
128 RtcDataChannelHandler::RtcDataChannelHandler(
129 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
130 webrtc::DataChannelInterface* channel)
131 : observer_(new Observer(this, main_thread, channel)),
132 webkit_client_(NULL) {
133 DVLOG(1) << "RtcDataChannelHandler " << channel->label();
135 // Detach from the ctor thread since we can be constructed on either the main
136 // or signaling threads.
137 thread_checker_.DetachFromThread();
139 IncrementCounter(CHANNEL_CREATED);
140 if (channel->reliable())
141 IncrementCounter(CHANNEL_RELIABLE);
142 if (channel->ordered())
143 IncrementCounter(CHANNEL_ORDERED);
144 if (channel->negotiated())
145 IncrementCounter(CHANNEL_NEGOTIATED);
147 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits",
148 channel->maxRetransmits(), 0,
149 std::numeric_limits<unsigned short>::max(), 50);
150 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime",
151 channel->maxRetransmitTime(), 0,
152 std::numeric_limits<unsigned short>::max(), 50);
155 RtcDataChannelHandler::~RtcDataChannelHandler() {
156 DCHECK(thread_checker_.CalledOnValidThread());
157 DVLOG(1) << "::dtor";
158 // setClient might not have been called at all if the data channel was not
159 // passed to Blink. So, we call it here explicitly just to make sure the
160 // observer gets properly unregistered.
161 // See RTCPeerConnectionHandler::OnDataChannel for more.
162 setClient(nullptr);
165 void RtcDataChannelHandler::setClient(
166 blink::WebRTCDataChannelHandlerClient* client) {
167 DCHECK(thread_checker_.CalledOnValidThread());
168 DVLOG(3) << "setClient " << client;
169 webkit_client_ = client;
170 if (!client && observer_.get()) {
171 observer_->Unregister();
172 observer_ = nullptr;
176 blink::WebString RtcDataChannelHandler::label() {
177 DCHECK(thread_checker_.CalledOnValidThread());
178 return base::UTF8ToUTF16(channel()->label());
181 bool RtcDataChannelHandler::isReliable() {
182 DCHECK(thread_checker_.CalledOnValidThread());
183 return channel()->reliable();
186 bool RtcDataChannelHandler::ordered() const {
187 DCHECK(thread_checker_.CalledOnValidThread());
188 return channel()->ordered();
191 unsigned short RtcDataChannelHandler::maxRetransmitTime() const {
192 DCHECK(thread_checker_.CalledOnValidThread());
193 return channel()->maxRetransmitTime();
196 unsigned short RtcDataChannelHandler::maxRetransmits() const {
197 DCHECK(thread_checker_.CalledOnValidThread());
198 return channel()->maxRetransmits();
201 blink::WebString RtcDataChannelHandler::protocol() const {
202 DCHECK(thread_checker_.CalledOnValidThread());
203 return base::UTF8ToUTF16(channel()->protocol());
206 bool RtcDataChannelHandler::negotiated() const {
207 DCHECK(thread_checker_.CalledOnValidThread());
208 return channel()->negotiated();
211 unsigned short RtcDataChannelHandler::id() const {
212 DCHECK(thread_checker_.CalledOnValidThread());
213 return channel()->id();
216 blink::WebRTCDataChannelHandlerClient::ReadyState convertReadyState(
217 webrtc::DataChannelInterface::DataState state) {
218 switch (state) {
219 case webrtc::DataChannelInterface::kConnecting:
220 return blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting;
221 break;
222 case webrtc::DataChannelInterface::kOpen:
223 return blink::WebRTCDataChannelHandlerClient::ReadyStateOpen;
224 break;
225 case webrtc::DataChannelInterface::kClosing:
226 return blink::WebRTCDataChannelHandlerClient::ReadyStateClosing;
227 break;
228 case webrtc::DataChannelInterface::kClosed:
229 return blink::WebRTCDataChannelHandlerClient::ReadyStateClosed;
230 break;
231 default:
232 NOTREACHED();
233 // MSVC does not respect |NOTREACHED()|, so we need a return value.
234 return blink::WebRTCDataChannelHandlerClient::ReadyStateClosed;
238 blink::WebRTCDataChannelHandlerClient::ReadyState
239 RtcDataChannelHandler::state() const {
240 DCHECK(thread_checker_.CalledOnValidThread());
241 if (!observer_.get()) {
242 return blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting;
243 } else {
244 return convertReadyState(observer_->channel()->state());
248 unsigned long RtcDataChannelHandler::bufferedAmount() {
249 DCHECK(thread_checker_.CalledOnValidThread());
250 return channel()->buffered_amount();
253 bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) {
254 DCHECK(thread_checker_.CalledOnValidThread());
255 std::string utf8_buffer = base::UTF16ToUTF8(base::StringPiece16(data));
256 rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length());
257 webrtc::DataBuffer data_buffer(buffer, false);
258 RecordMessageSent(data_buffer.size());
259 return channel()->Send(data_buffer);
262 bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) {
263 DCHECK(thread_checker_.CalledOnValidThread());
264 rtc::Buffer buffer(data, length);
265 webrtc::DataBuffer data_buffer(buffer, true);
266 RecordMessageSent(data_buffer.size());
267 return channel()->Send(data_buffer);
270 void RtcDataChannelHandler::close() {
271 DCHECK(thread_checker_.CalledOnValidThread());
272 channel()->Close();
273 // Note that even though Close() will run synchronously, the readyState has
274 // not changed yet since the state changes that occured on the signaling
275 // thread have been posted to this thread and will be delivered later.
276 // To work around this, we could have a nested loop here and deliver the
277 // callbacks before running from this function, but doing so can cause
278 // undesired side effects in webkit, so we don't, and instead rely on the
279 // user of the API handling readyState notifications.
282 const scoped_refptr<webrtc::DataChannelInterface>&
283 RtcDataChannelHandler::channel() const {
284 return observer_->channel();
287 void RtcDataChannelHandler::OnStateChange(
288 webrtc::DataChannelInterface::DataState state) {
289 DCHECK(thread_checker_.CalledOnValidThread());
290 DVLOG(1) << "OnStateChange " << state;
292 if (!webkit_client_) {
293 // If this happens, the web application will not get notified of changes.
294 NOTREACHED() << "WebRTCDataChannelHandlerClient not set.";
295 return;
298 if (state == webrtc::DataChannelInterface::kOpen)
299 IncrementCounter(CHANNEL_OPENED);
301 webkit_client_->didChangeReadyState(convertReadyState(state));
304 void RtcDataChannelHandler::OnBufferedAmountDecrease(
305 unsigned previous_amount) {
306 DCHECK(thread_checker_.CalledOnValidThread());
307 DVLOG(1) << "OnBufferedAmountDecrease " << previous_amount;
309 if (!webkit_client_) {
310 // If this happens, the web application will not get notified of changes.
311 NOTREACHED() << "WebRTCDataChannelHandlerClient not set.";
312 return;
315 webkit_client_->didDecreaseBufferedAmount(previous_amount);
318 void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) {
319 DCHECK(thread_checker_.CalledOnValidThread());
320 if (!webkit_client_) {
321 // If this happens, the web application will not get notified of changes.
322 NOTREACHED() << "WebRTCDataChannelHandlerClient not set.";
323 return;
326 if (buffer->binary) {
327 webkit_client_->didReceiveRawData(buffer->data.data<char>(),
328 buffer->data.size());
329 } else {
330 base::string16 utf16;
331 if (!base::UTF8ToUTF16(buffer->data.data<char>(), buffer->data.size(),
332 &utf16)) {
333 LOG(ERROR) << "Failed convert received data to UTF16";
334 return;
336 webkit_client_->didReceiveStringData(utf16);
340 void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) {
341 DCHECK(thread_checker_.CalledOnValidThread());
342 // Currently, messages are capped at some fairly low limit (16 Kb?)
343 // but we may allow unlimited-size messages at some point, so making
344 // the histogram maximum quite large (100 Mb) to have some
345 // granularity at the higher end in that eventuality. The histogram
346 // buckets are exponentially growing in size, so we'll still have
347 // good granularity at the low end.
349 // This makes the last bucket in the histogram count messages from
350 // 100 Mb to infinity.
351 const int kMaxBucketSize = 100 * 1024 * 1024;
352 const int kNumBuckets = 50;
354 if (channel()->reliable()) {
355 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize",
356 num_bytes,
357 1, kMaxBucketSize, kNumBuckets);
358 } else {
359 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize",
360 num_bytes,
361 1, kMaxBucketSize, kNumBuckets);
365 } // namespace content