Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / rtc_data_channel_handler.cc
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.
4
5 #include "content/renderer/media/rtc_data_channel_handler.h"
6
7 #include <limits>
8 #include <string>
9
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"
17
18 namespace content {
19
20 namespace {
21
22 enum DataChannelCounters {
23   CHANNEL_CREATED,
24   CHANNEL_OPENED,
25   CHANNEL_RELIABLE,
26   CHANNEL_ORDERED,
27   CHANNEL_NEGOTIATED,
28   CHANNEL_BOUNDARY
29 };
30
31 void IncrementCounter(DataChannelCounters counter) {
32   UMA_HISTOGRAM_ENUMERATION("WebRTC.DataChannelCounters",
33                             counter,
34                             CHANNEL_BOUNDARY);
35 }
36
37 }  // namespace
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
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
111   IncrementCounter(CHANNEL_CREATED);
112   if (channel->reliable())
113     IncrementCounter(CHANNEL_RELIABLE);
114   if (channel->ordered())
115     IncrementCounter(CHANNEL_ORDERED);
116   if (channel->negotiated())
117     IncrementCounter(CHANNEL_NEGOTIATED);
118
119   UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits",
120                               channel->maxRetransmits(), 0,
121                               std::numeric_limits<unsigned short>::max(), 50);
122   UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime",
123                               channel->maxRetransmitTime(), 0,
124                               std::numeric_limits<unsigned short>::max(), 50);
125 }
126
127 RtcDataChannelHandler::~RtcDataChannelHandler() {
128   DCHECK(thread_checker_.CalledOnValidThread());
129   DVLOG(1) << "::dtor";
130   observer_->ClearHandler();
131 }
132
133 void RtcDataChannelHandler::setClient(
134     blink::WebRTCDataChannelHandlerClient* client) {
135   DCHECK(thread_checker_.CalledOnValidThread());
136   webkit_client_ = client;
137 }
138
139 blink::WebString RtcDataChannelHandler::label() {
140   DCHECK(thread_checker_.CalledOnValidThread());
141   return base::UTF8ToUTF16(channel()->label());
142 }
143
144 bool RtcDataChannelHandler::isReliable() {
145   DCHECK(thread_checker_.CalledOnValidThread());
146   return channel()->reliable();
147 }
148
149 bool RtcDataChannelHandler::ordered() const {
150   DCHECK(thread_checker_.CalledOnValidThread());
151   return channel()->ordered();
152 }
153
154 unsigned short RtcDataChannelHandler::maxRetransmitTime() const {
155   DCHECK(thread_checker_.CalledOnValidThread());
156   return channel()->maxRetransmitTime();
157 }
158
159 unsigned short RtcDataChannelHandler::maxRetransmits() const {
160   DCHECK(thread_checker_.CalledOnValidThread());
161   return channel()->maxRetransmits();
162 }
163
164 blink::WebString RtcDataChannelHandler::protocol() const {
165   DCHECK(thread_checker_.CalledOnValidThread());
166   return base::UTF8ToUTF16(channel()->protocol());
167 }
168
169 bool RtcDataChannelHandler::negotiated() const {
170   DCHECK(thread_checker_.CalledOnValidThread());
171   return channel()->negotiated();
172 }
173
174 unsigned short RtcDataChannelHandler::id() const {
175   DCHECK(thread_checker_.CalledOnValidThread());
176   return channel()->id();
177 }
178
179 unsigned long RtcDataChannelHandler::bufferedAmount() {
180   DCHECK(thread_checker_.CalledOnValidThread());
181   return channel()->buffered_amount();
182 }
183
184 bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) {
185   DCHECK(thread_checker_.CalledOnValidThread());
186   std::string utf8_buffer = base::UTF16ToUTF8(data);
187   rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length());
188   webrtc::DataBuffer data_buffer(buffer, false);
189   RecordMessageSent(data_buffer.size());
190   return channel()->Send(data_buffer);
191 }
192
193 bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) {
194   DCHECK(thread_checker_.CalledOnValidThread());
195   rtc::Buffer buffer(data, length);
196   webrtc::DataBuffer data_buffer(buffer, true);
197   RecordMessageSent(data_buffer.size());
198   return channel()->Send(data_buffer);
199 }
200
201 void RtcDataChannelHandler::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.
211 }
212
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
223   if (!webkit_client_) {
224     // If this happens, the web application will not get notified of changes.
225     NOTREACHED() << "WebRTCDataChannelHandlerClient not set.";
226     return;
227   }
228
229   switch (state) {
230     case webrtc::DataChannelInterface::kConnecting:
231       webkit_client_->didChangeReadyState(
232           blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting);
233       break;
234     case webrtc::DataChannelInterface::kOpen:
235       IncrementCounter(CHANNEL_OPENED);
236       webkit_client_->didChangeReadyState(
237           blink::WebRTCDataChannelHandlerClient::ReadyStateOpen);
238       break;
239     case webrtc::DataChannelInterface::kClosing:
240       webkit_client_->didChangeReadyState(
241           blink::WebRTCDataChannelHandlerClient::ReadyStateClosing);
242       break;
243     case webrtc::DataChannelInterface::kClosed:
244       webkit_client_->didChangeReadyState(
245           blink::WebRTCDataChannelHandlerClient::ReadyStateClosed);
246       break;
247     default:
248       NOTREACHED();
249       break;
250   }
251 }
252
253 void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) {
254   DCHECK(thread_checker_.CalledOnValidThread());
255   if (!webkit_client_) {
256     // If this happens, the web application will not get notified of changes.
257     NOTREACHED() << "WebRTCDataChannelHandlerClient not set.";
258     return;
259   }
260
261   if (buffer->binary) {
262     webkit_client_->didReceiveRawData(buffer->data.data(),
263                                       buffer->data.length());
264   } else {
265     base::string16 utf16;
266     if (!base::UTF8ToUTF16(buffer->data.data(), buffer->data.length(),
267                            &utf16)) {
268       LOG(ERROR) << "Failed convert received data to UTF16";
269       return;
270     }
271     webkit_client_->didReceiveStringData(utf16);
272   }
273 }
274
275 void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) {
276   // Currently, messages are capped at some fairly low limit (16 Kb?)
277   // but we may allow unlimited-size messages at some point, so making
278   // the histogram maximum quite large (100 Mb) to have some
279   // granularity at the higher end in that eventuality. The histogram
280   // buckets are exponentially growing in size, so we'll still have
281   // good granularity at the low end.
282
283   // This makes the last bucket in the histogram count messages from
284   // 100 Mb to infinity.
285   const int kMaxBucketSize = 100 * 1024 * 1024;
286   const int kNumBuckets = 50;
287
288   if (channel()->reliable()) {
289     UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize",
290                                 num_bytes,
291                                 1, kMaxBucketSize, kNumBuckets);
292   } else {
293     UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize",
294                                 num_bytes,
295                                 1, kMaxBucketSize, kNumBuckets);
296   }
297 }
298
299 }  // namespace content