Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / media / cast_session_delegate.cc
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/lazy_instance.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "chrome/renderer/media/cast_threads.h"
11 #include "chrome/renderer/media/cast_transport_sender_ipc.h"
12 #include "content/public/renderer/render_thread.h"
13 #include "media/cast/cast_config.h"
14 #include "media/cast/cast_environment.h"
15 #include "media/cast/cast_sender.h"
16 #include "media/cast/logging/log_serializer.h"
17 #include "media/cast/logging/logging_defines.h"
18 #include "media/cast/logging/proto/raw_events.pb.h"
19 #include "media/cast/logging/raw_event_subscriber_bundle.h"
20 #include "media/cast/transport/cast_transport_config.h"
21 #include "media/cast/transport/cast_transport_sender.h"
22
23 using media::cast::AudioSenderConfig;
24 using media::cast::CastEnvironment;
25 using media::cast::CastSender;
26 using media::cast::VideoSenderConfig;
27
28 static base::LazyInstance<CastThreads> g_cast_threads =
29     LAZY_INSTANCE_INITIALIZER;
30
31 CastSessionDelegate::CastSessionDelegate()
32     : io_message_loop_proxy_(
33           content::RenderThread::Get()->GetIOMessageLoopProxy()),
34       weak_factory_(this) {
35   DCHECK(io_message_loop_proxy_);
36 }
37
38 CastSessionDelegate::~CastSessionDelegate() {
39   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
40 }
41
42 void CastSessionDelegate::StartAudio(
43     const AudioSenderConfig& config,
44     const AudioFrameInputAvailableCallback& callback,
45     const ErrorCallback& error_callback) {
46   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
47
48   if (!cast_transport_ || !cast_sender_) {
49     error_callback.Run("Destination not set.");
50     return;
51   }
52
53   audio_frame_input_available_callback_ = callback;
54   cast_sender_->InitializeAudio(
55       config,
56       base::Bind(&CastSessionDelegate::InitializationResultCB,
57                  weak_factory_.GetWeakPtr()));
58 }
59
60 void CastSessionDelegate::StartVideo(
61     const VideoSenderConfig& config,
62     const VideoFrameInputAvailableCallback& callback,
63     const ErrorCallback& error_callback,
64     const media::cast::CreateVideoEncodeAcceleratorCallback& create_vea_cb,
65     const media::cast::CreateVideoEncodeMemoryCallback&
66         create_video_encode_mem_cb) {
67   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
68
69   if (!cast_transport_ || !cast_sender_) {
70     error_callback.Run("Destination not set.");
71     return;
72   }
73
74   video_frame_input_available_callback_ = callback;
75
76   cast_sender_->InitializeVideo(
77       config,
78       base::Bind(&CastSessionDelegate::InitializationResultCB,
79                  weak_factory_.GetWeakPtr()),
80       create_vea_cb,
81       create_video_encode_mem_cb);
82 }
83
84 void CastSessionDelegate::StartUDP(const net::IPEndPoint& remote_endpoint) {
85   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
86
87   // CastSender uses the renderer's IO thread as the main thread. This reduces
88   // thread hopping for incoming video frames and outgoing network packets.
89   cast_environment_ = new CastEnvironment(
90       scoped_ptr<base::TickClock>(new base::DefaultTickClock()).Pass(),
91       base::MessageLoopProxy::current(),
92       g_cast_threads.Get().GetAudioEncodeMessageLoopProxy(),
93       g_cast_threads.Get().GetVideoEncodeMessageLoopProxy());
94
95   event_subscribers_.reset(
96       new media::cast::RawEventSubscriberBundle(cast_environment_));
97
98   // Rationale for using unretained: The callback cannot be called after the
99   // destruction of CastTransportSenderIPC, and they both share the same thread.
100   cast_transport_.reset(new CastTransportSenderIPC(
101       remote_endpoint,
102       base::Bind(&CastSessionDelegate::StatusNotificationCB,
103                  base::Unretained(this)),
104       base::Bind(&CastSessionDelegate::LogRawEvents, base::Unretained(this))));
105
106   cast_sender_ = CastSender::Create(cast_environment_, cast_transport_.get());
107   cast_transport_->SetPacketReceiver(cast_sender_->packet_receiver());
108 }
109
110 void CastSessionDelegate::ToggleLogging(bool is_audio, bool enable) {
111   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
112   if (!event_subscribers_.get())
113     return;
114
115   if (enable)
116     event_subscribers_->AddEventSubscribers(is_audio);
117   else
118     event_subscribers_->RemoveEventSubscribers(is_audio);
119 }
120
121 void CastSessionDelegate::GetEventLogsAndReset(
122     bool is_audio,
123     const EventLogsCallback& callback) {
124   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
125
126   if (!event_subscribers_.get()) {
127     callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
128     return;
129   }
130
131   media::cast::EncodingEventSubscriber* subscriber =
132       event_subscribers_->GetEncodingEventSubscriber(is_audio);
133   if (!subscriber) {
134     callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
135     return;
136   }
137
138   media::cast::proto::LogMetadata metadata;
139   media::cast::FrameEventList frame_events;
140   media::cast::PacketEventList packet_events;
141
142   subscriber->GetEventsAndReset(&metadata, &frame_events, &packet_events);
143
144   scoped_ptr<char[]> serialized_log(new char[media::cast::kMaxSerializedBytes]);
145   int output_bytes;
146   bool success = media::cast::SerializeEvents(metadata,
147                                               frame_events,
148                                               packet_events,
149                                               true,
150                                               media::cast::kMaxSerializedBytes,
151                                               serialized_log.get(),
152                                               &output_bytes);
153
154   if (!success) {
155     VLOG(2) << "Failed to serialize event log.";
156     callback.Run(make_scoped_ptr(new base::BinaryValue).Pass());
157     return;
158   }
159
160   DVLOG(2) << "Serialized log length: " << output_bytes;
161
162   scoped_ptr<base::BinaryValue> blob(
163       new base::BinaryValue(serialized_log.Pass(), output_bytes));
164   callback.Run(blob.Pass());
165 }
166
167 void CastSessionDelegate::GetStatsAndReset(bool is_audio,
168                                            const StatsCallback& callback) {
169   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
170
171   if (!event_subscribers_.get()) {
172     callback.Run(make_scoped_ptr(new base::DictionaryValue).Pass());
173     return;
174   }
175
176   media::cast::StatsEventSubscriber* subscriber =
177       event_subscribers_->GetStatsEventSubscriber(is_audio);
178   if (!subscriber) {
179     callback.Run(make_scoped_ptr(new base::DictionaryValue).Pass());
180     return;
181   }
182
183   scoped_ptr<base::DictionaryValue> stats = subscriber->GetStats();
184   subscriber->Reset();
185
186   callback.Run(stats.Pass());
187 }
188
189 void CastSessionDelegate::StatusNotificationCB(
190     media::cast::transport::CastTransportStatus unused_status) {
191   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
192   // TODO(hubbe): Call javascript UDPTransport error function.
193 }
194
195 void CastSessionDelegate::InitializationResultCB(
196     media::cast::CastInitializationStatus result) const {
197   DCHECK(cast_sender_);
198
199   // TODO(pwestin): handle the error codes.
200   if (result == media::cast::STATUS_AUDIO_INITIALIZED) {
201     audio_frame_input_available_callback_.Run(
202         cast_sender_->audio_frame_input());
203   } else if (result == media::cast::STATUS_VIDEO_INITIALIZED) {
204     video_frame_input_available_callback_.Run(
205         cast_sender_->video_frame_input());
206   }
207 }
208
209 void CastSessionDelegate::LogRawEvents(
210     const std::vector<media::cast::PacketEvent>& packet_events) {
211   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
212
213   for (std::vector<media::cast::PacketEvent>::const_iterator it =
214            packet_events.begin();
215        it != packet_events.end();
216        ++it) {
217     cast_environment_->Logging()->InsertPacketEvent(it->timestamp,
218                                                     it->type,
219                                                     it->rtp_timestamp,
220                                                     it->frame_id,
221                                                     it->packet_id,
222                                                     it->max_packet_id,
223                                                     it->size);
224   }
225 }