| 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 const media::cast::CastLoggingConfig& logging_config) { | 66 const AudioSenderConfig& config, |
| 68 if (cast_environment_) | 67 const AudioFrameInputAvailableCallback& callback) { |
| 69 return; // Already initialized. | 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()); |
| 70 | 107 |
| 71 // CastSender uses the renderer's IO thread as the main thread. This reduces | 108 // CastSender uses the renderer's IO thread as the main thread. This reduces |
| 72 // thread hopping for incoming video frames and outgoing network packets. | 109 // thread hopping for incoming video frames and outgoing network packets. |
| 73 // There's no need to decode so no thread assigned for decoding. | 110 // There's no need to decode so no thread assigned for decoding. |
| 74 cast_environment_ = new CastEnvironment( | 111 cast_environment_ = new CastEnvironment( |
| 75 scoped_ptr<base::TickClock>(new base::DefaultTickClock()).Pass(), | 112 scoped_ptr<base::TickClock>(new base::DefaultTickClock()).Pass(), |
| 76 base::MessageLoopProxy::current(), | 113 base::MessageLoopProxy::current(), |
| 77 g_cast_threads.Get().GetAudioEncodeMessageLoopProxy(), | 114 g_cast_threads.Get().GetAudioEncodeMessageLoopProxy(), |
| 78 NULL, | 115 NULL, |
| 79 g_cast_threads.Get().GetVideoEncodeMessageLoopProxy(), | 116 g_cast_threads.Get().GetVideoEncodeMessageLoopProxy(), |
| 80 NULL, | 117 NULL, |
| 81 base::MessageLoopProxy::current(), | 118 base::MessageLoopProxy::current(), |
| 82 logging_config); | 119 media::cast::GetLoggingConfigWithRawEventsAndStatsEnabled()); |
| 120 |
| 121 // Logging: enable raw events and stats collection. |
| 122 media::cast::CastLoggingConfig logging_config = |
| 123 media::cast::GetLoggingConfigWithRawEventsAndStatsEnabled(); |
| 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 logging_config, |
| 132 base::Bind(&CastSessionDelegate::LogRawEvents, base::Unretained(this)))); |
| 133 |
| 134 cast_sender_ = CastSender::Create(cast_environment_, cast_transport_.get()); |
| 135 cast_transport_->SetPacketReceiver(cast_sender_->packet_receiver()); |
| 83 } | 136 } |
| 84 | 137 |
| 85 void CastSessionDelegate::StartAudio( | 138 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()); | 139 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
| 117 if (enable) { | 140 if (enable) { |
| 118 if (is_audio) { | 141 if (is_audio) { |
| 119 if (audio_event_subscriber_.get()) | 142 if (audio_event_subscriber_.get()) |
| 120 return; | 143 return; |
| 121 audio_event_subscriber_.reset(new media::cast::EncodingEventSubscriber( | 144 audio_event_subscriber_.reset(new media::cast::EncodingEventSubscriber( |
| 122 media::cast::AUDIO_EVENT, kMaxAudioEventEntries)); | 145 media::cast::AUDIO_EVENT, kMaxAudioEventEntries)); |
| 123 cast_environment_->Logging()->AddRawEventSubscriber( | 146 cast_environment_->Logging()->AddRawEventSubscriber( |
| 124 audio_event_subscriber_.get()); | 147 audio_event_subscriber_.get()); |
| 125 } else { | 148 } else { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 141 if (!video_event_subscriber_.get()) | 164 if (!video_event_subscriber_.get()) |
| 142 return; | 165 return; |
| 143 cast_environment_->Logging()->RemoveRawEventSubscriber( | 166 cast_environment_->Logging()->RemoveRawEventSubscriber( |
| 144 video_event_subscriber_.get()); | 167 video_event_subscriber_.get()); |
| 145 video_event_subscriber_.reset(); | 168 video_event_subscriber_.reset(); |
| 146 } | 169 } |
| 147 } | 170 } |
| 148 } | 171 } |
| 149 | 172 |
| 150 void CastSessionDelegate::GetEventLogsAndReset( | 173 void CastSessionDelegate::GetEventLogsAndReset( |
| 151 bool is_audio, const EventLogsCallback& callback) { | 174 bool is_audio, |
| 175 const EventLogsCallback& callback) { |
| 152 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 176 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
| 153 | 177 |
| 154 media::cast::EncodingEventSubscriber* subscriber = is_audio ? | 178 media::cast::EncodingEventSubscriber* subscriber = |
| 155 audio_event_subscriber_.get() : video_event_subscriber_.get(); | 179 is_audio ? audio_event_subscriber_.get() : video_event_subscriber_.get(); |
| 156 if (!subscriber) { | 180 if (!subscriber) { |
| 157 callback.Run(make_scoped_ptr(new std::string).Pass()); | 181 callback.Run(make_scoped_ptr(new std::string).Pass()); |
| 158 return; | 182 return; |
| 159 } | 183 } |
| 160 | 184 |
| 161 media::cast::FrameEventMap frame_events; | 185 media::cast::FrameEventMap frame_events; |
| 162 media::cast::PacketEventMap packet_events; | 186 media::cast::PacketEventMap packet_events; |
| 163 media::cast::RtpTimestamp rtp_timestamp; | 187 media::cast::RtpTimestamp rtp_timestamp; |
| 164 | 188 |
| 165 subscriber->GetEventsAndReset(&frame_events, &packet_events, &rtp_timestamp); | 189 subscriber->GetEventsAndReset(&frame_events, &packet_events, &rtp_timestamp); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 195 | 219 |
| 196 callback.Run(stats.Pass()); | 220 callback.Run(stats.Pass()); |
| 197 } | 221 } |
| 198 | 222 |
| 199 void CastSessionDelegate::StatusNotificationCB( | 223 void CastSessionDelegate::StatusNotificationCB( |
| 200 media::cast::transport::CastTransportStatus unused_status) { | 224 media::cast::transport::CastTransportStatus unused_status) { |
| 201 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 225 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
| 202 // TODO(hubbe): Call javascript UDPTransport error function. | 226 // TODO(hubbe): Call javascript UDPTransport error function. |
| 203 } | 227 } |
| 204 | 228 |
| 205 void CastSessionDelegate::StartSendingInternal() { | |
| 206 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 207 | |
| 208 // No transport, wait. | |
| 209 if (!transport_configured_) | |
| 210 return; | |
| 211 | |
| 212 // No audio or video, wait. | |
| 213 if (!audio_config_ || !video_config_) | |
| 214 return; | |
| 215 | |
| 216 // Logging: enable raw events and stats collection. | |
| 217 media::cast::CastLoggingConfig logging_config = | |
| 218 media::cast::GetLoggingConfigWithRawEventsAndStatsEnabled(); | |
| 219 Initialize(logging_config); | |
| 220 | |
| 221 // Rationale for using unretained: The callback cannot be called after the | |
| 222 // destruction of CastTransportSenderIPC, and they both share the same thread. | |
| 223 cast_transport_.reset(new CastTransportSenderIPC( | |
| 224 local_endpoint_, | |
| 225 remote_endpoint_, | |
| 226 base::Bind(&CastSessionDelegate::StatusNotificationCB, | |
| 227 base::Unretained(this)), | |
| 228 logging_config, | |
| 229 base::Bind(&CastSessionDelegate::LogRawEvents, | |
| 230 base::Unretained(this)))); | |
| 231 | |
| 232 // TODO(hubbe): set config.aes_key and config.aes_iv_mask. | |
| 233 if (audio_config_) { | |
| 234 media::cast::transport::CastTransportAudioConfig config; | |
| 235 config.base.ssrc = audio_config_->sender_ssrc; | |
| 236 config.codec = audio_config_->codec; | |
| 237 config.base.rtp_config = audio_config_->rtp_config; | |
| 238 config.frequency = audio_config_->frequency; | |
| 239 config.channels = audio_config_->channels; | |
| 240 cast_transport_->InitializeAudio(config); | |
| 241 } | |
| 242 if (video_config_) { | |
| 243 media::cast::transport::CastTransportVideoConfig config; | |
| 244 config.base.ssrc = video_config_->sender_ssrc; | |
| 245 config.codec = video_config_->codec; | |
| 246 config.base.rtp_config = video_config_->rtp_config; | |
| 247 cast_transport_->InitializeVideo(config); | |
| 248 } | |
| 249 | |
| 250 cast_sender_.reset(CastSender::CreateCastSender( | |
| 251 cast_environment_, | |
| 252 audio_config_.get(), | |
| 253 video_config_.get(), | |
| 254 NULL, // GPU. | |
| 255 base::Bind(&CastSessionDelegate::InitializationResult, | |
| 256 weak_factory_.GetWeakPtr()), | |
| 257 cast_transport_.get())); | |
| 258 cast_transport_->SetPacketReceiver(cast_sender_->packet_receiver()); | |
| 259 } | |
| 260 | |
| 261 void CastSessionDelegate::InitializationResult( | 229 void CastSessionDelegate::InitializationResult( |
| 262 media::cast::CastInitializationStatus result) const { | 230 media::cast::CastInitializationStatus result) const { |
| 263 DCHECK(cast_sender_); | 231 DCHECK(cast_sender_); |
| 264 | 232 |
| 265 // TODO(pwestin): handle the error codes. | 233 // TODO(pwestin): handle the error codes. |
| 266 if (result == media::cast::STATUS_INITIALIZED) { | 234 if (result == media::cast::STATUS_AUDIO_INITIALIZED) { |
| 267 if (!audio_frame_input_available_callback_.is_null()) { | 235 if (!audio_frame_input_available_callback_.is_null()) { |
| 268 audio_frame_input_available_callback_.Run(cast_sender_->frame_input()); | 236 audio_frame_input_available_callback_.Run( |
| 237 cast_sender_->audio_frame_input()); |
| 269 } | 238 } |
| 239 } else if (result == media::cast::STATUS_VIDEO_INITIALIZED) { |
| 270 if (!video_frame_input_available_callback_.is_null()) { | 240 if (!video_frame_input_available_callback_.is_null()) { |
| 271 video_frame_input_available_callback_.Run(cast_sender_->frame_input()); | 241 video_frame_input_available_callback_.Run( |
| 242 cast_sender_->video_frame_input()); |
| 272 } | 243 } |
| 273 } | 244 } |
| 274 } | 245 } |
| 275 | 246 |
| 276 void CastSessionDelegate::LogRawEvents( | 247 void CastSessionDelegate::LogRawEvents( |
| 277 const std::vector<media::cast::PacketEvent>& packet_events) { | 248 const std::vector<media::cast::PacketEvent>& packet_events) { |
| 278 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 249 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
| 279 | 250 |
| 280 for (std::vector<media::cast::PacketEvent>::const_iterator it = | 251 for (std::vector<media::cast::PacketEvent>::const_iterator it = |
| 281 packet_events.begin(); | 252 packet_events.begin(); |
| 282 it != packet_events.end(); | 253 it != packet_events.end(); |
| 283 ++it) { | 254 ++it) { |
| 284 cast_environment_->Logging()->InsertPacketEvent(it->timestamp, | 255 cast_environment_->Logging()->InsertPacketEvent(it->timestamp, |
| 285 it->type, | 256 it->type, |
| 286 it->rtp_timestamp, | 257 it->rtp_timestamp, |
| 287 it->frame_id, | 258 it->frame_id, |
| 288 it->packet_id, | 259 it->packet_id, |
| 289 it->max_packet_id, | 260 it->max_packet_id, |
| 290 it->size); | 261 it->size); |
| 291 } | 262 } |
| 292 } | 263 } |
| OLD | NEW |