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 "media/cast/cast_sender_impl.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "media/base/video_frame.h"
12 #include "media/cast/sender/video_frame_factory.h"
17 // The LocalVideoFrameInput class posts all incoming video frames to the main
18 // cast thread for processing.
19 class LocalVideoFrameInput
: public VideoFrameInput
{
21 LocalVideoFrameInput(scoped_refptr
<CastEnvironment
> cast_environment
,
22 base::WeakPtr
<VideoSender
> video_sender
)
23 : cast_environment_(cast_environment
),
24 video_sender_(video_sender
),
27 video_sender
->CreateVideoFrameFactory().release() : nullptr) {}
29 void InsertRawVideoFrame(const scoped_refptr
<media::VideoFrame
>& video_frame
,
30 const base::TimeTicks
& capture_time
) final
{
31 cast_environment_
->PostTask(CastEnvironment::MAIN
,
33 base::Bind(&VideoSender::InsertRawVideoFrame
,
39 scoped_refptr
<VideoFrame
> MaybeCreateOptimizedFrame(
40 const gfx::Size
& frame_size
,
41 base::TimeDelta timestamp
) final
{
42 return video_frame_factory_
?
43 video_frame_factory_
->MaybeCreateFrame(frame_size
, timestamp
) : nullptr;
46 bool CanCreateOptimizedFrames() const final
{
47 return video_frame_factory_
.get() != nullptr;
51 ~LocalVideoFrameInput() final
{}
54 friend class base::RefCountedThreadSafe
<LocalVideoFrameInput
>;
56 const scoped_refptr
<CastEnvironment
> cast_environment_
;
57 const base::WeakPtr
<VideoSender
> video_sender_
;
58 const scoped_ptr
<VideoFrameFactory
> video_frame_factory_
;
60 DISALLOW_COPY_AND_ASSIGN(LocalVideoFrameInput
);
63 // The LocalAudioFrameInput class posts all incoming audio frames to the main
64 // cast thread for processing. Therefore frames can be inserted from any thread.
65 class LocalAudioFrameInput
: public AudioFrameInput
{
67 LocalAudioFrameInput(scoped_refptr
<CastEnvironment
> cast_environment
,
68 base::WeakPtr
<AudioSender
> audio_sender
)
69 : cast_environment_(cast_environment
), audio_sender_(audio_sender
) {}
71 void InsertAudio(scoped_ptr
<AudioBus
> audio_bus
,
72 const base::TimeTicks
& recorded_time
) final
{
73 cast_environment_
->PostTask(CastEnvironment::MAIN
,
75 base::Bind(&AudioSender::InsertAudio
,
77 base::Passed(&audio_bus
),
82 ~LocalAudioFrameInput() final
{}
85 friend class base::RefCountedThreadSafe
<LocalAudioFrameInput
>;
87 scoped_refptr
<CastEnvironment
> cast_environment_
;
88 base::WeakPtr
<AudioSender
> audio_sender_
;
90 DISALLOW_COPY_AND_ASSIGN(LocalAudioFrameInput
);
93 scoped_ptr
<CastSender
> CastSender::Create(
94 scoped_refptr
<CastEnvironment
> cast_environment
,
95 CastTransportSender
* const transport_sender
) {
96 CHECK(cast_environment
.get());
97 return scoped_ptr
<CastSender
>(
98 new CastSenderImpl(cast_environment
, transport_sender
));
101 CastSenderImpl::CastSenderImpl(
102 scoped_refptr
<CastEnvironment
> cast_environment
,
103 CastTransportSender
* const transport_sender
)
104 : cast_environment_(cast_environment
),
105 transport_sender_(transport_sender
),
106 weak_factory_(this) {
107 CHECK(cast_environment
.get());
110 void CastSenderImpl::InitializeAudio(
111 const AudioSenderConfig
& audio_config
,
112 const StatusChangeCallback
& status_change_cb
) {
113 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
114 CHECK(audio_config
.use_external_encoder
||
115 cast_environment_
->HasAudioThread());
117 VLOG(1) << "CastSenderImpl@" << this << "::InitializeAudio()";
120 new AudioSender(cast_environment_
,
122 base::Bind(&CastSenderImpl::OnAudioStatusChange
,
123 weak_factory_
.GetWeakPtr(),
127 DCHECK(audio_sender_
->GetTargetPlayoutDelay() ==
128 video_sender_
->GetTargetPlayoutDelay());
132 void CastSenderImpl::InitializeVideo(
133 const VideoSenderConfig
& video_config
,
134 const StatusChangeCallback
& status_change_cb
,
135 const CreateVideoEncodeAcceleratorCallback
& create_vea_cb
,
136 const CreateVideoEncodeMemoryCallback
& create_video_encode_mem_cb
) {
137 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
139 VLOG(1) << "CastSenderImpl@" << this << "::InitializeVideo()";
141 video_sender_
.reset(new VideoSender(
144 base::Bind(&CastSenderImpl::OnVideoStatusChange
,
145 weak_factory_
.GetWeakPtr(),
148 create_video_encode_mem_cb
,
150 base::Bind(&CastSenderImpl::SetTargetPlayoutDelay
,
151 weak_factory_
.GetWeakPtr())));
153 DCHECK(audio_sender_
->GetTargetPlayoutDelay() ==
154 video_sender_
->GetTargetPlayoutDelay());
158 CastSenderImpl::~CastSenderImpl() {
159 VLOG(1) << "CastSenderImpl@" << this << "::~CastSenderImpl()";
162 scoped_refptr
<AudioFrameInput
> CastSenderImpl::audio_frame_input() {
163 return audio_frame_input_
;
166 scoped_refptr
<VideoFrameInput
> CastSenderImpl::video_frame_input() {
167 return video_frame_input_
;
170 void CastSenderImpl::SetTargetPlayoutDelay(
171 base::TimeDelta new_target_playout_delay
) {
172 VLOG(1) << "CastSenderImpl@" << this << "::SetTargetPlayoutDelay("
173 << new_target_playout_delay
.InMilliseconds() << " ms)";
175 audio_sender_
->SetTargetPlayoutDelay(new_target_playout_delay
);
178 video_sender_
->SetTargetPlayoutDelay(new_target_playout_delay
);
182 void CastSenderImpl::OnAudioStatusChange(
183 const StatusChangeCallback
& status_change_cb
,
184 OperationalStatus status
) {
185 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
186 if (status
== STATUS_INITIALIZED
&& !audio_frame_input_
) {
188 new LocalAudioFrameInput(cast_environment_
, audio_sender_
->AsWeakPtr());
190 status_change_cb
.Run(status
);
193 void CastSenderImpl::OnVideoStatusChange(
194 const StatusChangeCallback
& status_change_cb
,
195 OperationalStatus status
) {
196 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
197 if (status
== STATUS_INITIALIZED
&& !video_frame_input_
) {
199 new LocalVideoFrameInput(cast_environment_
, video_sender_
->AsWeakPtr());
201 status_change_cb
.Run(status
);