OLD | NEW |
| (Empty) |
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/webrtc_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/webrtc_cast_send_transport.h" | |
12 #include "chrome/common/extensions/api/webrtc_cast_udp_transport.h" | |
13 #include "chrome/renderer/extensions/chrome_v8_context.h" | |
14 #include "chrome/renderer/media/cast_send_transport.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::webrtc_cast_send_transport::CodecSpecificParams; | |
26 using extensions::api::webrtc_cast_send_transport::RtpCaps; | |
27 using extensions::api::webrtc_cast_send_transport::RtpParams; | |
28 using extensions::api::webrtc_cast_send_transport::RtpPayloadParams; | |
29 using extensions::api::webrtc_cast_udp_transport::UdpParams; | |
30 | |
31 namespace extensions { | |
32 | |
33 namespace { | |
34 const char kSendTransportNotFound[] = "The send transport 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. | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
125 WebRtcNativeHandler::WebRtcNativeHandler(ChromeV8Context* context) | |
126 : ObjectBackedNativeHandler(context), | |
127 last_transport_id_(0), | |
128 weak_factory_(this) { | |
129 RouteFunction("CreateSession", | |
130 base::Bind(&WebRtcNativeHandler::CreateCastSession, | |
131 base::Unretained(this))); | |
132 RouteFunction("DestroyCastSendTransport", | |
133 base::Bind(&WebRtcNativeHandler::DestroyCastSendTransport, | |
134 base::Unretained(this))); | |
135 RouteFunction("GetCapsCastSendTransport", | |
136 base::Bind(&WebRtcNativeHandler::GetCapsCastSendTransport, | |
137 base::Unretained(this))); | |
138 RouteFunction("StartCastSendTransport", | |
139 base::Bind(&WebRtcNativeHandler::StartCastSendTransport, | |
140 base::Unretained(this))); | |
141 RouteFunction("StopCastSendTransport", | |
142 base::Bind(&WebRtcNativeHandler::StopCastSendTransport, | |
143 base::Unretained(this))); | |
144 RouteFunction("DestroyCastUdpTransport", | |
145 base::Bind(&WebRtcNativeHandler::DestroyCastUdpTransport, | |
146 base::Unretained(this))); | |
147 RouteFunction("StartCastUdpTransport", | |
148 base::Bind(&WebRtcNativeHandler::StartCastUdpTransport, | |
149 base::Unretained(this))); | |
150 } | |
151 | |
152 WebRtcNativeHandler::~WebRtcNativeHandler() { | |
153 } | |
154 | |
155 void WebRtcNativeHandler::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<CastSendTransport> stream1( | |
173 new CastSendTransport(track1.component(), session)); | |
174 scoped_ptr<CastSendTransport> stream2( | |
175 new CastSendTransport(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 &WebRtcNativeHandler::CallCreateCallback, | |
185 weak_factory_.GetWeakPtr(), | |
186 base::Passed(&stream1), | |
187 base::Passed(&stream2), | |
188 base::Passed(&udp_transport))); | |
189 } | |
190 | |
191 void WebRtcNativeHandler::CallCreateCallback( | |
192 scoped_ptr<CastSendTransport> stream1, | |
193 scoped_ptr<CastSendTransport> 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 send_transport_map_[stream1_id] = | |
200 linked_ptr<CastSendTransport>(stream1.release()); | |
201 const int stream2_id = last_transport_id_++; | |
202 send_transport_map_[stream2_id] = | |
203 linked_ptr<CastSendTransport>(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 | |
217 void WebRtcNativeHandler::DestroyCastSendTransport( | |
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 (!GetSendTransportOrThrow(transport_id)) | |
224 return; | |
225 send_transport_map_.erase(transport_id); | |
226 } | |
227 | |
228 void WebRtcNativeHandler::GetCapsCastSendTransport( | |
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 CastSendTransport* transport = GetSendTransportOrThrow(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 | |
248 void WebRtcNativeHandler::StartCastSendTransport( | |
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 CastSendTransport* transport = GetSendTransportOrThrow(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 | |
279 void WebRtcNativeHandler::StopCastSendTransport( | |
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 CastSendTransport* transport = GetSendTransportOrThrow(transport_id); | |
286 if (!transport) | |
287 return; | |
288 transport->Stop(); | |
289 } | |
290 | |
291 void WebRtcNativeHandler::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 | |
302 void WebRtcNativeHandler::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 transport->Start(net::HostPortPair(udp_params->address, udp_params->port)); | |
328 } | |
329 | |
330 CastSendTransport* WebRtcNativeHandler::GetSendTransportOrThrow( | |
331 int transport_id) const { | |
332 SendTransportMap::const_iterator iter = send_transport_map_.find( | |
333 transport_id); | |
334 if (iter != send_transport_map_.end()) | |
335 return iter->second.get(); | |
336 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); | |
337 isolate->ThrowException(v8::Exception::RangeError( | |
338 v8::String::NewFromUtf8(isolate, kSendTransportNotFound))); | |
339 return NULL; | |
340 } | |
341 | |
342 CastUdpTransport* WebRtcNativeHandler::GetUdpTransportOrThrow( | |
343 int transport_id) const { | |
344 UdpTransportMap::const_iterator iter = udp_transport_map_.find( | |
345 transport_id); | |
346 if (iter != udp_transport_map_.end()) | |
347 return iter->second.get(); | |
348 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); | |
349 isolate->ThrowException(v8::Exception::RangeError( | |
350 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound))); | |
351 return NULL; | |
352 } | |
353 | |
354 } // namespace extensions | |
OLD | NEW |