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 |