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

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: comments addressed 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 kInvalidLatency[] = "Invalid value for max_latency. (0-1000)";
52 const char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)";
53 const char kInvalidStreamArgs[] = "Invalid stream arguments";
35 const char kRtpStreamNotFound[] = "The RTP stream cannot be found"; 54 const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
36 const char kUdpTransportNotFound[] = "The UDP transport cannot be found"; 55 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"; 56 const char kUnableToConvertArgs[] = "Unable to convert arguments";
43 const char kUnableToConvertParams[] = "Unable to convert params"; 57 const char kUnableToConvertParams[] = "Unable to convert params";
44 58
45 // These helper methods are used to convert between Extension API 59 // These helper methods are used to convert between Extension API
46 // types and Cast types. 60 // types and Cast types.
47 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params, 61 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params,
48 CastCodecSpecificParams* cast_params) { 62 CastCodecSpecificParams* cast_params) {
49 cast_params->key = ext_params.key; 63 cast_params->key = ext_params.key;
50 cast_params->value = ext_params.value; 64 cast_params->value = ext_params.value;
51 } 65 }
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 base::Unretained(this))); 206 base::Unretained(this)));
193 RouteFunction("ToggleLogging", 207 RouteFunction("ToggleLogging",
194 base::Bind(&CastStreamingNativeHandler::ToggleLogging, 208 base::Bind(&CastStreamingNativeHandler::ToggleLogging,
195 base::Unretained(this))); 209 base::Unretained(this)));
196 RouteFunction("GetRawEvents", 210 RouteFunction("GetRawEvents",
197 base::Bind(&CastStreamingNativeHandler::GetRawEvents, 211 base::Bind(&CastStreamingNativeHandler::GetRawEvents,
198 base::Unretained(this))); 212 base::Unretained(this)));
199 RouteFunction("GetStats", 213 RouteFunction("GetStats",
200 base::Bind(&CastStreamingNativeHandler::GetStats, 214 base::Bind(&CastStreamingNativeHandler::GetStats,
201 base::Unretained(this))); 215 base::Unretained(this)));
216 RouteFunction("StartCastRtpReceiver",
217 base::Bind(&CastStreamingNativeHandler::StartCastRtpReceiver,
218 base::Unretained(this)));
202 } 219 }
203 220
204 CastStreamingNativeHandler::~CastStreamingNativeHandler() { 221 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
205 } 222 }
206 223
207 void CastStreamingNativeHandler::CreateCastSession( 224 void CastStreamingNativeHandler::CreateCastSession(
208 const v8::FunctionCallbackInfo<v8::Value>& args) { 225 const v8::FunctionCallbackInfo<v8::Value>& args) {
209 CHECK_EQ(3, args.Length()); 226 CHECK_EQ(3, args.Length());
210 CHECK(args[2]->IsFunction()); 227 CHECK(args[2]->IsFunction());
211 228
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 const v8::FunctionCallbackInfo<v8::Value>& args) { 450 const v8::FunctionCallbackInfo<v8::Value>& args) {
434 CHECK_EQ(2, args.Length()); 451 CHECK_EQ(2, args.Length());
435 CHECK(args[0]->IsInt32()); 452 CHECK(args[0]->IsInt32());
436 CHECK(args[1]->IsObject()); 453 CHECK(args[1]->IsObject());
437 454
438 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); 455 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
439 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id); 456 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
440 if (!transport) 457 if (!transport)
441 return; 458 return;
442 459
443 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); 460 net::IPEndPoint dest;
444 scoped_ptr<base::Value> destination_value( 461 if (!IPEndPointFromArg(args.GetIsolate(),
445 converter->FromV8Value(args[1], context()->v8_context())); 462 args[1],
446 if (!destination_value) { 463 &dest)) {
447 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
448 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
449 return; 464 return;
450 } 465 }
451 scoped_ptr<IPEndPoint> destination = 466 transport->SetDestination(
452 IPEndPoint::FromValue(*destination_value); 467 dest,
453 if (!destination) { 468 base::Bind(&CastStreamingNativeHandler::CallErrorCallback,
454 args.GetIsolate()->ThrowException(v8::Exception::TypeError( 469 weak_factory_.GetWeakPtr(),
455 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination))); 470 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 } 471 }
466 472
467 void CastStreamingNativeHandler::SetOptionsCastUdpTransport( 473 void CastStreamingNativeHandler::SetOptionsCastUdpTransport(
468 const v8::FunctionCallbackInfo<v8::Value>& args) { 474 const v8::FunctionCallbackInfo<v8::Value>& args) {
469 CHECK_EQ(2, args.Length()); 475 CHECK_EQ(2, args.Length());
470 CHECK(args[0]->IsInt32()); 476 CHECK(args[0]->IsInt32());
471 CHECK(args[1]->IsObject()); 477 CHECK(args[1]->IsObject());
472 478
473 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); 479 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value();
474 CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id); 480 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( 615 UdpTransportMap::const_iterator iter = udp_transport_map_.find(
610 transport_id); 616 transport_id);
611 if (iter != udp_transport_map_.end()) 617 if (iter != udp_transport_map_.end())
612 return iter->second.get(); 618 return iter->second.get();
613 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); 619 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
614 isolate->ThrowException(v8::Exception::RangeError( 620 isolate->ThrowException(v8::Exception::RangeError(
615 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound))); 621 v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
616 return NULL; 622 return NULL;
617 } 623 }
618 624
625 bool CastStreamingNativeHandler::FrameReceiverConfigFromArg(
626 v8::Isolate* isolate,
627 const v8::Handle<v8::Value>& arg,
628 media::cast::FrameReceiverConfig* config) {
629
630 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
631 scoped_ptr<base::Value> params_value(
632 converter->FromV8Value(arg, context()->v8_context()));
633 if (!params_value) {
634 isolate->ThrowException(v8::Exception::TypeError(
635 v8::String::NewFromUtf8(isolate, kUnableToConvertParams)));
636 return false;
637 }
638 scoped_ptr<RtpReceiverParams> params =
639 RtpReceiverParams::FromValue(*params_value);
640 if (!params) {
641 isolate->ThrowException(v8::Exception::TypeError(
642 v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
643 return false;
644 }
645
646 config->receiver_ssrc = params->receiver_ssrc;
647 config->sender_ssrc = params->sender_ssrc;
648 config->rtp_max_delay_ms = params->max_latency;
649 if (config->rtp_max_delay_ms < 0 || config->rtp_max_delay_ms > 1000) {
650 isolate->ThrowException(v8::Exception::TypeError(
651 v8::String::NewFromUtf8(isolate, kInvalidLatency)));
652 return false;
653 }
654 config->channels = 2;
655 if (params->codec_name == "OPUS") {
656 config->codec = media::cast::CODEC_AUDIO_OPUS;
657 config->rtp_timebase = 48000;
658 config->rtp_payload_type = 127;
659 } else if (params->codec_name == "PCM16") {
660 config->codec = media::cast::CODEC_AUDIO_PCM16;
661 config->rtp_timebase = 48000;
662 config->rtp_payload_type =127;
663 } else if (params->codec_name == "AAC") {
664 config->codec = media::cast::CODEC_AUDIO_AAC;
665 config->rtp_timebase = 48000;
666 config->rtp_payload_type = 127;
667 } else if (params->codec_name == "VP8") {
668 config->codec = media::cast::CODEC_VIDEO_VP8;
669 config->rtp_timebase = 90000;
670 config->rtp_payload_type = 96;
671 } else if (params->codec_name == "H264") {
672 config->codec = media::cast::CODEC_VIDEO_H264;
673 config->rtp_timebase = 90000;
674 config->rtp_payload_type = 96;
675 }
676 if (params->rtp_timebase) {
677 config->rtp_timebase = *params->rtp_timebase;
678 if (config->rtp_timebase < 1000 || config->rtp_timebase > 1000000) {
679 isolate->ThrowException(v8::Exception::TypeError(
680 v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase)));
681 return false;
682 }
683 }
684 if (params->aes_key &&
685 !HexDecode(*params->aes_key, &config->aes_key)) {
686 isolate->ThrowException(v8::Exception::Error(
687 v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
688 return false;
689 }
690 if (params->aes_iv_mask &&
691 !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) {
692 isolate->ThrowException(v8::Exception::Error(
693 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
694 return false;
695 }
696 return true;
697 }
698
699 bool CastStreamingNativeHandler::IPEndPointFromArg(
700 v8::Isolate* isolate,
701 const v8::Handle<v8::Value>& arg,
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 (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
720 isolate->ThrowException(v8::Exception::TypeError(
721 v8::String::NewFromUtf8(isolate, kInvalidDestination)));
722 return false;
723 }
724 *ip_endpoint = net::IPEndPoint(ip, destination->port);
725 return true;
726 }
727
728 void CastStreamingNativeHandler::StartCastRtpReceiver(
729 const v8::FunctionCallbackInfo<v8::Value>& args) {
730 if (args.Length() < 8 || args.Length() > 9 ||
731 !args[0]->IsObject() ||
732 !args[1]->IsObject() ||
733 !args[2]->IsObject() ||
734 !args[3]->IsInt32() ||
735 !args[4]->IsInt32() ||
736 !args[5]->IsNumber() ||
737 !args[6]->IsString()) {
738 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
739 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
740 return;
741 }
742
743 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
744
745 scoped_refptr<CastReceiverSession> session(
746 new CastReceiverSession());
747 media::cast::FrameReceiverConfig audio_config;
748 media::cast::FrameReceiverConfig video_config;
749 net::IPEndPoint local_endpoint;
750 net::IPEndPoint remote_endpoint;
751
752 if (!FrameReceiverConfigFromArg(isolate, args[0], &audio_config) ||
753 !FrameReceiverConfigFromArg(isolate, args[1], &video_config) ||
754 !IPEndPointFromArg(isolate, args[2], &local_endpoint)) {
755 return;
756 }
757
758 const std::string url = *v8::String::Utf8Value(args[7]);
759 blink::WebMediaStream stream =
760 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
761
762 if (stream.isNull()) {
763 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
764 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL)));
765 return;
766 }
767
768 const int max_width = args[3]->ToInt32(args.GetIsolate())->Value();
769 const int max_height = args[4]->ToInt32(args.GetIsolate())->Value();
770 const double fps = args[5]->NumberValue();
771
772 if (fps <= 1) {
773 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
774 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS)));
775 return;
776 }
777
778 media::VideoCaptureFormat capture_format(
779 gfx::Size(max_width, max_height),
780 fps,
781 media::PIXEL_FORMAT_I420);
782
783 video_config.target_frame_rate = fps;
784 audio_config.target_frame_rate = 100;
785
786 media::AudioParameters params(
787 media::AudioParameters::AUDIO_PCM_LINEAR,
788 media::CHANNEL_LAYOUT_STEREO,
789 audio_config.rtp_timebase, // sampling rate
790 16,
791 audio_config.rtp_timebase / audio_config.target_frame_rate);
792
793 if (!params.IsValid()) {
794 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
795 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams)));
796 return;
797 }
798
799 base::DictionaryValue* options = NULL;
800 if (args.Length() >= 10) {
801 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
802 base::Value* options_value =
803 converter->FromV8Value(args[8], context()->v8_context());
804 if (!options_value->IsType(base::Value::TYPE_NULL)) {
805 if (!options_value || !options_value->GetAsDictionary(&options)) {
806 delete options_value;
807 args.GetIsolate()->ThrowException(v8::Exception::TypeError(
808 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
809 return;
810 }
811 }
812 }
813
814 if (!options) {
815 options = new base::DictionaryValue();
816 }
817
818 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent error_callback;
819 error_callback.Reset(args.GetIsolate(),
820 v8::Handle<v8::Function>(args[7].As<v8::Function>()));
821
822 session->Start(
823 audio_config,
824 video_config,
825 local_endpoint,
826 remote_endpoint,
827 make_scoped_ptr(options),
828 capture_format,
829 base::Bind(&CastStreamingNativeHandler::AddTracksToMediaStream,
830 weak_factory_.GetWeakPtr(),
831 url,
832 params),
833 base::Bind(&CastStreamingNativeHandler::CallReceiverErrorCallback,
834 weak_factory_.GetWeakPtr(),
835 error_callback));
836 }
837
838 void CastStreamingNativeHandler::CallReceiverErrorCallback(
839 v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function,
840 const std::string& error_message) {
841 v8::Isolate* isolate = context()->v8_context()->GetIsolate();
842 v8::Handle<v8::Value> arg = v8::String::NewFromUtf8(isolate,
843 error_message.data(),
844 v8::String::kNormalString,
845 error_message.size());
846 context()->CallFunction(
847 v8::Local<v8::Function>::New(isolate, function), 1, &arg);
848 }
849
850
851 void CastStreamingNativeHandler::AddTracksToMediaStream(
852 const std::string& url,
853 const media::AudioParameters& params,
854 scoped_refptr<media::AudioCapturerSource> audio,
855 scoped_ptr<media::VideoCapturerSource> video) {
856 content::AddAudioTrackToMediaStream(audio, params, true, true, url);
857 content::AddVideoTrackToMediaStream(video.Pass(), true, true, url);
858 }
859
619 } // namespace extensions 860 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698