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

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(
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;
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) {
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;
miu 2015/02/28 04:32:58 Hmm...Taking a closer look at FrameReceiver, it se
hubbe 2015/03/03 01:23:03 Made it optional.
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->aes_key &&
676 !HexDecode(*params->aes_key, &config->aes_key)) {
677 isolate->ThrowException(v8::Exception::Error(
678 v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
679 return false;
680 }
681 if (params->aes_iv_mask &&
682 !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) {
683 isolate->ThrowException(v8::Exception::Error(
684 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
685 return false;
686 }
687 return true;
688 }
689
690 bool CastStreamingNativeHandler::IPEndPointFromArg(
691 v8::Isolate* isolate,
692 const v8::Handle<v8::Value>& arg,
693 bool empty_ok,
694 net::IPEndPoint* ip_endpoint) {
695 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
696 scoped_ptr<base::Value> destination_value(
697 converter->FromV8Value(arg, context()->v8_context()));
698 if (!destination_value) {
699 isolate->ThrowException(v8::Exception::TypeError(
700 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
701 return false;
702 }
703 scoped_ptr<IPEndPoint> destination =
704 IPEndPoint::FromValue(*destination_value);
705 if (!destination) {
706 isolate->ThrowException(v8::Exception::TypeError(
707 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
708 return false;
709 }
710 net::IPAddressNumber ip;
711 if (destination->address != "" || !empty_ok) {
712 if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
713 isolate->ThrowException(v8::Exception::TypeError(
714 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
715 return false;
716 }
717 }
718 *ip_endpoint = net::IPEndPoint(ip, destination->port);
719 return true;
720 }
721
722 void CastStreamingNativeHandler::StartCastRtpReceiver(
723 const v8::FunctionCallbackInfo<v8::Value>& args) {
724 if (args.Length() < 9 || args.Length() > 10 ||
725 !args[0]->IsObject() ||
726 !args[1]->IsObject() ||
727 !args[2]->IsObject() ||
728 !args[3]->IsObject() ||
729 !args[4]->IsInt32() ||
730 !args[5]->IsInt32() ||
731 !args[6]->IsNumber() ||
732 !args[7]->IsString()) {
733 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
734 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
735 return;
736 }
737
738 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
739
740 scoped_refptr<CastReceiverSession> session(
741 new CastReceiverSession());
742 media::cast::FrameReceiverConfig audio_config;
743 media::cast::FrameReceiverConfig video_config;
744 net::IPEndPoint local_endpoint;
745 net::IPEndPoint remote_endpoint;
746
747 if (!FrameReceiverConfigFromArg(isolate, args[0], &audio_config) ||
748 !FrameReceiverConfigFromArg(isolate, args[1], &video_config) ||
749 !IPEndPointFromArg(isolate, args[2], true, &local_endpoint) ||
750 !IPEndPointFromArg(isolate, args[3], true, &remote_endpoint)) {
751 return;
752 }
753
754 const std::string url = *v8::String::Utf8Value(args[7]);
755 blink::WebMediaStream stream =
756 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
757
758 if (stream.isNull()) {
759 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
760 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL)));
761 return;
762 }
763
764 const int width = args[4]->ToInt32(args.GetIsolate())->Value();
765 const int height = args[5]->ToInt32(args.GetIsolate())->Value();
766 const double fps = args[6]->NumberValue();
767
768 if (fps <= 1) {
769 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
770 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS)));
771 return;
772 }
773
774 media::VideoCaptureFormat capture_format(
775 gfx::Size(width, height),
776 fps,
777 media::PIXEL_FORMAT_I420);
778
779 video_config.target_frame_rate = fps;
780 audio_config.target_frame_rate = 100;
781
782 media::AudioParameters params(
783 media::AudioParameters::AUDIO_PCM_LINEAR,
784 media::CHANNEL_LAYOUT_STEREO,
785 audio_config.rtp_timebase, // sampling rate
786 16,
787 audio_config.rtp_timebase / audio_config.target_frame_rate);
788
789 if (!params.IsValid()) {
790 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
791 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams)));
792 return;
793 }
794
795 base::DictionaryValue* options = NULL;
796 if (args.Length() >= 10) {
797 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
798 base::Value* options_value =
799 converter->FromV8Value(args[9], context()->v8_context());
800 if (!options_value->IsType(base::Value::TYPE_NULL)) {
801 if (!options_value || !options_value->GetAsDictionary(&options)) {
802 delete options_value;
803 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
804 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
805 return;
806 }
807 }
808 }
809
810 if (!options) {
811 options = new base::DictionaryValue();
812 }
813
814 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent error_callback;
815 error_callback.Reset(args.GetIsolate(),
816 v8::Handle<v8::Function>(args[8].As<v8::Function>()));
817
818 session->Start(
819 audio_config,
820 video_config,
821 local_endpoint,
822 remote_endpoint,
823 make_scoped_ptr(options),
824 capture_format,
825 base::Bind(&CastStreamingNativeHandler::AddTracksToMediaStream,
826 weak_factory_.GetWeakPtr(),
827 url,
828 params),
829 base::Bind(&CastStreamingNativeHandler::CallReceiverErrorCallback,
830 weak_factory_.GetWeakPtr(),
831 error_callback));
832 }
833
834 void CastStreamingNativeHandler::CallReceiverErrorCallback(
835 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function,
836 const std::string& error_message) {
837 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
838 v8::Handle<v8::Value> arg = v8::String::NewFromUtf8(isolate,
839 error_message.data(),
840 v8::String::kNormalString,
841 error_message.size());
842 context()->CallFunction(
843 v8::Local<v8::Function>::New(isolate, function), 1, &arg);
844 }
845
846
847 void CastStreamingNativeHandler::AddTracksToMediaStream(
848 const std::string& url,
849 const media::AudioParameters& params,
850 scoped_refptr<media::AudioCapturerSource> audio,
851 scoped_ptr<media::VideoCapturerSource> video) {
852 content::AddAudioTrackToMediaStream(audio, params, true, true, url);
853 content::AddVideoTrackToMediaStream(video.Pass(), true, true, url);
854 }
855
619 } // namespace extensions 856 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698