• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <iterator>
9 
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"
23 
24 using content::V8ValueConverter;
25 
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;
31 
32 namespace extensions {
33 
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";
43 
44 // These helper methods are used to convert between Extension API
45 // types and Cast types.
ToCastCodecSpecificParams(const CodecSpecificParams & ext_params,CastCodecSpecificParams * cast_params)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;
50 }
51 
FromCastCodecSpecificParams(const CastCodecSpecificParams & cast_params,CodecSpecificParams * ext_params)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;
56 }
57 
58 namespace {
HexDecode(const std::string & input,std::string * output)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;
65 }
66 }  // namespace
67 
ToCastRtpPayloadParamsOrThrow(v8::Isolate * isolate,const RtpPayloadParams & ext_params,CastRtpPayloadParams * cast_params)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;
89   }
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;
95   }
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);
101   }
102   return true;
103 }
104 
FromCastRtpPayloadParams(const CastRtpPayloadParams & cast_params,RtpPayloadParams * ext_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);
130   }
131 }
132 
FromCastRtpParams(const CastRtpParams & cast_params,RtpParams * ext_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);
139 }
140 
ToCastRtpParamsOrThrow(v8::Isolate * isolate,const RtpParams & ext_params,CastRtpParams * cast_params)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;
151   }
152   return true;
153 }
154 
155 }  // namespace
156 
CastStreamingNativeHandler(ScriptContext * context)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)));
191 }
192 
~CastStreamingNativeHandler()193 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
194 }
195 
CreateCastSession(const v8::FunctionCallbackInfo<v8::Value> & args)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());
202 
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;
211 
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));
219 
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>());
223 
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)));
232 }
233 
CallCreateCallback(scoped_ptr<CastRtpStream> stream1,scoped_ptr<CastRtpStream> stream2,scoped_ptr<CastUdpTransport> 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());
241 
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());
251 
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();
259 }
260 
CallStartCallback(int stream_id)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);
268 }
269 
CallStopCallback(int stream_id)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);
277 }
278 
CallErrorCallback(int stream_id,const std::string & message)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(
287       1,
288       v8::String::NewFromUtf8(
289           isolate, message.data(), v8::String::kNormalString, message.size()));
290   context()->DispatchEvent("cast.streaming.rtpStream.onError", event_args);
291 }
292 
DestroyCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)293 void CastStreamingNativeHandler::DestroyCastRtpStream(
294     const v8::FunctionCallbackInfo<v8::Value>& args) {
295   CHECK_EQ(1, args.Length());
296   CHECK(args[0]->IsInt32());
297 
298   const int transport_id = args[0]->ToInt32()->Value();
299   if (!GetRtpStreamOrThrow(transport_id))
300     return;
301   rtp_stream_map_.erase(transport_id);
302 }
303 
GetSupportedParamsCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)304 void CastStreamingNativeHandler::GetSupportedParamsCastRtpStream(
305     const v8::FunctionCallbackInfo<v8::Value>& args) {
306   CHECK_EQ(1, args.Length());
307   CHECK(args[0]->IsInt32());
308 
309   const int transport_id = args[0]->ToInt32()->Value();
310   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
311   if (!transport)
312     return;
313 
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()));
326   }
327   args.GetReturnValue().Set(result);
328 }
329 
StartCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)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());
335 
336   const int transport_id = args[0]->ToInt32()->Value();
337   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
338   if (!transport)
339     return;
340 
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;
348   }
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;
354   }
355 
356   CastRtpParams cast_params;
357   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
358   if (!ToCastRtpParamsOrThrow(isolate, *params, &cast_params))
359     return;
360 
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);
374 }
375 
StopCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)376 void CastStreamingNativeHandler::StopCastRtpStream(
377     const v8::FunctionCallbackInfo<v8::Value>& args) {
378   CHECK_EQ(1, args.Length());
379   CHECK(args[0]->IsInt32());
380 
381   const int transport_id = args[0]->ToInt32()->Value();
382   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
383   if (!transport)
384     return;
385   transport->Stop();
386 }
387 
DestroyCastUdpTransport(const v8::FunctionCallbackInfo<v8::Value> & args)388 void CastStreamingNativeHandler::DestroyCastUdpTransport(
389     const v8::FunctionCallbackInfo<v8::Value>& args) {
390   CHECK_EQ(1, args.Length());
391   CHECK(args[0]->IsInt32());
392 
393   const int transport_id = args[0]->ToInt32()->Value();
394   if (!GetUdpTransportOrThrow(transport_id))
395     return;
396   udp_transport_map_.erase(transport_id);
397 }
398 
SetDestinationCastUdpTransport(const v8::FunctionCallbackInfo<v8::Value> & args)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());
404 
405   const int transport_id = args[0]->ToInt32()->Value();
406   CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
407   if (!transport)
408     return;
409 
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;
417   }
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;
424   }
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;
430   }
431   transport->SetDestination(net::IPEndPoint(ip, destination->port));
432 }
433 
ToggleLogging(const v8::FunctionCallbackInfo<v8::Value> & args)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());
439 
440   const int stream_id = args[0]->ToInt32()->Value();
441   CastRtpStream* stream = GetRtpStreamOrThrow(stream_id);
442   if (!stream)
443     return;
444 
445   const bool enable = args[1]->ToBoolean()->Value();
446   stream->ToggleLogging(enable);
447 }
448 
GetRawEvents(const v8::FunctionCallbackInfo<v8::Value> & args)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());
455 
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]);
464   }
465 
466   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
467   if (!transport)
468     return;
469 
470   get_raw_events_callbacks_.insert(std::make_pair(transport_id, callback));
471 
472   transport->GetRawEvents(
473       base::Bind(&CastStreamingNativeHandler::CallGetRawEventsCallback,
474                  weak_factory_.GetWeakPtr(),
475                  transport_id),
476       extra_data);
477 }
478 
GetStats(const v8::FunctionCallbackInfo<v8::Value> & args)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;
488 
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));
494 
495   transport->GetStats(
496       base::Bind(&CastStreamingNativeHandler::CallGetStatsCallback,
497                  weak_factory_.GetWeakPtr(),
498                  transport_id));
499 }
500 
CallGetRawEventsCallback(int transport_id,scoped_ptr<base::BinaryValue> raw_events)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());
507 
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);
518 }
519 
CallGetStatsCallback(int transport_id,scoped_ptr<base::DictionaryValue> stats)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());
526 
527   RtpStreamCallbackMap::iterator it = get_stats_callbacks_.find(transport_id);
528   if (it == get_stats_callbacks_.end())
529     return;
530 
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);
536 }
537 
GetRtpStreamOrThrow(int transport_id) const538 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;
548 }
549 
GetUdpTransportOrThrow(int transport_id) const550 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;
560 }
561 
562 }  // namespace extensions
563