GoogleURLTrackerInfoBarDelegate: Initialize uninitialized member in constructor.
[chromium-blink-merge.git] / chrome / renderer / extensions / cast_streaming_native_handler.cc
blob284ad774ef33df6d214d3ada1426fcd2d5184ca9
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.
5 #include "chrome/renderer/extensions/cast_streaming_native_handler.h"
7 #include <functional>
8 #include <iterator>
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
14 #include "chrome/common/extensions/api/cast_streaming_udp_transport.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 "extensions/renderer/script_context.h"
20 #include "net/base/host_port_pair.h"
21 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
22 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
24 using content::V8ValueConverter;
26 // Extension types.
27 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams;
28 using extensions::api::cast_streaming_rtp_stream::RtpParams;
29 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams;
30 using extensions::api::cast_streaming_udp_transport::IPEndPoint;
32 namespace extensions {
34 namespace {
35 const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
36 const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
37 const char kInvalidDestination[] = "Invalid destination";
38 const char kInvalidRtpParams[] = "Invalid value for RTP params";
39 const char kInvalidAesKey[] = "Invalid value for AES key";
40 const char kInvalidAesIvMask[] = "Invalid value for AES IV mask";
41 const char kUnableToConvertArgs[] = "Unable to convert arguments";
42 const char kUnableToConvertParams[] = "Unable to convert params";
44 // These helper methods are used to convert between Extension API
45 // types and Cast types.
46 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params,
47 CastCodecSpecificParams* cast_params) {
48 cast_params->key = ext_params.key;
49 cast_params->value = ext_params.value;
52 void FromCastCodecSpecificParams(const CastCodecSpecificParams& cast_params,
53 CodecSpecificParams* ext_params) {
54 ext_params->key = cast_params.key;
55 ext_params->value = cast_params.value;
58 namespace {
59 bool HexDecode(const std::string& input, std::string* output) {
60 std::vector<uint8> bytes;
61 if (!base::HexStringToBytes(input, &bytes))
62 return false;
63 output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size());
64 return true;
66 } // namespace
68 bool ToCastRtpPayloadParamsOrThrow(v8::Isolate* isolate,
69 const RtpPayloadParams& ext_params,
70 CastRtpPayloadParams* cast_params) {
71 cast_params->payload_type = ext_params.payload_type;
72 cast_params->max_latency_ms = ext_params.max_latency;
73 cast_params->codec_name = ext_params.codec_name;
74 cast_params->ssrc = ext_params.ssrc;
75 cast_params->feedback_ssrc = ext_params.feedback_ssrc;
76 cast_params->clock_rate = ext_params.clock_rate ? *ext_params.clock_rate : 0;
77 cast_params->min_bitrate =
78 ext_params.min_bitrate ? *ext_params.min_bitrate : 0;
79 cast_params->max_bitrate =
80 ext_params.max_bitrate ? *ext_params.max_bitrate : 0;
81 cast_params->channels = ext_params.channels ? *ext_params.channels : 0;
82 cast_params->width = ext_params.width ? *ext_params.width : 0;
83 cast_params->height = ext_params.height ? *ext_params.height : 0;
84 if (ext_params.aes_key &&
85 !HexDecode(*ext_params.aes_key, &cast_params->aes_key)) {
86 isolate->ThrowException(v8::Exception::Error(
87 v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
88 return false;
90 if (ext_params.aes_iv_mask &&
91 !HexDecode(*ext_params.aes_iv_mask, &cast_params->aes_iv_mask)) {
92 isolate->ThrowException(v8::Exception::Error(
93 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
94 return false;
96 for (size_t i = 0; i < ext_params.codec_specific_params.size(); ++i) {
97 CastCodecSpecificParams cast_codec_params;
98 ToCastCodecSpecificParams(*ext_params.codec_specific_params[i],
99 &cast_codec_params);
100 cast_params->codec_specific_params.push_back(cast_codec_params);
102 return true;
105 void FromCastRtpPayloadParams(const CastRtpPayloadParams& cast_params,
106 RtpPayloadParams* ext_params) {
107 ext_params->payload_type = cast_params.payload_type;
108 ext_params->max_latency = cast_params.max_latency_ms;
109 ext_params->codec_name = cast_params.codec_name;
110 ext_params->ssrc = cast_params.ssrc;
111 ext_params->feedback_ssrc = cast_params.feedback_ssrc;
112 if (cast_params.clock_rate)
113 ext_params->clock_rate.reset(new int(cast_params.clock_rate));
114 if (cast_params.min_bitrate)
115 ext_params->min_bitrate.reset(new int(cast_params.min_bitrate));
116 if (cast_params.max_bitrate)
117 ext_params->max_bitrate.reset(new int(cast_params.max_bitrate));
118 if (cast_params.channels)
119 ext_params->channels.reset(new int(cast_params.channels));
120 if (cast_params.width)
121 ext_params->width.reset(new int(cast_params.width));
122 if (cast_params.height)
123 ext_params->height.reset(new int(cast_params.height));
124 for (size_t i = 0; i < cast_params.codec_specific_params.size(); ++i) {
125 linked_ptr<CodecSpecificParams> ext_codec_params(
126 new CodecSpecificParams());
127 FromCastCodecSpecificParams(cast_params.codec_specific_params[i],
128 ext_codec_params.get());
129 ext_params->codec_specific_params.push_back(ext_codec_params);
133 void FromCastRtpParams(const CastRtpParams& cast_params,
134 RtpParams* ext_params) {
135 std::copy(cast_params.rtcp_features.begin(),
136 cast_params.rtcp_features.end(),
137 std::back_inserter(ext_params->rtcp_features));
138 FromCastRtpPayloadParams(cast_params.payload, &ext_params->payload);
141 bool ToCastRtpParamsOrThrow(v8::Isolate* isolate,
142 const RtpParams& ext_params,
143 CastRtpParams* cast_params) {
144 std::copy(ext_params.rtcp_features.begin(),
145 ext_params.rtcp_features.end(),
146 std::back_inserter(cast_params->rtcp_features));
147 if (!ToCastRtpPayloadParamsOrThrow(isolate,
148 ext_params.payload,
149 &cast_params->payload)) {
150 return false;
152 return true;
155 } // namespace
157 CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext* context)
158 : ObjectBackedNativeHandler(context),
159 last_transport_id_(1),
160 weak_factory_(this) {
161 RouteFunction("CreateSession",
162 base::Bind(&CastStreamingNativeHandler::CreateCastSession,
163 base::Unretained(this)));
164 RouteFunction("DestroyCastRtpStream",
165 base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream,
166 base::Unretained(this)));
167 RouteFunction("GetSupportedParamsCastRtpStream",
168 base::Bind(&CastStreamingNativeHandler::GetSupportedParamsCastRtpStream,
169 base::Unretained(this)));
170 RouteFunction("StartCastRtpStream",
171 base::Bind(&CastStreamingNativeHandler::StartCastRtpStream,
172 base::Unretained(this)));
173 RouteFunction("StopCastRtpStream",
174 base::Bind(&CastStreamingNativeHandler::StopCastRtpStream,
175 base::Unretained(this)));
176 RouteFunction("DestroyCastUdpTransport",
177 base::Bind(&CastStreamingNativeHandler::DestroyCastUdpTransport,
178 base::Unretained(this)));
179 RouteFunction("SetDestinationCastUdpTransport",
180 base::Bind(&CastStreamingNativeHandler::SetDestinationCastUdpTransport,
181 base::Unretained(this)));
182 RouteFunction("ToggleLogging",
183 base::Bind(&CastStreamingNativeHandler::ToggleLogging,
184 base::Unretained(this)));
185 RouteFunction("GetRawEvents",
186 base::Bind(&CastStreamingNativeHandler::GetRawEvents,
187 base::Unretained(this)));
188 RouteFunction("GetStats",
189 base::Bind(&CastStreamingNativeHandler::GetStats,
190 base::Unretained(this)));
193 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
196 void CastStreamingNativeHandler::CreateCastSession(
197 const v8::FunctionCallbackInfo<v8::Value>& args) {
198 CHECK_EQ(3, args.Length());
199 CHECK(args[0]->IsObject());
200 CHECK(args[1]->IsObject());
201 CHECK(args[2]->IsFunction());
203 blink::WebDOMMediaStreamTrack track1 =
204 blink::WebDOMMediaStreamTrack::fromV8Value(args[0]);
205 if (track1.isNull())
206 return;
207 blink::WebDOMMediaStreamTrack track2 =
208 blink::WebDOMMediaStreamTrack::fromV8Value(args[1]);
209 if (track2.isNull())
210 return;
212 scoped_refptr<CastSession> session(new CastSession());
213 scoped_ptr<CastRtpStream> stream1(
214 new CastRtpStream(track1.component(), session));
215 scoped_ptr<CastRtpStream> stream2(
216 new CastRtpStream(track2.component(), session));
217 scoped_ptr<CastUdpTransport> udp_transport(
218 new CastUdpTransport(session));
220 // TODO(imcheng): Use a weak reference to ensure we don't call into an
221 // invalid context when the callback is invoked.
222 create_callback_.reset(args[2].As<v8::Function>());
224 base::MessageLoop::current()->PostTask(
225 FROM_HERE,
226 base::Bind(
227 &CastStreamingNativeHandler::CallCreateCallback,
228 weak_factory_.GetWeakPtr(),
229 base::Passed(&stream1),
230 base::Passed(&stream2),
231 base::Passed(&udp_transport)));
234 void CastStreamingNativeHandler::CallCreateCallback(
235 scoped_ptr<CastRtpStream> stream1,
236 scoped_ptr<CastRtpStream> stream2,
237 scoped_ptr<CastUdpTransport> udp_transport) {
238 v8::Isolate* isolate = context()->isolate();
239 v8::HandleScope handle_scope(isolate);
240 v8::Context::Scope context_scope(context()->v8_context());
242 const int stream1_id = last_transport_id_++;
243 rtp_stream_map_[stream1_id] =
244 linked_ptr<CastRtpStream>(stream1.release());
245 const int stream2_id = last_transport_id_++;
246 rtp_stream_map_[stream2_id] =
247 linked_ptr<CastRtpStream>(stream2.release());
248 const int udp_id = last_transport_id_++;
249 udp_transport_map_[udp_id] =
250 linked_ptr<CastUdpTransport>(udp_transport.release());
252 v8::Handle<v8::Value> callback_args[3];
253 callback_args[0] = v8::Integer::New(isolate, stream1_id);
254 callback_args[1] = v8::Integer::New(isolate, stream2_id);
255 callback_args[2] = v8::Integer::New(isolate, udp_id);
256 context()->CallFunction(create_callback_.NewHandle(isolate),
257 3, callback_args);
258 create_callback_.reset();
261 void CastStreamingNativeHandler::CallStartCallback(int stream_id) {
262 v8::Isolate* isolate = context()->isolate();
263 v8::HandleScope handle_scope(isolate);
264 v8::Context::Scope context_scope(context()->v8_context());
265 v8::Handle<v8::Array> event_args = v8::Array::New(isolate, 1);
266 event_args->Set(0, v8::Integer::New(isolate, stream_id));
267 context()->DispatchEvent("cast.streaming.rtpStream.onStarted", event_args);
270 void CastStreamingNativeHandler::CallStopCallback(int stream_id) {
271 v8::Isolate* isolate = context()->isolate();
272 v8::HandleScope handle_scope(isolate);
273 v8::Context::Scope context_scope(context()->v8_context());
274 v8::Handle<v8::Array> event_args = v8::Array::New(isolate, 1);
275 event_args->Set(0, v8::Integer::New(isolate, stream_id));
276 context()->DispatchEvent("cast.streaming.rtpStream.onStopped", event_args);
279 void CastStreamingNativeHandler::CallErrorCallback(int stream_id,
280 const std::string& message) {
281 v8::Isolate* isolate = context()->isolate();
282 v8::HandleScope handle_scope(isolate);
283 v8::Context::Scope context_scope(context()->v8_context());
284 v8::Handle<v8::Array> event_args = v8::Array::New(isolate, 2);
285 event_args->Set(0, v8::Integer::New(isolate, stream_id));
286 event_args->Set(
288 v8::String::NewFromUtf8(
289 isolate, message.data(), v8::String::kNormalString, message.size()));
290 context()->DispatchEvent("cast.streaming.rtpStream.onError", event_args);
293 void CastStreamingNativeHandler::DestroyCastRtpStream(
294 const v8::FunctionCallbackInfo<v8::Value>& args) {
295 CHECK_EQ(1, args.Length());
296 CHECK(args[0]->IsInt32());
298 const int transport_id = args[0]->ToInt32()->Value();
299 if (!GetRtpStreamOrThrow(transport_id))
300 return;
301 rtp_stream_map_.erase(transport_id);
304 void CastStreamingNativeHandler::GetSupportedParamsCastRtpStream(
305 const v8::FunctionCallbackInfo<v8::Value>& args) {
306 CHECK_EQ(1, args.Length());
307 CHECK(args[0]->IsInt32());
309 const int transport_id = args[0]->ToInt32()->Value();
310 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
311 if (!transport)
312 return;
314 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
315 std::vector<CastRtpParams> cast_params = transport->GetSupportedParams();
316 v8::Handle<v8::Array> result =
317 v8::Array::New(args.GetIsolate(),
318 static_cast<int>(cast_params.size()));
319 for (size_t i = 0; i < cast_params.size(); ++i) {
320 RtpParams params;
321 FromCastRtpParams(cast_params[i], &params);
322 scoped_ptr<base::DictionaryValue> params_value = params.ToValue();
323 result->Set(
324 static_cast<int>(i),
325 converter->ToV8Value(params_value.get(), context()->v8_context()));
327 args.GetReturnValue().Set(result);
330 void CastStreamingNativeHandler::StartCastRtpStream(
331 const v8::FunctionCallbackInfo<v8::Value>& args) {
332 CHECK_EQ(2, args.Length());
333 CHECK(args[0]->IsInt32());
334 CHECK(args[1]->IsObject());
336 const int transport_id = args[0]->ToInt32()->Value();
337 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
338 if (!transport)
339 return;
341 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
342 scoped_ptr<base::Value> params_value(
343 converter->FromV8Value(args[1], context()->v8_context()));
344 if (!params_value) {
345 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
346 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams)));
347 return;
349 scoped_ptr<RtpParams> params = RtpParams::FromValue(*params_value);
350 if (!params) {
351 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
352 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams)));
353 return;
356 CastRtpParams cast_params;
357 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
358 if (!ToCastRtpParamsOrThrow(isolate, *params, &cast_params))
359 return;
361 base::Closure start_callback =
362 base::Bind(&CastStreamingNativeHandler::CallStartCallback,
363 weak_factory_.GetWeakPtr(),
364 transport_id);
365 base::Closure stop_callback =
366 base::Bind(&CastStreamingNativeHandler::CallStopCallback,
367 weak_factory_.GetWeakPtr(),
368 transport_id);
369 CastRtpStream::ErrorCallback error_callback =
370 base::Bind(&CastStreamingNativeHandler::CallErrorCallback,
371 weak_factory_.GetWeakPtr(),
372 transport_id);
373 transport->Start(cast_params, start_callback, stop_callback, error_callback);
376 void CastStreamingNativeHandler::StopCastRtpStream(
377 const v8::FunctionCallbackInfo<v8::Value>& args) {
378 CHECK_EQ(1, args.Length());
379 CHECK(args[0]->IsInt32());
381 const int transport_id = args[0]->ToInt32()->Value();
382 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
383 if (!transport)
384 return;
385 transport->Stop();
388 void CastStreamingNativeHandler::DestroyCastUdpTransport(
389 const v8::FunctionCallbackInfo<v8::Value>& args) {
390 CHECK_EQ(1, args.Length());
391 CHECK(args[0]->IsInt32());
393 const int transport_id = args[0]->ToInt32()->Value();
394 if (!GetUdpTransportOrThrow(transport_id))
395 return;
396 udp_transport_map_.erase(transport_id);
399 void CastStreamingNativeHandler::SetDestinationCastUdpTransport(
400 const v8::FunctionCallbackInfo<v8::Value>& args) {
401 CHECK_EQ(2, args.Length());
402 CHECK(args[0]->IsInt32());
403 CHECK(args[1]->IsObject());
405 const int transport_id = args[0]->ToInt32()->Value();
406 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
407 if (!transport)
408 return;
410 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
411 scoped_ptr<base::Value> destination_value(
412 converter->FromV8Value(args[1], context()->v8_context()));
413 if (!destination_value) {
414 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
415 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
416 return;
418 scoped_ptr<IPEndPoint> destination =
419 IPEndPoint::FromValue(*destination_value);
420 if (!destination) {
421 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
422 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
423 return;
425 net::IPAddressNumber ip;
426 if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
427 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
428 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
429 return;
431 transport->SetDestination(net::IPEndPoint(ip, destination->port));
434 void CastStreamingNativeHandler::ToggleLogging(
435 const v8::FunctionCallbackInfo<v8::Value>& args) {
436 CHECK_EQ(2, args.Length());
437 CHECK(args[0]->IsInt32());
438 CHECK(args[1]->IsBoolean());
440 const int stream_id = args[0]->ToInt32()->Value();
441 CastRtpStream* stream = GetRtpStreamOrThrow(stream_id);
442 if (!stream)
443 return;
445 const bool enable = args[1]->ToBoolean()->Value();
446 stream->ToggleLogging(enable);
449 void CastStreamingNativeHandler::GetRawEvents(
450 const v8::FunctionCallbackInfo<v8::Value>& args) {
451 CHECK_EQ(3, args.Length());
452 CHECK(args[0]->IsInt32());
453 CHECK(args[1]->IsNull() || args[1]->IsString());
454 CHECK(args[2]->IsFunction());
456 const int transport_id = args[0]->ToInt32()->Value();
457 // TODO(imcheng): Use a weak reference to ensure we don't call into an
458 // invalid context when the callback is invoked.
459 linked_ptr<ScopedPersistent<v8::Function> > callback(
460 new ScopedPersistent<v8::Function>(args[2].As<v8::Function>()));
461 std::string extra_data;
462 if (!args[1]->IsNull()) {
463 extra_data = *v8::String::Utf8Value(args[1]);
466 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
467 if (!transport)
468 return;
470 get_raw_events_callbacks_.insert(std::make_pair(transport_id, callback));
472 transport->GetRawEvents(
473 base::Bind(&CastStreamingNativeHandler::CallGetRawEventsCallback,
474 weak_factory_.GetWeakPtr(),
475 transport_id),
476 extra_data);
479 void CastStreamingNativeHandler::GetStats(
480 const v8::FunctionCallbackInfo<v8::Value>& args) {
481 CHECK_EQ(2, args.Length());
482 CHECK(args[0]->IsInt32());
483 CHECK(args[1]->IsFunction());
484 const int transport_id = args[0]->ToInt32()->Value();
485 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
486 if (!transport)
487 return;
489 // TODO(imcheng): Use a weak reference to ensure we don't call into an
490 // invalid context when the callback is invoked.
491 linked_ptr<ScopedPersistent<v8::Function> > callback(
492 new ScopedPersistent<v8::Function>(args[1].As<v8::Function>()));
493 get_stats_callbacks_.insert(std::make_pair(transport_id, callback));
495 transport->GetStats(
496 base::Bind(&CastStreamingNativeHandler::CallGetStatsCallback,
497 weak_factory_.GetWeakPtr(),
498 transport_id));
501 void CastStreamingNativeHandler::CallGetRawEventsCallback(
502 int transport_id,
503 scoped_ptr<base::BinaryValue> raw_events) {
504 v8::Isolate* isolate = context()->isolate();
505 v8::HandleScope handle_scope(isolate);
506 v8::Context::Scope context_scope(context()->v8_context());
508 RtpStreamCallbackMap::iterator it =
509 get_raw_events_callbacks_.find(transport_id);
510 if (it == get_raw_events_callbacks_.end())
511 return;
512 v8::Handle<v8::Value> callback_args[1];
513 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
514 callback_args[0] =
515 converter->ToV8Value(raw_events.get(), context()->v8_context());
516 context()->CallFunction(it->second->NewHandle(isolate), 1, callback_args);
517 get_raw_events_callbacks_.erase(it);
520 void CastStreamingNativeHandler::CallGetStatsCallback(
521 int transport_id,
522 scoped_ptr<base::DictionaryValue> stats) {
523 v8::Isolate* isolate = context()->isolate();
524 v8::HandleScope handle_scope(isolate);
525 v8::Context::Scope context_scope(context()->v8_context());
527 RtpStreamCallbackMap::iterator it = get_stats_callbacks_.find(transport_id);
528 if (it == get_stats_callbacks_.end())
529 return;
531 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
532 v8::Handle<v8::Value> callback_args[1];
533 callback_args[0] = converter->ToV8Value(stats.get(), context()->v8_context());
534 context()->CallFunction(it->second->NewHandle(isolate), 1, callback_args);
535 get_stats_callbacks_.erase(it);
538 CastRtpStream* CastStreamingNativeHandler::GetRtpStreamOrThrow(
539 int transport_id) const {
540 RtpStreamMap::const_iterator iter = rtp_stream_map_.find(
541 transport_id);
542 if (iter != rtp_stream_map_.end())
543 return iter->second.get();
544 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
545 isolate->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
546 isolate, kRtpStreamNotFound)));
547 return NULL;
550 CastUdpTransport* CastStreamingNativeHandler::GetUdpTransportOrThrow(
551 int transport_id) const {
552 UdpTransportMap::const_iterator iter = udp_transport_map_.find(
553 transport_id);
554 if (iter != udp_transport_map_.end())
555 return iter->second.get();
556 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
557 isolate->ThrowException(v8::Exception::RangeError(
558 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
559 return NULL;
562 } // namespace extensions