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"
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
;
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
{
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
;
59 bool HexDecode(const std::string
& input
, std::string
* output
) {
60 std::vector
<uint8
> bytes
;
61 if (!base::HexStringToBytes(input
, &bytes
))
63 output
->assign(reinterpret_cast<const char*>(&bytes
[0]), bytes
.size());
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
)));
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
)));
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
],
100 cast_params
->codec_specific_params
.push_back(cast_codec_params
);
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
,
149 &cast_params
->payload
)) {
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]);
207 blink::WebDOMMediaStreamTrack track2
=
208 blink::WebDOMMediaStreamTrack::fromV8Value(args
[1]);
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(
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
),
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
));
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
))
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
);
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
) {
321 FromCastRtpParams(cast_params
[i
], ¶ms
);
322 scoped_ptr
<base::DictionaryValue
> params_value
= params
.ToValue();
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
);
341 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
342 scoped_ptr
<base::Value
> params_value(
343 converter
->FromV8Value(args
[1], context()->v8_context()));
345 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
346 v8::String::NewFromUtf8(args
.GetIsolate(), kUnableToConvertParams
)));
349 scoped_ptr
<RtpParams
> params
= RtpParams::FromValue(*params_value
);
351 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
352 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidRtpParams
)));
356 CastRtpParams cast_params
;
357 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
358 if (!ToCastRtpParamsOrThrow(isolate
, *params
, &cast_params
))
361 base::Closure start_callback
=
362 base::Bind(&CastStreamingNativeHandler::CallStartCallback
,
363 weak_factory_
.GetWeakPtr(),
365 base::Closure stop_callback
=
366 base::Bind(&CastStreamingNativeHandler::CallStopCallback
,
367 weak_factory_
.GetWeakPtr(),
369 CastRtpStream::ErrorCallback error_callback
=
370 base::Bind(&CastStreamingNativeHandler::CallErrorCallback
,
371 weak_factory_
.GetWeakPtr(),
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
);
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
))
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
);
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
)));
418 scoped_ptr
<IPEndPoint
> destination
=
419 IPEndPoint::FromValue(*destination_value
);
421 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
422 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidDestination
)));
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
)));
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
);
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
);
470 get_raw_events_callbacks_
.insert(std::make_pair(transport_id
, callback
));
472 transport
->GetRawEvents(
473 base::Bind(&CastStreamingNativeHandler::CallGetRawEventsCallback
,
474 weak_factory_
.GetWeakPtr(),
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
);
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
));
496 base::Bind(&CastStreamingNativeHandler::CallGetStatsCallback
,
497 weak_factory_
.GetWeakPtr(),
501 void CastStreamingNativeHandler::CallGetRawEventsCallback(
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())
512 v8::Handle
<v8::Value
> callback_args
[1];
513 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
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(
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())
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(
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
)));
550 CastUdpTransport
* CastStreamingNativeHandler::GetUdpTransportOrThrow(
551 int transport_id
) const {
552 UdpTransportMap::const_iterator iter
= udp_transport_map_
.find(
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
)));
562 } // namespace extensions