Home | History | Annotate | Download | only in media
      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/media/cast_session_delegate.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "content/public/renderer/p2p_socket_client.h"
     10 #include "content/public/renderer/render_thread.h"
     11 #include "media/cast/cast_config.h"
     12 #include "media/cast/cast_environment.h"
     13 #include "media/cast/cast_sender.h"
     14 #include "media/cast/logging/logging_defines.h"
     15 
     16 using media::cast::AudioSenderConfig;
     17 using media::cast::CastEnvironment;
     18 using media::cast::CastSender;
     19 using media::cast::VideoSenderConfig;
     20 
     21 CastSessionDelegate::CastSessionDelegate()
     22     : audio_encode_thread_("CastAudioEncodeThread"),
     23       video_encode_thread_("CastVideoEncodeThread"),
     24       audio_configured_(false),
     25       video_configured_(false),
     26       io_message_loop_proxy_(
     27           content::RenderThread::Get()->GetIOMessageLoopProxy()) {
     28 }
     29 
     30 CastSessionDelegate::~CastSessionDelegate() {
     31   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
     32 }
     33 
     34 void CastSessionDelegate::SetSocketFactory(
     35     scoped_ptr<CastSession::P2PSocketFactory> socket_factory,
     36     const net::IPEndPoint& remote_address) {
     37   socket_factory_ = socket_factory.Pass();
     38   remote_address_ = remote_address;
     39 }
     40 
     41 void CastSessionDelegate::StartAudio(
     42     const AudioSenderConfig& config,
     43     const FrameInputAvailableCallback& callback) {
     44   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
     45 
     46   audio_configured_ = true;
     47   audio_config_ = config;
     48   frame_input_available_callbacks_.push_back(callback);
     49   MaybeStartSending();
     50 }
     51 
     52 void CastSessionDelegate::StartVideo(
     53     const VideoSenderConfig& config,
     54     const FrameInputAvailableCallback& callback) {
     55   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
     56 
     57   video_configured_ = true;
     58   video_config_ = config;
     59   frame_input_available_callbacks_.push_back(callback);
     60   MaybeStartSending();
     61 }
     62 
     63 void CastSessionDelegate::StartSending() {
     64   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
     65 
     66   if (cast_environment_)
     67     return;
     68 
     69   if (!socket_factory_) {
     70     // TODO(hubbe): Post an error back to the user
     71     return;
     72   }
     73 
     74   socket_ = socket_factory_->Create();
     75   socket_->SetDelegate(this);
     76 
     77   audio_encode_thread_.Start();
     78   video_encode_thread_.Start();
     79 
     80   // CastSender uses the renderer's IO thread as the main thread. This reduces
     81   // thread hopping for incoming video frames and outgoing network packets.
     82   // There's no need to decode so no thread assigned for decoding.
     83   // Get default logging: All disabled.
     84   cast_environment_ = new CastEnvironment(
     85       &clock_,
     86       base::MessageLoopProxy::current(),
     87       audio_encode_thread_.message_loop_proxy(),
     88       NULL,
     89       video_encode_thread_.message_loop_proxy(),
     90       NULL,
     91       media::cast::GetDefaultCastLoggingConfig());
     92 
     93   // TODO(hclam): Implement VideoEncoderController to configure hardware
     94   // encoder.
     95   cast_sender_.reset(CastSender::CreateCastSender(
     96       cast_environment_,
     97       audio_config_,
     98       video_config_,
     99       NULL,
    100       this));
    101 
    102   for (size_t i = 0; i < frame_input_available_callbacks_.size(); ++i) {
    103     frame_input_available_callbacks_[i].Run(
    104         cast_sender_->frame_input());
    105   }
    106   frame_input_available_callbacks_.clear();
    107 }
    108 
    109   // media::cast::PacketSender Implementation
    110 bool CastSessionDelegate::SendPacket(
    111     const media::cast::Packet& packet) {
    112   // TODO(hubbe): Make sure audio and video packets gets the right DSCP.
    113   socket_->SendWithDscp(
    114       remote_address_,
    115       *reinterpret_cast<const std::vector<char> *>(&packet),
    116       net::DSCP_AF41);
    117   return true;
    118 }
    119 
    120 bool CastSessionDelegate::SendPackets(
    121     const media::cast::PacketList& packets) {
    122   // TODO(hubbe): Add ability to send multiple packets in one IPC message.
    123   for (size_t i = 0; i < packets.size(); i++) {
    124     SendPacket(packets[i]);
    125   }
    126   return true;
    127 }
    128 
    129 // content::P2PSocketClient::Delegate Implementation
    130 void CastSessionDelegate::OnOpen(
    131     const net::IPEndPoint& address) {
    132   // Called once Init completes. Ignored.
    133 }
    134 
    135 void CastSessionDelegate::OnIncomingTcpConnection(
    136     const net::IPEndPoint& address,
    137     content::P2PSocketClient* client) {
    138   // We only support UDP sockets. This function should not be called
    139   // for UDP sockets.
    140   NOTREACHED();
    141 }
    142 
    143 void CastSessionDelegate::OnSendComplete() {
    144   // Ignored for now.
    145 }
    146 
    147 void CastSessionDelegate::OnError() {
    148   // TODO(hubbe): Report this back to the user.
    149 }
    150 
    151 void CastSessionDelegate::OnDataReceived(const net::IPEndPoint& address,
    152                                          const std::vector<char>& data,
    153                                          const base::TimeTicks& timestamp) {
    154   uint8 *packet_copy = new uint8[data.size()];
    155   memcpy(packet_copy, &data[0], data.size());
    156   cast_sender_->packet_receiver()->ReceivedPacket(
    157       packet_copy,
    158       data.size(),
    159       base::Bind(&media::cast::PacketReceiver::DeletePacket,
    160                  packet_copy));
    161 }
    162 
    163 void CastSessionDelegate::MaybeStartSending() {
    164   if (!audio_configured_ || !video_configured_)
    165     return;
    166   StartSending();
    167 }
    168