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 kInvalidStreamArgs
[] = "Invalid stream arguments";
42 const char kUnableToConvertArgs
[] = "Unable to convert arguments";
43 const char kUnableToConvertParams
[] = "Unable to convert params";
45 // These helper methods are used to convert between Extension API
46 // types and Cast types.
47 void ToCastCodecSpecificParams(const CodecSpecificParams
& ext_params
,
48 CastCodecSpecificParams
* cast_params
) {
49 cast_params
->key
= ext_params
.key
;
50 cast_params
->value
= ext_params
.value
;
53 void FromCastCodecSpecificParams(const CastCodecSpecificParams
& cast_params
,
54 CodecSpecificParams
* ext_params
) {
55 ext_params
->key
= cast_params
.key
;
56 ext_params
->value
= cast_params
.value
;
60 bool HexDecode(const std::string
& input
, std::string
* output
) {
61 std::vector
<uint8
> bytes
;
62 if (!base::HexStringToBytes(input
, &bytes
))
64 output
->assign(reinterpret_cast<const char*>(&bytes
[0]), bytes
.size());
69 bool ToCastRtpPayloadParamsOrThrow(v8::Isolate
* isolate
,
70 const RtpPayloadParams
& ext_params
,
71 CastRtpPayloadParams
* cast_params
) {
72 cast_params
->payload_type
= ext_params
.payload_type
;
73 cast_params
->max_latency_ms
= ext_params
.max_latency
;
74 cast_params
->min_latency_ms
=
75 ext_params
.min_latency
? *ext_params
.min_latency
: ext_params
.max_latency
;
76 cast_params
->codec_name
= ext_params
.codec_name
;
77 cast_params
->ssrc
= ext_params
.ssrc
;
78 cast_params
->feedback_ssrc
= ext_params
.feedback_ssrc
;
79 cast_params
->clock_rate
= ext_params
.clock_rate
? *ext_params
.clock_rate
: 0;
80 cast_params
->min_bitrate
=
81 ext_params
.min_bitrate
? *ext_params
.min_bitrate
: 0;
82 cast_params
->max_bitrate
=
83 ext_params
.max_bitrate
? *ext_params
.max_bitrate
: 0;
84 cast_params
->channels
= ext_params
.channels
? *ext_params
.channels
: 0;
85 cast_params
->max_frame_rate
=
86 ext_params
.max_frame_rate
? *ext_params
.max_frame_rate
: 0.0;
87 cast_params
->width
= ext_params
.width
? *ext_params
.width
: 0;
88 cast_params
->height
= ext_params
.height
? *ext_params
.height
: 0;
89 if (ext_params
.aes_key
&&
90 !HexDecode(*ext_params
.aes_key
, &cast_params
->aes_key
)) {
91 isolate
->ThrowException(v8::Exception::Error(
92 v8::String::NewFromUtf8(isolate
, kInvalidAesKey
)));
95 if (ext_params
.aes_iv_mask
&&
96 !HexDecode(*ext_params
.aes_iv_mask
, &cast_params
->aes_iv_mask
)) {
97 isolate
->ThrowException(v8::Exception::Error(
98 v8::String::NewFromUtf8(isolate
, kInvalidAesIvMask
)));
101 for (size_t i
= 0; i
< ext_params
.codec_specific_params
.size(); ++i
) {
102 CastCodecSpecificParams cast_codec_params
;
103 ToCastCodecSpecificParams(*ext_params
.codec_specific_params
[i
],
105 cast_params
->codec_specific_params
.push_back(cast_codec_params
);
110 void FromCastRtpPayloadParams(const CastRtpPayloadParams
& cast_params
,
111 RtpPayloadParams
* ext_params
) {
112 ext_params
->payload_type
= cast_params
.payload_type
;
113 ext_params
->max_latency
= cast_params
.max_latency_ms
;
114 ext_params
->min_latency
.reset(new int(cast_params
.min_latency_ms
));
115 ext_params
->codec_name
= cast_params
.codec_name
;
116 ext_params
->ssrc
= cast_params
.ssrc
;
117 ext_params
->feedback_ssrc
= cast_params
.feedback_ssrc
;
118 if (cast_params
.clock_rate
)
119 ext_params
->clock_rate
.reset(new int(cast_params
.clock_rate
));
120 if (cast_params
.min_bitrate
)
121 ext_params
->min_bitrate
.reset(new int(cast_params
.min_bitrate
));
122 if (cast_params
.max_bitrate
)
123 ext_params
->max_bitrate
.reset(new int(cast_params
.max_bitrate
));
124 if (cast_params
.channels
)
125 ext_params
->channels
.reset(new int(cast_params
.channels
));
126 if (cast_params
.max_frame_rate
> 0.0)
127 ext_params
->max_frame_rate
.reset(new double(cast_params
.max_frame_rate
));
128 if (cast_params
.width
)
129 ext_params
->width
.reset(new int(cast_params
.width
));
130 if (cast_params
.height
)
131 ext_params
->height
.reset(new int(cast_params
.height
));
132 for (size_t i
= 0; i
< cast_params
.codec_specific_params
.size(); ++i
) {
133 linked_ptr
<CodecSpecificParams
> ext_codec_params(
134 new CodecSpecificParams());
135 FromCastCodecSpecificParams(cast_params
.codec_specific_params
[i
],
136 ext_codec_params
.get());
137 ext_params
->codec_specific_params
.push_back(ext_codec_params
);
141 void FromCastRtpParams(const CastRtpParams
& cast_params
,
142 RtpParams
* ext_params
) {
143 std::copy(cast_params
.rtcp_features
.begin(),
144 cast_params
.rtcp_features
.end(),
145 std::back_inserter(ext_params
->rtcp_features
));
146 FromCastRtpPayloadParams(cast_params
.payload
, &ext_params
->payload
);
149 bool ToCastRtpParamsOrThrow(v8::Isolate
* isolate
,
150 const RtpParams
& ext_params
,
151 CastRtpParams
* cast_params
) {
152 std::copy(ext_params
.rtcp_features
.begin(),
153 ext_params
.rtcp_features
.end(),
154 std::back_inserter(cast_params
->rtcp_features
));
155 if (!ToCastRtpPayloadParamsOrThrow(isolate
,
157 &cast_params
->payload
)) {
165 CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext
* context
)
166 : ObjectBackedNativeHandler(context
),
167 last_transport_id_(1),
168 weak_factory_(this) {
169 RouteFunction("CreateSession",
170 base::Bind(&CastStreamingNativeHandler::CreateCastSession
,
171 base::Unretained(this)));
172 RouteFunction("DestroyCastRtpStream",
173 base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream
,
174 base::Unretained(this)));
175 RouteFunction("GetSupportedParamsCastRtpStream",
176 base::Bind(&CastStreamingNativeHandler::GetSupportedParamsCastRtpStream
,
177 base::Unretained(this)));
178 RouteFunction("StartCastRtpStream",
179 base::Bind(&CastStreamingNativeHandler::StartCastRtpStream
,
180 base::Unretained(this)));
181 RouteFunction("StopCastRtpStream",
182 base::Bind(&CastStreamingNativeHandler::StopCastRtpStream
,
183 base::Unretained(this)));
184 RouteFunction("DestroyCastUdpTransport",
185 base::Bind(&CastStreamingNativeHandler::DestroyCastUdpTransport
,
186 base::Unretained(this)));
187 RouteFunction("SetDestinationCastUdpTransport",
188 base::Bind(&CastStreamingNativeHandler::SetDestinationCastUdpTransport
,
189 base::Unretained(this)));
190 RouteFunction("SetOptionsCastUdpTransport",
191 base::Bind(&CastStreamingNativeHandler::SetOptionsCastUdpTransport
,
192 base::Unretained(this)));
193 RouteFunction("ToggleLogging",
194 base::Bind(&CastStreamingNativeHandler::ToggleLogging
,
195 base::Unretained(this)));
196 RouteFunction("GetRawEvents",
197 base::Bind(&CastStreamingNativeHandler::GetRawEvents
,
198 base::Unretained(this)));
199 RouteFunction("GetStats",
200 base::Bind(&CastStreamingNativeHandler::GetStats
,
201 base::Unretained(this)));
204 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
207 void CastStreamingNativeHandler::CreateCastSession(
208 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
209 CHECK_EQ(3, args
.Length());
210 CHECK(args
[2]->IsFunction());
212 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
213 if ((args
[0]->IsNull() || args
[0]->IsUndefined()) &&
214 (args
[1]->IsNull() || args
[1]->IsUndefined())) {
215 isolate
->ThrowException(v8::Exception::Error(
216 v8::String::NewFromUtf8(isolate
, kInvalidStreamArgs
)));
220 scoped_refptr
<CastSession
> session(new CastSession());
221 scoped_ptr
<CastRtpStream
> stream1
, stream2
;
222 if (!args
[0]->IsNull() && !args
[0]->IsUndefined()) {
223 CHECK(args
[0]->IsObject());
224 blink::WebDOMMediaStreamTrack track
=
225 blink::WebDOMMediaStreamTrack::fromV8Value(args
[0]);
226 if (track
.isNull()) {
227 isolate
->ThrowException(v8::Exception::Error(
228 v8::String::NewFromUtf8(isolate
, kInvalidStreamArgs
)));
231 stream1
.reset(new CastRtpStream(track
.component(), session
));
233 if (!args
[1]->IsNull() && !args
[1]->IsUndefined()) {
234 CHECK(args
[1]->IsObject());
235 blink::WebDOMMediaStreamTrack track
=
236 blink::WebDOMMediaStreamTrack::fromV8Value(args
[1]);
237 if (track
.isNull()) {
238 isolate
->ThrowException(v8::Exception::Error(
239 v8::String::NewFromUtf8(isolate
, kInvalidStreamArgs
)));
242 stream2
.reset(new CastRtpStream(track
.component(), session
));
244 scoped_ptr
<CastUdpTransport
> udp_transport(
245 new CastUdpTransport(session
));
247 // TODO(imcheng): Use a weak reference to ensure we don't call into an
248 // invalid context when the callback is invoked.
249 create_callback_
.reset(args
[2].As
<v8::Function
>());
251 base::MessageLoop::current()->PostTask(
254 &CastStreamingNativeHandler::CallCreateCallback
,
255 weak_factory_
.GetWeakPtr(),
256 base::Passed(&stream1
),
257 base::Passed(&stream2
),
258 base::Passed(&udp_transport
)));
261 void CastStreamingNativeHandler::CallCreateCallback(
262 scoped_ptr
<CastRtpStream
> stream1
,
263 scoped_ptr
<CastRtpStream
> stream2
,
264 scoped_ptr
<CastUdpTransport
> udp_transport
) {
265 v8::Isolate
* isolate
= context()->isolate();
266 v8::HandleScope
handle_scope(isolate
);
267 v8::Context::Scope
context_scope(context()->v8_context());
269 v8::Handle
<v8::Value
> callback_args
[3];
270 callback_args
[0] = v8::Null(isolate
);
271 callback_args
[1] = v8::Null(isolate
);
274 const int stream1_id
= last_transport_id_
++;
275 callback_args
[0] = v8::Integer::New(isolate
, stream1_id
);
276 rtp_stream_map_
[stream1_id
] =
277 linked_ptr
<CastRtpStream
>(stream1
.release());
280 const int stream2_id
= last_transport_id_
++;
281 callback_args
[1] = v8::Integer::New(isolate
, stream2_id
);
282 rtp_stream_map_
[stream2_id
] =
283 linked_ptr
<CastRtpStream
>(stream2
.release());
285 const int udp_id
= last_transport_id_
++;
286 udp_transport_map_
[udp_id
] =
287 linked_ptr
<CastUdpTransport
>(udp_transport
.release());
288 callback_args
[2] = v8::Integer::New(isolate
, udp_id
);
289 context()->CallFunction(create_callback_
.NewHandle(isolate
),
291 create_callback_
.reset();
294 void CastStreamingNativeHandler::CallStartCallback(int stream_id
) {
295 v8::Isolate
* isolate
= context()->isolate();
296 v8::HandleScope
handle_scope(isolate
);
297 v8::Context::Scope
context_scope(context()->v8_context());
298 v8::Handle
<v8::Array
> event_args
= v8::Array::New(isolate
, 1);
299 event_args
->Set(0, v8::Integer::New(isolate
, stream_id
));
300 context()->DispatchEvent("cast.streaming.rtpStream.onStarted", event_args
);
303 void CastStreamingNativeHandler::CallStopCallback(int stream_id
) {
304 v8::Isolate
* isolate
= context()->isolate();
305 v8::HandleScope
handle_scope(isolate
);
306 v8::Context::Scope
context_scope(context()->v8_context());
307 v8::Handle
<v8::Array
> event_args
= v8::Array::New(isolate
, 1);
308 event_args
->Set(0, v8::Integer::New(isolate
, stream_id
));
309 context()->DispatchEvent("cast.streaming.rtpStream.onStopped", event_args
);
312 void CastStreamingNativeHandler::CallErrorCallback(int stream_id
,
313 const std::string
& message
) {
314 v8::Isolate
* isolate
= context()->isolate();
315 v8::HandleScope
handle_scope(isolate
);
316 v8::Context::Scope
context_scope(context()->v8_context());
317 v8::Handle
<v8::Array
> event_args
= v8::Array::New(isolate
, 2);
318 event_args
->Set(0, v8::Integer::New(isolate
, stream_id
));
321 v8::String::NewFromUtf8(
322 isolate
, message
.data(), v8::String::kNormalString
, message
.size()));
323 context()->DispatchEvent("cast.streaming.rtpStream.onError", event_args
);
326 void CastStreamingNativeHandler::DestroyCastRtpStream(
327 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
328 CHECK_EQ(1, args
.Length());
329 CHECK(args
[0]->IsInt32());
331 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
332 if (!GetRtpStreamOrThrow(transport_id
))
334 rtp_stream_map_
.erase(transport_id
);
337 void CastStreamingNativeHandler::GetSupportedParamsCastRtpStream(
338 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
339 CHECK_EQ(1, args
.Length());
340 CHECK(args
[0]->IsInt32());
342 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
343 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
347 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
348 std::vector
<CastRtpParams
> cast_params
= transport
->GetSupportedParams();
349 v8::Handle
<v8::Array
> result
=
350 v8::Array::New(args
.GetIsolate(),
351 static_cast<int>(cast_params
.size()));
352 for (size_t i
= 0; i
< cast_params
.size(); ++i
) {
354 FromCastRtpParams(cast_params
[i
], ¶ms
);
355 scoped_ptr
<base::DictionaryValue
> params_value
= params
.ToValue();
358 converter
->ToV8Value(params_value
.get(), context()->v8_context()));
360 args
.GetReturnValue().Set(result
);
363 void CastStreamingNativeHandler::StartCastRtpStream(
364 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
365 CHECK_EQ(2, args
.Length());
366 CHECK(args
[0]->IsInt32());
367 CHECK(args
[1]->IsObject());
369 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
370 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
374 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
375 scoped_ptr
<base::Value
> params_value(
376 converter
->FromV8Value(args
[1], context()->v8_context()));
378 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
379 v8::String::NewFromUtf8(args
.GetIsolate(), kUnableToConvertParams
)));
382 scoped_ptr
<RtpParams
> params
= RtpParams::FromValue(*params_value
);
384 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
385 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidRtpParams
)));
389 CastRtpParams cast_params
;
390 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
391 if (!ToCastRtpParamsOrThrow(isolate
, *params
, &cast_params
))
394 base::Closure start_callback
=
395 base::Bind(&CastStreamingNativeHandler::CallStartCallback
,
396 weak_factory_
.GetWeakPtr(),
398 base::Closure stop_callback
=
399 base::Bind(&CastStreamingNativeHandler::CallStopCallback
,
400 weak_factory_
.GetWeakPtr(),
402 CastRtpStream::ErrorCallback error_callback
=
403 base::Bind(&CastStreamingNativeHandler::CallErrorCallback
,
404 weak_factory_
.GetWeakPtr(),
406 transport
->Start(cast_params
, start_callback
, stop_callback
, error_callback
);
409 void CastStreamingNativeHandler::StopCastRtpStream(
410 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
411 CHECK_EQ(1, args
.Length());
412 CHECK(args
[0]->IsInt32());
414 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
415 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
421 void CastStreamingNativeHandler::DestroyCastUdpTransport(
422 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
423 CHECK_EQ(1, args
.Length());
424 CHECK(args
[0]->IsInt32());
426 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
427 if (!GetUdpTransportOrThrow(transport_id
))
429 udp_transport_map_
.erase(transport_id
);
432 void CastStreamingNativeHandler::SetDestinationCastUdpTransport(
433 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
434 CHECK_EQ(2, args
.Length());
435 CHECK(args
[0]->IsInt32());
436 CHECK(args
[1]->IsObject());
438 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
439 CastUdpTransport
* transport
= GetUdpTransportOrThrow(transport_id
);
443 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
444 scoped_ptr
<base::Value
> destination_value(
445 converter
->FromV8Value(args
[1], context()->v8_context()));
446 if (!destination_value
) {
447 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
448 v8::String::NewFromUtf8(args
.GetIsolate(), kUnableToConvertArgs
)));
451 scoped_ptr
<IPEndPoint
> destination
=
452 IPEndPoint::FromValue(*destination_value
);
454 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
455 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidDestination
)));
458 net::IPAddressNumber ip
;
459 if (!net::ParseIPLiteralToNumber(destination
->address
, &ip
)) {
460 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
461 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidDestination
)));
464 transport
->SetDestination(net::IPEndPoint(ip
, destination
->port
));
467 void CastStreamingNativeHandler::SetOptionsCastUdpTransport(
468 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
469 CHECK_EQ(2, args
.Length());
470 CHECK(args
[0]->IsInt32());
471 CHECK(args
[1]->IsObject());
473 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
474 CastUdpTransport
* transport
= GetUdpTransportOrThrow(transport_id
);
478 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
479 base::Value
* options_value
=
480 converter
->FromV8Value(args
[1], context()->v8_context());
481 base::DictionaryValue
* options
;
482 if (!options_value
|| !options_value
->GetAsDictionary(&options
)) {
483 delete options_value
;
484 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
485 v8::String::NewFromUtf8(args
.GetIsolate(), kUnableToConvertArgs
)));
488 transport
->SetOptions(make_scoped_ptr(options
));
491 void CastStreamingNativeHandler::ToggleLogging(
492 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
493 CHECK_EQ(2, args
.Length());
494 CHECK(args
[0]->IsInt32());
495 CHECK(args
[1]->IsBoolean());
497 const int stream_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
498 CastRtpStream
* stream
= GetRtpStreamOrThrow(stream_id
);
502 const bool enable
= args
[1]->ToBoolean(args
.GetIsolate())->Value();
503 stream
->ToggleLogging(enable
);
506 void CastStreamingNativeHandler::GetRawEvents(
507 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
508 CHECK_EQ(3, args
.Length());
509 CHECK(args
[0]->IsInt32());
510 CHECK(args
[1]->IsNull() || args
[1]->IsString());
511 CHECK(args
[2]->IsFunction());
513 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
514 // TODO(imcheng): Use a weak reference to ensure we don't call into an
515 // invalid context when the callback is invoked.
516 linked_ptr
<ScopedPersistent
<v8::Function
> > callback(
517 new ScopedPersistent
<v8::Function
>(args
[2].As
<v8::Function
>()));
518 std::string extra_data
;
519 if (!args
[1]->IsNull()) {
520 extra_data
= *v8::String::Utf8Value(args
[1]);
523 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
527 get_raw_events_callbacks_
.insert(std::make_pair(transport_id
, callback
));
529 transport
->GetRawEvents(
530 base::Bind(&CastStreamingNativeHandler::CallGetRawEventsCallback
,
531 weak_factory_
.GetWeakPtr(),
536 void CastStreamingNativeHandler::GetStats(
537 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
538 CHECK_EQ(2, args
.Length());
539 CHECK(args
[0]->IsInt32());
540 CHECK(args
[1]->IsFunction());
541 const int transport_id
= args
[0]->ToInt32(args
.GetIsolate())->Value();
542 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
546 // TODO(imcheng): Use a weak reference to ensure we don't call into an
547 // invalid context when the callback is invoked.
548 linked_ptr
<ScopedPersistent
<v8::Function
> > callback(
549 new ScopedPersistent
<v8::Function
>(args
[1].As
<v8::Function
>()));
550 get_stats_callbacks_
.insert(std::make_pair(transport_id
, callback
));
553 base::Bind(&CastStreamingNativeHandler::CallGetStatsCallback
,
554 weak_factory_
.GetWeakPtr(),
558 void CastStreamingNativeHandler::CallGetRawEventsCallback(
560 scoped_ptr
<base::BinaryValue
> raw_events
) {
561 v8::Isolate
* isolate
= context()->isolate();
562 v8::HandleScope
handle_scope(isolate
);
563 v8::Context::Scope
context_scope(context()->v8_context());
565 RtpStreamCallbackMap::iterator it
=
566 get_raw_events_callbacks_
.find(transport_id
);
567 if (it
== get_raw_events_callbacks_
.end())
569 v8::Handle
<v8::Value
> callback_args
[1];
570 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
572 converter
->ToV8Value(raw_events
.get(), context()->v8_context());
573 context()->CallFunction(it
->second
->NewHandle(isolate
), 1, callback_args
);
574 get_raw_events_callbacks_
.erase(it
);
577 void CastStreamingNativeHandler::CallGetStatsCallback(
579 scoped_ptr
<base::DictionaryValue
> stats
) {
580 v8::Isolate
* isolate
= context()->isolate();
581 v8::HandleScope
handle_scope(isolate
);
582 v8::Context::Scope
context_scope(context()->v8_context());
584 RtpStreamCallbackMap::iterator it
= get_stats_callbacks_
.find(transport_id
);
585 if (it
== get_stats_callbacks_
.end())
588 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
589 v8::Handle
<v8::Value
> callback_args
[1];
590 callback_args
[0] = converter
->ToV8Value(stats
.get(), context()->v8_context());
591 context()->CallFunction(it
->second
->NewHandle(isolate
), 1, callback_args
);
592 get_stats_callbacks_
.erase(it
);
595 CastRtpStream
* CastStreamingNativeHandler::GetRtpStreamOrThrow(
596 int transport_id
) const {
597 RtpStreamMap::const_iterator iter
= rtp_stream_map_
.find(
599 if (iter
!= rtp_stream_map_
.end())
600 return iter
->second
.get();
601 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
602 isolate
->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
603 isolate
, kRtpStreamNotFound
)));
607 CastUdpTransport
* CastStreamingNativeHandler::GetUdpTransportOrThrow(
608 int transport_id
) const {
609 UdpTransportMap::const_iterator iter
= udp_transport_map_
.find(
611 if (iter
!= udp_transport_map_
.end())
612 return iter
->second
.get();
613 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
614 isolate
->ThrowException(v8::Exception::RangeError(
615 v8::String::NewFromUtf8(isolate
, kUdpTransportNotFound
)));
619 } // namespace extensions