| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/renderer/extensions/cast_streaming_native_handler.h" | 5 #include "chrome/renderer/extensions/cast_streaming_native_handler.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "base/threading/thread_task_runner_handle.h" | 25 #include "base/threading/thread_task_runner_handle.h" |
| 26 #include "chrome/common/extensions/api/cast_streaming_receiver_session.h" | 26 #include "chrome/common/extensions/api/cast_streaming_receiver_session.h" |
| 27 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h" | 27 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h" |
| 28 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h" | 28 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h" |
| 29 #include "chrome/renderer/media/cast_receiver_session.h" | 29 #include "chrome/renderer/media/cast_receiver_session.h" |
| 30 #include "chrome/renderer/media/cast_rtp_stream.h" | 30 #include "chrome/renderer/media/cast_rtp_stream.h" |
| 31 #include "chrome/renderer/media/cast_session.h" | 31 #include "chrome/renderer/media/cast_session.h" |
| 32 #include "chrome/renderer/media/cast_udp_transport.h" | 32 #include "chrome/renderer/media/cast_udp_transport.h" |
| 33 #include "content/public/child/v8_value_converter.h" | 33 #include "content/public/child/v8_value_converter.h" |
| 34 #include "content/public/renderer/media_stream_utils.h" | 34 #include "content/public/renderer/media_stream_utils.h" |
| 35 #include "extensions/common/extension.h" |
| 35 #include "extensions/renderer/script_context.h" | 36 #include "extensions/renderer/script_context.h" |
| 36 #include "media/base/audio_parameters.h" | 37 #include "media/base/audio_parameters.h" |
| 37 #include "media/base/limits.h" | 38 #include "media/base/limits.h" |
| 38 #include "net/base/host_port_pair.h" | 39 #include "net/base/host_port_pair.h" |
| 39 #include "net/base/ip_address.h" | 40 #include "net/base/ip_address.h" |
| 40 #include "third_party/WebKit/public/platform/WebMediaStream.h" | 41 #include "third_party/WebKit/public/platform/WebMediaStream.h" |
| 41 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" | 42 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" |
| 42 #include "third_party/WebKit/public/platform/WebURL.h" | 43 #include "third_party/WebKit/public/platform/WebURL.h" |
| 43 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" | 44 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" |
| 44 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" | 45 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" |
| (...skipping 22 matching lines...) Expand all Loading... |
| 67 constexpr char kInvalidLatency[] = "Invalid value for max_latency. (0-1000)"; | 68 constexpr char kInvalidLatency[] = "Invalid value for max_latency. (0-1000)"; |
| 68 constexpr char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)"; | 69 constexpr char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)"; |
| 69 constexpr char kInvalidStreamArgs[] = "Invalid stream arguments"; | 70 constexpr char kInvalidStreamArgs[] = "Invalid stream arguments"; |
| 70 constexpr char kRtpStreamNotFound[] = "The RTP stream cannot be found"; | 71 constexpr char kRtpStreamNotFound[] = "The RTP stream cannot be found"; |
| 71 constexpr char kUdpTransportNotFound[] = "The UDP transport cannot be found"; | 72 constexpr char kUdpTransportNotFound[] = "The UDP transport cannot be found"; |
| 72 constexpr char kUnableToConvertArgs[] = "Unable to convert arguments"; | 73 constexpr char kUnableToConvertArgs[] = "Unable to convert arguments"; |
| 73 constexpr char kUnableToConvertParams[] = "Unable to convert params"; | 74 constexpr char kUnableToConvertParams[] = "Unable to convert params"; |
| 74 constexpr char kCodecNameOpus[] = "OPUS"; | 75 constexpr char kCodecNameOpus[] = "OPUS"; |
| 75 constexpr char kCodecNameVp8[] = "VP8"; | 76 constexpr char kCodecNameVp8[] = "VP8"; |
| 76 constexpr char kCodecNameH264[] = "H264"; | 77 constexpr char kCodecNameH264[] = "H264"; |
| 78 constexpr char kCodecNameRemoteAudio[] = "REMOTE_AUDIO"; |
| 79 constexpr char kCodecNameRemoteVideo[] = "REMOTE_VIDEO"; |
| 77 | 80 |
| 78 // To convert from kilobits per second to bits per second. | 81 // To convert from kilobits per second to bits per second. |
| 79 constexpr int kBitsPerKilobit = 1000; | 82 constexpr int kBitsPerKilobit = 1000; |
| 80 | 83 |
| 81 bool HexDecode(const std::string& input, std::string* output) { | 84 bool HexDecode(const std::string& input, std::string* output) { |
| 82 std::vector<uint8_t> bytes; | 85 std::vector<uint8_t> bytes; |
| 83 if (!base::HexStringToBytes(input, &bytes)) | 86 if (!base::HexStringToBytes(input, &bytes)) |
| 84 return false; | 87 return false; |
| 85 output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size()); | 88 output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size()); |
| 86 return true; | 89 return true; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 CastRtpStream::IsHardwareVP8EncodingSupported(); | 209 CastRtpStream::IsHardwareVP8EncodingSupported(); |
| 207 } else { | 210 } else { |
| 208 config->rtp_payload_type = media::cast::RtpPayloadType::VIDEO_H264; | 211 config->rtp_payload_type = media::cast::RtpPayloadType::VIDEO_H264; |
| 209 config->codec = media::cast::CODEC_VIDEO_H264; | 212 config->codec = media::cast::CODEC_VIDEO_H264; |
| 210 config->use_external_encoder = | 213 config->use_external_encoder = |
| 211 CastRtpStream::IsHardwareH264EncodingSupported(); | 214 CastRtpStream::IsHardwareH264EncodingSupported(); |
| 212 } | 215 } |
| 213 if (!config->use_external_encoder) | 216 if (!config->use_external_encoder) |
| 214 config->video_codec_params.number_of_encode_threads = | 217 config->video_codec_params.number_of_encode_threads = |
| 215 NumberOfEncodeThreads(); | 218 NumberOfEncodeThreads(); |
| 219 } else if (ext_params.codec_name == kCodecNameRemoteAudio) { |
| 220 config->rtp_payload_type = media::cast::RtpPayloadType::REMOTE_AUDIO; |
| 221 config->codec = media::cast::CODEC_AUDIO_REMOTE; |
| 222 } else if (ext_params.codec_name == kCodecNameRemoteVideo) { |
| 223 config->rtp_payload_type = media::cast::RtpPayloadType::REMOTE_VIDEO; |
| 224 config->codec = media::cast::CODEC_VIDEO_REMOTE; |
| 216 } else { | 225 } else { |
| 217 DVLOG(1) << "codec_name " << ext_params.codec_name << " is invalid"; | 226 DVLOG(1) << "codec_name " << ext_params.codec_name << " is invalid"; |
| 218 isolate->ThrowException(v8::Exception::Error( | 227 isolate->ThrowException(v8::Exception::Error( |
| 219 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); | 228 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 220 return false; | 229 return false; |
| 221 } | 230 } |
| 222 if (ext_params.aes_key && !HexDecode(*ext_params.aes_key, &config->aes_key)) { | 231 if (ext_params.aes_key && !HexDecode(*ext_params.aes_key, &config->aes_key)) { |
| 223 isolate->ThrowException(v8::Exception::Error( | 232 isolate->ThrowException(v8::Exception::Error( |
| 224 v8::String::NewFromUtf8(isolate, kInvalidAesKey))); | 233 v8::String::NewFromUtf8(isolate, kInvalidAesKey))); |
| 225 return false; | 234 return false; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 244 switch (config.codec) { | 253 switch (config.codec) { |
| 245 case media::cast::CODEC_AUDIO_OPUS: | 254 case media::cast::CODEC_AUDIO_OPUS: |
| 246 ext_params->codec_name = kCodecNameOpus; | 255 ext_params->codec_name = kCodecNameOpus; |
| 247 break; | 256 break; |
| 248 case media::cast::CODEC_VIDEO_VP8: | 257 case media::cast::CODEC_VIDEO_VP8: |
| 249 ext_params->codec_name = kCodecNameVp8; | 258 ext_params->codec_name = kCodecNameVp8; |
| 250 break; | 259 break; |
| 251 case media::cast::CODEC_VIDEO_H264: | 260 case media::cast::CODEC_VIDEO_H264: |
| 252 ext_params->codec_name = kCodecNameH264; | 261 ext_params->codec_name = kCodecNameH264; |
| 253 break; | 262 break; |
| 263 case media::cast::CODEC_AUDIO_REMOTE: |
| 264 ext_params->codec_name = kCodecNameRemoteAudio; |
| 265 break; |
| 266 case media::cast::CODEC_VIDEO_REMOTE: |
| 267 ext_params->codec_name = kCodecNameRemoteVideo; |
| 268 break; |
| 254 default: | 269 default: |
| 255 NOTREACHED(); | 270 NOTREACHED(); |
| 256 } | 271 } |
| 257 ext_params->ssrc = config.sender_ssrc; | 272 ext_params->ssrc = config.sender_ssrc; |
| 258 ext_params->feedback_ssrc = config.receiver_ssrc; | 273 ext_params->feedback_ssrc = config.receiver_ssrc; |
| 259 if (config.rtp_timebase) | 274 if (config.rtp_timebase) |
| 260 ext_params->clock_rate.reset(new int(config.rtp_timebase)); | 275 ext_params->clock_rate.reset(new int(config.rtp_timebase)); |
| 261 if (config.min_bitrate) | 276 if (config.min_bitrate) |
| 262 ext_params->min_bitrate.reset( | 277 ext_params->min_bitrate.reset( |
| 263 new int(config.min_bitrate / kBitsPerKilobit)); | 278 new int(config.min_bitrate / kBitsPerKilobit)); |
| 264 if (config.max_bitrate) | 279 if (config.max_bitrate) |
| 265 ext_params->max_bitrate.reset( | 280 ext_params->max_bitrate.reset( |
| 266 new int(config.max_bitrate / kBitsPerKilobit)); | 281 new int(config.max_bitrate / kBitsPerKilobit)); |
| 267 if (config.channels) | 282 if (config.channels) |
| 268 ext_params->channels.reset(new int(config.channels)); | 283 ext_params->channels.reset(new int(config.channels)); |
| 269 if (config.max_frame_rate > 0.0) | 284 if (config.max_frame_rate > 0.0) |
| 270 ext_params->max_frame_rate.reset(new double(config.max_frame_rate)); | 285 ext_params->max_frame_rate.reset(new double(config.max_frame_rate)); |
| 271 } | 286 } |
| 272 | 287 |
| 273 } // namespace | 288 } // namespace |
| 274 | 289 |
| 290 // |last_transport_id_| is the identifier for the next created RTP stream. To |
| 291 // create globally unique IDs used for referring to RTP stream objects in |
| 292 // browser process, we set its higher 16 bits as HASH(extension_id)&0x7fff, and |
| 293 // lower 16 bits as the sequence number of the RTP stream created in the same |
| 294 // extension. Collision will happen when the first RTP stream keeps alive after |
| 295 // creating another 64k-1 RTP streams in the same extension, which is very |
| 296 // unlikely to happen in normal use cases. |
| 275 CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext* context) | 297 CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext* context) |
| 276 : ObjectBackedNativeHandler(context), | 298 : ObjectBackedNativeHandler(context), |
| 277 last_transport_id_(1), | 299 last_transport_id_( |
| 300 context->extension() |
| 301 ? (((base::Hash(context->extension()->id()) & 0x7fff) << 16) + 1) |
| 302 : 1), |
| 278 weak_factory_(this) { | 303 weak_factory_(this) { |
| 279 RouteFunction("CreateSession", "cast.streaming.session", | 304 RouteFunction("CreateSession", "cast.streaming.session", |
| 280 base::Bind(&CastStreamingNativeHandler::CreateCastSession, | 305 base::Bind(&CastStreamingNativeHandler::CreateCastSession, |
| 281 weak_factory_.GetWeakPtr())); | 306 weak_factory_.GetWeakPtr())); |
| 282 RouteFunction("DestroyCastRtpStream", "cast.streaming.rtpStream", | 307 RouteFunction("DestroyCastRtpStream", "cast.streaming.rtpStream", |
| 283 base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream, | 308 base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream, |
| 284 weak_factory_.GetWeakPtr())); | 309 weak_factory_.GetWeakPtr())); |
| 285 RouteFunction( | 310 RouteFunction( |
| 286 "GetSupportedParamsCastRtpStream", "cast.streaming.rtpStream", | 311 "GetSupportedParamsCastRtpStream", "cast.streaming.rtpStream", |
| 287 base::Bind(&CastStreamingNativeHandler::GetSupportedParamsCastRtpStream, | 312 base::Bind(&CastStreamingNativeHandler::GetSupportedParamsCastRtpStream, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 | 361 |
| 337 ObjectBackedNativeHandler::Invalidate(); | 362 ObjectBackedNativeHandler::Invalidate(); |
| 338 } | 363 } |
| 339 | 364 |
| 340 void CastStreamingNativeHandler::CreateCastSession( | 365 void CastStreamingNativeHandler::CreateCastSession( |
| 341 const v8::FunctionCallbackInfo<v8::Value>& args) { | 366 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 342 CHECK_EQ(3, args.Length()); | 367 CHECK_EQ(3, args.Length()); |
| 343 CHECK(args[2]->IsFunction()); | 368 CHECK(args[2]->IsFunction()); |
| 344 | 369 |
| 345 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); | 370 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); |
| 346 if ((args[0]->IsNull() || args[0]->IsUndefined()) && | |
| 347 (args[1]->IsNull() || args[1]->IsUndefined())) { | |
| 348 isolate->ThrowException(v8::Exception::Error( | |
| 349 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | |
| 350 return; | |
| 351 } | |
| 352 | 371 |
| 353 scoped_refptr<CastSession> session(new CastSession()); | 372 scoped_refptr<CastSession> session(new CastSession()); |
| 354 std::unique_ptr<CastRtpStream> stream1, stream2; | 373 std::unique_ptr<CastRtpStream> stream1, stream2; |
| 355 if (!args[0]->IsNull() && !args[0]->IsUndefined()) { | 374 if ((args[0]->IsNull() || args[0]->IsUndefined()) && |
| 356 CHECK(args[0]->IsObject()); | 375 (args[1]->IsNull() || args[1]->IsUndefined())) { |
| 357 blink::WebDOMMediaStreamTrack track = | 376 DVLOG(3) << "CreateCastSession for remoting."; |
| 358 blink::WebDOMMediaStreamTrack::fromV8Value(args[0]); | 377 // Creates audio/video RTP streams for media remoting. |
| 359 if (track.isNull()) { | 378 stream1.reset(new CastRtpStream(true, session)); |
| 360 isolate->ThrowException(v8::Exception::Error( | 379 stream2.reset(new CastRtpStream(false, session)); |
| 361 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | 380 } else { |
| 362 return; | 381 // Creates RTP streams that consume from an audio and/or a video |
| 382 // MediaStreamTrack. |
| 383 if (!args[0]->IsNull() && !args[0]->IsUndefined()) { |
| 384 CHECK(args[0]->IsObject()); |
| 385 blink::WebDOMMediaStreamTrack track = |
| 386 blink::WebDOMMediaStreamTrack::fromV8Value(args[0]); |
| 387 if (track.isNull()) { |
| 388 isolate->ThrowException(v8::Exception::Error( |
| 389 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); |
| 390 return; |
| 391 } |
| 392 stream1.reset(new CastRtpStream(track.component(), session)); |
| 363 } | 393 } |
| 364 stream1.reset(new CastRtpStream(track.component(), session)); | 394 if (!args[1]->IsNull() && !args[1]->IsUndefined()) { |
| 365 } | 395 CHECK(args[1]->IsObject()); |
| 366 if (!args[1]->IsNull() && !args[1]->IsUndefined()) { | 396 blink::WebDOMMediaStreamTrack track = |
| 367 CHECK(args[1]->IsObject()); | 397 blink::WebDOMMediaStreamTrack::fromV8Value(args[1]); |
| 368 blink::WebDOMMediaStreamTrack track = | 398 if (track.isNull()) { |
| 369 blink::WebDOMMediaStreamTrack::fromV8Value(args[1]); | 399 isolate->ThrowException(v8::Exception::Error( |
| 370 if (track.isNull()) { | 400 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); |
| 371 isolate->ThrowException(v8::Exception::Error( | 401 return; |
| 372 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | 402 } |
| 373 return; | 403 stream2.reset(new CastRtpStream(track.component(), session)); |
| 374 } | 404 } |
| 375 stream2.reset(new CastRtpStream(track.component(), session)); | |
| 376 } | 405 } |
| 377 std::unique_ptr<CastUdpTransport> udp_transport( | 406 std::unique_ptr<CastUdpTransport> udp_transport( |
| 378 new CastUdpTransport(session)); | 407 new CastUdpTransport(session)); |
| 379 | 408 |
| 380 create_callback_.Reset(isolate, args[2].As<v8::Function>()); | 409 create_callback_.Reset(isolate, args[2].As<v8::Function>()); |
| 381 | 410 |
| 382 base::ThreadTaskRunnerHandle::Get()->PostTask( | 411 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 383 FROM_HERE, | 412 FROM_HERE, |
| 384 base::Bind(&CastStreamingNativeHandler::CallCreateCallback, | 413 base::Bind(&CastStreamingNativeHandler::CallCreateCallback, |
| 385 weak_factory_.GetWeakPtr(), base::Passed(&stream1), | 414 weak_factory_.GetWeakPtr(), base::Passed(&stream1), |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 weak_factory_.GetWeakPtr(), | 551 weak_factory_.GetWeakPtr(), |
| 523 transport_id); | 552 transport_id); |
| 524 base::Closure stop_callback = | 553 base::Closure stop_callback = |
| 525 base::Bind(&CastStreamingNativeHandler::CallStopCallback, | 554 base::Bind(&CastStreamingNativeHandler::CallStopCallback, |
| 526 weak_factory_.GetWeakPtr(), | 555 weak_factory_.GetWeakPtr(), |
| 527 transport_id); | 556 transport_id); |
| 528 CastRtpStream::ErrorCallback error_callback = | 557 CastRtpStream::ErrorCallback error_callback = |
| 529 base::Bind(&CastStreamingNativeHandler::CallErrorCallback, | 558 base::Bind(&CastStreamingNativeHandler::CallErrorCallback, |
| 530 weak_factory_.GetWeakPtr(), | 559 weak_factory_.GetWeakPtr(), |
| 531 transport_id); | 560 transport_id); |
| 532 transport->Start(config, start_callback, stop_callback, error_callback); | 561 |
| 562 // |transport_id| is a globally unique identifier for the RTP stream. |
| 563 transport->Start(transport_id, config, start_callback, stop_callback, |
| 564 error_callback); |
| 533 } | 565 } |
| 534 | 566 |
| 535 void CastStreamingNativeHandler::StopCastRtpStream( | 567 void CastStreamingNativeHandler::StopCastRtpStream( |
| 536 const v8::FunctionCallbackInfo<v8::Value>& args) { | 568 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 537 CHECK_EQ(1, args.Length()); | 569 CHECK_EQ(1, args.Length()); |
| 538 CHECK(args[0]->IsInt32()); | 570 CHECK(args[0]->IsInt32()); |
| 539 | 571 |
| 540 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); | 572 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); |
| 541 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id); | 573 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id); |
| 542 if (!transport) | 574 if (!transport) |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 962 LOG(ERROR) << "Failed to add Cast audio track to media stream."; | 994 LOG(ERROR) << "Failed to add Cast audio track to media stream."; |
| 963 } | 995 } |
| 964 if (!content::AddVideoTrackToMediaStream(std::move(video), true, // is_remote | 996 if (!content::AddVideoTrackToMediaStream(std::move(video), true, // is_remote |
| 965 true, // is_readonly | 997 true, // is_readonly |
| 966 &web_stream)) { | 998 &web_stream)) { |
| 967 LOG(ERROR) << "Failed to add Cast video track to media stream."; | 999 LOG(ERROR) << "Failed to add Cast video track to media stream."; |
| 968 } | 1000 } |
| 969 } | 1001 } |
| 970 | 1002 |
| 971 } // namespace extensions | 1003 } // namespace extensions |
| OLD | NEW |