• 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 
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
12 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
13 #include "chrome/renderer/extensions/chrome_v8_context.h"
14 #include "chrome/renderer/media/cast_rtp_stream.h"
15 #include "chrome/renderer/media/cast_session.h"
16 #include "chrome/renderer/media/cast_udp_transport.h"
17 #include "content/public/renderer/v8_value_converter.h"
18 #include "net/base/host_port_pair.h"
19 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
20 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
21 
22 using content::V8ValueConverter;
23 
24 // Extension types.
25 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams;
26 using extensions::api::cast_streaming_rtp_stream::RtpCaps;
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::UdpParams;
30 
31 namespace extensions {
32 
33 namespace {
34 const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
35 const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
36 const char kInvalidUdpParams[] = "Invalid UDP params";
37 const char kInvalidRtpParams[] = "Invalid value for RTP params";
38 const char kUnableToConvertArgs[] = "Unable to convert arguments";
39 const char kUnableToConvertParams[] = "Unable to convert params";
40 
41 // These helper methods are used to convert between Extension API
42 // types and Cast types.
ToCastCodecSpecificParams(const CodecSpecificParams & ext_params,CastCodecSpecificParams * cast_params)43 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params,
44                                CastCodecSpecificParams* cast_params) {
45   cast_params->key = ext_params.key;
46   cast_params->value = ext_params.value;
47 }
48 
FromCastCodecSpecificParams(const CastCodecSpecificParams & cast_params,CodecSpecificParams * ext_params)49 void FromCastCodecSpecificParams(const CastCodecSpecificParams& cast_params,
50                                  CodecSpecificParams* ext_params) {
51   ext_params->key = cast_params.key;
52   ext_params->value = cast_params.value;
53 }
54 
ToCastRtpPayloadParams(const RtpPayloadParams & ext_params,CastRtpPayloadParams * cast_params)55 void ToCastRtpPayloadParams(const RtpPayloadParams& ext_params,
56                             CastRtpPayloadParams* cast_params) {
57   cast_params->payload_type = ext_params.payload_type;
58   cast_params->codec_name = ext_params.codec_name;
59   cast_params->ssrc = ext_params.ssrc ? *ext_params.ssrc : 0;
60   cast_params->clock_rate = ext_params.clock_rate ? *ext_params.clock_rate : 0;
61   cast_params->min_bitrate =
62       ext_params.min_bitrate ? *ext_params.min_bitrate : 0;
63   cast_params->max_bitrate =
64       ext_params.max_bitrate ? *ext_params.max_bitrate : 0;
65   cast_params->channels = ext_params.channels ? *ext_params.channels : 0;
66   cast_params->width = ext_params.width ? *ext_params.width : 0;
67   cast_params->height = ext_params.height ? *ext_params.height : 0;
68   for (size_t i = 0; i < ext_params.codec_specific_params.size(); ++i) {
69     CastCodecSpecificParams cast_codec_params;
70     ToCastCodecSpecificParams(*ext_params.codec_specific_params[i],
71                               &cast_codec_params);
72     cast_params->codec_specific_params.push_back(cast_codec_params);
73   }
74 }
75 
FromCastRtpPayloadParams(const CastRtpPayloadParams & cast_params,RtpPayloadParams * ext_params)76 void FromCastRtpPayloadParams(const CastRtpPayloadParams& cast_params,
77                               RtpPayloadParams* ext_params) {
78   ext_params->payload_type = cast_params.payload_type;
79   ext_params->codec_name = cast_params.codec_name;
80   if (cast_params.ssrc)
81     ext_params->ssrc.reset(new int(cast_params.ssrc));
82   if (cast_params.clock_rate)
83     ext_params->clock_rate.reset(new int(cast_params.clock_rate));
84   if (cast_params.min_bitrate)
85     ext_params->min_bitrate.reset(new int(cast_params.min_bitrate));
86   if (cast_params.max_bitrate)
87     ext_params->max_bitrate.reset(new int(cast_params.max_bitrate));
88   if (cast_params.channels)
89     ext_params->channels.reset(new int(cast_params.channels));
90   if (cast_params.width)
91     ext_params->width.reset(new int(cast_params.width));
92   if (cast_params.height)
93     ext_params->height.reset(new int(cast_params.height));
94   for (size_t i = 0; i < cast_params.codec_specific_params.size(); ++i) {
95     linked_ptr<CodecSpecificParams> ext_codec_params(
96         new CodecSpecificParams());
97     FromCastCodecSpecificParams(cast_params.codec_specific_params[i],
98                                 ext_codec_params.get());
99     ext_params->codec_specific_params.push_back(ext_codec_params);
100   }
101 }
102 
FromCastRtpCaps(const CastRtpCaps & cast_caps,RtpCaps * ext_caps)103 void FromCastRtpCaps(const CastRtpCaps& cast_caps, RtpCaps* ext_caps) {
104   std::copy(cast_caps.rtcp_features.begin(), cast_caps.rtcp_features.end(),
105             ext_caps->rtcp_features.begin());
106   for (size_t i = 0; i < cast_caps.payloads.size(); ++i) {
107     linked_ptr<RtpPayloadParams> ext_payload_params(new RtpPayloadParams());
108     FromCastRtpPayloadParams(cast_caps.payloads[i], ext_payload_params.get());
109     ext_caps->payloads.push_back(ext_payload_params);
110   }
111 }
112 
ToCastRtpParams(const RtpParams & ext_params,CastRtpParams * cast_params)113 void ToCastRtpParams(const RtpParams& ext_params, CastRtpParams* cast_params) {
114   std::copy(ext_params.rtcp_features.begin(), ext_params.rtcp_features.end(),
115             cast_params->rtcp_features.begin());
116   for (size_t i = 0; i < ext_params.payloads.size(); ++i) {
117     CastRtpPayloadParams cast_payload_params;
118     ToCastRtpPayloadParams(*ext_params.payloads[i], &cast_payload_params);
119     cast_params->payloads.push_back(cast_payload_params);
120   }
121 }
122 
123 }  // namespace
124 
CastStreamingNativeHandler(ChromeV8Context * context)125 CastStreamingNativeHandler::CastStreamingNativeHandler(ChromeV8Context* context)
126     : ObjectBackedNativeHandler(context),
127       last_transport_id_(0),
128       weak_factory_(this) {
129   RouteFunction("CreateSession",
130       base::Bind(&CastStreamingNativeHandler::CreateCastSession,
131                  base::Unretained(this)));
132   RouteFunction("DestroyCastRtpStream",
133       base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream,
134                  base::Unretained(this)));
135   RouteFunction("GetCapsCastRtpStream",
136       base::Bind(&CastStreamingNativeHandler::GetCapsCastRtpStream,
137                  base::Unretained(this)));
138   RouteFunction("StartCastRtpStream",
139       base::Bind(&CastStreamingNativeHandler::StartCastRtpStream,
140                  base::Unretained(this)));
141   RouteFunction("StopCastRtpStream",
142       base::Bind(&CastStreamingNativeHandler::StopCastRtpStream,
143                  base::Unretained(this)));
144   RouteFunction("DestroyCastUdpTransport",
145       base::Bind(&CastStreamingNativeHandler::DestroyCastUdpTransport,
146                  base::Unretained(this)));
147   RouteFunction("StartCastUdpTransport",
148       base::Bind(&CastStreamingNativeHandler::StartCastUdpTransport,
149                  base::Unretained(this)));
150 }
151 
~CastStreamingNativeHandler()152 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
153 }
154 
CreateCastSession(const v8::FunctionCallbackInfo<v8::Value> & args)155 void CastStreamingNativeHandler::CreateCastSession(
156     const v8::FunctionCallbackInfo<v8::Value>& args) {
157   CHECK_EQ(3, args.Length());
158   CHECK(args[0]->IsObject());
159   CHECK(args[1]->IsObject());
160   CHECK(args[2]->IsFunction());
161 
162   blink::WebDOMMediaStreamTrack track1 =
163       blink::WebDOMMediaStreamTrack::fromV8Value(args[0]);
164   if (track1.isNull())
165     return;
166   blink::WebDOMMediaStreamTrack track2 =
167       blink::WebDOMMediaStreamTrack::fromV8Value(args[1]);
168   if (track2.isNull())
169     return;
170 
171   scoped_refptr<CastSession> session(new CastSession());
172   scoped_ptr<CastRtpStream> stream1(
173       new CastRtpStream(track1.component(), session));
174   scoped_ptr<CastRtpStream> stream2(
175       new CastRtpStream(track2.component(), session));
176   scoped_ptr<CastUdpTransport> udp_transport(
177       new CastUdpTransport(session));
178 
179   create_callback_.reset(args[2].As<v8::Function>());
180 
181   base::MessageLoop::current()->PostTask(
182       FROM_HERE,
183       base::Bind(
184           &CastStreamingNativeHandler::CallCreateCallback,
185           weak_factory_.GetWeakPtr(),
186           base::Passed(&stream1),
187           base::Passed(&stream2),
188           base::Passed(&udp_transport)));
189 }
190 
CallCreateCallback(scoped_ptr<CastRtpStream> stream1,scoped_ptr<CastRtpStream> stream2,scoped_ptr<CastUdpTransport> udp_transport)191 void CastStreamingNativeHandler::CallCreateCallback(
192     scoped_ptr<CastRtpStream> stream1,
193     scoped_ptr<CastRtpStream> stream2,
194     scoped_ptr<CastUdpTransport> udp_transport) {
195   v8::HandleScope handle_scope(context()->isolate());
196   v8::Context::Scope context_scope(context()->v8_context());
197 
198   const int stream1_id = last_transport_id_++;
199   rtp_stream_map_[stream1_id] =
200       linked_ptr<CastRtpStream>(stream1.release());
201   const int stream2_id = last_transport_id_++;
202   rtp_stream_map_[stream2_id] =
203       linked_ptr<CastRtpStream>(stream2.release());
204   const int udp_id = last_transport_id_++;
205   udp_transport_map_[udp_id] =
206       linked_ptr<CastUdpTransport>(udp_transport.release());
207 
208   v8::Handle<v8::Value> callback_args[3];
209   callback_args[0] = v8::Integer::New(stream1_id);
210   callback_args[1] = v8::Integer::New(stream2_id);
211   callback_args[2] = v8::Integer::New(udp_id);
212   context()->CallFunction(create_callback_.NewHandle(context()->isolate()),
213                           3, callback_args);
214   create_callback_.reset();
215 }
216 
DestroyCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)217 void CastStreamingNativeHandler::DestroyCastRtpStream(
218     const v8::FunctionCallbackInfo<v8::Value>& args) {
219   CHECK_EQ(1, args.Length());
220   CHECK(args[0]->IsInt32());
221 
222   const int transport_id = args[0]->ToInt32()->Value();
223   if (!GetRtpStreamOrThrow(transport_id))
224     return;
225   rtp_stream_map_.erase(transport_id);
226 }
227 
GetCapsCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)228 void CastStreamingNativeHandler::GetCapsCastRtpStream(
229     const v8::FunctionCallbackInfo<v8::Value>& args) {
230   CHECK_EQ(1, args.Length());
231   CHECK(args[0]->IsInt32());
232 
233   const int transport_id = args[0]->ToInt32()->Value();
234   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
235   if (!transport)
236     return;
237 
238   CastRtpCaps cast_caps = transport->GetCaps();
239   RtpCaps caps;
240   FromCastRtpCaps(cast_caps, &caps);
241 
242   scoped_ptr<base::DictionaryValue> caps_value = caps.ToValue();
243   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
244   args.GetReturnValue().Set(converter->ToV8Value(
245       caps_value.get(), context()->v8_context()));
246 }
247 
StartCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)248 void CastStreamingNativeHandler::StartCastRtpStream(
249     const v8::FunctionCallbackInfo<v8::Value>& args) {
250   CHECK_EQ(2, args.Length());
251   CHECK(args[0]->IsInt32());
252   CHECK(args[1]->IsObject());
253 
254   const int transport_id = args[0]->ToInt32()->Value();
255   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
256   if (!transport)
257     return;
258 
259   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
260   scoped_ptr<Value> params_value(
261       converter->FromV8Value(args[1], context()->v8_context()));
262   if (!params_value) {
263     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
264         v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams)));
265     return;
266   }
267   scoped_ptr<RtpParams> params = RtpParams::FromValue(*params_value);
268   if (!params) {
269     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
270         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams)));
271     return;
272   }
273 
274   CastRtpCaps cast_params;
275   ToCastRtpParams(*params, &cast_params);
276   transport->Start(cast_params);
277 }
278 
StopCastRtpStream(const v8::FunctionCallbackInfo<v8::Value> & args)279 void CastStreamingNativeHandler::StopCastRtpStream(
280     const v8::FunctionCallbackInfo<v8::Value>& args) {
281   CHECK_EQ(1, args.Length());
282   CHECK(args[0]->IsInt32());
283 
284   const int transport_id = args[0]->ToInt32()->Value();
285   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
286   if (!transport)
287     return;
288   transport->Stop();
289 }
290 
DestroyCastUdpTransport(const v8::FunctionCallbackInfo<v8::Value> & args)291 void CastStreamingNativeHandler::DestroyCastUdpTransport(
292     const v8::FunctionCallbackInfo<v8::Value>& args) {
293   CHECK_EQ(1, args.Length());
294   CHECK(args[0]->IsInt32());
295 
296   const int transport_id = args[0]->ToInt32()->Value();
297   if (!GetUdpTransportOrThrow(transport_id))
298     return;
299   udp_transport_map_.erase(transport_id);
300 }
301 
StartCastUdpTransport(const v8::FunctionCallbackInfo<v8::Value> & args)302 void CastStreamingNativeHandler::StartCastUdpTransport(
303     const v8::FunctionCallbackInfo<v8::Value>& args) {
304   CHECK_EQ(2, args.Length());
305   CHECK(args[0]->IsInt32());
306   CHECK(args[1]->IsObject());
307 
308   const int transport_id = args[0]->ToInt32()->Value();
309   CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
310   if (!transport)
311     return;
312 
313   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
314   scoped_ptr<Value> udp_params_value(
315       converter->FromV8Value(args[1], context()->v8_context()));
316   if (!udp_params_value) {
317     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
318         v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
319     return;
320   }
321   scoped_ptr<UdpParams> udp_params = UdpParams::FromValue(*udp_params_value);
322   if (!udp_params) {
323     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
324         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidUdpParams)));
325     return;
326   }
327   net::IPAddressNumber ip;
328   if (!net::ParseIPLiteralToNumber(udp_params->address, &ip)) {
329     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
330         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidUdpParams)));
331     return;
332   }
333   transport->Start(net::IPEndPoint(ip, udp_params->port));
334 }
335 
GetRtpStreamOrThrow(int transport_id) const336 CastRtpStream* CastStreamingNativeHandler::GetRtpStreamOrThrow(
337     int transport_id) const {
338   RtpStreamMap::const_iterator iter = rtp_stream_map_.find(
339       transport_id);
340   if (iter != rtp_stream_map_.end())
341     return iter->second.get();
342   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
343   isolate->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
344       isolate, kRtpStreamNotFound)));
345   return NULL;
346 }
347 
GetUdpTransportOrThrow(int transport_id) const348 CastUdpTransport* CastStreamingNativeHandler::GetUdpTransportOrThrow(
349     int transport_id) const {
350   UdpTransportMap::const_iterator iter = udp_transport_map_.find(
351       transport_id);
352   if (iter != udp_transport_map_.end())
353     return iter->second.get();
354   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
355   isolate->ThrowException(v8::Exception::RangeError(
356       v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
357   return NULL;
358 }
359 
360 }  // namespace extensions
361