[NaCl SDK] Remove gtest_main.cc from libgtest
[chromium-blink-merge.git] / chrome / renderer / media / cast_session_delegate.cc
blob6a0da851835b11cef2b727f2b83222923474accf
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.
5 #include "chrome/renderer/media/cast_session_delegate.h"
7 #include "base/callback_helpers.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/common/chrome_version_info.h"
13 #include "chrome/renderer/media/cast_threads.h"
14 #include "chrome/renderer/media/cast_transport_sender_ipc.h"
15 #include "content/public/renderer/render_thread.h"
16 #include "media/cast/cast_config.h"
17 #include "media/cast/cast_environment.h"
18 #include "media/cast/cast_sender.h"
19 #include "media/cast/logging/log_serializer.h"
20 #include "media/cast/logging/logging_defines.h"
21 #include "media/cast/logging/proto/raw_events.pb.h"
22 #include "media/cast/logging/raw_event_subscriber_bundle.h"
23 #include "media/cast/net/cast_transport_config.h"
24 #include "media/cast/net/cast_transport_sender.h"
26 using media::cast::AudioSenderConfig;
27 using media::cast::CastEnvironment;
28 using media::cast::CastSender;
29 using media::cast::VideoSenderConfig;
31 static base::LazyInstance<CastThreads> g_cast_threads =
32 LAZY_INSTANCE_INITIALIZER;
34 CastSessionDelegateBase::CastSessionDelegateBase()
35 : io_message_loop_proxy_(
36 content::RenderThread::Get()->GetIOMessageLoopProxy()),
37 weak_factory_(this) {
38 DCHECK(io_message_loop_proxy_.get());
41 CastSessionDelegateBase::~CastSessionDelegateBase() {
42 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
45 void CastSessionDelegateBase::StartUDP(
46 const net::IPEndPoint& local_endpoint,
47 const net::IPEndPoint& remote_endpoint,
48 scoped_ptr<base::DictionaryValue> options) {
49 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
51 // CastSender uses the renderer's IO thread as the main thread. This reduces
52 // thread hopping for incoming video frames and outgoing network packets.
53 // TODO(hubbe): Create cast environment in ctor instead.
54 cast_environment_ = new CastEnvironment(
55 scoped_ptr<base::TickClock>(new base::DefaultTickClock()).Pass(),
56 base::MessageLoopProxy::current(),
57 g_cast_threads.Get().GetAudioEncodeMessageLoopProxy(),
58 g_cast_threads.Get().GetVideoEncodeMessageLoopProxy());
60 // Rationale for using unretained: The callback cannot be called after the
61 // destruction of CastTransportSenderIPC, and they both share the same thread.
62 cast_transport_.reset(new CastTransportSenderIPC(
63 local_endpoint,
64 remote_endpoint,
65 options.Pass(),
66 base::Bind(&CastSessionDelegateBase::ReceivePacket,
67 base::Unretained(this)),
68 base::Bind(&CastSessionDelegateBase::StatusNotificationCB,
69 base::Unretained(this)),
70 base::Bind(&CastSessionDelegateBase::LogRawEvents,
71 base::Unretained(this))));
74 void CastSessionDelegateBase::StatusNotificationCB(
75 media::cast::CastTransportStatus unused_status) {
76 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
77 // TODO(hubbe): Call javascript UDPTransport error function.
80 CastSessionDelegate::CastSessionDelegate()
81 : weak_factory_(this) {
82 DCHECK(io_message_loop_proxy_.get());
85 CastSessionDelegate::~CastSessionDelegate() {
86 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
89 void CastSessionDelegate::StartAudio(
90 const AudioSenderConfig& config,
91 const AudioFrameInputAvailableCallback& callback,
92 const ErrorCallback& error_callback) {
93 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
95 if (!cast_transport_ || !cast_sender_) {
96 error_callback.Run("Destination not set.");
97 return;
100 audio_frame_input_available_callback_ = callback;
101 cast_sender_->InitializeAudio(
102 config,
103 base::Bind(&CastSessionDelegate::OnOperationalStatusChange,
104 weak_factory_.GetWeakPtr(), true, error_callback));
107 void CastSessionDelegate::StartVideo(
108 const VideoSenderConfig& config,
109 const VideoFrameInputAvailableCallback& callback,
110 const ErrorCallback& error_callback,
111 const media::cast::CreateVideoEncodeAcceleratorCallback& create_vea_cb,
112 const media::cast::CreateVideoEncodeMemoryCallback&
113 create_video_encode_mem_cb) {
114 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
116 if (!cast_transport_ || !cast_sender_) {
117 error_callback.Run("Destination not set.");
118 return;
121 video_frame_input_available_callback_ = callback;
123 cast_sender_->InitializeVideo(
124 config,
125 base::Bind(&CastSessionDelegate::OnOperationalStatusChange,
126 weak_factory_.GetWeakPtr(), false, error_callback),
127 create_vea_cb,
128 create_video_encode_mem_cb);
132 void CastSessionDelegate::StartUDP(
133 const net::IPEndPoint& local_endpoint,
134 const net::IPEndPoint& remote_endpoint,
135 scoped_ptr<base::DictionaryValue> options) {
136 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
137 CastSessionDelegateBase::StartUDP(local_endpoint,
138 remote_endpoint,
139 options.Pass());
140 event_subscribers_.reset(
141 new media::cast::RawEventSubscriberBundle(cast_environment_));
143 cast_sender_ = CastSender::Create(cast_environment_, cast_transport_.get());
146 void CastSessionDelegate::ToggleLogging(bool is_audio, bool enable) {
147 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
148 if (!event_subscribers_.get())
149 return;
151 if (enable)
152 event_subscribers_->AddEventSubscribers(is_audio);
153 else
154 event_subscribers_->RemoveEventSubscribers(is_audio);
157 void CastSessionDelegate::GetEventLogsAndReset(
158 bool is_audio,
159 const std::string& extra_data,
160 const EventLogsCallback& callback) {
161 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
163 if (!event_subscribers_.get()) {
164 callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
165 return;
168 media::cast::EncodingEventSubscriber* subscriber =
169 event_subscribers_->GetEncodingEventSubscriber(is_audio);
170 if (!subscriber) {
171 callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
172 return;
175 media::cast::proto::LogMetadata metadata;
176 media::cast::FrameEventList frame_events;
177 media::cast::PacketEventList packet_events;
179 subscriber->GetEventsAndReset(&metadata, &frame_events, &packet_events);
181 if (!extra_data.empty())
182 metadata.set_extra_data(extra_data);
183 media::cast::proto::GeneralDescription* gen_desc =
184 metadata.mutable_general_description();
185 chrome::VersionInfo version_info;
186 gen_desc->set_product(version_info.Name());
187 gen_desc->set_product_version(version_info.Version());
188 gen_desc->set_os(version_info.OSType());
190 scoped_ptr<char[]> serialized_log(new char[media::cast::kMaxSerializedBytes]);
191 int output_bytes;
192 bool success = media::cast::SerializeEvents(metadata,
193 frame_events,
194 packet_events,
195 true,
196 media::cast::kMaxSerializedBytes,
197 serialized_log.get(),
198 &output_bytes);
200 if (!success) {
201 DVLOG(2) << "Failed to serialize event log.";
202 callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
203 return;
206 DVLOG(2) << "Serialized log length: " << output_bytes;
208 scoped_ptr<base::BinaryValue> blob(
209 new base::BinaryValue(serialized_log.Pass(), output_bytes));
210 callback.Run(blob.Pass());
213 void CastSessionDelegate::GetStatsAndReset(bool is_audio,
214 const StatsCallback& callback) {
215 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
217 if (!event_subscribers_.get()) {
218 callback.Run(make_scoped_ptr(new base::DictionaryValue).Pass());
219 return;
222 media::cast::StatsEventSubscriber* subscriber =
223 event_subscribers_->GetStatsEventSubscriber(is_audio);
224 if (!subscriber) {
225 callback.Run(make_scoped_ptr(new base::DictionaryValue).Pass());
226 return;
229 scoped_ptr<base::DictionaryValue> stats = subscriber->GetStats();
230 subscriber->Reset();
232 callback.Run(stats.Pass());
235 void CastSessionDelegate::OnOperationalStatusChange(
236 bool is_for_audio,
237 const ErrorCallback& error_callback,
238 media::cast::OperationalStatus status) {
239 DCHECK(cast_sender_);
241 switch (status) {
242 case media::cast::STATUS_UNINITIALIZED:
243 case media::cast::STATUS_CODEC_REINIT_PENDING:
244 // Not an error.
245 // TODO(miu): As an optimization, signal the client to pause sending more
246 // frames until the state becomes STATUS_INITIALIZED again.
247 break;
248 case media::cast::STATUS_INITIALIZED:
249 // Once initialized, run the "frame input available" callback to allow the
250 // client to begin sending frames. If STATUS_INITIALIZED is encountered
251 // again, do nothing since this is only an indication that the codec has
252 // successfully re-initialized.
253 if (is_for_audio) {
254 if (!audio_frame_input_available_callback_.is_null()) {
255 base::ResetAndReturn(&audio_frame_input_available_callback_).Run(
256 cast_sender_->audio_frame_input());
258 } else {
259 if (!video_frame_input_available_callback_.is_null()) {
260 base::ResetAndReturn(&video_frame_input_available_callback_).Run(
261 cast_sender_->video_frame_input());
264 break;
265 case media::cast::STATUS_INVALID_CONFIGURATION:
266 error_callback.Run(base::StringPrintf("Invalid %s configuration.",
267 is_for_audio ? "audio" : "video"));
268 break;
269 case media::cast::STATUS_UNSUPPORTED_CODEC:
270 error_callback.Run(base::StringPrintf("%s codec not supported.",
271 is_for_audio ? "Audio" : "Video"));
272 break;
273 case media::cast::STATUS_CODEC_INIT_FAILED:
274 error_callback.Run(base::StringPrintf("%s codec initialization failed.",
275 is_for_audio ? "Audio" : "Video"));
276 break;
277 case media::cast::STATUS_CODEC_RUNTIME_ERROR:
278 error_callback.Run(base::StringPrintf("%s codec runtime error.",
279 is_for_audio ? "Audio" : "Video"));
280 break;
284 void CastSessionDelegate::ReceivePacket(
285 scoped_ptr<media::cast::Packet> packet) {
286 // Do nothing (frees packet)
289 void CastSessionDelegate::LogRawEvents(
290 const std::vector<media::cast::PacketEvent>& packet_events,
291 const std::vector<media::cast::FrameEvent>& frame_events) {
292 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
294 for (std::vector<media::cast::PacketEvent>::const_iterator it =
295 packet_events.begin();
296 it != packet_events.end();
297 ++it) {
298 cast_environment_->Logging()->InsertPacketEvent(it->timestamp,
299 it->type,
300 it->media_type,
301 it->rtp_timestamp,
302 it->frame_id,
303 it->packet_id,
304 it->max_packet_id,
305 it->size);
307 for (std::vector<media::cast::FrameEvent>::const_iterator it =
308 frame_events.begin();
309 it != frame_events.end();
310 ++it) {
311 if (it->type == media::cast::FRAME_PLAYOUT) {
312 cast_environment_->Logging()->InsertFrameEventWithDelay(
313 it->timestamp,
314 it->type,
315 it->media_type,
316 it->rtp_timestamp,
317 it->frame_id,
318 it->delay_delta);
319 } else {
320 cast_environment_->Logging()->InsertFrameEvent(
321 it->timestamp,
322 it->type,
323 it->media_type,
324 it->rtp_timestamp,
325 it->frame_id);