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/logging.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "chrome/renderer/media/cast_transport_sender_ipc.h"
10 #include "content/public/renderer/p2p_socket_client.h"
11 #include "content/public/renderer/render_thread.h"
12 #include "media/cast/cast_config.h"
13 #include "media/cast/cast_environment.h"
14 #include "media/cast/cast_sender.h"
15 #include "media/cast/logging/logging_defines.h"
16 #include "media/cast/transport/cast_transport_config.h"
17 #include "media/cast/transport/cast_transport_sender.h"
19 using media::cast::AudioSenderConfig
;
20 using media::cast::CastEnvironment
;
21 using media::cast::CastSender
;
22 using media::cast::VideoSenderConfig
;
24 CastSessionDelegate::CastSessionDelegate()
25 : audio_encode_thread_("CastAudioEncodeThread"),
26 video_encode_thread_("CastVideoEncodeThread"),
27 transport_configured_(false),
28 io_message_loop_proxy_(
29 content::RenderThread::Get()->GetIOMessageLoopProxy()) {
30 DCHECK(io_message_loop_proxy_
);
33 CastSessionDelegate::~CastSessionDelegate() {
34 DCHECK(io_message_loop_proxy_
->BelongsToCurrentThread());
37 void CastSessionDelegate::Initialize() {
38 if (cast_environment_
)
39 return; // Already initialized.
41 audio_encode_thread_
.Start();
42 video_encode_thread_
.Start();
44 // CastSender uses the renderer's IO thread as the main thread. This reduces
45 // thread hopping for incoming video frames and outgoing network packets.
46 // There's no need to decode so no thread assigned for decoding.
47 // Get default logging: All disabled.
48 cast_environment_
= new CastEnvironment(
49 scoped_ptr
<base::TickClock
>(new base::DefaultTickClock()).Pass(),
50 base::MessageLoopProxy::current(),
51 audio_encode_thread_
.message_loop_proxy(),
53 video_encode_thread_
.message_loop_proxy(),
55 base::MessageLoopProxy::current(),
56 media::cast::GetDefaultCastSenderLoggingConfig());
59 void CastSessionDelegate::StartAudio(
60 const AudioSenderConfig
& config
,
61 const FrameInputAvailableCallback
& callback
) {
62 DCHECK(io_message_loop_proxy_
->BelongsToCurrentThread());
64 audio_config_
.reset(new AudioSenderConfig(config
));
65 video_frame_input_available_callback_
= callback
;
66 StartSendingInternal();
69 void CastSessionDelegate::StartVideo(
70 const VideoSenderConfig
& config
,
71 const FrameInputAvailableCallback
& callback
) {
72 DCHECK(io_message_loop_proxy_
->BelongsToCurrentThread());
73 audio_frame_input_available_callback_
= callback
;
75 video_config_
.reset(new VideoSenderConfig(config
));
76 StartSendingInternal();
79 void CastSessionDelegate::StartUDP(
80 const net::IPEndPoint
& local_endpoint
,
81 const net::IPEndPoint
& remote_endpoint
) {
82 DCHECK(io_message_loop_proxy_
->BelongsToCurrentThread());
83 transport_configured_
= true;
84 local_endpoint_
= local_endpoint
;
85 remote_endpoint_
= remote_endpoint
;
86 StartSendingInternal();
89 void CastSessionDelegate::StatusNotificationCB(
90 media::cast::transport::CastTransportStatus unused_status
) {
91 DCHECK(io_message_loop_proxy_
->BelongsToCurrentThread());
92 // TODO(hubbe): Call javascript UDPTransport error function.
95 void CastSessionDelegate::StartSendingInternal() {
96 DCHECK(io_message_loop_proxy_
->BelongsToCurrentThread());
98 // No transport, wait.
99 if (!transport_configured_
)
102 // No audio or video, wait.
103 if (!audio_config_
&& !video_config_
)
108 media::cast::transport::CastTransportConfig config
;
110 // TODO(hubbe): set config.aes_key and config.aes_iv_mask.
111 config
.local_endpoint
= local_endpoint_
;
112 config
.receiver_endpoint
= remote_endpoint_
;
114 config
.audio_ssrc
= audio_config_
->sender_ssrc
;
115 config
.audio_codec
= audio_config_
->codec
;
116 config
.audio_rtp_config
= audio_config_
->rtp_config
;
117 config
.audio_frequency
= audio_config_
->frequency
;
118 config
.audio_channels
= audio_config_
->channels
;
121 config
.video_ssrc
= video_config_
->sender_ssrc
;
122 config
.video_codec
= video_config_
->codec
;
123 config
.video_rtp_config
= video_config_
->rtp_config
;
126 cast_transport_
.reset(new CastTransportSenderIPC(
128 base::Bind(&CastSessionDelegate::StatusNotificationCB
,
129 base::Unretained(this))));
131 cast_sender_
.reset(CastSender::CreateCastSender(
136 base::Bind(&CastSessionDelegate::InitializationResult
,
137 base::Unretained(this)),
138 cast_transport_
.get()));
139 cast_transport_
->SetPacketReceiver(cast_sender_
->packet_receiver());
142 void CastSessionDelegate::InitializationResult(
143 media::cast::CastInitializationStatus result
) const {
144 DCHECK(cast_sender_
);
146 // TODO(pwestin): handle the error codes.
147 if (result
== media::cast::STATUS_INITIALIZED
) {
148 if (!audio_frame_input_available_callback_
.is_null()) {
149 audio_frame_input_available_callback_
.Run(cast_sender_
->frame_input());
151 if (!video_frame_input_available_callback_
.is_null()) {
152 video_frame_input_available_callback_
.Run(cast_sender_
->frame_input());