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. 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 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 152 CastStreamingNativeHandler::~CastStreamingNativeHandler() { 153 } 154 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 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 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 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 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 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 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 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 336 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 348 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