Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / media / cast_session_delegate.cc
index 2562121..9514e13 100644 (file)
@@ -4,14 +4,19 @@
 
 #include "chrome/renderer/media/cast_session_delegate.h"
 
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop_proxy.h"
-#include "content/public/renderer/p2p_socket_client.h"
+#include "chrome/renderer/media/cast_threads.h"
+#include "chrome/renderer/media/cast_transport_sender_ipc.h"
 #include "content/public/renderer/render_thread.h"
 #include "media/cast/cast_config.h"
 #include "media/cast/cast_environment.h"
 #include "media/cast/cast_sender.h"
+#include "media/cast/logging/log_serializer.h"
 #include "media/cast/logging/logging_defines.h"
+#include "media/cast/logging/proto/raw_events.pb.h"
+#include "media/cast/logging/raw_event_subscriber_bundle.h"
 #include "media/cast/transport/cast_transport_config.h"
 #include "media/cast/transport/cast_transport_sender.h"
 
@@ -20,59 +25,14 @@ using media::cast::CastEnvironment;
 using media::cast::CastSender;
 using media::cast::VideoSenderConfig;
 
-namespace {
-
-// This is a dummy class that does nothing. This is needed temporarily
-// to enable tests for cast.streaming extension APIs.
-// The real implementation of CastTransportSender is to use IPC to send
-// data to the browser process.
-// See crbug.com/327482 for more details.
-class DummyTransport : public media::cast::transport::CastTransportSender {
- public:
-  DummyTransport() {}
-  virtual ~DummyTransport() {}
-
-  // CastTransportSender implementations.
-  virtual void SetPacketReceiver(
-      scoped_refptr<
-        media::cast::transport::PacketReceiver> packet_receiver) OVERRIDE {}
-  virtual void InsertCodedAudioFrame(
-      const media::cast::transport::EncodedAudioFrame* audio_frame,
-      const base::TimeTicks& recorded_time) OVERRIDE {}
-  virtual void InsertCodedVideoFrame(
-      const media::cast::transport::EncodedVideoFrame* video_frame,
-      const base::TimeTicks& capture_time) OVERRIDE {}
-  virtual void SendRtcpFromRtpSender(
-      uint32 packet_type_flags,
-      const media::cast::transport::RtcpSenderInfo& sender_info,
-      const media::cast::transport::RtcpDlrrReportBlock& dlrr,
-      const media::cast::transport::RtcpSenderLogMessage& sender_log,
-      uint32 sending_ssrc,
-      const std::string& c_name) OVERRIDE {}
-  virtual void ResendPackets(
-      bool is_audio,
-      const media::cast::transport::MissingFramesAndPacketsMap& missing_packets)
-      OVERRIDE {}
-  virtual void RtpAudioStatistics(
-      const base::TimeTicks& now,
-      media::cast::transport::RtcpSenderInfo* sender_info) OVERRIDE {}
-  virtual void RtpVideoStatistics(
-      const base::TimeTicks& now,
-      media::cast::transport::RtcpSenderInfo* sender_info) OVERRIDE {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DummyTransport);
-};
-
-}  // namespace
+static base::LazyInstance<CastThreads> g_cast_threads =
+    LAZY_INSTANCE_INITIALIZER;
 
 CastSessionDelegate::CastSessionDelegate()
-    : audio_encode_thread_("CastAudioEncodeThread"),
-      video_encode_thread_("CastVideoEncodeThread"),
-      audio_configured_(false),
-      video_configured_(false),
-      io_message_loop_proxy_(
-          content::RenderThread::Get()->GetIOMessageLoopProxy()) {
+    : io_message_loop_proxy_(
+          content::RenderThread::Get()->GetIOMessageLoopProxy()),
+      weak_factory_(this) {
+  DCHECK(io_message_loop_proxy_);
 }
 
 CastSessionDelegate::~CastSessionDelegate() {
@@ -81,62 +41,185 @@ CastSessionDelegate::~CastSessionDelegate() {
 
 void CastSessionDelegate::StartAudio(
     const AudioSenderConfig& config,
-    const FrameInputAvailableCallback& callback) {
+    const AudioFrameInputAvailableCallback& callback,
+    const ErrorCallback& error_callback) {
   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
 
-  audio_configured_ = true;
-  audio_config_ = config;
-  frame_input_available_callbacks_.push_back(callback);
-  StartSendingInternal();
+  if (!cast_transport_ || !cast_sender_) {
+    error_callback.Run("Destination not set.");
+    return;
+  }
+
+  audio_frame_input_available_callback_ = callback;
+  cast_sender_->InitializeAudio(
+      config,
+      base::Bind(&CastSessionDelegate::InitializationResultCB,
+                 weak_factory_.GetWeakPtr()));
 }
 
 void CastSessionDelegate::StartVideo(
     const VideoSenderConfig& config,
-    const FrameInputAvailableCallback& callback) {
+    const VideoFrameInputAvailableCallback& callback,
+    const ErrorCallback& error_callback,
+    const media::cast::CreateVideoEncodeAcceleratorCallback& create_vea_cb,
+    const media::cast::CreateVideoEncodeMemoryCallback&
+        create_video_encode_mem_cb) {
   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
 
-  video_configured_ = true;
-  video_config_ = config;
-  frame_input_available_callbacks_.push_back(callback);
-  StartSendingInternal();
-}
+  if (!cast_transport_ || !cast_sender_) {
+    error_callback.Run("Destination not set.");
+    return;
+  }
 
-void CastSessionDelegate::StartSendingInternal() {
-  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+  video_frame_input_available_callback_ = callback;
 
-  if (cast_environment_)
-    return;
-  if (!audio_configured_ || !video_configured_)
-    return;
+  cast_sender_->InitializeVideo(
+      config,
+      base::Bind(&CastSessionDelegate::InitializationResultCB,
+                 weak_factory_.GetWeakPtr()),
+      create_vea_cb,
+      create_video_encode_mem_cb);
+}
 
-  cast_transport_.reset(new DummyTransport());
-  audio_encode_thread_.Start();
-  video_encode_thread_.Start();
+void CastSessionDelegate::StartUDP(const net::IPEndPoint& remote_endpoint) {
+  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
 
   // CastSender uses the renderer's IO thread as the main thread. This reduces
   // thread hopping for incoming video frames and outgoing network packets.
-  // There's no need to decode so no thread assigned for decoding.
-  // Get default logging: All disabled.
   cast_environment_ = new CastEnvironment(
       scoped_ptr<base::TickClock>(new base::DefaultTickClock()).Pass(),
       base::MessageLoopProxy::current(),
-      audio_encode_thread_.message_loop_proxy(),
-      NULL,
-      video_encode_thread_.message_loop_proxy(),
-      NULL,
-      base::MessageLoopProxy::current(),
-      media::cast::GetDefaultCastSenderLoggingConfig());
-
-  cast_sender_.reset(CastSender::CreateCastSender(
-      cast_environment_,
-      audio_config_,
-      video_config_,
-      NULL,
-      cast_transport_.get()));
-
-  for (size_t i = 0; i < frame_input_available_callbacks_.size(); ++i) {
-    frame_input_available_callbacks_[i].Run(
-        cast_sender_->frame_input());
+      g_cast_threads.Get().GetAudioEncodeMessageLoopProxy(),
+      g_cast_threads.Get().GetVideoEncodeMessageLoopProxy());
+
+  event_subscribers_.reset(
+      new media::cast::RawEventSubscriberBundle(cast_environment_));
+
+  // Rationale for using unretained: The callback cannot be called after the
+  // destruction of CastTransportSenderIPC, and they both share the same thread.
+  cast_transport_.reset(new CastTransportSenderIPC(
+      remote_endpoint,
+      base::Bind(&CastSessionDelegate::StatusNotificationCB,
+                 base::Unretained(this)),
+      base::Bind(&CastSessionDelegate::LogRawEvents, base::Unretained(this))));
+
+  cast_sender_ = CastSender::Create(cast_environment_, cast_transport_.get());
+  cast_transport_->SetPacketReceiver(cast_sender_->packet_receiver());
+}
+
+void CastSessionDelegate::ToggleLogging(bool is_audio, bool enable) {
+  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+  if (!event_subscribers_.get())
+    return;
+
+  if (enable)
+    event_subscribers_->AddEventSubscribers(is_audio);
+  else
+    event_subscribers_->RemoveEventSubscribers(is_audio);
+}
+
+void CastSessionDelegate::GetEventLogsAndReset(
+    bool is_audio,
+    const EventLogsCallback& callback) {
+  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+
+  if (!event_subscribers_.get()) {
+    callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
+    return;
+  }
+
+  media::cast::EncodingEventSubscriber* subscriber =
+      event_subscribers_->GetEncodingEventSubscriber(is_audio);
+  if (!subscriber) {
+    callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
+    return;
+  }
+
+  media::cast::proto::LogMetadata metadata;
+  media::cast::FrameEventList frame_events;
+  media::cast::PacketEventList packet_events;
+
+  subscriber->GetEventsAndReset(&metadata, &frame_events, &packet_events);
+
+  scoped_ptr<char[]> serialized_log(new char[media::cast::kMaxSerializedBytes]);
+  int output_bytes;
+  bool success = media::cast::SerializeEvents(metadata,
+                                              frame_events,
+                                              packet_events,
+                                              true,
+                                              media::cast::kMaxSerializedBytes,
+                                              serialized_log.get(),
+                                              &output_bytes);
+
+  if (!success) {
+    VLOG(2) << "Failed to serialize event log.";
+    callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
+    return;
+  }
+
+  DVLOG(2) << "Serialized log length: " << output_bytes;
+
+  scoped_ptr<base::BinaryValue> blob(
+      new base::BinaryValue(serialized_log.Pass(), output_bytes));
+  callback.Run(blob.Pass());
+}
+
+void CastSessionDelegate::GetStatsAndReset(bool is_audio,
+                                           const StatsCallback& callback) {
+  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+
+  if (!event_subscribers_.get()) {
+    callback.Run(make_scoped_ptr(new base::DictionaryValue).Pass());
+    return;
+  }
+
+  media::cast::StatsEventSubscriber* subscriber =
+      event_subscribers_->GetStatsEventSubscriber(is_audio);
+  if (!subscriber) {
+    callback.Run(make_scoped_ptr(new base::DictionaryValue).Pass());
+    return;
+  }
+
+  scoped_ptr<base::DictionaryValue> stats = subscriber->GetStats();
+  subscriber->Reset();
+
+  callback.Run(stats.Pass());
+}
+
+void CastSessionDelegate::StatusNotificationCB(
+    media::cast::transport::CastTransportStatus unused_status) {
+  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+  // TODO(hubbe): Call javascript UDPTransport error function.
+}
+
+void CastSessionDelegate::InitializationResultCB(
+    media::cast::CastInitializationStatus result) const {
+  DCHECK(cast_sender_);
+
+  // TODO(pwestin): handle the error codes.
+  if (result == media::cast::STATUS_AUDIO_INITIALIZED) {
+    audio_frame_input_available_callback_.Run(
+        cast_sender_->audio_frame_input());
+  } else if (result == media::cast::STATUS_VIDEO_INITIALIZED) {
+    video_frame_input_available_callback_.Run(
+        cast_sender_->video_frame_input());
+  }
+}
+
+void CastSessionDelegate::LogRawEvents(
+    const std::vector<media::cast::PacketEvent>& packet_events) {
+  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+
+  for (std::vector<media::cast::PacketEvent>::const_iterator it =
+           packet_events.begin();
+       it != packet_events.end();
+       ++it) {
+    cast_environment_->Logging()->InsertPacketEvent(it->timestamp,
+                                                    it->type,
+                                                    it->rtp_timestamp,
+                                                    it->frame_id,
+                                                    it->packet_id,
+                                                    it->max_packet_id,
+                                                    it->size);
   }
-  frame_input_available_callbacks_.clear();
 }