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

Unified 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, 10 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 side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/extensions/cast_streaming_native_handler.cc
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc
index a10a15446d58ba9b441b07204e2cdd3e4137e573..63cfbf2cff3abe4cbf64ac57bcf8f408df22a78c 100644
--- a/chrome/renderer/extensions/cast_streaming_native_handler.cc
+++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -10,20 +10,29 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "chrome/common/extensions/api/cast_streaming_receiver_session.h"
#include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
#include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
+#include "chrome/renderer/media/cast_receiver_session.h"
#include "chrome/renderer/media/cast_rtp_stream.h"
#include "chrome/renderer/media/cast_session.h"
#include "chrome/renderer/media/cast_udp_transport.h"
#include "content/public/child/v8_value_converter.h"
+#include "content/public/renderer/media_stream_api.h"
#include "extensions/renderer/script_context.h"
+#include "media/audio/audio_parameters.h"
#include "net/base/host_port_pair.h"
+#include "third_party/WebKit/public/platform/WebMediaStream.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
+#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
+#include "url/gurl.h"
using content::V8ValueConverter;
// Extension types.
+using extensions::api::cast_streaming_receiver_session::RtpReceiverParams;
using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams;
using extensions::api::cast_streaming_rtp_stream::RtpParams;
using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams;
@@ -32,13 +41,16 @@ using extensions::api::cast_streaming_udp_transport::IPEndPoint;
namespace extensions {
namespace {
-const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
-const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
+const char kInvalidAesIvMask[] = "Invalid value for AES IV mask";
+const char kInvalidAesKey[] = "Invalid value for AES key";
+const char kInvalidAudioParams[] = "Invalid audio params";
const char kInvalidDestination[] = "Invalid destination";
+const char kInvalidFPS[] = "Invalid FPS";
+const char kInvalidMediaStreamURL[] = "Invalid MediaStream URL";
const char kInvalidRtpParams[] = "Invalid value for RTP params";
-const char kInvalidAesKey[] = "Invalid value for AES key";
-const char kInvalidAesIvMask[] = "Invalid value for AES IV mask";
const char kInvalidStreamArgs[] = "Invalid stream arguments";
+const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
+const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
const char kUnableToConvertArgs[] = "Unable to convert arguments";
const char kUnableToConvertParams[] = "Unable to convert params";
@@ -199,6 +211,9 @@ CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext* context)
RouteFunction("GetStats",
base::Bind(&CastStreamingNativeHandler::GetStats,
base::Unretained(this)));
+ RouteFunction("StartCastRtpReceiver",
+ base::Bind(&CastStreamingNativeHandler::StartCastRtpReceiver,
+ base::Unretained(this)));
}
CastStreamingNativeHandler::~CastStreamingNativeHandler() {
@@ -440,28 +455,18 @@ void CastStreamingNativeHandler::SetDestinationCastUdpTransport(
if (!transport)
return;
- scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
- scoped_ptr<base::Value> destination_value(
- converter->FromV8Value(args[1], context()->v8_context()));
- if (!destination_value) {
- args.GetIsolate()->ThrowException(v8::Exception::TypeError(
- v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
+ net::IPEndPoint dest;
+ if (!IPEndPointFromArg(args.GetIsolate(),
+ args[1],
+ false,
+ &dest)) {
return;
}
- scoped_ptr<IPEndPoint> destination =
- IPEndPoint::FromValue(*destination_value);
- if (!destination) {
- args.GetIsolate()->ThrowException(v8::Exception::TypeError(
- v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
- return;
- }
- net::IPAddressNumber ip;
- if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
- args.GetIsolate()->ThrowException(v8::Exception::TypeError(
- v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination)));
- return;
- }
- transport->SetDestination(net::IPEndPoint(ip, destination->port));
+ transport->SetDestination(
+ dest,
+ base::Bind(&CastStreamingNativeHandler::CallErrorCallback,
+ weak_factory_.GetWeakPtr(),
+ transport_id));
}
void CastStreamingNativeHandler::SetOptionsCastUdpTransport(
@@ -616,4 +621,242 @@ CastUdpTransport* CastStreamingNativeHandler::GetUdpTransportOrThrow(
return NULL;
}
+bool CastStreamingNativeHandler::FrameReceiverConfigFromArg(
+ v8::Isolate* isolate,
+ const v8::Handle<v8::Value>& arg,
+ media::cast::FrameReceiverConfig* config) {
+
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ scoped_ptr<base::Value> params_value(
+ converter->FromV8Value(arg, context()->v8_context()));
+ if (!params_value) {
+ isolate->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(isolate, kUnableToConvertParams)));
+ return false;
+ }
+ scoped_ptr<RtpReceiverParams> params =
+ RtpReceiverParams::FromValue(*params_value);
+ if (!params) {
+ isolate->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+ return false;
+ }
+
+ 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.
+ config->sender_ssrc = params->ssrc;
+ config->rtp_max_delay_ms = params->max_latency;
+ 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.
+ isolate->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+ return false;
+ }
+ config->channels = 2;
+ if (params->codec_name == "OPUS") {
+ config->codec = media::cast::CODEC_AUDIO_OPUS;
+ config->rtp_timebase = 48000;
+ config->rtp_payload_type = 127;
+ } else if (params->codec_name == "PCM16") {
+ config->codec = media::cast::CODEC_AUDIO_PCM16;
+ config->rtp_timebase = 48000;
+ config->rtp_payload_type =127;
+ } else if (params->codec_name == "AAC") {
+ config->codec = media::cast::CODEC_AUDIO_AAC;
+ config->rtp_timebase = 48000;
+ config->rtp_payload_type = 127;
+ } else if (params->codec_name == "VP8") {
+ config->codec = media::cast::CODEC_VIDEO_VP8;
+ config->rtp_timebase = 90000;
+ config->rtp_payload_type = 96;
+ } else if (params->codec_name == "H264") {
+ config->codec = media::cast::CODEC_VIDEO_H264;
+ config->rtp_timebase = 90000;
+ config->rtp_payload_type = 96;
+ }
+ if (params->rtp_timebase) {
+ config->rtp_timebase = *params->rtp_timebase;
+ 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.
+ isolate->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+ return false;
+ }
+ }
+ if (params->aes_key &&
+ !HexDecode(*params->aes_key, &config->aes_key)) {
+ isolate->ThrowException(v8::Exception::Error(
+ v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
+ return false;
+ }
+ if (params->aes_iv_mask &&
+ !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) {
+ isolate->ThrowException(v8::Exception::Error(
+ v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
+ return false;
+ }
+ return true;
+}
+
+bool CastStreamingNativeHandler::IPEndPointFromArg(
+ v8::Isolate* isolate,
+ const v8::Handle<v8::Value>& arg,
+ bool empty_ok,
+ net::IPEndPoint* ip_endpoint) {
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ scoped_ptr<base::Value> destination_value(
+ converter->FromV8Value(arg, context()->v8_context()));
+ if (!destination_value) {
+ isolate->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
+ return false;
+ }
+ scoped_ptr<IPEndPoint> destination =
+ IPEndPoint::FromValue(*destination_value);
+ if (!destination) {
+ isolate->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(isolate, kInvalidDestination)));
+ return false;
+ }
+ net::IPAddressNumber ip;
+ 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
+ if (!net::ParseIPLiteralToNumber(destination->address, &ip)) {
+ isolate->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(isolate, kInvalidDestination)));
+ return false;
+ }
+ }
+ *ip_endpoint = net::IPEndPoint(ip, destination->port);
+ return true;
+}
+
+void CastStreamingNativeHandler::StartCastRtpReceiver(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ if (args.Length() < 8 || args.Length() > 9 ||
+ !args[0]->IsObject() ||
+ !args[1]->IsObject() ||
+ !args[2]->IsObject() ||
+ !args[3]->IsInt32() ||
+ !args[4]->IsInt32() ||
+ !args[5]->IsNumber() ||
+ !args[6]->IsString()) {
+ args.GetIsolate()->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
+ return;
+ }
+
+ v8::Isolate* isolate = context()->v8_context()->GetIsolate();
+
+ scoped_refptr<CastReceiverSession> session(
+ new CastReceiverSession());
+ media::cast::FrameReceiverConfig audio_config;
+ media::cast::FrameReceiverConfig video_config;
+ net::IPEndPoint local_endpoint;
+ net::IPEndPoint remote_endpoint;
+
+ if (!FrameReceiverConfigFromArg(isolate, args[0], &audio_config) ||
+ !FrameReceiverConfigFromArg(isolate, args[1], &video_config) ||
+ !IPEndPointFromArg(isolate, args[2], false, &local_endpoint)) {
+ return;
+ }
+
+ const std::string url = *v8::String::Utf8Value(args[7]);
+ blink::WebMediaStream stream =
+ blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
+
+ if (stream.isNull()) {
+ args.GetIsolate()->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL)));
+ return;
+ }
+
+ const int max_width = args[3]->ToInt32(args.GetIsolate())->Value();
+ const int max_height = args[4]->ToInt32(args.GetIsolate())->Value();
+ const double fps = args[5]->NumberValue();
+
+ if (fps <= 1) {
+ args.GetIsolate()->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS)));
+ return;
+ }
+
+ media::VideoCaptureFormat capture_format(
+ gfx::Size(max_width, max_height),
+ fps,
+ media::PIXEL_FORMAT_I420);
+
+ video_config.target_frame_rate = fps;
+ audio_config.target_frame_rate = 100;
+
+ media::AudioParameters params(
+ media::AudioParameters::AUDIO_PCM_LINEAR,
+ media::CHANNEL_LAYOUT_STEREO,
+ audio_config.rtp_timebase, // sampling rate
+ 16,
+ audio_config.rtp_timebase / audio_config.target_frame_rate);
+
+ if (!params.IsValid()) {
+ args.GetIsolate()->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams)));
+ return;
+ }
+
+ base::DictionaryValue* options = NULL;
+ if (args.Length() >= 10) {
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ base::Value* options_value =
+ converter->FromV8Value(args[8], context()->v8_context());
+ if (!options_value->IsType(base::Value::TYPE_NULL)) {
+ if (!options_value || !options_value->GetAsDictionary(&options)) {
+ delete options_value;
+ args.GetIsolate()->ThrowException(v8::Exception::TypeError(
+ v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
+ return;
+ }
+ }
+ }
+
+ if (!options) {
+ options = new base::DictionaryValue();
+ }
+
+ v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent error_callback;
+ error_callback.Reset(args.GetIsolate(),
+ v8::Handle<v8::Function>(args[7].As<v8::Function>()));
+
+ session->Start(
+ audio_config,
+ video_config,
+ local_endpoint,
+ remote_endpoint,
+ make_scoped_ptr(options),
+ capture_format,
+ base::Bind(&CastStreamingNativeHandler::AddTracksToMediaStream,
+ weak_factory_.GetWeakPtr(),
+ url,
+ params),
+ base::Bind(&CastStreamingNativeHandler::CallReceiverErrorCallback,
+ weak_factory_.GetWeakPtr(),
+ error_callback));
+}
+
+void CastStreamingNativeHandler::CallReceiverErrorCallback(
+ v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function,
+ const std::string& error_message) {
+ v8::Isolate* isolate = context()->v8_context()->GetIsolate();
+ v8::Handle<v8::Value> arg = v8::String::NewFromUtf8(isolate,
+ error_message.data(),
+ v8::String::kNormalString,
+ error_message.size());
+ context()->CallFunction(
+ v8::Local<v8::Function>::New(isolate, function), 1, &arg);
+}
+
+
+void CastStreamingNativeHandler::AddTracksToMediaStream(
+ const std::string& url,
+ const media::AudioParameters& params,
+ scoped_refptr<media::AudioCapturerSource> audio,
+ scoped_ptr<media::VideoCapturerSource> video) {
+ content::AddAudioTrackToMediaStream(audio, params, true, true, url);
+ content::AddVideoTrackToMediaStream(video.Pass(), true, true, url);
+}
+
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698