Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / renderer / extensions / cast_streaming_native_handler.cc
blob160b6fbd78a0fa05d0bb116d774b98048e2fa276
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/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "chrome/common/extensions/api/cast_streaming_receiver_session.h"
16 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
17 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
18 #include "chrome/renderer/media/cast_receiver_session.h"
19 #include "chrome/renderer/media/cast_rtp_stream.h"
20 #include "chrome/renderer/media/cast_session.h"
21 #include "chrome/renderer/media/cast_udp_transport.h"
22 #include "content/public/child/v8_value_converter.h"
23 #include "content/public/renderer/media_stream_api.h"
24 #include "extensions/renderer/script_context.h"
25 #include "media/audio/audio_parameters.h"
26 #include "net/base/host_port_pair.h"
27 #include "third_party/WebKit/public/platform/WebMediaStream.h"
28 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
29 #include "third_party/WebKit/public/platform/WebURL.h"
30 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
31 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
32 #include "url/gurl.h"
34 using content::V8ValueConverter;
36 // Extension types.
37 using extensions::api::cast_streaming_receiver_session::RtpReceiverParams;
38 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams;
39 using extensions::api::cast_streaming_rtp_stream::RtpParams;
40 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams;
41 using extensions::api::cast_streaming_udp_transport::IPEndPoint;
43 namespace extensions {
45 namespace {
46 const char kInvalidAesIvMask[] = "Invalid value for AES IV mask";
47 const char kInvalidAesKey[] = "Invalid value for AES key";
48 const char kInvalidAudioParams[] = "Invalid audio params";
49 const char kInvalidDestination[] = "Invalid destination";
50 const char kInvalidFPS[] = "Invalid FPS";
51 const char kInvalidMediaStreamURL[] = "Invalid MediaStream URL";
52 const char kInvalidRtpParams[] = "Invalid value for RTP params";
53 const char kInvalidLatency[] = "Invalid value for max_latency. (0-1000)";
54 const char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)";
55 const char kInvalidStreamArgs[] = "Invalid stream arguments";
56 const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
57 const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
58 const char kUnableToConvertArgs[] = "Unable to convert arguments";
59 const char kUnableToConvertParams[] = "Unable to convert params";
61 // These helper methods are used to convert between Extension API
62 // types and Cast types.
63 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params,
64 CastCodecSpecificParams* cast_params) {
65 cast_params->key = ext_params.key;
66 cast_params->value = ext_params.value;
69 void FromCastCodecSpecificParams(const CastCodecSpecificParams& cast_params,
70 CodecSpecificParams* ext_params) {
71 ext_params->key = cast_params.key;
72 ext_params->value = cast_params.value;
75 namespace {
76 bool HexDecode(const std::string& input, std::string* output) {
77 std::vector<uint8> bytes;
78 if (!base::HexStringToBytes(input, &bytes))
79 return false;
80 output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size());
81 return true;
83 } // namespace
85 bool ToCastRtpPayloadParamsOrThrow(v8::Isolate* isolate,
86 const RtpPayloadParams& ext_params,
87 CastRtpPayloadParams* cast_params) {
88 cast_params->payload_type = ext_params.payload_type;
89 cast_params->max_latency_ms = ext_params.max_latency;
90 cast_params->min_latency_ms =
91 ext_params.min_latency ? *ext_params.min_latency : ext_params.max_latency;
92 cast_params->codec_name = ext_params.codec_name;
93 cast_params->ssrc = ext_params.ssrc;
94 cast_params->feedback_ssrc = ext_params.feedback_ssrc;
95 cast_params->clock_rate = ext_params.clock_rate ? *ext_params.clock_rate : 0;
96 cast_params->min_bitrate =
97 ext_params.min_bitrate ? *ext_params.min_bitrate : 0;
98 cast_params->max_bitrate =
99 ext_params.max_bitrate ? *ext_params.max_bitrate : 0;
100 cast_params->channels = ext_params.channels ? *ext_params.channels : 0;
101 cast_params->max_frame_rate =
102 ext_params.max_frame_rate ? *ext_params.max_frame_rate : 0.0;
103 if (ext_params.aes_key &&
104 !HexDecode(*ext_params.aes_key, &cast_params->aes_key)) {
105 isolate->ThrowException(v8::Exception::Error(
106 v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
107 return false;
109 if (ext_params.aes_iv_mask &&
110 !HexDecode(*ext_params.aes_iv_mask, &cast_params->aes_iv_mask)) {
111 isolate->ThrowException(v8::Exception::Error(
112 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
113 return false;
115 for (size_t i = 0; i < ext_params.codec_specific_params.size(); ++i) {
116 CastCodecSpecificParams cast_codec_params;
117 ToCastCodecSpecificParams(*ext_params.codec_specific_params[i],
118 &cast_codec_params);
119 cast_params->codec_specific_params.push_back(cast_codec_params);
121 return true;
124 void FromCastRtpPayloadParams(const CastRtpPayloadParams& cast_params,
125 RtpPayloadParams* ext_params) {
126 ext_params->payload_type = cast_params.payload_type;
127 ext_params->max_latency = cast_params.max_latency_ms;
128 ext_params->min_latency.reset(new int(cast_params.min_latency_ms));
129 ext_params->codec_name = cast_params.codec_name;
130 ext_params->ssrc = cast_params.ssrc;
131 ext_params->feedback_ssrc = cast_params.feedback_ssrc;
132 if (cast_params.clock_rate)
133 ext_params->clock_rate.reset(new int(cast_params.clock_rate));
134 if (cast_params.min_bitrate)
135 ext_params->min_bitrate.reset(new int(cast_params.min_bitrate));
136 if (cast_params.max_bitrate)
137 ext_params->max_bitrate.reset(new int(cast_params.max_bitrate));
138 if (cast_params.channels)
139 ext_params->channels.reset(new int(cast_params.channels));
140 if (cast_params.max_frame_rate > 0.0)
141 ext_params->max_frame_rate.reset(new double(cast_params.max_frame_rate));
142 for (size_t i = 0; i < cast_params.codec_specific_params.size(); ++i) {
143 linked_ptr<CodecSpecificParams> ext_codec_params(
144 new CodecSpecificParams());
145 FromCastCodecSpecificParams(cast_params.codec_specific_params[i],
146 ext_codec_params.get());
147 ext_params->codec_specific_params.push_back(ext_codec_params);
151 void FromCastRtpParams(const CastRtpParams& cast_params,
152 RtpParams* ext_params) {
153 std::copy(cast_params.rtcp_features.begin(),
154 cast_params.rtcp_features.end(),
155 std::back_inserter(ext_params->rtcp_features));
156 FromCastRtpPayloadParams(cast_params.payload, &ext_params->payload);
159 bool ToCastRtpParamsOrThrow(v8::Isolate* isolate,
160 const RtpParams& ext_params,
161 CastRtpParams* cast_params) {
162 std::copy(ext_params.rtcp_features.begin(),
163 ext_params.rtcp_features.end(),
164 std::back_inserter(cast_params->rtcp_features));
165 if (!ToCastRtpPayloadParamsOrThrow(isolate,
166 ext_params.payload,
167 &cast_params->payload)) {
168 return false;
170 return true;
173 } // namespace
175 CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext* context)
176 : ObjectBackedNativeHandler(context),
177 last_transport_id_(1),
178 weak_factory_(this) {
179 RouteFunction("CreateSession",
180 base::Bind(&CastStreamingNativeHandler::CreateCastSession,
181 weak_factory_.GetWeakPtr()));
182 RouteFunction("DestroyCastRtpStream",
183 base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream,
184 weak_factory_.GetWeakPtr()));
185 RouteFunction(
186 "GetSupportedParamsCastRtpStream",
187 base::Bind(&CastStreamingNativeHandler::GetSupportedParamsCastRtpStream,
188 weak_factory_.GetWeakPtr()));
189 RouteFunction("StartCastRtpStream",
190 base::Bind(&CastStreamingNativeHandler::StartCastRtpStream,
191 weak_factory_.GetWeakPtr()));
192 RouteFunction("StopCastRtpStream",
193 base::Bind(&CastStreamingNativeHandler::StopCastRtpStream,
194 weak_factory_.GetWeakPtr()));
195 RouteFunction("DestroyCastUdpTransport",
196 base::Bind(&CastStreamingNativeHandler::DestroyCastUdpTransport,
197 weak_factory_.GetWeakPtr()));
198 RouteFunction(
199 "SetDestinationCastUdpTransport",
200 base::Bind(&CastStreamingNativeHandler::SetDestinationCastUdpTransport,
201 weak_factory_.GetWeakPtr()));
202 RouteFunction(
203 "SetOptionsCastUdpTransport",
204 base::Bind(&CastStreamingNativeHandler::SetOptionsCastUdpTransport,
205 weak_factory_.GetWeakPtr()));
206 RouteFunction("ToggleLogging",
207 base::Bind(&CastStreamingNativeHandler::ToggleLogging,
208 weak_factory_.GetWeakPtr()));
209 RouteFunction("GetRawEvents",
210 base::Bind(&CastStreamingNativeHandler::GetRawEvents,
211 weak_factory_.GetWeakPtr()));
212 RouteFunction("GetStats", base::Bind(&CastStreamingNativeHandler::GetStats,
213 weak_factory_.GetWeakPtr()));
214 RouteFunction("StartCastRtpReceiver",
215 base::Bind(&CastStreamingNativeHandler::StartCastRtpReceiver,
216 weak_factory_.GetWeakPtr()));
219 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
220 // Note: A superclass's destructor will call Invalidate(), but Invalidate()
221 // may also be called at any time before destruction.
224 void CastStreamingNativeHandler::Invalidate() {
225 // Cancel all function call routing and callbacks.
226 weak_factory_.InvalidateWeakPtrs();
228 // Clear all references to V8 and Cast objects, which will trigger
229 // auto-destructions (effectively stopping all sessions).
230 get_stats_callbacks_.clear();
231 get_raw_events_callbacks_.clear();
232 create_callback_.Reset();
233 udp_transport_map_.clear();
234 rtp_stream_map_.clear();
236 ObjectBackedNativeHandler::Invalidate();
239 void CastStreamingNativeHandler::CreateCastSession(
240 const v8::FunctionCallbackInfo<v8::Value>& args) {
241 CHECK_EQ(3, args.Length());
242 CHECK(args[2]->IsFunction());
244 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
245 if ((args[0]->IsNull() || args[0]->IsUndefined()) &&
246 (args[1]->IsNull() || args[1]->IsUndefined())) {
247 isolate->ThrowException(v8::Exception::Error(
248 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
249 return;
252 scoped_refptr<CastSession> session(new CastSession());
253 scoped_ptr<CastRtpStream> stream1, stream2;
254 if (!args[0]->IsNull() && !args[0]->IsUndefined()) {
255 CHECK(args[0]->IsObject());
256 blink::WebDOMMediaStreamTrack track =
257 blink::WebDOMMediaStreamTrack::fromV8Value(args[0]);
258 if (track.isNull()) {
259 isolate->ThrowException(v8::Exception::Error(
260 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
261 return;
263 stream1.reset(new CastRtpStream(track.component(), session));
265 if (!args[1]->IsNull() && !args[1]->IsUndefined()) {
266 CHECK(args[1]->IsObject());
267 blink::WebDOMMediaStreamTrack track =
268 blink::WebDOMMediaStreamTrack::fromV8Value(args[1]);
269 if (track.isNull()) {
270 isolate->ThrowException(v8::Exception::Error(
271 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
272 return;
274 stream2.reset(new CastRtpStream(track.component(), session));
276 scoped_ptr<CastUdpTransport> udp_transport(
277 new CastUdpTransport(session));
279 create_callback_.Reset(isolate, args[2].As<v8::Function>());
281 base::ThreadTaskRunnerHandle::Get()->PostTask(
282 FROM_HERE,
283 base::Bind(&CastStreamingNativeHandler::CallCreateCallback,
284 weak_factory_.GetWeakPtr(), base::Passed(&stream1),
285 base::Passed(&stream2), base::Passed(&udp_transport)));
288 void CastStreamingNativeHandler::CallCreateCallback(
289 scoped_ptr<CastRtpStream> stream1,
290 scoped_ptr<CastRtpStream> stream2,
291 scoped_ptr<CastUdpTransport> udp_transport) {
292 v8::Isolate* isolate = context()->isolate();
293 v8::HandleScope handle_scope(isolate);
294 v8::Context::Scope context_scope(context()->v8_context());
296 v8::Local<v8::Value> callback_args[3];
297 callback_args[0] = v8::Null(isolate);
298 callback_args[1] = v8::Null(isolate);
300 if (stream1) {
301 const int stream1_id = last_transport_id_++;
302 callback_args[0] = v8::Integer::New(isolate, stream1_id);
303 rtp_stream_map_[stream1_id] =
304 linked_ptr<CastRtpStream>(stream1.release());
306 if (stream2) {
307 const int stream2_id = last_transport_id_++;
308 callback_args[1] = v8::Integer::New(isolate, stream2_id);
309 rtp_stream_map_[stream2_id] =
310 linked_ptr<CastRtpStream>(stream2.release());
312 const int udp_id = last_transport_id_++;
313 udp_transport_map_[udp_id] =
314 linked_ptr<CastUdpTransport>(udp_transport.release());
315 callback_args[2] = v8::Integer::New(isolate, udp_id);
316 context()->CallFunction(
317 v8::Local<v8::Function>::New(isolate, create_callback_), 3,
318 callback_args);
319 create_callback_.Reset();
322 void CastStreamingNativeHandler::CallStartCallback(int stream_id) const {
323 v8::Isolate* isolate = context()->isolate();
324 v8::HandleScope handle_scope(isolate);
325 v8::Context::Scope context_scope(context()->v8_context());
326 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1);
327 event_args->Set(0, v8::Integer::New(isolate, stream_id));
328 context()->DispatchEvent("cast.streaming.rtpStream.onStarted", event_args);
331 void CastStreamingNativeHandler::CallStopCallback(int stream_id) const {
332 v8::Isolate* isolate = context()->isolate();
333 v8::HandleScope handle_scope(isolate);
334 v8::Context::Scope context_scope(context()->v8_context());
335 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1);
336 event_args->Set(0, v8::Integer::New(isolate, stream_id));
337 context()->DispatchEvent("cast.streaming.rtpStream.onStopped", event_args);
340 void CastStreamingNativeHandler::CallErrorCallback(
341 int stream_id,
342 const std::string& message) const {
343 v8::Isolate* isolate = context()->isolate();
344 v8::HandleScope handle_scope(isolate);
345 v8::Context::Scope context_scope(context()->v8_context());
346 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 2);
347 event_args->Set(0, v8::Integer::New(isolate, stream_id));
348 event_args->Set(
350 v8::String::NewFromUtf8(
351 isolate, message.data(), v8::String::kNormalString, message.size()));
352 context()->DispatchEvent("cast.streaming.rtpStream.onError", event_args);
355 void CastStreamingNativeHandler::DestroyCastRtpStream(
356 const v8::FunctionCallbackInfo<v8::Value>& args) {
357 CHECK_EQ(1, args.Length());
358 CHECK(args[0]->IsInt32());
360 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
361 if (!GetRtpStreamOrThrow(transport_id))
362 return;
363 rtp_stream_map_.erase(transport_id);
366 void CastStreamingNativeHandler::GetSupportedParamsCastRtpStream(
367 const v8::FunctionCallbackInfo<v8::Value>& args) const {
368 CHECK_EQ(1, args.Length());
369 CHECK(args[0]->IsInt32());
371 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
372 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
373 if (!transport)
374 return;
376 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
377 std::vector<CastRtpParams> cast_params = transport->GetSupportedParams();
378 v8::Local<v8::Array> result =
379 v8::Array::New(args.GetIsolate(),
380 static_cast<int>(cast_params.size()));
381 for (size_t i = 0; i < cast_params.size(); ++i) {
382 RtpParams params;
383 FromCastRtpParams(cast_params[i], &params);
384 scoped_ptr<base::DictionaryValue> params_value = params.ToValue();
385 result->Set(
386 static_cast<int>(i),
387 converter->ToV8Value(params_value.get(), context()->v8_context()));
389 args.GetReturnValue().Set(result);
392 void CastStreamingNativeHandler::StartCastRtpStream(
393 const v8::FunctionCallbackInfo<v8::Value>& args) {
394 CHECK_EQ(2, args.Length());
395 CHECK(args[0]->IsInt32());
396 CHECK(args[1]->IsObject());
398 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
399 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
400 if (!transport)
401 return;
403 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
404 scoped_ptr<base::Value> params_value(
405 converter->FromV8Value(args[1], context()->v8_context()));
406 if (!params_value) {
407 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
408 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams)));
409 return;
411 scoped_ptr<RtpParams> params = RtpParams::FromValue(*params_value);
412 if (!params) {
413 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
414 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams)));
415 return;
418 CastRtpParams cast_params;
419 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
420 if (!ToCastRtpParamsOrThrow(isolate, *params, &cast_params))
421 return;
423 base::Closure start_callback =
424 base::Bind(&CastStreamingNativeHandler::CallStartCallback,
425 weak_factory_.GetWeakPtr(),
426 transport_id);
427 base::Closure stop_callback =
428 base::Bind(&CastStreamingNativeHandler::CallStopCallback,
429 weak_factory_.GetWeakPtr(),
430 transport_id);
431 CastRtpStream::ErrorCallback error_callback =
432 base::Bind(&CastStreamingNativeHandler::CallErrorCallback,
433 weak_factory_.GetWeakPtr(),
434 transport_id);
435 transport->Start(cast_params, start_callback, stop_callback, error_callback);
438 void CastStreamingNativeHandler::StopCastRtpStream(
439 const v8::FunctionCallbackInfo<v8::Value>& args) {
440 CHECK_EQ(1, args.Length());
441 CHECK(args[0]->IsInt32());
443 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
444 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
445 if (!transport)
446 return;
447 transport->Stop();
450 void CastStreamingNativeHandler::DestroyCastUdpTransport(
451 const v8::FunctionCallbackInfo<v8::Value>& args) {
452 CHECK_EQ(1, args.Length());
453 CHECK(args[0]->IsInt32());
455 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
456 if (!GetUdpTransportOrThrow(transport_id))
457 return;
458 udp_transport_map_.erase(transport_id);
461 void CastStreamingNativeHandler::SetDestinationCastUdpTransport(
462 const v8::FunctionCallbackInfo<v8::Value>& args) {
463 CHECK_EQ(2, args.Length());
464 CHECK(args[0]->IsInt32());
465 CHECK(args[1]->IsObject());
467 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
468 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
469 if (!transport)
470 return;
472 net::IPEndPoint dest;
473 if (!IPEndPointFromArg(args.GetIsolate(),
474 args[1],
475 &dest)) {
476 return;
478 transport->SetDestination(
479 dest,
480 base::Bind(&CastStreamingNativeHandler::CallErrorCallback,
481 weak_factory_.GetWeakPtr(),
482 transport_id));
485 void CastStreamingNativeHandler::SetOptionsCastUdpTransport(
486 const v8::FunctionCallbackInfo<v8::Value>& args) {
487 CHECK_EQ(2, args.Length());
488 CHECK(args[0]->IsInt32());
489 CHECK(args[1]->IsObject());
491 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
492 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
493 if (!transport)
494 return;
496 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
497 base::Value* options_value =
498 converter->FromV8Value(args[1], context()->v8_context());
499 base::DictionaryValue* options;
500 if (!options_value || !options_value->GetAsDictionary(&options)) {
501 delete options_value;
502 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
503 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
504 return;
506 transport->SetOptions(make_scoped_ptr(options));
509 void CastStreamingNativeHandler::ToggleLogging(
510 const v8::FunctionCallbackInfo<v8::Value>& args) {
511 CHECK_EQ(2, args.Length());
512 CHECK(args[0]->IsInt32());
513 CHECK(args[1]->IsBoolean());
515 const int stream_id = args[0]->ToInt32(args.GetIsolate())->Value();
516 CastRtpStream* stream = GetRtpStreamOrThrow(stream_id);
517 if (!stream)
518 return;
520 const bool enable = args[1]->ToBoolean(args.GetIsolate())->Value();
521 stream->ToggleLogging(enable);
524 void CastStreamingNativeHandler::GetRawEvents(
525 const v8::FunctionCallbackInfo<v8::Value>& args) {
526 CHECK_EQ(3, args.Length());
527 CHECK(args[0]->IsInt32());
528 CHECK(args[1]->IsNull() || args[1]->IsString());
529 CHECK(args[2]->IsFunction());
531 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
532 linked_ptr<v8::Global<v8::Function>> callback(new v8::Global<v8::Function>(
533 args.GetIsolate(), args[2].As<v8::Function>()));
534 std::string extra_data;
535 if (!args[1]->IsNull()) {
536 extra_data = *v8::String::Utf8Value(args[1]);
539 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
540 if (!transport)
541 return;
543 get_raw_events_callbacks_.insert(std::make_pair(transport_id, callback));
545 transport->GetRawEvents(
546 base::Bind(&CastStreamingNativeHandler::CallGetRawEventsCallback,
547 weak_factory_.GetWeakPtr(),
548 transport_id),
549 extra_data);
552 void CastStreamingNativeHandler::GetStats(
553 const v8::FunctionCallbackInfo<v8::Value>& args) {
554 CHECK_EQ(2, args.Length());
555 CHECK(args[0]->IsInt32());
556 CHECK(args[1]->IsFunction());
557 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
558 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
559 if (!transport)
560 return;
562 linked_ptr<v8::Global<v8::Function>> callback(new v8::Global<v8::Function>(
563 args.GetIsolate(), args[1].As<v8::Function>()));
564 get_stats_callbacks_.insert(std::make_pair(transport_id, callback));
566 transport->GetStats(
567 base::Bind(&CastStreamingNativeHandler::CallGetStatsCallback,
568 weak_factory_.GetWeakPtr(),
569 transport_id));
572 void CastStreamingNativeHandler::CallGetRawEventsCallback(
573 int transport_id,
574 scoped_ptr<base::BinaryValue> raw_events) {
575 v8::Isolate* isolate = context()->isolate();
576 v8::HandleScope handle_scope(isolate);
577 v8::Context::Scope context_scope(context()->v8_context());
579 RtpStreamCallbackMap::iterator it =
580 get_raw_events_callbacks_.find(transport_id);
581 if (it == get_raw_events_callbacks_.end())
582 return;
583 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
584 v8::Local<v8::Value> callback_args[] = {
585 converter->ToV8Value(raw_events.get(), context()->v8_context())};
586 context()->CallFunction(v8::Local<v8::Function>::New(isolate, *it->second),
587 arraysize(callback_args), callback_args);
588 get_raw_events_callbacks_.erase(it);
591 void CastStreamingNativeHandler::CallGetStatsCallback(
592 int transport_id,
593 scoped_ptr<base::DictionaryValue> stats) {
594 v8::Isolate* isolate = context()->isolate();
595 v8::HandleScope handle_scope(isolate);
596 v8::Context::Scope context_scope(context()->v8_context());
598 RtpStreamCallbackMap::iterator it = get_stats_callbacks_.find(transport_id);
599 if (it == get_stats_callbacks_.end())
600 return;
602 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
603 v8::Local<v8::Value> callback_args[] = {
604 converter->ToV8Value(stats.get(), context()->v8_context())};
605 context()->CallFunction(v8::Local<v8::Function>::New(isolate, *it->second),
606 arraysize(callback_args), callback_args);
607 get_stats_callbacks_.erase(it);
610 CastRtpStream* CastStreamingNativeHandler::GetRtpStreamOrThrow(
611 int transport_id) const {
612 RtpStreamMap::const_iterator iter = rtp_stream_map_.find(
613 transport_id);
614 if (iter != rtp_stream_map_.end())
615 return iter->second.get();
616 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
617 isolate->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
618 isolate, kRtpStreamNotFound)));
619 return NULL;
622 CastUdpTransport* CastStreamingNativeHandler::GetUdpTransportOrThrow(
623 int transport_id) const {
624 UdpTransportMap::const_iterator iter = udp_transport_map_.find(
625 transport_id);
626 if (iter != udp_transport_map_.end())
627 return iter->second.get();
628 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
629 isolate->ThrowException(v8::Exception::RangeError(
630 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
631 return NULL;
634 bool CastStreamingNativeHandler::FrameReceiverConfigFromArg(
635 v8::Isolate* isolate,
636 const v8::Local<v8::Value>& arg,
637 media::cast::FrameReceiverConfig* config) const {
638 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
639 scoped_ptr<base::Value> params_value(
640 converter->FromV8Value(arg, context()->v8_context()));
641 if (!params_value) {
642 isolate->ThrowException(v8::Exception::TypeError(
643 v8::String::NewFromUtf8(isolate, kUnableToConvertParams)));
644 return false;
646 scoped_ptr<RtpReceiverParams> params =
647 RtpReceiverParams::FromValue(*params_value);
648 if (!params) {
649 isolate->ThrowException(v8::Exception::TypeError(
650 v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
651 return false;
654 config->receiver_ssrc = params->receiver_ssrc;
655 config->sender_ssrc = params->sender_ssrc;
656 config->rtp_max_delay_ms = params->max_latency;
657 if (config->rtp_max_delay_ms < 0 || config->rtp_max_delay_ms > 1000) {
658 isolate->ThrowException(v8::Exception::TypeError(
659 v8::String::NewFromUtf8(isolate, kInvalidLatency)));
660 return false;
662 config->channels = 2;
663 if (params->codec_name == "OPUS") {
664 config->codec = media::cast::CODEC_AUDIO_OPUS;
665 config->rtp_timebase = 48000;
666 config->rtp_payload_type = 127;
667 } else if (params->codec_name == "PCM16") {
668 config->codec = media::cast::CODEC_AUDIO_PCM16;
669 config->rtp_timebase = 48000;
670 config->rtp_payload_type = 127;
671 } else if (params->codec_name == "AAC") {
672 config->codec = media::cast::CODEC_AUDIO_AAC;
673 config->rtp_timebase = 48000;
674 config->rtp_payload_type = 127;
675 } else if (params->codec_name == "VP8") {
676 config->codec = media::cast::CODEC_VIDEO_VP8;
677 config->rtp_timebase = 90000;
678 config->rtp_payload_type = 96;
679 } else if (params->codec_name == "H264") {
680 config->codec = media::cast::CODEC_VIDEO_H264;
681 config->rtp_timebase = 90000;
682 config->rtp_payload_type = 96;
684 if (params->rtp_timebase) {
685 config->rtp_timebase = *params->rtp_timebase;
686 if (config->rtp_timebase < 1000 || config->rtp_timebase > 1000000) {
687 isolate->ThrowException(v8::Exception::TypeError(
688 v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase)));
689 return false;
692 if (params->aes_key &&
693 !HexDecode(*params->aes_key, &config->aes_key)) {
694 isolate->ThrowException(v8::Exception::Error(
695 v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
696 return false;
698 if (params->aes_iv_mask &&
699 !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) {
700 isolate->ThrowException(v8::Exception::Error(
701 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
702 return false;
704 return true;
707 bool CastStreamingNativeHandler::IPEndPointFromArg(
708 v8::Isolate* isolate,
709 const v8::Local<v8::Value>& arg,
710 net::IPEndPoint* ip_endpoint) const {
711 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
712 scoped_ptr<base::Value> destination_value(
713 converter->FromV8Value(arg, context()->v8_context()));
714 if (!destination_value) {
715 isolate->ThrowException(v8::Exception::TypeError(
716 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
717 return false;
719 scoped_ptr<IPEndPoint> destination =
720 IPEndPoint::FromValue(*destination_value);
721 if (!destination) {
722 isolate->ThrowException(v8::Exception::TypeError(
723 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
724 return false;
726 net::IPAddressNumber ip;
727 if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
728 isolate->ThrowException(v8::Exception::TypeError(
729 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
730 return false;
732 *ip_endpoint = net::IPEndPoint(ip, destination->port);
733 return true;
736 void CastStreamingNativeHandler::StartCastRtpReceiver(
737 const v8::FunctionCallbackInfo<v8::Value>& args) {
738 if (args.Length() < 8 || args.Length() > 9 ||
739 !args[0]->IsObject() ||
740 !args[1]->IsObject() ||
741 !args[2]->IsObject() ||
742 !args[3]->IsInt32() ||
743 !args[4]->IsInt32() ||
744 !args[5]->IsNumber() ||
745 !args[6]->IsString()) {
746 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
747 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
748 return;
751 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
753 scoped_refptr<CastReceiverSession> session(
754 new CastReceiverSession());
755 media::cast::FrameReceiverConfig audio_config;
756 media::cast::FrameReceiverConfig video_config;
757 net::IPEndPoint local_endpoint;
758 net::IPEndPoint remote_endpoint;
760 if (!FrameReceiverConfigFromArg(isolate, args[0], &audio_config) ||
761 !FrameReceiverConfigFromArg(isolate, args[1], &video_config) ||
762 !IPEndPointFromArg(isolate, args[2], &local_endpoint)) {
763 return;
766 const std::string url = *v8::String::Utf8Value(args[7]);
767 blink::WebMediaStream stream =
768 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
770 if (stream.isNull()) {
771 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
772 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL)));
773 return;
776 const int max_width = args[3]->ToInt32(args.GetIsolate())->Value();
777 const int max_height = args[4]->ToInt32(args.GetIsolate())->Value();
778 const double fps = args[5]->NumberValue();
780 if (fps <= 1) {
781 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
782 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS)));
783 return;
786 media::VideoCaptureFormat capture_format(gfx::Size(max_width, max_height),
787 fps, media::PIXEL_FORMAT_I420);
789 video_config.target_frame_rate = fps;
790 audio_config.target_frame_rate = 100;
792 media::AudioParameters params(
793 media::AudioParameters::AUDIO_PCM_LINEAR,
794 media::CHANNEL_LAYOUT_STEREO,
795 audio_config.rtp_timebase, // sampling rate
797 audio_config.rtp_timebase / audio_config.target_frame_rate);
799 if (!params.IsValid()) {
800 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
801 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams)));
802 return;
805 base::DictionaryValue* options = NULL;
806 if (args.Length() >= 10) {
807 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
808 base::Value* options_value =
809 converter->FromV8Value(args[8], context()->v8_context());
810 if (!options_value->IsType(base::Value::TYPE_NULL)) {
811 if (!options_value || !options_value->GetAsDictionary(&options)) {
812 delete options_value;
813 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
814 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
815 return;
820 if (!options) {
821 options = new base::DictionaryValue();
824 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent error_callback;
825 error_callback.Reset(args.GetIsolate(),
826 v8::Local<v8::Function>(args[7].As<v8::Function>()));
828 session->Start(
829 audio_config,
830 video_config,
831 local_endpoint,
832 remote_endpoint,
833 make_scoped_ptr(options),
834 capture_format,
835 base::Bind(&CastStreamingNativeHandler::AddTracksToMediaStream,
836 weak_factory_.GetWeakPtr(),
837 url,
838 params),
839 base::Bind(&CastStreamingNativeHandler::CallReceiverErrorCallback,
840 weak_factory_.GetWeakPtr(),
841 error_callback));
844 void CastStreamingNativeHandler::CallReceiverErrorCallback(
845 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function,
846 const std::string& error_message) {
847 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
848 v8::Local<v8::Value> arg = v8::String::NewFromUtf8(isolate,
849 error_message.data(),
850 v8::String::kNormalString,
851 error_message.size());
852 context()->CallFunction(
853 v8::Local<v8::Function>::New(isolate, function), 1, &arg);
857 void CastStreamingNativeHandler::AddTracksToMediaStream(
858 const std::string& url,
859 const media::AudioParameters& params,
860 scoped_refptr<media::AudioCapturerSource> audio,
861 scoped_ptr<media::VideoCapturerSource> video) {
862 content::AddAudioTrackToMediaStream(audio, params, true, true, url);
863 content::AddVideoTrackToMediaStream(video.Pass(), true, true, url);
866 } // namespace extensions