Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / extensions / cast_streaming_native_handler.cc
1 // Copyright 2013 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 "chrome/renderer/extensions/cast_streaming_native_handler.h"
6
7 #include <functional>
8
9 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
13 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
14 #include "chrome/renderer/extensions/chrome_v8_context.h"
15 #include "chrome/renderer/media/cast_rtp_stream.h"
16 #include "chrome/renderer/media/cast_session.h"
17 #include "chrome/renderer/media/cast_udp_transport.h"
18 #include "content/public/renderer/v8_value_converter.h"
19 #include "net/base/host_port_pair.h"
20 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
21 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
22
23 using content::V8ValueConverter;
24
25 // Extension types.
26 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams;
27 using extensions::api::cast_streaming_rtp_stream::RtpParams;
28 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams;
29 using extensions::api::cast_streaming_udp_transport::IPEndPoint;
30
31 namespace extensions {
32
33 namespace {
34 const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
35 const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
36 const char kInvalidDestination[] = "Invalid destination";
37 const char kInvalidRtpParams[] = "Invalid value for RTP params";
38 const char kInvalidAesKey[] = "Invalid value for AES key";
39 const char kInvalidAesIvMask[] = "Invalid value for AES IV mask";
40 const char kUnableToConvertArgs[] = "Unable to convert arguments";
41 const char kUnableToConvertParams[] = "Unable to convert params";
42
43 // These helper methods are used to convert between Extension API
44 // types and Cast types.
45 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params,
46                                CastCodecSpecificParams* cast_params) {
47   cast_params->key = ext_params.key;
48   cast_params->value = ext_params.value;
49 }
50
51 void FromCastCodecSpecificParams(const CastCodecSpecificParams& cast_params,
52                                  CodecSpecificParams* ext_params) {
53   ext_params->key = cast_params.key;
54   ext_params->value = cast_params.value;
55 }
56
57 bool ToCastRtpPayloadParamsOrThrow(v8::Isolate* isolate,
58                                    const RtpPayloadParams& ext_params,
59                                    CastRtpPayloadParams* cast_params) {
60   cast_params->payload_type = ext_params.payload_type;
61   cast_params->codec_name = ext_params.codec_name;
62   cast_params->ssrc = ext_params.ssrc ? *ext_params.ssrc : 0;
63   cast_params->feedback_ssrc =
64       ext_params.feedback_ssrc ? *ext_params.feedback_ssrc : 0;
65   cast_params->clock_rate = ext_params.clock_rate ? *ext_params.clock_rate : 0;
66   cast_params->min_bitrate =
67       ext_params.min_bitrate ? *ext_params.min_bitrate : 0;
68   cast_params->max_bitrate =
69       ext_params.max_bitrate ? *ext_params.max_bitrate : 0;
70   cast_params->channels = ext_params.channels ? *ext_params.channels : 0;
71   cast_params->width = ext_params.width ? *ext_params.width : 0;
72   cast_params->height = ext_params.height ? *ext_params.height : 0;
73   if (ext_params.aes_key &&
74       !base::Base64Decode(*ext_params.aes_key, &cast_params->aes_key)) {
75     isolate->ThrowException(v8::Exception::Error(
76         v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
77     return false;
78   }
79   if (ext_params.aes_iv_mask &&
80       !base::Base64Decode(*ext_params.aes_iv_mask,
81                           &cast_params->aes_iv_mask)) {
82     isolate->ThrowException(v8::Exception::Error(
83         v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
84     return false;
85   }
86   for (size_t i = 0; i < ext_params.codec_specific_params.size(); ++i) {
87     CastCodecSpecificParams cast_codec_params;
88     ToCastCodecSpecificParams(*ext_params.codec_specific_params[i],
89                               &cast_codec_params);
90     cast_params->codec_specific_params.push_back(cast_codec_params);
91   }
92   return true;
93 }
94
95 void FromCastRtpPayloadParams(const CastRtpPayloadParams& cast_params,
96                               RtpPayloadParams* ext_params) {
97   ext_params->payload_type = cast_params.payload_type;
98   ext_params->codec_name = cast_params.codec_name;
99   if (cast_params.ssrc)
100     ext_params->ssrc.reset(new int(cast_params.ssrc));
101   if (cast_params.feedback_ssrc)
102     ext_params->feedback_ssrc.reset(new int(cast_params.feedback_ssrc));
103   if (cast_params.clock_rate)
104     ext_params->clock_rate.reset(new int(cast_params.clock_rate));
105   if (cast_params.min_bitrate)
106     ext_params->min_bitrate.reset(new int(cast_params.min_bitrate));
107   if (cast_params.max_bitrate)
108     ext_params->max_bitrate.reset(new int(cast_params.max_bitrate));
109   if (cast_params.channels)
110     ext_params->channels.reset(new int(cast_params.channels));
111   if (cast_params.width)
112     ext_params->width.reset(new int(cast_params.width));
113   if (cast_params.height)
114     ext_params->height.reset(new int(cast_params.height));
115   for (size_t i = 0; i < cast_params.codec_specific_params.size(); ++i) {
116     linked_ptr<CodecSpecificParams> ext_codec_params(
117         new CodecSpecificParams());
118     FromCastCodecSpecificParams(cast_params.codec_specific_params[i],
119                                 ext_codec_params.get());
120     ext_params->codec_specific_params.push_back(ext_codec_params);
121   }
122 }
123
124 void FromCastRtpParams(const CastRtpParams& cast_params,
125                        RtpParams* ext_params) {
126   std::copy(cast_params.rtcp_features.begin(), cast_params.rtcp_features.end(),
127             ext_params->rtcp_features.begin());
128   FromCastRtpPayloadParams(cast_params.payload, &ext_params->payload);
129 }
130
131 bool ToCastRtpParamsOrThrow(v8::Isolate* isolate,
132                             const RtpParams& ext_params,
133                             CastRtpParams* cast_params) {
134   std::copy(ext_params.rtcp_features.begin(), ext_params.rtcp_features.end(),
135             cast_params->rtcp_features.begin());
136   if (!ToCastRtpPayloadParamsOrThrow(isolate,
137                                      ext_params.payload,
138                                      &cast_params->payload)) {
139     return false;
140   }
141   return true;
142 }
143
144 }  // namespace
145
146 CastStreamingNativeHandler::CastStreamingNativeHandler(ChromeV8Context* context)
147     : ObjectBackedNativeHandler(context),
148       last_transport_id_(0),
149       weak_factory_(this) {
150   RouteFunction("CreateSession",
151       base::Bind(&CastStreamingNativeHandler::CreateCastSession,
152                  base::Unretained(this)));
153   RouteFunction("DestroyCastRtpStream",
154       base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream,
155                  base::Unretained(this)));
156   RouteFunction("GetSupportedParamsCastRtpStream",
157       base::Bind(&CastStreamingNativeHandler::GetSupportedParamsCastRtpStream,
158                  base::Unretained(this)));
159   RouteFunction("StartCastRtpStream",
160       base::Bind(&CastStreamingNativeHandler::StartCastRtpStream,
161                  base::Unretained(this)));
162   RouteFunction("StopCastRtpStream",
163       base::Bind(&CastStreamingNativeHandler::StopCastRtpStream,
164                  base::Unretained(this)));
165   RouteFunction("DestroyCastUdpTransport",
166       base::Bind(&CastStreamingNativeHandler::DestroyCastUdpTransport,
167                  base::Unretained(this)));
168   RouteFunction("SetDestinationCastUdpTransport",
169       base::Bind(&CastStreamingNativeHandler::SetDestinationCastUdpTransport,
170                  base::Unretained(this)));
171 }
172
173 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
174 }
175
176 void CastStreamingNativeHandler::CreateCastSession(
177     const v8::FunctionCallbackInfo<v8::Value>& args) {
178   CHECK_EQ(3, args.Length());
179   CHECK(args[0]->IsObject());
180   CHECK(args[1]->IsObject());
181   CHECK(args[2]->IsFunction());
182
183   blink::WebDOMMediaStreamTrack track1 =
184       blink::WebDOMMediaStreamTrack::fromV8Value(args[0]);
185   if (track1.isNull())
186     return;
187   blink::WebDOMMediaStreamTrack track2 =
188       blink::WebDOMMediaStreamTrack::fromV8Value(args[1]);
189   if (track2.isNull())
190     return;
191
192   scoped_refptr<CastSession> session(new CastSession());
193   scoped_ptr<CastRtpStream> stream1(
194       new CastRtpStream(track1.component(), session));
195   scoped_ptr<CastRtpStream> stream2(
196       new CastRtpStream(track2.component(), session));
197   scoped_ptr<CastUdpTransport> udp_transport(
198       new CastUdpTransport(session));
199
200   create_callback_.reset(args[2].As<v8::Function>());
201
202   base::MessageLoop::current()->PostTask(
203       FROM_HERE,
204       base::Bind(
205           &CastStreamingNativeHandler::CallCreateCallback,
206           weak_factory_.GetWeakPtr(),
207           base::Passed(&stream1),
208           base::Passed(&stream2),
209           base::Passed(&udp_transport)));
210 }
211
212 void CastStreamingNativeHandler::CallCreateCallback(
213     scoped_ptr<CastRtpStream> stream1,
214     scoped_ptr<CastRtpStream> stream2,
215     scoped_ptr<CastUdpTransport> udp_transport) {
216   v8::Isolate* isolate = context()->isolate();
217   v8::HandleScope handle_scope(isolate);
218   v8::Context::Scope context_scope(context()->v8_context());
219
220   const int stream1_id = last_transport_id_++;
221   rtp_stream_map_[stream1_id] =
222       linked_ptr<CastRtpStream>(stream1.release());
223   const int stream2_id = last_transport_id_++;
224   rtp_stream_map_[stream2_id] =
225       linked_ptr<CastRtpStream>(stream2.release());
226   const int udp_id = last_transport_id_++;
227   udp_transport_map_[udp_id] =
228       linked_ptr<CastUdpTransport>(udp_transport.release());
229
230   v8::Handle<v8::Value> callback_args[3];
231   callback_args[0] = v8::Integer::New(isolate, stream1_id);
232   callback_args[1] = v8::Integer::New(isolate, stream2_id);
233   callback_args[2] = v8::Integer::New(isolate, udp_id);
234   context()->CallFunction(create_callback_.NewHandle(isolate),
235                           3, callback_args);
236   create_callback_.reset();
237 }
238
239 void CastStreamingNativeHandler::CallStartCallback(int stream_id) {
240   v8::Isolate* isolate = context()->isolate();
241   v8::HandleScope handle_scope(isolate);
242   v8::Context::Scope context_scope(context()->v8_context());
243   v8::Handle<v8::Array> event_args = v8::Array::New(isolate, 1);
244   event_args->Set(0, v8::Integer::New(isolate, stream_id));
245   context()->DispatchEvent("cast.streaming.rtpStream.onStarted", event_args);
246 }
247
248 void CastStreamingNativeHandler::CallStopCallback(int stream_id) {
249   v8::Isolate* isolate = context()->isolate();
250   v8::HandleScope handle_scope(isolate);
251   v8::Context::Scope context_scope(context()->v8_context());
252   v8::Handle<v8::Array> event_args = v8::Array::New(isolate, 1);
253   event_args->Set(0, v8::Integer::New(isolate, stream_id));
254   context()->DispatchEvent("cast.streaming.rtpStream.onStopped", event_args);
255 }
256
257 void CastStreamingNativeHandler::CallErrorCallback(int stream_id,
258                                                    const std::string& message) {
259   v8::Isolate* isolate = context()->isolate();
260   v8::HandleScope handle_scope(isolate);
261   v8::Context::Scope context_scope(context()->v8_context());
262   v8::Handle<v8::Array> event_args = v8::Array::New(isolate, 2);
263   event_args->Set(0, v8::Integer::New(isolate, stream_id));
264   event_args->Set(
265       1,
266       v8::String::NewFromUtf8(
267           isolate, message.data(), v8::String::kNormalString, message.size()));
268   context()->DispatchEvent("cast.streaming.rtpStream.onError", event_args);
269 }
270
271 void CastStreamingNativeHandler::DestroyCastRtpStream(
272     const v8::FunctionCallbackInfo<v8::Value>& args) {
273   CHECK_EQ(1, args.Length());
274   CHECK(args[0]->IsInt32());
275
276   const int transport_id = args[0]->ToInt32()->Value();
277   if (!GetRtpStreamOrThrow(transport_id))
278     return;
279   rtp_stream_map_.erase(transport_id);
280 }
281
282 void CastStreamingNativeHandler::GetSupportedParamsCastRtpStream(
283     const v8::FunctionCallbackInfo<v8::Value>& args) {
284   CHECK_EQ(1, args.Length());
285   CHECK(args[0]->IsInt32());
286
287   const int transport_id = args[0]->ToInt32()->Value();
288   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
289   if (!transport)
290     return;
291
292   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
293   std::vector<CastRtpParams> cast_params = transport->GetSupportedParams();
294   v8::Handle<v8::Array> result =
295       v8::Array::New(args.GetIsolate(),
296                      static_cast<int>(cast_params.size()));
297   for (size_t i = 0; i < cast_params.size(); ++i) {
298     RtpParams params;
299     FromCastRtpParams(cast_params[i], &params);
300     scoped_ptr<base::DictionaryValue> params_value = params.ToValue();
301     result->Set(
302         static_cast<int>(i),
303         converter->ToV8Value(params_value.get(), context()->v8_context()));
304   }
305   args.GetReturnValue().Set(result);
306 }
307
308 void CastStreamingNativeHandler::StartCastRtpStream(
309     const v8::FunctionCallbackInfo<v8::Value>& args) {
310   CHECK_EQ(2, args.Length());
311   CHECK(args[0]->IsInt32());
312   CHECK(args[1]->IsObject());
313
314   const int transport_id = args[0]->ToInt32()->Value();
315   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
316   if (!transport)
317     return;
318
319   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
320   scoped_ptr<base::Value> params_value(
321       converter->FromV8Value(args[1], context()->v8_context()));
322   if (!params_value) {
323     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
324         v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams)));
325     return;
326   }
327   scoped_ptr<RtpParams> params = RtpParams::FromValue(*params_value);
328   if (!params) {
329     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
330         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams)));
331     return;
332   }
333
334   CastRtpParams cast_params;
335   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
336   if (!ToCastRtpParamsOrThrow(isolate, *params, &cast_params))
337     return;
338
339   base::Closure start_callback =
340       base::Bind(&CastStreamingNativeHandler::CallStartCallback,
341                  weak_factory_.GetWeakPtr(),
342                  transport_id);
343   base::Closure stop_callback =
344       base::Bind(&CastStreamingNativeHandler::CallStopCallback,
345                  weak_factory_.GetWeakPtr(),
346                  transport_id);
347   CastRtpStream::ErrorCallback error_callback =
348       base::Bind(&CastStreamingNativeHandler::CallErrorCallback,
349                  weak_factory_.GetWeakPtr(),
350                  transport_id);
351   transport->Start(cast_params, start_callback, stop_callback, error_callback);
352 }
353
354 void CastStreamingNativeHandler::StopCastRtpStream(
355     const v8::FunctionCallbackInfo<v8::Value>& args) {
356   CHECK_EQ(1, args.Length());
357   CHECK(args[0]->IsInt32());
358
359   const int transport_id = args[0]->ToInt32()->Value();
360   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
361   if (!transport)
362     return;
363   transport->Stop();
364 }
365
366 void CastStreamingNativeHandler::DestroyCastUdpTransport(
367     const v8::FunctionCallbackInfo<v8::Value>& args) {
368   CHECK_EQ(1, args.Length());
369   CHECK(args[0]->IsInt32());
370
371   const int transport_id = args[0]->ToInt32()->Value();
372   if (!GetUdpTransportOrThrow(transport_id))
373     return;
374   udp_transport_map_.erase(transport_id);
375 }
376
377 void CastStreamingNativeHandler::SetDestinationCastUdpTransport(
378     const v8::FunctionCallbackInfo<v8::Value>& args) {
379   CHECK_EQ(2, args.Length());
380   CHECK(args[0]->IsInt32());
381   CHECK(args[1]->IsObject());
382
383   const int transport_id = args[0]->ToInt32()->Value();
384   CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
385   if (!transport)
386     return;
387
388   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
389   scoped_ptr<base::Value> destination_value(
390       converter->FromV8Value(args[1], context()->v8_context()));
391   if (!destination_value) {
392     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
393         v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
394     return;
395   }
396   scoped_ptr<IPEndPoint> destination =
397       IPEndPoint::FromValue(*destination_value);
398   if (!destination) {
399     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
400         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
401     return;
402   }
403   net::IPAddressNumber ip;
404   if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
405     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
406         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
407     return;
408   }
409   transport->SetDestination(net::IPEndPoint(ip, destination->port));
410 }
411
412 CastRtpStream* CastStreamingNativeHandler::GetRtpStreamOrThrow(
413     int transport_id) const {
414   RtpStreamMap::const_iterator iter = rtp_stream_map_.find(
415       transport_id);
416   if (iter != rtp_stream_map_.end())
417     return iter->second.get();
418   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
419   isolate->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
420       isolate, kRtpStreamNotFound)));
421   return NULL;
422 }
423
424 CastUdpTransport* CastStreamingNativeHandler::GetUdpTransportOrThrow(
425     int transport_id) const {
426   UdpTransportMap::const_iterator iter = udp_transport_map_.find(
427       transport_id);
428   if (iter != udp_transport_map_.end())
429     return iter->second.get();
430   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
431   isolate->ThrowException(v8::Exception::RangeError(
432       v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
433   return NULL;
434 }
435
436 }  // namespace extensions