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"
9 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
13 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
14 #include "chrome/renderer/extensions/chrome_v8_context.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 "net/base/host_port_pair.h"
20 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
21 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
23 using content::V8ValueConverter
;
26 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams
;
27 using extensions::api::cast_streaming_rtp_stream::RtpParams
;
28 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams
;
29 using extensions::api::cast_streaming_udp_transport::IPEndPoint
;
31 namespace extensions
{
34 const char kRtpStreamNotFound
[] = "The RTP stream cannot be found";
35 const char kUdpTransportNotFound
[] = "The UDP transport cannot be found";
36 const char kInvalidDestination
[] = "Invalid destination";
37 const char kInvalidRtpParams
[] = "Invalid value for RTP params";
38 const char kInvalidAesKey
[] = "Invalid value for AES key";
39 const char kInvalidAesIvMask
[] = "Invalid value for AES IV mask";
40 const char kUnableToConvertArgs
[] = "Unable to convert arguments";
41 const char kUnableToConvertParams
[] = "Unable to convert params";
43 // These helper methods are used to convert between Extension API
44 // types and Cast types.
45 void ToCastCodecSpecificParams(const CodecSpecificParams
& ext_params
,
46 CastCodecSpecificParams
* cast_params
) {
47 cast_params
->key
= ext_params
.key
;
48 cast_params
->value
= ext_params
.value
;
51 void FromCastCodecSpecificParams(const CastCodecSpecificParams
& cast_params
,
52 CodecSpecificParams
* ext_params
) {
53 ext_params
->key
= cast_params
.key
;
54 ext_params
->value
= cast_params
.value
;
57 bool ToCastRtpPayloadParamsOrThrow(v8::Isolate
* isolate
,
58 const RtpPayloadParams
& ext_params
,
59 CastRtpPayloadParams
* cast_params
) {
60 cast_params
->payload_type
= ext_params
.payload_type
;
61 cast_params
->codec_name
= ext_params
.codec_name
;
62 cast_params
->ssrc
= ext_params
.ssrc
? *ext_params
.ssrc
: 0;
63 cast_params
->feedback_ssrc
=
64 ext_params
.feedback_ssrc
? *ext_params
.feedback_ssrc
: 0;
65 cast_params
->clock_rate
= ext_params
.clock_rate
? *ext_params
.clock_rate
: 0;
66 cast_params
->min_bitrate
=
67 ext_params
.min_bitrate
? *ext_params
.min_bitrate
: 0;
68 cast_params
->max_bitrate
=
69 ext_params
.max_bitrate
? *ext_params
.max_bitrate
: 0;
70 cast_params
->channels
= ext_params
.channels
? *ext_params
.channels
: 0;
71 cast_params
->width
= ext_params
.width
? *ext_params
.width
: 0;
72 cast_params
->height
= ext_params
.height
? *ext_params
.height
: 0;
73 if (ext_params
.aes_key
&&
74 !base::Base64Decode(*ext_params
.aes_key
, &cast_params
->aes_key
)) {
75 isolate
->ThrowException(v8::Exception::Error(
76 v8::String::NewFromUtf8(isolate
, kInvalidAesKey
)));
79 if (ext_params
.aes_iv_mask
&&
80 !base::Base64Decode(*ext_params
.aes_iv_mask
,
81 &cast_params
->aes_iv_mask
)) {
82 isolate
->ThrowException(v8::Exception::Error(
83 v8::String::NewFromUtf8(isolate
, kInvalidAesIvMask
)));
86 for (size_t i
= 0; i
< ext_params
.codec_specific_params
.size(); ++i
) {
87 CastCodecSpecificParams cast_codec_params
;
88 ToCastCodecSpecificParams(*ext_params
.codec_specific_params
[i
],
90 cast_params
->codec_specific_params
.push_back(cast_codec_params
);
95 void FromCastRtpPayloadParams(const CastRtpPayloadParams
& cast_params
,
96 RtpPayloadParams
* ext_params
) {
97 ext_params
->payload_type
= cast_params
.payload_type
;
98 ext_params
->codec_name
= cast_params
.codec_name
;
100 ext_params
->ssrc
.reset(new int(cast_params
.ssrc
));
101 if (cast_params
.feedback_ssrc
)
102 ext_params
->feedback_ssrc
.reset(new int(cast_params
.feedback_ssrc
));
103 if (cast_params
.clock_rate
)
104 ext_params
->clock_rate
.reset(new int(cast_params
.clock_rate
));
105 if (cast_params
.min_bitrate
)
106 ext_params
->min_bitrate
.reset(new int(cast_params
.min_bitrate
));
107 if (cast_params
.max_bitrate
)
108 ext_params
->max_bitrate
.reset(new int(cast_params
.max_bitrate
));
109 if (cast_params
.channels
)
110 ext_params
->channels
.reset(new int(cast_params
.channels
));
111 if (cast_params
.width
)
112 ext_params
->width
.reset(new int(cast_params
.width
));
113 if (cast_params
.height
)
114 ext_params
->height
.reset(new int(cast_params
.height
));
115 for (size_t i
= 0; i
< cast_params
.codec_specific_params
.size(); ++i
) {
116 linked_ptr
<CodecSpecificParams
> ext_codec_params(
117 new CodecSpecificParams());
118 FromCastCodecSpecificParams(cast_params
.codec_specific_params
[i
],
119 ext_codec_params
.get());
120 ext_params
->codec_specific_params
.push_back(ext_codec_params
);
124 void FromCastRtpParams(const CastRtpParams
& cast_params
,
125 RtpParams
* ext_params
) {
126 std::copy(cast_params
.rtcp_features
.begin(), cast_params
.rtcp_features
.end(),
127 ext_params
->rtcp_features
.begin());
128 FromCastRtpPayloadParams(cast_params
.payload
, &ext_params
->payload
);
131 bool ToCastRtpParamsOrThrow(v8::Isolate
* isolate
,
132 const RtpParams
& ext_params
,
133 CastRtpParams
* cast_params
) {
134 std::copy(ext_params
.rtcp_features
.begin(), ext_params
.rtcp_features
.end(),
135 cast_params
->rtcp_features
.begin());
136 if (!ToCastRtpPayloadParamsOrThrow(isolate
,
138 &cast_params
->payload
)) {
146 CastStreamingNativeHandler::CastStreamingNativeHandler(ChromeV8Context
* context
)
147 : ObjectBackedNativeHandler(context
),
148 last_transport_id_(0),
149 weak_factory_(this) {
150 RouteFunction("CreateSession",
151 base::Bind(&CastStreamingNativeHandler::CreateCastSession
,
152 base::Unretained(this)));
153 RouteFunction("DestroyCastRtpStream",
154 base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream
,
155 base::Unretained(this)));
156 RouteFunction("GetSupportedParamsCastRtpStream",
157 base::Bind(&CastStreamingNativeHandler::GetSupportedParamsCastRtpStream
,
158 base::Unretained(this)));
159 RouteFunction("StartCastRtpStream",
160 base::Bind(&CastStreamingNativeHandler::StartCastRtpStream
,
161 base::Unretained(this)));
162 RouteFunction("StopCastRtpStream",
163 base::Bind(&CastStreamingNativeHandler::StopCastRtpStream
,
164 base::Unretained(this)));
165 RouteFunction("DestroyCastUdpTransport",
166 base::Bind(&CastStreamingNativeHandler::DestroyCastUdpTransport
,
167 base::Unretained(this)));
168 RouteFunction("SetDestinationCastUdpTransport",
169 base::Bind(&CastStreamingNativeHandler::SetDestinationCastUdpTransport
,
170 base::Unretained(this)));
173 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
176 void CastStreamingNativeHandler::CreateCastSession(
177 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
178 CHECK_EQ(3, args
.Length());
179 CHECK(args
[0]->IsObject());
180 CHECK(args
[1]->IsObject());
181 CHECK(args
[2]->IsFunction());
183 blink::WebDOMMediaStreamTrack track1
=
184 blink::WebDOMMediaStreamTrack::fromV8Value(args
[0]);
187 blink::WebDOMMediaStreamTrack track2
=
188 blink::WebDOMMediaStreamTrack::fromV8Value(args
[1]);
192 scoped_refptr
<CastSession
> session(new CastSession());
193 scoped_ptr
<CastRtpStream
> stream1(
194 new CastRtpStream(track1
.component(), session
));
195 scoped_ptr
<CastRtpStream
> stream2(
196 new CastRtpStream(track2
.component(), session
));
197 scoped_ptr
<CastUdpTransport
> udp_transport(
198 new CastUdpTransport(session
));
200 create_callback_
.reset(args
[2].As
<v8::Function
>());
202 base::MessageLoop::current()->PostTask(
205 &CastStreamingNativeHandler::CallCreateCallback
,
206 weak_factory_
.GetWeakPtr(),
207 base::Passed(&stream1
),
208 base::Passed(&stream2
),
209 base::Passed(&udp_transport
)));
212 void CastStreamingNativeHandler::CallCreateCallback(
213 scoped_ptr
<CastRtpStream
> stream1
,
214 scoped_ptr
<CastRtpStream
> stream2
,
215 scoped_ptr
<CastUdpTransport
> udp_transport
) {
216 v8::Isolate
* isolate
= context()->isolate();
217 v8::HandleScope
handle_scope(isolate
);
218 v8::Context::Scope
context_scope(context()->v8_context());
220 const int stream1_id
= last_transport_id_
++;
221 rtp_stream_map_
[stream1_id
] =
222 linked_ptr
<CastRtpStream
>(stream1
.release());
223 const int stream2_id
= last_transport_id_
++;
224 rtp_stream_map_
[stream2_id
] =
225 linked_ptr
<CastRtpStream
>(stream2
.release());
226 const int udp_id
= last_transport_id_
++;
227 udp_transport_map_
[udp_id
] =
228 linked_ptr
<CastUdpTransport
>(udp_transport
.release());
230 v8::Handle
<v8::Value
> callback_args
[3];
231 callback_args
[0] = v8::Integer::New(isolate
, stream1_id
);
232 callback_args
[1] = v8::Integer::New(isolate
, stream2_id
);
233 callback_args
[2] = v8::Integer::New(isolate
, udp_id
);
234 context()->CallFunction(create_callback_
.NewHandle(isolate
),
236 create_callback_
.reset();
239 void CastStreamingNativeHandler::DestroyCastRtpStream(
240 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
241 CHECK_EQ(1, args
.Length());
242 CHECK(args
[0]->IsInt32());
244 const int transport_id
= args
[0]->ToInt32()->Value();
245 if (!GetRtpStreamOrThrow(transport_id
))
247 rtp_stream_map_
.erase(transport_id
);
250 void CastStreamingNativeHandler::GetSupportedParamsCastRtpStream(
251 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
252 CHECK_EQ(1, args
.Length());
253 CHECK(args
[0]->IsInt32());
255 const int transport_id
= args
[0]->ToInt32()->Value();
256 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
260 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
261 std::vector
<CastRtpParams
> cast_params
= transport
->GetSupportedParams();
262 v8::Handle
<v8::Array
> result
=
263 v8::Array::New(args
.GetIsolate(),
264 static_cast<int>(cast_params
.size()));
265 for (size_t i
= 0; i
< cast_params
.size(); ++i
) {
267 FromCastRtpParams(cast_params
[i
], ¶ms
);
268 scoped_ptr
<base::DictionaryValue
> params_value
= params
.ToValue();
271 converter
->ToV8Value(params_value
.get(), context()->v8_context()));
273 args
.GetReturnValue().Set(result
);
276 void CastStreamingNativeHandler::StartCastRtpStream(
277 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
278 CHECK_EQ(2, args
.Length());
279 CHECK(args
[0]->IsInt32());
280 CHECK(args
[1]->IsObject());
282 const int transport_id
= args
[0]->ToInt32()->Value();
283 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
287 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
288 scoped_ptr
<base::Value
> params_value(
289 converter
->FromV8Value(args
[1], context()->v8_context()));
291 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
292 v8::String::NewFromUtf8(args
.GetIsolate(), kUnableToConvertParams
)));
295 scoped_ptr
<RtpParams
> params
= RtpParams::FromValue(*params_value
);
297 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
298 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidRtpParams
)));
302 CastRtpParams cast_params
;
303 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
304 if (!ToCastRtpParamsOrThrow(isolate
, *params
, &cast_params
))
306 transport
->Start(cast_params
);
309 void CastStreamingNativeHandler::StopCastRtpStream(
310 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
311 CHECK_EQ(1, args
.Length());
312 CHECK(args
[0]->IsInt32());
314 const int transport_id
= args
[0]->ToInt32()->Value();
315 CastRtpStream
* transport
= GetRtpStreamOrThrow(transport_id
);
321 void CastStreamingNativeHandler::DestroyCastUdpTransport(
322 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
323 CHECK_EQ(1, args
.Length());
324 CHECK(args
[0]->IsInt32());
326 const int transport_id
= args
[0]->ToInt32()->Value();
327 if (!GetUdpTransportOrThrow(transport_id
))
329 udp_transport_map_
.erase(transport_id
);
332 void CastStreamingNativeHandler::SetDestinationCastUdpTransport(
333 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
334 CHECK_EQ(2, args
.Length());
335 CHECK(args
[0]->IsInt32());
336 CHECK(args
[1]->IsObject());
338 const int transport_id
= args
[0]->ToInt32()->Value();
339 CastUdpTransport
* transport
= GetUdpTransportOrThrow(transport_id
);
343 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
344 scoped_ptr
<base::Value
> destination_value(
345 converter
->FromV8Value(args
[1], context()->v8_context()));
346 if (!destination_value
) {
347 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
348 v8::String::NewFromUtf8(args
.GetIsolate(), kUnableToConvertArgs
)));
351 scoped_ptr
<IPEndPoint
> destination
=
352 IPEndPoint::FromValue(*destination_value
);
354 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
355 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidDestination
)));
358 net::IPAddressNumber ip
;
359 if (!net::ParseIPLiteralToNumber(destination
->address
, &ip
)) {
360 args
.GetIsolate()->ThrowException(v8::Exception::TypeError(
361 v8::String::NewFromUtf8(args
.GetIsolate(), kInvalidDestination
)));
364 transport
->SetDestination(net::IPEndPoint(ip
, destination
->port
));
367 CastRtpStream
* CastStreamingNativeHandler::GetRtpStreamOrThrow(
368 int transport_id
) const {
369 RtpStreamMap::const_iterator iter
= rtp_stream_map_
.find(
371 if (iter
!= rtp_stream_map_
.end())
372 return iter
->second
.get();
373 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
374 isolate
->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
375 isolate
, kRtpStreamNotFound
)));
379 CastUdpTransport
* CastStreamingNativeHandler::GetUdpTransportOrThrow(
380 int transport_id
) const {
381 UdpTransportMap::const_iterator iter
= udp_transport_map_
.find(
383 if (iter
!= udp_transport_map_
.end())
384 return iter
->second
.get();
385 v8::Isolate
* isolate
= context()->v8_context()->GetIsolate();
386 isolate
->ThrowException(v8::Exception::RangeError(
387 v8::String::NewFromUtf8(isolate
, kUdpTransportNotFound
)));
391 } // namespace extensions