| 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 |