[ServiceWorker] Implement WebServiceWorkerContextClient::openWindow().
[chromium-blink-merge.git] / content / renderer / media / rtc_data_channel_handler.cc
blob5a21184dcc717ab7afb1b3836416a7387707f856
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::OnMessage(
87 const webrtc::DataBuffer& buffer) {
88 // TODO(tommi): Figure out a way to transfer ownership of the buffer without
89 // having to create a copy. See webrtc bug 3967.
90 scoped_ptr<webrtc::DataBuffer> new_buffer(new webrtc::DataBuffer(buffer));
91 main_thread_->PostTask(FROM_HERE,
92 base::Bind(&RtcDataChannelHandler::Observer::OnMessageImpl, this,
93 base::Passed(&new_buffer)));
96 void RtcDataChannelHandler::Observer::OnStateChangeImpl(
97 webrtc::DataChannelInterface::DataState state) {
98 DCHECK(main_thread_->BelongsToCurrentThread());
99 if (handler_)
100 handler_->OnStateChange(state);
103 void RtcDataChannelHandler::Observer::OnMessageImpl(
104 scoped_ptr<webrtc::DataBuffer> buffer) {
105 DCHECK(main_thread_->BelongsToCurrentThread());
106 if (handler_)
107 handler_->OnMessage(buffer.Pass());
110 RtcDataChannelHandler::RtcDataChannelHandler(
111 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
112 webrtc::DataChannelInterface* channel)
113 : observer_(new Observer(this, main_thread, channel)),
114 webkit_client_(NULL) {
115 DVLOG(1) << "RtcDataChannelHandler " << channel->label();
117 // Detach from the ctor thread since we can be constructed on either the main
118 // or signaling threads.
119 thread_checker_.DetachFromThread();
121 IncrementCounter(CHANNEL_CREATED);
122 if (channel->reliable())
123 IncrementCounter(CHANNEL_RELIABLE);
124 if (channel->ordered())
125 IncrementCounter(CHANNEL_ORDERED);
126 if (channel->negotiated())
127 IncrementCounter(CHANNEL_NEGOTIATED);
129 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits",
130 channel->maxRetransmits(), 0,
131 std::numeric_limits<unsigned short>::max(), 50);
132 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime",
133 channel->maxRetransmitTime(), 0,
134 std::numeric_limits<unsigned short>::max(), 50);
137 RtcDataChannelHandler::~RtcDataChannelHandler() {
138 DCHECK(thread_checker_.CalledOnValidThread());
139 DVLOG(1) << "::dtor";
140 // setClient might not have been called at all if the data channel was not
141 // passed to Blink. So, we call it here explicitly just to make sure the
142 // observer gets properly unregistered.
143 // See RTCPeerConnectionHandler::OnDataChannel for more.
144 setClient(nullptr);
147 void RtcDataChannelHandler::setClient(
148 blink::WebRTCDataChannelHandlerClient* client) {
149 DCHECK(thread_checker_.CalledOnValidThread());
150 DVLOG(3) << "setClient " << client;
151 webkit_client_ = client;
152 if (!client && observer_.get()) {
153 observer_->Unregister();
154 observer_ = nullptr;
158 blink::WebString RtcDataChannelHandler::label() {
159 DCHECK(thread_checker_.CalledOnValidThread());
160 return base::UTF8ToUTF16(channel()->label());
163 bool RtcDataChannelHandler::isReliable() {
164 DCHECK(thread_checker_.CalledOnValidThread());
165 return channel()->reliable();
168 bool RtcDataChannelHandler::ordered() const {
169 DCHECK(thread_checker_.CalledOnValidThread());
170 return channel()->ordered();
173 unsigned short RtcDataChannelHandler::maxRetransmitTime() const {
174 DCHECK(thread_checker_.CalledOnValidThread());
175 return channel()->maxRetransmitTime();
178 unsigned short RtcDataChannelHandler::maxRetransmits() const {
179 DCHECK(thread_checker_.CalledOnValidThread());
180 return channel()->maxRetransmits();
183 blink::WebString RtcDataChannelHandler::protocol() const {
184 DCHECK(thread_checker_.CalledOnValidThread());
185 return base::UTF8ToUTF16(channel()->protocol());
188 bool RtcDataChannelHandler::negotiated() const {
189 DCHECK(thread_checker_.CalledOnValidThread());
190 return channel()->negotiated();
193 unsigned short RtcDataChannelHandler::id() const {
194 DCHECK(thread_checker_.CalledOnValidThread());
195 return channel()->id();
198 blink::WebRTCDataChannelHandlerClient::ReadyState convertReadyState(
199 webrtc::DataChannelInterface::DataState state) {
200 switch (state) {
201 case webrtc::DataChannelInterface::kConnecting:
202 return blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting;
203 break;
204 case webrtc::DataChannelInterface::kOpen:
205 return blink::WebRTCDataChannelHandlerClient::ReadyStateOpen;
206 break;
207 case webrtc::DataChannelInterface::kClosing:
208 return blink::WebRTCDataChannelHandlerClient::ReadyStateClosing;
209 break;
210 case webrtc::DataChannelInterface::kClosed:
211 return blink::WebRTCDataChannelHandlerClient::ReadyStateClosed;
212 break;
213 default:
214 NOTREACHED();
215 // MSVC does not respect |NOTREACHED()|, so we need a return value.
216 return blink::WebRTCDataChannelHandlerClient::ReadyStateClosed;
220 blink::WebRTCDataChannelHandlerClient::ReadyState
221 RtcDataChannelHandler::state() const {
222 DCHECK(thread_checker_.CalledOnValidThread());
223 if (!observer_.get()) {
224 return blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting;
225 } else {
226 return convertReadyState(observer_->channel()->state());
230 unsigned long RtcDataChannelHandler::bufferedAmount() {
231 DCHECK(thread_checker_.CalledOnValidThread());
232 return channel()->buffered_amount();
235 bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) {
236 DCHECK(thread_checker_.CalledOnValidThread());
237 std::string utf8_buffer = base::UTF16ToUTF8(data);
238 rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length());
239 webrtc::DataBuffer data_buffer(buffer, false);
240 RecordMessageSent(data_buffer.size());
241 return channel()->Send(data_buffer);
244 bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) {
245 DCHECK(thread_checker_.CalledOnValidThread());
246 rtc::Buffer buffer(data, length);
247 webrtc::DataBuffer data_buffer(buffer, true);
248 RecordMessageSent(data_buffer.size());
249 return channel()->Send(data_buffer);
252 void RtcDataChannelHandler::close() {
253 DCHECK(thread_checker_.CalledOnValidThread());
254 channel()->Close();
255 // Note that even though Close() will run synchronously, the readyState has
256 // not changed yet since the state changes that occured on the signaling
257 // thread have been posted to this thread and will be delivered later.
258 // To work around this, we could have a nested loop here and deliver the
259 // callbacks before running from this function, but doing so can cause
260 // undesired side effects in webkit, so we don't, and instead rely on the
261 // user of the API handling readyState notifications.
264 const scoped_refptr<webrtc::DataChannelInterface>&
265 RtcDataChannelHandler::channel() const {
266 return observer_->channel();
269 void RtcDataChannelHandler::OnStateChange(
270 webrtc::DataChannelInterface::DataState state) {
271 DCHECK(thread_checker_.CalledOnValidThread());
272 DVLOG(1) << "OnStateChange " << state;
274 if (!webkit_client_) {
275 // If this happens, the web application will not get notified of changes.
276 NOTREACHED() << "WebRTCDataChannelHandlerClient not set.";
277 return;
280 if (state == webrtc::DataChannelInterface::kOpen)
281 IncrementCounter(CHANNEL_OPENED);
283 webkit_client_->didChangeReadyState(convertReadyState(state));
286 void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) {
287 DCHECK(thread_checker_.CalledOnValidThread());
288 if (!webkit_client_) {
289 // If this happens, the web application will not get notified of changes.
290 NOTREACHED() << "WebRTCDataChannelHandlerClient not set.";
291 return;
294 if (buffer->binary) {
295 webkit_client_->didReceiveRawData(buffer->data.data(),
296 buffer->data.length());
297 } else {
298 base::string16 utf16;
299 if (!base::UTF8ToUTF16(buffer->data.data(), buffer->data.length(),
300 &utf16)) {
301 LOG(ERROR) << "Failed convert received data to UTF16";
302 return;
304 webkit_client_->didReceiveStringData(utf16);
308 void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) {
309 DCHECK(thread_checker_.CalledOnValidThread());
310 // Currently, messages are capped at some fairly low limit (16 Kb?)
311 // but we may allow unlimited-size messages at some point, so making
312 // the histogram maximum quite large (100 Mb) to have some
313 // granularity at the higher end in that eventuality. The histogram
314 // buckets are exponentially growing in size, so we'll still have
315 // good granularity at the low end.
317 // This makes the last bucket in the histogram count messages from
318 // 100 Mb to infinity.
319 const int kMaxBucketSize = 100 * 1024 * 1024;
320 const int kNumBuckets = 50;
322 if (channel()->reliable()) {
323 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize",
324 num_bytes,
325 1, kMaxBucketSize, kNumBuckets);
326 } else {
327 UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize",
328 num_bytes,
329 1, kMaxBucketSize, kNumBuckets);
333 } // namespace content