OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/media/cast_session_delegate.h" | 5 #include "chrome/renderer/media/cast_session_delegate.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop/message_loop_proxy.h" | 9 #include "base/message_loop/message_loop_proxy.h" |
10 #include "chrome/renderer/media/cast_threads.h" | 10 #include "chrome/renderer/media/cast_threads.h" |
(...skipping 25 matching lines...) Expand all Loading... | |
36 // each frame will take up to 150 bytes. | 36 // each frame will take up to 150 bytes. |
37 const int kMaxVideoEventEntries = kMaxSerializedBytes / 150; | 37 const int kMaxVideoEventEntries = kMaxSerializedBytes / 150; |
38 | 38 |
39 // Allow about 9MB for audio event logs. Assume serialized log data for | 39 // Allow about 9MB for audio event logs. Assume serialized log data for |
40 // each frame will take up to 75 bytes. | 40 // each frame will take up to 75 bytes. |
41 const int kMaxAudioEventEntries = kMaxSerializedBytes / 75; | 41 const int kMaxAudioEventEntries = kMaxSerializedBytes / 75; |
42 | 42 |
43 } // namespace | 43 } // namespace |
44 | 44 |
45 CastSessionDelegate::CastSessionDelegate() | 45 CastSessionDelegate::CastSessionDelegate() |
46 : transport_configured_(false), | 46 : io_message_loop_proxy_( |
47 io_message_loop_proxy_( | |
48 content::RenderThread::Get()->GetIOMessageLoopProxy()), | 47 content::RenderThread::Get()->GetIOMessageLoopProxy()), |
49 weak_factory_(this) { | 48 weak_factory_(this) { |
50 DCHECK(io_message_loop_proxy_); | 49 DCHECK(io_message_loop_proxy_); |
51 } | 50 } |
52 | 51 |
53 CastSessionDelegate::~CastSessionDelegate() { | 52 CastSessionDelegate::~CastSessionDelegate() { |
54 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 53 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
55 | 54 |
56 if (audio_event_subscriber_.get()) { | 55 if (audio_event_subscriber_.get()) { |
57 cast_environment_->Logging()->RemoveRawEventSubscriber( | 56 cast_environment_->Logging()->RemoveRawEventSubscriber( |
58 audio_event_subscriber_.get()); | 57 audio_event_subscriber_.get()); |
59 } | 58 } |
60 if (video_event_subscriber_.get()) { | 59 if (video_event_subscriber_.get()) { |
61 cast_environment_->Logging()->RemoveRawEventSubscriber( | 60 cast_environment_->Logging()->RemoveRawEventSubscriber( |
62 video_event_subscriber_.get()); | 61 video_event_subscriber_.get()); |
63 } | 62 } |
64 } | 63 } |
65 | 64 |
66 void CastSessionDelegate::Initialize() { | 65 void CastSessionDelegate::StartAudio( |
67 if (cast_environment_) | 66 const AudioSenderConfig& config, |
68 return; // Already initialized. | 67 const AudioFrameInputAvailableCallback& callback) { |
68 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
69 | |
70 audio_frame_input_available_callback_ = callback; | |
71 media::cast::transport::CastTransportAudioConfig transport_config; | |
72 transport_config.base.ssrc = config.sender_ssrc; | |
73 transport_config.codec = config.codec; | |
74 transport_config.base.rtp_config = config.rtp_config; | |
75 transport_config.frequency = config.frequency; | |
76 transport_config.channels = config.channels; | |
77 cast_transport_->InitializeAudio(transport_config); | |
78 cast_sender_->InitializeAudio( | |
79 config, | |
80 base::Bind(&CastSessionDelegate::InitializationResult, | |
81 weak_factory_.GetWeakPtr())); | |
82 } | |
83 | |
84 void CastSessionDelegate::StartVideo( | |
85 const VideoSenderConfig& config, | |
86 const VideoFrameInputAvailableCallback& callback) { | |
87 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
88 video_frame_input_available_callback_ = callback; | |
89 | |
90 media::cast::transport::CastTransportVideoConfig transport_config; | |
91 transport_config.base.ssrc = config.sender_ssrc; | |
92 transport_config.codec = config.codec; | |
93 transport_config.base.rtp_config = config.rtp_config; | |
94 cast_transport_->InitializeVideo(transport_config); | |
95 // TODO(mikhal): Pass in a valid GpuVideoAcceleratorFactories to support | |
96 // hardware video encoding. | |
97 cast_sender_->InitializeVideo( | |
98 config, | |
99 base::Bind(&CastSessionDelegate::InitializationResult, | |
100 weak_factory_.GetWeakPtr()), | |
101 NULL /* GPU*/); | |
102 } | |
103 | |
104 void CastSessionDelegate::StartUDP(const net::IPEndPoint& local_endpoint, | |
105 const net::IPEndPoint& remote_endpoint) { | |
106 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
107 // local_endpoint_ = local_endpoint; | |
Alpha Left Google
2014/03/06 23:10:04
These two lines are not needed.
mikhal1
2014/03/06 23:38:53
Done.
| |
108 // remote_endpoint_ = remote_endpoint; | |
69 | 109 |
70 // CastSender uses the renderer's IO thread as the main thread. This reduces | 110 // CastSender uses the renderer's IO thread as the main thread. This reduces |
71 // thread hopping for incoming video frames and outgoing network packets. | 111 // thread hopping for incoming video frames and outgoing network packets. |
72 // There's no need to decode so no thread assigned for decoding. | 112 // There's no need to decode so no thread assigned for decoding. |
73 // Logging: enable raw events and stats collection. | 113 // Logging: enable raw events and stats collection. |
74 cast_environment_ = new CastEnvironment( | 114 cast_environment_ = new CastEnvironment( |
75 scoped_ptr<base::TickClock>(new base::DefaultTickClock()).Pass(), | 115 scoped_ptr<base::TickClock>(new base::DefaultTickClock()).Pass(), |
76 base::MessageLoopProxy::current(), | 116 base::MessageLoopProxy::current(), |
77 g_cast_threads.Get().GetAudioEncodeMessageLoopProxy(), | 117 g_cast_threads.Get().GetAudioEncodeMessageLoopProxy(), |
78 NULL, | 118 NULL, |
79 g_cast_threads.Get().GetVideoEncodeMessageLoopProxy(), | 119 g_cast_threads.Get().GetVideoEncodeMessageLoopProxy(), |
80 NULL, | 120 NULL, |
81 base::MessageLoopProxy::current(), | 121 base::MessageLoopProxy::current(), |
82 media::cast::GetLoggingConfigWithRawEventsAndStatsEnabled()); | 122 media::cast::GetLoggingConfigWithRawEventsAndStatsEnabled()); |
123 | |
124 // Rationale for using unretained: The callback cannot be called after the | |
125 // destruction of CastTransportSenderIPC, and they both share the same thread. | |
126 cast_transport_.reset(new CastTransportSenderIPC( | |
127 local_endpoint, | |
128 remote_endpoint, | |
129 base::Bind(&CastSessionDelegate::StatusNotificationCB, | |
130 base::Unretained(this)))); | |
131 | |
132 cast_sender_ = CastSender::Create(cast_environment_, cast_transport_.get()); | |
133 cast_transport_->SetPacketReceiver(cast_sender_->packet_receiver()); | |
83 } | 134 } |
84 | 135 |
85 void CastSessionDelegate::StartAudio( | 136 void CastSessionDelegate::ToggleLogging(bool is_audio, bool enable) { |
86 const AudioSenderConfig& config, | |
87 const FrameInputAvailableCallback& callback) { | |
88 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
89 | |
90 audio_config_.reset(new AudioSenderConfig(config)); | |
91 video_frame_input_available_callback_ = callback; | |
92 StartSendingInternal(); | |
93 } | |
94 | |
95 void CastSessionDelegate::StartVideo( | |
96 const VideoSenderConfig& config, | |
97 const FrameInputAvailableCallback& callback) { | |
98 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
99 audio_frame_input_available_callback_ = callback; | |
100 | |
101 video_config_.reset(new VideoSenderConfig(config)); | |
102 StartSendingInternal(); | |
103 } | |
104 | |
105 void CastSessionDelegate::StartUDP(const net::IPEndPoint& local_endpoint, | |
106 const net::IPEndPoint& remote_endpoint) { | |
107 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
108 transport_configured_ = true; | |
109 local_endpoint_ = local_endpoint; | |
110 remote_endpoint_ = remote_endpoint; | |
111 StartSendingInternal(); | |
112 } | |
113 | |
114 void CastSessionDelegate::ToggleLogging(bool is_audio, | |
115 bool enable) { | |
116 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 137 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
117 if (enable) { | 138 if (enable) { |
118 if (is_audio) { | 139 if (is_audio) { |
119 if (audio_event_subscriber_.get()) | 140 if (audio_event_subscriber_.get()) |
120 return; | 141 return; |
121 audio_event_subscriber_.reset(new media::cast::EncodingEventSubscriber( | 142 audio_event_subscriber_.reset(new media::cast::EncodingEventSubscriber( |
122 media::cast::AUDIO_EVENT, kMaxAudioEventEntries)); | 143 media::cast::AUDIO_EVENT, kMaxAudioEventEntries)); |
123 cast_environment_->Logging()->AddRawEventSubscriber( | 144 cast_environment_->Logging()->AddRawEventSubscriber( |
124 audio_event_subscriber_.get()); | 145 audio_event_subscriber_.get()); |
125 } else { | 146 } else { |
(...skipping 15 matching lines...) Expand all Loading... | |
141 if (!video_event_subscriber_.get()) | 162 if (!video_event_subscriber_.get()) |
142 return; | 163 return; |
143 cast_environment_->Logging()->RemoveRawEventSubscriber( | 164 cast_environment_->Logging()->RemoveRawEventSubscriber( |
144 video_event_subscriber_.get()); | 165 video_event_subscriber_.get()); |
145 video_event_subscriber_.reset(); | 166 video_event_subscriber_.reset(); |
146 } | 167 } |
147 } | 168 } |
148 } | 169 } |
149 | 170 |
150 void CastSessionDelegate::GetEventLogsAndReset( | 171 void CastSessionDelegate::GetEventLogsAndReset( |
151 bool is_audio, const EventLogsCallback& callback) { | 172 bool is_audio, |
173 const EventLogsCallback& callback) { | |
152 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 174 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
153 | 175 |
154 media::cast::EncodingEventSubscriber* subscriber = is_audio ? | 176 media::cast::EncodingEventSubscriber* subscriber = |
155 audio_event_subscriber_.get() : video_event_subscriber_.get(); | 177 is_audio ? audio_event_subscriber_.get() : video_event_subscriber_.get(); |
156 if (!subscriber) { | 178 if (!subscriber) { |
157 callback.Run(make_scoped_ptr(new std::string).Pass()); | 179 callback.Run(make_scoped_ptr(new std::string).Pass()); |
158 return; | 180 return; |
159 } | 181 } |
160 | 182 |
161 media::cast::FrameEventMap frame_events; | 183 media::cast::FrameEventMap frame_events; |
162 media::cast::PacketEventMap packet_events; | 184 media::cast::PacketEventMap packet_events; |
163 media::cast::RtpTimestamp rtp_timestamp; | 185 media::cast::RtpTimestamp rtp_timestamp; |
164 | 186 |
165 subscriber->GetEventsAndReset(&frame_events, &packet_events, &rtp_timestamp); | 187 subscriber->GetEventsAndReset(&frame_events, &packet_events, &rtp_timestamp); |
(...skipping 14 matching lines...) Expand all Loading... | |
180 | 202 |
181 callback.Run(serialized_log.Pass()); | 203 callback.Run(serialized_log.Pass()); |
182 } | 204 } |
183 | 205 |
184 void CastSessionDelegate::StatusNotificationCB( | 206 void CastSessionDelegate::StatusNotificationCB( |
185 media::cast::transport::CastTransportStatus unused_status) { | 207 media::cast::transport::CastTransportStatus unused_status) { |
186 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 208 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
187 // TODO(hubbe): Call javascript UDPTransport error function. | 209 // TODO(hubbe): Call javascript UDPTransport error function. |
188 } | 210 } |
189 | 211 |
190 void CastSessionDelegate::StartSendingInternal() { | |
191 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
192 | |
193 // No transport, wait. | |
194 if (!transport_configured_) | |
195 return; | |
196 | |
197 // No audio or video, wait. | |
198 if (!audio_config_ || !video_config_) | |
199 return; | |
200 | |
201 Initialize(); | |
202 | |
203 // Rationale for using unretained: The callback cannot be called after the | |
204 // destruction of CastTransportSenderIPC, and they both share the same thread. | |
205 cast_transport_.reset(new CastTransportSenderIPC( | |
206 local_endpoint_, | |
207 remote_endpoint_, | |
208 base::Bind(&CastSessionDelegate::StatusNotificationCB, | |
209 base::Unretained(this)))); | |
210 | |
211 // TODO(hubbe): set config.aes_key and config.aes_iv_mask. | |
212 if (audio_config_) { | |
213 media::cast::transport::CastTransportAudioConfig config; | |
214 config.base.ssrc = audio_config_->sender_ssrc; | |
215 config.codec = audio_config_->codec; | |
216 config.base.rtp_config = audio_config_->rtp_config; | |
217 config.frequency = audio_config_->frequency; | |
218 config.channels = audio_config_->channels; | |
219 cast_transport_->InitializeAudio(config); | |
220 } | |
221 if (video_config_) { | |
222 media::cast::transport::CastTransportVideoConfig config; | |
223 config.base.ssrc = video_config_->sender_ssrc; | |
224 config.codec = video_config_->codec; | |
225 config.base.rtp_config = video_config_->rtp_config; | |
226 cast_transport_->InitializeVideo(config); | |
227 } | |
228 | |
229 cast_sender_.reset(CastSender::CreateCastSender( | |
230 cast_environment_, | |
231 audio_config_.get(), | |
232 video_config_.get(), | |
233 NULL, // GPU. | |
234 base::Bind(&CastSessionDelegate::InitializationResult, | |
235 weak_factory_.GetWeakPtr()), | |
236 cast_transport_.get())); | |
237 cast_transport_->SetPacketReceiver(cast_sender_->packet_receiver()); | |
238 } | |
239 | |
240 void CastSessionDelegate::InitializationResult( | 212 void CastSessionDelegate::InitializationResult( |
241 media::cast::CastInitializationStatus result) const { | 213 media::cast::CastInitializationStatus result) const { |
242 DCHECK(cast_sender_); | 214 DCHECK(cast_sender_); |
243 | 215 |
244 // TODO(pwestin): handle the error codes. | 216 // TODO(pwestin): handle the error codes. |
245 if (result == media::cast::STATUS_INITIALIZED) { | 217 if (result == media::cast::STATUS_AUDIO_INITIALIZED) { |
246 if (!audio_frame_input_available_callback_.is_null()) { | 218 if (!audio_frame_input_available_callback_.is_null()) { |
247 audio_frame_input_available_callback_.Run(cast_sender_->frame_input()); | 219 audio_frame_input_available_callback_.Run( |
220 cast_sender_->audio_frame_input()); | |
248 } | 221 } |
222 } else if (result == media::cast::STATUS_VIDEO_INITIALIZED) { | |
249 if (!video_frame_input_available_callback_.is_null()) { | 223 if (!video_frame_input_available_callback_.is_null()) { |
250 video_frame_input_available_callback_.Run(cast_sender_->frame_input()); | 224 video_frame_input_available_callback_.Run( |
225 cast_sender_->video_frame_input()); | |
251 } | 226 } |
252 } | 227 } |
253 } | 228 } |
254 | |
OLD | NEW |