Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(452)

Side by Side Diff: chrome/renderer/extensions/cast_streaming_native_handler.cc

Issue 938903003: Cast: Javascript bindings for cast receiver (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cast_receiver_session
Patch Set: merged Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <functional> 7 #include <functional>
8 #include <iterator> 8 #include <iterator>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "chrome/common/extensions/api/cast_streaming_receiver_session.h"
13 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h" 14 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
14 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h" 15 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
16 #include "chrome/renderer/media/cast_receiver_session.h"
15 #include "chrome/renderer/media/cast_rtp_stream.h" 17 #include "chrome/renderer/media/cast_rtp_stream.h"
16 #include "chrome/renderer/media/cast_session.h" 18 #include "chrome/renderer/media/cast_session.h"
17 #include "chrome/renderer/media/cast_udp_transport.h" 19 #include "chrome/renderer/media/cast_udp_transport.h"
18 #include "content/public/child/v8_value_converter.h" 20 #include "content/public/child/v8_value_converter.h"
21 #include "content/public/renderer/media_stream_api.h"
19 #include "extensions/renderer/script_context.h" 22 #include "extensions/renderer/script_context.h"
23 #include "media/audio/audio_parameters.h"
20 #include "net/base/host_port_pair.h" 24 #include "net/base/host_port_pair.h"
25 #include "third_party/WebKit/public/platform/WebMediaStream.h"
21 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 26 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
27 #include "third_party/WebKit/public/platform/WebURL.h"
22 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" 28 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
29 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
30 #include "url/gurl.h"
23 31
24 using content::V8ValueConverter; 32 using content::V8ValueConverter;
25 33
26 // Extension types. 34 // Extension types.
35 using extensions::api::cast_streaming_receiver_session::RtpReceiverParams;
27 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams; 36 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams;
28 using extensions::api::cast_streaming_rtp_stream::RtpParams; 37 using extensions::api::cast_streaming_rtp_stream::RtpParams;
29 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams; 38 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams;
30 using extensions::api::cast_streaming_udp_transport::IPEndPoint; 39 using extensions::api::cast_streaming_udp_transport::IPEndPoint;
31 40
32 namespace extensions { 41 namespace extensions {
33 42
34 namespace { 43 namespace {
44 const char kInvalidAesIvMask[] = "Invalid value for AES IV mask";
45 const char kInvalidAesKey[] = "Invalid value for AES key";
46 const char kInvalidAudioParams[] = "Invalid audio params";
47 const char kInvalidDestination[] = "Invalid destination";
48 const char kInvalidFPS[] = "Invalid FPS";
49 const char kInvalidMediaStreamURL[] = "Invalid MediaStream URL";
50 const char kInvalidRtpParams[] = "Invalid value for RTP params";
51 const char kInvalidStreamArgs[] = "Invalid stream arguments";
35 const char kRtpStreamNotFound[] = "The RTP stream cannot be found"; 52 const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
36 const char kUdpTransportNotFound[] = "The UDP transport cannot be found"; 53 const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
37 const char kInvalidDestination[] = "Invalid destination";
38 const char kInvalidRtpParams[] = "Invalid value for RTP params";
39 const char kInvalidAesKey[] = "Invalid value for AES key";
40 const char kInvalidAesIvMask[] = "Invalid value for AES IV mask";
41 const char kInvalidStreamArgs[] = "Invalid stream arguments";
42 const char kUnableToConvertArgs[] = "Unable to convert arguments"; 54 const char kUnableToConvertArgs[] = "Unable to convert arguments";
43 const char kUnableToConvertParams[] = "Unable to convert params"; 55 const char kUnableToConvertParams[] = "Unable to convert params";
44 56
45 // These helper methods are used to convert between Extension API 57 // These helper methods are used to convert between Extension API
46 // types and Cast types. 58 // types and Cast types.
47 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params, 59 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params,
48 CastCodecSpecificParams* cast_params) { 60 CastCodecSpecificParams* cast_params) {
49 cast_params->key = ext_params.key; 61 cast_params->key = ext_params.key;
50 cast_params->value = ext_params.value; 62 cast_params->value = ext_params.value;
51 } 63 }
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 base::Unretained(this))); 204 base::Unretained(this)));
193 RouteFunction("ToggleLogging", 205 RouteFunction("ToggleLogging",
194 base::Bind(&CastStreamingNativeHandler::ToggleLogging, 206 base::Bind(&CastStreamingNativeHandler::ToggleLogging,
195 base::Unretained(this))); 207 base::Unretained(this)));
196 RouteFunction("GetRawEvents", 208 RouteFunction("GetRawEvents",
197 base::Bind(&CastStreamingNativeHandler::GetRawEvents, 209 base::Bind(&CastStreamingNativeHandler::GetRawEvents,
198 base::Unretained(this))); 210 base::Unretained(this)));
199 RouteFunction("GetStats", 211 RouteFunction("GetStats",
200 base::Bind(&CastStreamingNativeHandler::GetStats, 212 base::Bind(&CastStreamingNativeHandler::GetStats,
201 base::Unretained(this))); 213 base::Unretained(this)));
214 RouteFunction("StartCastRtpReceiver",
215 base::Bind(&CastStreamingNativeHandler::StartCastRtpReceiver,
216 base::Unretained(this)));
202 } 217 }
203 218
204 CastStreamingNativeHandler::~CastStreamingNativeHandler() { 219 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
205 } 220 }
206 221
207 void CastStreamingNativeHandler::CreateCastSession( 222 void CastStreamingNativeHandler::CreateCastSession(
208 const v8::FunctionCallbackInfo<v8::Value>& args) { 223 const v8::FunctionCallbackInfo<v8::Value>& args) {
209 CHECK_EQ(3, args.Length()); 224 CHECK_EQ(3, args.Length());
210 CHECK(args[2]->IsFunction()); 225 CHECK(args[2]->IsFunction());
211 226
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 const v8::FunctionCallbackInfo<v8::Value>& args) { 448 const v8::FunctionCallbackInfo<v8::Value>& args) {
434 CHECK_EQ(2, args.Length()); 449 CHECK_EQ(2, args.Length());
435 CHECK(args[0]->IsInt32()); 450 CHECK(args[0]->IsInt32());
436 CHECK(args[1]->IsObject()); 451 CHECK(args[1]->IsObject());
437 452
438 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); 453 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
439 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id); 454 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
440 if (!transport) 455 if (!transport)
441 return; 456 return;
442 457
443 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); 458 net::IPEndPoint dest;
444 scoped_ptr<base::Value> destination_value( 459 if (!IPEndPointFromArg(args.GetIsolate(),
445 converter->FromV8Value(args[1], context()->v8_context())); 460 args[1],
446 if (!destination_value) { 461 false,
447 args.GetIsolate()->ThrowException(v8::Exception::TypeError( 462 &dest)) {
448 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
449 return; 463 return;
450 } 464 }
451 scoped_ptr<IPEndPoint> destination = 465 transport->SetDestination(dest);
452 IPEndPoint::FromValue(*destination_value);
453 if (!destination) {
454 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
455 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
456 return;
457 }
458 net::IPAddressNumber ip;
459 if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
460 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
461 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
462 return;
463 }
464 transport->SetDestination(net::IPEndPoint(ip, destination->port));
465 } 466 }
466 467
467 void CastStreamingNativeHandler::SetOptionsCastUdpTransport( 468 void CastStreamingNativeHandler::SetOptionsCastUdpTransport(
468 const v8::FunctionCallbackInfo<v8::Value>& args) { 469 const v8::FunctionCallbackInfo<v8::Value>& args) {
469 CHECK_EQ(2, args.Length()); 470 CHECK_EQ(2, args.Length());
470 CHECK(args[0]->IsInt32()); 471 CHECK(args[0]->IsInt32());
471 CHECK(args[1]->IsObject()); 472 CHECK(args[1]->IsObject());
472 473
473 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); 474 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
474 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id); 475 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 UdpTransportMap::const_iterator iter = udp_transport_map_.find( 610 UdpTransportMap::const_iterator iter = udp_transport_map_.find(
610 transport_id); 611 transport_id);
611 if (iter != udp_transport_map_.end()) 612 if (iter != udp_transport_map_.end())
612 return iter->second.get(); 613 return iter->second.get();
613 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); 614 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
614 isolate->ThrowException(v8::Exception::RangeError( 615 isolate->ThrowException(v8::Exception::RangeError(
615 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound))); 616 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
616 return NULL; 617 return NULL;
617 } 618 }
618 619
620 bool CastStreamingNativeHandler::FrameReceiverFromArg(
621 v8::Isolate* isolate,
622 const v8::Handle<v8::Value>& arg,
623 media::cast::FrameReceiverConfig* config) {
624
625 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
626 scoped_ptr<base::Value> params_value(
627 converter->FromV8Value(arg, context()->v8_context()));
628 if (!params_value) {
629 isolate->ThrowException(v8::Exception::TypeError(
630 v8::String::NewFromUtf8(isolate, kUnableToConvertParams)));
631 return false;
632 }
633 scoped_ptr<RtpReceiverParams> params =
634 RtpReceiverParams::FromValue(*params_value);
635 if (!params) {
636 isolate->ThrowException(v8::Exception::TypeError(
637 v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
638 return false;
639 }
640
641 config->feedback_ssrc = params->feedback_ssrc;
642 config->incoming_ssrc = params->ssrc;
643 config->rtp_max_delay_ms = params->max_latency;
miu 2015/02/26 06:23:34 Please range-check this value, and throw a v8 exce
hubbe 2015/02/28 00:17:12 Done.
644 config->rtp_payload_type = params->payload_type;
645 config->channels = params->channels ? *params->channels : 0;
646 if (params->codec_name == "OPUS") {
647 config->codec = media::cast::CODEC_AUDIO_OPUS;
648 config->rtp_timebase = 48000;
649 } else if (params->codec_name == "PCM16") {
650 config->codec = media::cast::CODEC_AUDIO_PCM16;
651 config->rtp_timebase = 48000;
652 } else if (params->codec_name == "AAC") {
653 config->codec = media::cast::CODEC_AUDIO_AAC;
654 config->rtp_timebase = 48000;
655 } else if (params->codec_name == "VP8") {
656 config->codec = media::cast::CODEC_VIDEO_VP8;
657 config->rtp_timebase = 90000;
658 } else if (params->codec_name == "H264") {
659 config->codec = media::cast::CODEC_VIDEO_H264;
660 config->rtp_timebase = 90000;
661 }
662 config->rtp_timebase = params->clock_rate ? *params->clock_rate : 0;
miu 2015/02/26 06:23:34 This overwrites the previous assignments of config
hubbe 2015/02/28 00:17:11 Done.
663 if (params->aes_key &&
664 !HexDecode(*params->aes_key, &config->aes_key)) {
665 isolate->ThrowException(v8::Exception::Error(
666 v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
667 return false;
668 }
669 if (params->aes_iv_mask &&
670 !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) {
671 isolate->ThrowException(v8::Exception::Error(
672 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
673 return false;
674 }
675 return true;
676 }
677
678 bool CastStreamingNativeHandler::IPEndPointFromArg(
679 v8::Isolate* isolate,
680 const v8::Handle<v8::Value>& arg,
681 bool empty_ok,
682 net::IPEndPoint* ip_endpoint) {
683 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
684 scoped_ptr<base::Value> destination_value(
685 converter->FromV8Value(arg, context()->v8_context()));
686 if (!destination_value) {
687 isolate->ThrowException(v8::Exception::TypeError(
688 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
689 return false;
690 }
691 scoped_ptr<IPEndPoint> destination =
692 IPEndPoint::FromValue(*destination_value);
693 if (!destination) {
694 isolate->ThrowException(v8::Exception::TypeError(
695 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
696 return false;
697 }
698 net::IPAddressNumber ip;
699 if (destination->address != "" || !empty_ok) {
700 if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
701 isolate->ThrowException(v8::Exception::TypeError(
702 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
703 return false;
704 }
705 }
706 *ip_endpoint = net::IPEndPoint(ip, destination->port);
707 return true;
708 }
709
710 void CastStreamingNativeHandler::StartCastRtpReceiver(
711 const v8::FunctionCallbackInfo<v8::Value>& args) {
712 if (args.Length() < 8 || args.Length() > 9 ||
713 !args[0]->IsObject() ||
714 !args[1]->IsObject() ||
715 !args[2]->IsObject() ||
716 !args[3]->IsObject() ||
717 !args[4]->IsInt32() ||
718 !args[5]->IsInt32() ||
719 !args[6]->IsNumber() ||
720 !args[7]->IsString()) {
721 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
722 v8::String::NewFromUtf8(args.GetIsolate(), "ARG!!!")));
Alpha Left Google 2015/02/25 20:37:28 Should be a more user friendly string.
hubbe 2015/02/28 00:17:11 OOps, fixed.
723 return;
724 }
725
726 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
727
728 scoped_refptr<CastReceiverSession> session(
729 new CastReceiverSession());
730 media::cast::FrameReceiverConfig audio_config;
731 media::cast::FrameReceiverConfig video_config;
732 net::IPEndPoint local_endpoint;
733 net::IPEndPoint remote_endpoint;
734
735 if (!FrameReceiverFromArg(isolate, args[0], &audio_config) ||
736 !FrameReceiverFromArg(isolate, args[1], &video_config) ||
737 !IPEndPointFromArg(isolate, args[2], true, &local_endpoint) ||
738 !IPEndPointFromArg(isolate, args[3], true, &remote_endpoint)) {
739 return;
miu 2015/02/26 06:23:34 Throw error exception here?
hubbe 2015/02/28 00:17:12 An exception will have already been raised in this
740 }
741
742 const std::string url = *v8::String::Utf8Value(args[7]);
743 blink::WebMediaStream stream =
744 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
745
746 if (stream.isNull()) {
747 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
748 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL)));
749 return;
750 }
751
752 const int width = args[4]->ToInt32(args.GetIsolate())->Value();
753 const int height = args[5]->ToInt32(args.GetIsolate())->Value();
754 const double fps = args[6]->NumberValue();
755
756 if (fps <= 1) {
757 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
758 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS)));
759 return;
760 }
761
762 media::VideoCaptureFormat capture_format(
763 gfx::Size(width, height),
764 fps,
765 media::PIXEL_FORMAT_I420);
766
767 video_config.target_frame_rate = fps;
Alpha Left Google 2015/02/25 20:37:28 I think the fps parameter in VideoCaptureFormat ha
miu 2015/02/26 06:23:34 Doesn't a Cast Receiver have NO concept of frame r
hubbe 2015/02/28 00:17:12 That might be true, but I don't actually know how
hubbe 2015/02/28 00:17:12 Unfortunately capture_format.IsValid() must be tru
768 audio_config.target_frame_rate = 100;
769
770 media::AudioParameters params(
771 media::AudioParameters::AUDIO_PCM_LINEAR,
772 media::CHANNEL_LAYOUT_STEREO,
773 audio_config.rtp_timebase, // sampling rate
774 16,
775 audio_config.rtp_timebase / 100); // frames per buffer,
Alpha Left Google 2015/02/25 20:37:28 Divide by audio_config.target_frame_rate instead.
hubbe 2015/02/28 00:17:11 Done.
776
777 if (!params.IsValid()) {
778 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
779 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams)));
780 return;
781 }
782
783 base::DictionaryValue* options = NULL;
784 if (args.Length() >= 9) {
785 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
786 base::Value* options_value =
787 converter->FromV8Value(args[8], context()->v8_context());
788 if (!options_value->IsType(base::Value::TYPE_NULL)) {
789 if (!options_value || !options_value->GetAsDictionary(&options)) {
790 delete options_value;
791 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
792 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
793 return;
794 }
795 }
796 }
797
798 if (!options) {
799 options = new base::DictionaryValue();
800 }
801
802 session->Start(audio_config,
803 video_config,
804 local_endpoint,
805 remote_endpoint,
806 make_scoped_ptr(options),
807 capture_format,
808 base::Bind(&CastStreamingNativeHandler::CallReceiverCB,
809 weak_factory_.GetWeakPtr(),
810 url,
811 params));
812 }
813
814 void CastStreamingNativeHandler::CallReceiverCB(
815 const std::string& url,
816 const media::AudioParameters& params,
817 scoped_refptr<media::AudioCapturerSource> audio,
818 scoped_ptr<media::VideoCapturerSource> video) {
819
820 content::AddAudioTrackToMediaStream(audio, params, true, true, url);
821 content::AddVideoTrackToMediaStream(video.Pass(), true, true, url);
822 }
823
824
Alpha Left Google 2015/02/25 20:37:28 nit: remove this extra empty line.
hubbe 2015/02/28 00:17:12 Done.
619 } // namespace extensions 825 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698