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

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: removed local port 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(
452 IPEndPoint::FromValue(*destination_value); 466 dest,
453 if (!destination) { 467 base::Bind(&CastStreamingNativeHandler::CallErrorCallback,
454 args.GetIsolate()->ThrowException(v8::Exception::TypeError( 468 weak_factory_.GetWeakPtr(),
455 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination))); 469 transport_id));
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 } 470 }
466 471
467 void CastStreamingNativeHandler::SetOptionsCastUdpTransport( 472 void CastStreamingNativeHandler::SetOptionsCastUdpTransport(
468 const v8::FunctionCallbackInfo<v8::Value>& args) { 473 const v8::FunctionCallbackInfo<v8::Value>& args) {
469 CHECK_EQ(2, args.Length()); 474 CHECK_EQ(2, args.Length());
470 CHECK(args[0]->IsInt32()); 475 CHECK(args[0]->IsInt32());
471 CHECK(args[1]->IsObject()); 476 CHECK(args[1]->IsObject());
472 477
473 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); 478 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
474 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id); 479 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( 614 UdpTransportMap::const_iterator iter = udp_transport_map_.find(
610 transport_id); 615 transport_id);
611 if (iter != udp_transport_map_.end()) 616 if (iter != udp_transport_map_.end())
612 return iter->second.get(); 617 return iter->second.get();
613 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); 618 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
614 isolate->ThrowException(v8::Exception::RangeError( 619 isolate->ThrowException(v8::Exception::RangeError(
615 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound))); 620 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
616 return NULL; 621 return NULL;
617 } 622 }
618 623
624 bool CastStreamingNativeHandler::FrameReceiverConfigFromArg(
625 v8::Isolate* isolate,
626 const v8::Handle<v8::Value>& arg,
627 media::cast::FrameReceiverConfig* config) {
628
629 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
630 scoped_ptr<base::Value> params_value(
631 converter->FromV8Value(arg, context()->v8_context()));
632 if (!params_value) {
633 isolate->ThrowException(v8::Exception::TypeError(
634 v8::String::NewFromUtf8(isolate, kUnableToConvertParams)));
635 return false;
636 }
637 scoped_ptr<RtpReceiverParams> params =
638 RtpReceiverParams::FromValue(*params_value);
639 if (!params) {
640 isolate->ThrowException(v8::Exception::TypeError(
641 v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
642 return false;
643 }
644
645 config->receiver_ssrc = params->feedback_ssrc;
Yoyo Zhou 2015/03/04 03:12:16 I'm not sure if you intend for these to have diffe
hubbe 2015/03/04 23:12:33 Result of a merge, fixed now.
646 config->sender_ssrc = params->ssrc;
647 config->rtp_max_delay_ms = params->max_latency;
648 if (config->rtp_max_delay_ms < 0 || config->rtp_max_delay_ms > 1000) {
Yoyo Zhou 2015/03/04 03:12:15 I'm not sure how important it is for this private
hubbe 2015/03/04 23:12:33 Done.
649 isolate->ThrowException(v8::Exception::TypeError(
650 v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
651 return false;
652 }
653 config->channels = 2;
654 if (params->codec_name == "OPUS") {
655 config->codec = media::cast::CODEC_AUDIO_OPUS;
656 config->rtp_timebase = 48000;
657 config->rtp_payload_type = 127;
658 } else if (params->codec_name == "PCM16") {
659 config->codec = media::cast::CODEC_AUDIO_PCM16;
660 config->rtp_timebase = 48000;
661 config->rtp_payload_type =127;
662 } else if (params->codec_name == "AAC") {
663 config->codec = media::cast::CODEC_AUDIO_AAC;
664 config->rtp_timebase = 48000;
665 config->rtp_payload_type = 127;
666 } else if (params->codec_name == "VP8") {
667 config->codec = media::cast::CODEC_VIDEO_VP8;
668 config->rtp_timebase = 90000;
669 config->rtp_payload_type = 96;
670 } else if (params->codec_name == "H264") {
671 config->codec = media::cast::CODEC_VIDEO_H264;
672 config->rtp_timebase = 90000;
673 config->rtp_payload_type = 96;
674 }
675 if (params->rtp_timebase) {
676 config->rtp_timebase = *params->rtp_timebase;
677 if (config->rtp_timebase < 1000 || config->rtp_timebase > 100000) {
Yoyo Zhou 2015/03/04 03:12:16 likewise here.
hubbe 2015/03/04 23:12:33 Done.
678 isolate->ThrowException(v8::Exception::TypeError(
679 v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
680 return false;
681 }
682 }
683 if (params->aes_key &&
684 !HexDecode(*params->aes_key, &config->aes_key)) {
685 isolate->ThrowException(v8::Exception::Error(
686 v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
687 return false;
688 }
689 if (params->aes_iv_mask &&
690 !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) {
691 isolate->ThrowException(v8::Exception::Error(
692 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
693 return false;
694 }
695 return true;
696 }
697
698 bool CastStreamingNativeHandler::IPEndPointFromArg(
699 v8::Isolate* isolate,
700 const v8::Handle<v8::Value>& arg,
701 bool empty_ok,
702 net::IPEndPoint* ip_endpoint) {
703 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
704 scoped_ptr<base::Value> destination_value(
705 converter->FromV8Value(arg, context()->v8_context()));
706 if (!destination_value) {
707 isolate->ThrowException(v8::Exception::TypeError(
708 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
709 return false;
710 }
711 scoped_ptr<IPEndPoint> destination =
712 IPEndPoint::FromValue(*destination_value);
713 if (!destination) {
714 isolate->ThrowException(v8::Exception::TypeError(
715 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
716 return false;
717 }
718 net::IPAddressNumber ip;
719 if (destination->address != "" || !empty_ok) {
Yoyo Zhou 2015/03/04 03:12:16 I would rewrite this (assuming I understand it cor
hubbe 2015/03/04 23:12:33 Since empty_ok is now always false, I simplified i
720 if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
721 isolate->ThrowException(v8::Exception::TypeError(
722 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
723 return false;
724 }
725 }
726 *ip_endpoint = net::IPEndPoint(ip, destination->port);
727 return true;
728 }
729
730 void CastStreamingNativeHandler::StartCastRtpReceiver(
731 const v8::FunctionCallbackInfo<v8::Value>& args) {
732 if (args.Length() < 8 || args.Length() > 9 ||
733 !args[0]->IsObject() ||
734 !args[1]->IsObject() ||
735 !args[2]->IsObject() ||
736 !args[3]->IsInt32() ||
737 !args[4]->IsInt32() ||
738 !args[5]->IsNumber() ||
739 !args[6]->IsString()) {
740 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
741 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
742 return;
743 }
744
745 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
746
747 scoped_refptr<CastReceiverSession> session(
748 new CastReceiverSession());
749 media::cast::FrameReceiverConfig audio_config;
750 media::cast::FrameReceiverConfig video_config;
751 net::IPEndPoint local_endpoint;
752 net::IPEndPoint remote_endpoint;
753
754 if (!FrameReceiverConfigFromArg(isolate, args[0], &audio_config) ||
755 !FrameReceiverConfigFromArg(isolate, args[1], &video_config) ||
756 !IPEndPointFromArg(isolate, args[2], false, &local_endpoint)) {
757 return;
758 }
759
760 const std::string url = *v8::String::Utf8Value(args[7]);
761 blink::WebMediaStream stream =
762 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
763
764 if (stream.isNull()) {
765 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
766 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL)));
767 return;
768 }
769
770 const int max_width = args[3]->ToInt32(args.GetIsolate())->Value();
771 const int max_height = args[4]->ToInt32(args.GetIsolate())->Value();
772 const double fps = args[5]->NumberValue();
773
774 if (fps <= 1) {
775 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
776 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS)));
777 return;
778 }
779
780 media::VideoCaptureFormat capture_format(
781 gfx::Size(max_width, max_height),
782 fps,
783 media::PIXEL_FORMAT_I420);
784
785 video_config.target_frame_rate = fps;
786 audio_config.target_frame_rate = 100;
787
788 media::AudioParameters params(
789 media::AudioParameters::AUDIO_PCM_LINEAR,
790 media::CHANNEL_LAYOUT_STEREO,
791 audio_config.rtp_timebase, // sampling rate
792 16,
793 audio_config.rtp_timebase / audio_config.target_frame_rate);
794
795 if (!params.IsValid()) {
796 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
797 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams)));
798 return;
799 }
800
801 base::DictionaryValue* options = NULL;
802 if (args.Length() >= 10) {
803 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
804 base::Value* options_value =
805 converter->FromV8Value(args[8], context()->v8_context());
806 if (!options_value->IsType(base::Value::TYPE_NULL)) {
807 if (!options_value || !options_value->GetAsDictionary(&options)) {
808 delete options_value;
809 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
810 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
811 return;
812 }
813 }
814 }
815
816 if (!options) {
817 options = new base::DictionaryValue();
818 }
819
820 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent error_callback;
821 error_callback.Reset(args.GetIsolate(),
822 v8::Handle<v8::Function>(args[7].As<v8::Function>()));
823
824 session->Start(
825 audio_config,
826 video_config,
827 local_endpoint,
828 remote_endpoint,
829 make_scoped_ptr(options),
830 capture_format,
831 base::Bind(&CastStreamingNativeHandler::AddTracksToMediaStream,
832 weak_factory_.GetWeakPtr(),
833 url,
834 params),
835 base::Bind(&CastStreamingNativeHandler::CallReceiverErrorCallback,
836 weak_factory_.GetWeakPtr(),
837 error_callback));
838 }
839
840 void CastStreamingNativeHandler::CallReceiverErrorCallback(
841 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function,
842 const std::string& error_message) {
843 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
844 v8::Handle<v8::Value> arg = v8::String::NewFromUtf8(isolate,
845 error_message.data(),
846 v8::String::kNormalString,
847 error_message.size());
848 context()->CallFunction(
849 v8::Local<v8::Function>::New(isolate, function), 1, &arg);
850 }
851
852
853 void CastStreamingNativeHandler::AddTracksToMediaStream(
854 const std::string& url,
855 const media::AudioParameters& params,
856 scoped_refptr<media::AudioCapturerSource> audio,
857 scoped_ptr<media::VideoCapturerSource> video) {
858 content::AddAudioTrackToMediaStream(audio, params, true, true, url);
859 content::AddVideoTrackToMediaStream(video.Pass(), true, true, url);
860 }
861
619 } // namespace extensions 862 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698