Home | History | Annotate | Download | only in extensions
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/renderer/extensions/cast_streaming_native_handler.h"
      6 
      7 #include <functional>
      8 
      9 #include "base/logging.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
     12 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
     13 #include "chrome/renderer/extensions/chrome_v8_context.h"
     14 #include "chrome/renderer/media/cast_rtp_stream.h"
     15 #include "chrome/renderer/media/cast_session.h"
     16 #include "chrome/renderer/media/cast_udp_transport.h"
     17 #include "content/public/renderer/v8_value_converter.h"
     18 #include "net/base/host_port_pair.h"
     19 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
     20 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
     21 
     22 using content::V8ValueConverter;
     23 
     24 // Extension types.
     25 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams;
     26 using extensions::api::cast_streaming_rtp_stream::RtpCaps;
     27 using extensions::api::cast_streaming_rtp_stream::RtpParams;
     28 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams;
     29 using extensions::api::cast_streaming_udp_transport::UdpParams;
     30 
     31 namespace extensions {
     32 
     33 namespace {
     34 const char kRtpStreamNotFound[] = "The RTP stream cannot be found";
     35 const char kUdpTransportNotFound[] = "The UDP transport cannot be found";
     36 const char kInvalidUdpParams[] = "Invalid UDP params";
     37 const char kInvalidRtpParams[] = "Invalid value for RTP params";
     38 const char kUnableToConvertArgs[] = "Unable to convert arguments";
     39 const char kUnableToConvertParams[] = "Unable to convert params";
     40 
     41 // These helper methods are used to convert between Extension API
     42 // types and Cast types.
     43 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params,
     44                                CastCodecSpecificParams* cast_params) {
     45   cast_params->key = ext_params.key;
     46   cast_params->value = ext_params.value;
     47 }
     48 
     49 void FromCastCodecSpecificParams(const CastCodecSpecificParams& cast_params,
     50                                  CodecSpecificParams* ext_params) {
     51   ext_params->key = cast_params.key;
     52   ext_params->value = cast_params.value;
     53 }
     54 
     55 void ToCastRtpPayloadParams(const RtpPayloadParams& ext_params,
     56                             CastRtpPayloadParams* cast_params) {
     57   cast_params->payload_type = ext_params.payload_type;
     58   cast_params->codec_name = ext_params.codec_name;
     59   cast_params->ssrc = ext_params.ssrc ? *ext_params.ssrc : 0;
     60   cast_params->clock_rate = ext_params.clock_rate ? *ext_params.clock_rate : 0;
     61   cast_params->min_bitrate =
     62       ext_params.min_bitrate ? *ext_params.min_bitrate : 0;
     63   cast_params->max_bitrate =
     64       ext_params.max_bitrate ? *ext_params.max_bitrate : 0;
     65   cast_params->channels = ext_params.channels ? *ext_params.channels : 0;
     66   cast_params->width = ext_params.width ? *ext_params.width : 0;
     67   cast_params->height = ext_params.height ? *ext_params.height : 0;
     68   for (size_t i = 0; i < ext_params.codec_specific_params.size(); ++i) {
     69     CastCodecSpecificParams cast_codec_params;
     70     ToCastCodecSpecificParams(*ext_params.codec_specific_params[i],
     71                               &cast_codec_params);
     72     cast_params->codec_specific_params.push_back(cast_codec_params);
     73   }
     74 }
     75 
     76 void FromCastRtpPayloadParams(const CastRtpPayloadParams& cast_params,
     77                               RtpPayloadParams* ext_params) {
     78   ext_params->payload_type = cast_params.payload_type;
     79   ext_params->codec_name = cast_params.codec_name;
     80   if (cast_params.ssrc)
     81     ext_params->ssrc.reset(new int(cast_params.ssrc));
     82   if (cast_params.clock_rate)
     83     ext_params->clock_rate.reset(new int(cast_params.clock_rate));
     84   if (cast_params.min_bitrate)
     85     ext_params->min_bitrate.reset(new int(cast_params.min_bitrate));
     86   if (cast_params.max_bitrate)
     87     ext_params->max_bitrate.reset(new int(cast_params.max_bitrate));
     88   if (cast_params.channels)
     89     ext_params->channels.reset(new int(cast_params.channels));
     90   if (cast_params.width)
     91     ext_params->width.reset(new int(cast_params.width));
     92   if (cast_params.height)
     93     ext_params->height.reset(new int(cast_params.height));
     94   for (size_t i = 0; i < cast_params.codec_specific_params.size(); ++i) {
     95     linked_ptr<CodecSpecificParams> ext_codec_params(
     96         new CodecSpecificParams());
     97     FromCastCodecSpecificParams(cast_params.codec_specific_params[i],
     98                                 ext_codec_params.get());
     99     ext_params->codec_specific_params.push_back(ext_codec_params);
    100   }
    101 }
    102 
    103 void FromCastRtpCaps(const CastRtpCaps& cast_caps, RtpCaps* ext_caps) {
    104   std::copy(cast_caps.rtcp_features.begin(), cast_caps.rtcp_features.end(),
    105             ext_caps->rtcp_features.begin());
    106   for (size_t i = 0; i < cast_caps.payloads.size(); ++i) {
    107     linked_ptr<RtpPayloadParams> ext_payload_params(new RtpPayloadParams());
    108     FromCastRtpPayloadParams(cast_caps.payloads[i], ext_payload_params.get());
    109     ext_caps->payloads.push_back(ext_payload_params);
    110   }
    111 }
    112 
    113 void ToCastRtpParams(const RtpParams& ext_params, CastRtpParams* cast_params) {
    114   std::copy(ext_params.rtcp_features.begin(), ext_params.rtcp_features.end(),
    115             cast_params->rtcp_features.begin());
    116   for (size_t i = 0; i < ext_params.payloads.size(); ++i) {
    117     CastRtpPayloadParams cast_payload_params;
    118     ToCastRtpPayloadParams(*ext_params.payloads[i], &cast_payload_params);
    119     cast_params->payloads.push_back(cast_payload_params);
    120   }
    121 }
    122 
    123 }  // namespace
    124 
    125 CastStreamingNativeHandler::CastStreamingNativeHandler(ChromeV8Context* context)
    126     : ObjectBackedNativeHandler(context),
    127       last_transport_id_(0),
    128       weak_factory_(this) {
    129   RouteFunction("CreateSession",
    130       base::Bind(&CastStreamingNativeHandler::CreateCastSession,
    131                  base::Unretained(this)));
    132   RouteFunction("DestroyCastRtpStream",
    133       base::Bind(&CastStreamingNativeHandler::DestroyCastRtpStream,
    134                  base::Unretained(this)));
    135   RouteFunction("GetCapsCastRtpStream",
    136       base::Bind(&CastStreamingNativeHandler::GetCapsCastRtpStream,
    137                  base::Unretained(this)));
    138   RouteFunction("StartCastRtpStream",
    139       base::Bind(&CastStreamingNativeHandler::StartCastRtpStream,
    140                  base::Unretained(this)));
    141   RouteFunction("StopCastRtpStream",
    142       base::Bind(&CastStreamingNativeHandler::StopCastRtpStream,
    143                  base::Unretained(this)));
    144   RouteFunction("DestroyCastUdpTransport",
    145       base::Bind(&CastStreamingNativeHandler::DestroyCastUdpTransport,
    146                  base::Unretained(this)));
    147   RouteFunction("StartCastUdpTransport",
    148       base::Bind(&CastStreamingNativeHandler::StartCastUdpTransport,
    149                  base::Unretained(this)));
    150 }
    151 
    152 CastStreamingNativeHandler::~CastStreamingNativeHandler() {
    153 }
    154 
    155 void CastStreamingNativeHandler::CreateCastSession(
    156     const v8::FunctionCallbackInfo<v8::Value>& args) {
    157   CHECK_EQ(3, args.Length());
    158   CHECK(args[0]->IsObject());
    159   CHECK(args[1]->IsObject());
    160   CHECK(args[2]->IsFunction());
    161 
    162   blink::WebDOMMediaStreamTrack track1 =
    163       blink::WebDOMMediaStreamTrack::fromV8Value(args[0]);
    164   if (track1.isNull())
    165     return;
    166   blink::WebDOMMediaStreamTrack track2 =
    167       blink::WebDOMMediaStreamTrack::fromV8Value(args[1]);
    168   if (track2.isNull())
    169     return;
    170 
    171   scoped_refptr<CastSession> session(new CastSession());
    172   scoped_ptr<CastRtpStream> stream1(
    173       new CastRtpStream(track1.component(), session));
    174   scoped_ptr<CastRtpStream> stream2(
    175       new CastRtpStream(track2.component(), session));
    176   scoped_ptr<CastUdpTransport> udp_transport(
    177       new CastUdpTransport(session));
    178 
    179   create_callback_.reset(args[2].As<v8::Function>());
    180 
    181   base::MessageLoop::current()->PostTask(
    182       FROM_HERE,
    183       base::Bind(
    184           &CastStreamingNativeHandler::CallCreateCallback,
    185           weak_factory_.GetWeakPtr(),
    186           base::Passed(&stream1),
    187           base::Passed(&stream2),
    188           base::Passed(&udp_transport)));
    189 }
    190 
    191 void CastStreamingNativeHandler::CallCreateCallback(
    192     scoped_ptr<CastRtpStream> stream1,
    193     scoped_ptr<CastRtpStream> stream2,
    194     scoped_ptr<CastUdpTransport> udp_transport) {
    195   v8::HandleScope handle_scope(context()->isolate());
    196   v8::Context::Scope context_scope(context()->v8_context());
    197 
    198   const int stream1_id = last_transport_id_++;
    199   rtp_stream_map_[stream1_id] =
    200       linked_ptr<CastRtpStream>(stream1.release());
    201   const int stream2_id = last_transport_id_++;
    202   rtp_stream_map_[stream2_id] =
    203       linked_ptr<CastRtpStream>(stream2.release());
    204   const int udp_id = last_transport_id_++;
    205   udp_transport_map_[udp_id] =
    206       linked_ptr<CastUdpTransport>(udp_transport.release());
    207 
    208   v8::Handle<v8::Value> callback_args[3];
    209   callback_args[0] = v8::Integer::New(stream1_id);
    210   callback_args[1] = v8::Integer::New(stream2_id);
    211   callback_args[2] = v8::Integer::New(udp_id);
    212   context()->CallFunction(create_callback_.NewHandle(context()->isolate()),
    213                           3, callback_args);
    214   create_callback_.reset();
    215 }
    216 
    217 void CastStreamingNativeHandler::DestroyCastRtpStream(
    218     const v8::FunctionCallbackInfo<v8::Value>& args) {
    219   CHECK_EQ(1, args.Length());
    220   CHECK(args[0]->IsInt32());
    221 
    222   const int transport_id = args[0]->ToInt32()->Value();
    223   if (!GetRtpStreamOrThrow(transport_id))
    224     return;
    225   rtp_stream_map_.erase(transport_id);
    226 }
    227 
    228 void CastStreamingNativeHandler::GetCapsCastRtpStream(
    229     const v8::FunctionCallbackInfo<v8::Value>& args) {
    230   CHECK_EQ(1, args.Length());
    231   CHECK(args[0]->IsInt32());
    232 
    233   const int transport_id = args[0]->ToInt32()->Value();
    234   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
    235   if (!transport)
    236     return;
    237 
    238   CastRtpCaps cast_caps = transport->GetCaps();
    239   RtpCaps caps;
    240   FromCastRtpCaps(cast_caps, &caps);
    241 
    242   scoped_ptr<base::DictionaryValue> caps_value = caps.ToValue();
    243   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
    244   args.GetReturnValue().Set(converter->ToV8Value(
    245       caps_value.get(), context()->v8_context()));
    246 }
    247 
    248 void CastStreamingNativeHandler::StartCastRtpStream(
    249     const v8::FunctionCallbackInfo<v8::Value>& args) {
    250   CHECK_EQ(2, args.Length());
    251   CHECK(args[0]->IsInt32());
    252   CHECK(args[1]->IsObject());
    253 
    254   const int transport_id = args[0]->ToInt32()->Value();
    255   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
    256   if (!transport)
    257     return;
    258 
    259   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
    260   scoped_ptr<Value> params_value(
    261       converter->FromV8Value(args[1], context()->v8_context()));
    262   if (!params_value) {
    263     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
    264         v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams)));
    265     return;
    266   }
    267   scoped_ptr<RtpParams> params = RtpParams::FromValue(*params_value);
    268   if (!params) {
    269     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
    270         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams)));
    271     return;
    272   }
    273 
    274   CastRtpCaps cast_params;
    275   ToCastRtpParams(*params, &cast_params);
    276   transport->Start(cast_params);
    277 }
    278 
    279 void CastStreamingNativeHandler::StopCastRtpStream(
    280     const v8::FunctionCallbackInfo<v8::Value>& args) {
    281   CHECK_EQ(1, args.Length());
    282   CHECK(args[0]->IsInt32());
    283 
    284   const int transport_id = args[0]->ToInt32()->Value();
    285   CastRtpStream* transport = GetRtpStreamOrThrow(transport_id);
    286   if (!transport)
    287     return;
    288   transport->Stop();
    289 }
    290 
    291 void CastStreamingNativeHandler::DestroyCastUdpTransport(
    292     const v8::FunctionCallbackInfo<v8::Value>& args) {
    293   CHECK_EQ(1, args.Length());
    294   CHECK(args[0]->IsInt32());
    295 
    296   const int transport_id = args[0]->ToInt32()->Value();
    297   if (!GetUdpTransportOrThrow(transport_id))
    298     return;
    299   udp_transport_map_.erase(transport_id);
    300 }
    301 
    302 void CastStreamingNativeHandler::StartCastUdpTransport(
    303     const v8::FunctionCallbackInfo<v8::Value>& args) {
    304   CHECK_EQ(2, args.Length());
    305   CHECK(args[0]->IsInt32());
    306   CHECK(args[1]->IsObject());
    307 
    308   const int transport_id = args[0]->ToInt32()->Value();
    309   CastUdpTransport* transport = GetUdpTransportOrThrow(transport_id);
    310   if (!transport)
    311     return;
    312 
    313   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
    314   scoped_ptr<Value> udp_params_value(
    315       converter->FromV8Value(args[1], context()->v8_context()));
    316   if (!udp_params_value) {
    317     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
    318         v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
    319     return;
    320   }
    321   scoped_ptr<UdpParams> udp_params = UdpParams::FromValue(*udp_params_value);
    322   if (!udp_params) {
    323     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
    324         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidUdpParams)));
    325     return;
    326   }
    327   net::IPAddressNumber ip;
    328   if (!net::ParseIPLiteralToNumber(udp_params->address, &ip)) {
    329     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
    330         v8::String::NewFromUtf8(args.GetIsolate(), kInvalidUdpParams)));
    331     return;
    332   }
    333   transport->Start(net::IPEndPoint(ip, udp_params->port));
    334 }
    335 
    336 CastRtpStream* CastStreamingNativeHandler::GetRtpStreamOrThrow(
    337     int transport_id) const {
    338   RtpStreamMap::const_iterator iter = rtp_stream_map_.find(
    339       transport_id);
    340   if (iter != rtp_stream_map_.end())
    341     return iter->second.get();
    342   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
    343   isolate->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
    344       isolate, kRtpStreamNotFound)));
    345   return NULL;
    346 }
    347 
    348 CastUdpTransport* CastStreamingNativeHandler::GetUdpTransportOrThrow(
    349     int transport_id) const {
    350   UdpTransportMap::const_iterator iter = udp_transport_map_.find(
    351       transport_id);
    352   if (iter != udp_transport_map_.end())
    353     return iter->second.get();
    354   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
    355   isolate->ThrowException(v8::Exception::RangeError(
    356       v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
    357   return NULL;
    358 }
    359 
    360 }  // namespace extensions
    361