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