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 "media/cast/cast_sender_impl.h"
6
7#include "base/bind.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
13namespace media {
14namespace cast {
15
16// The LocalVideoFrameInput class posts all incoming video frames to the main
17// cast thread for processing.
18class LocalVideoFrameInput : public VideoFrameInput {
19 public:
20  LocalVideoFrameInput(scoped_refptr<CastEnvironment> cast_environment,
21                       base::WeakPtr<VideoSender> video_sender)
22      : cast_environment_(cast_environment), video_sender_(video_sender) {}
23
24  virtual void InsertRawVideoFrame(
25      const scoped_refptr<media::VideoFrame>& video_frame,
26      const base::TimeTicks& capture_time) OVERRIDE {
27    cast_environment_->PostTask(CastEnvironment::MAIN,
28                                FROM_HERE,
29                                base::Bind(&VideoSender::InsertRawVideoFrame,
30                                           video_sender_,
31                                           video_frame,
32                                           capture_time));
33  }
34
35 protected:
36  virtual ~LocalVideoFrameInput() {}
37
38 private:
39  friend class base::RefCountedThreadSafe<LocalVideoFrameInput>;
40
41  scoped_refptr<CastEnvironment> cast_environment_;
42  base::WeakPtr<VideoSender> video_sender_;
43
44  DISALLOW_COPY_AND_ASSIGN(LocalVideoFrameInput);
45};
46
47// The LocalAudioFrameInput class posts all incoming audio frames to the main
48// cast thread for processing. Therefore frames can be inserted from any thread.
49class LocalAudioFrameInput : public AudioFrameInput {
50 public:
51  LocalAudioFrameInput(scoped_refptr<CastEnvironment> cast_environment,
52                       base::WeakPtr<AudioSender> audio_sender)
53      : cast_environment_(cast_environment), audio_sender_(audio_sender) {}
54
55  virtual void InsertAudio(scoped_ptr<AudioBus> audio_bus,
56                           const base::TimeTicks& recorded_time) OVERRIDE {
57    cast_environment_->PostTask(CastEnvironment::MAIN,
58                                FROM_HERE,
59                                base::Bind(&AudioSender::InsertAudio,
60                                           audio_sender_,
61                                           base::Passed(&audio_bus),
62                                           recorded_time));
63  }
64
65 protected:
66  virtual ~LocalAudioFrameInput() {}
67
68 private:
69  friend class base::RefCountedThreadSafe<LocalAudioFrameInput>;
70
71  scoped_refptr<CastEnvironment> cast_environment_;
72  base::WeakPtr<AudioSender> audio_sender_;
73
74  DISALLOW_COPY_AND_ASSIGN(LocalAudioFrameInput);
75};
76
77scoped_ptr<CastSender> CastSender::Create(
78    scoped_refptr<CastEnvironment> cast_environment,
79    CastTransportSender* const transport_sender) {
80  CHECK(cast_environment.get());
81  return scoped_ptr<CastSender>(
82      new CastSenderImpl(cast_environment, transport_sender));
83}
84
85CastSenderImpl::CastSenderImpl(
86    scoped_refptr<CastEnvironment> cast_environment,
87    CastTransportSender* const transport_sender)
88    : cast_environment_(cast_environment),
89      transport_sender_(transport_sender),
90      weak_factory_(this) {
91  CHECK(cast_environment.get());
92}
93
94void CastSenderImpl::InitializeAudio(
95    const AudioSenderConfig& audio_config,
96    const CastInitializationCallback& cast_initialization_cb) {
97  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
98  CHECK(audio_config.use_external_encoder ||
99        cast_environment_->HasAudioThread());
100
101  VLOG(1) << "CastSenderImpl@" << this << "::InitializeAudio()";
102
103  audio_sender_.reset(
104      new AudioSender(cast_environment_, audio_config, transport_sender_));
105
106  const CastInitializationStatus status = audio_sender_->InitializationResult();
107  if (status == STATUS_AUDIO_INITIALIZED) {
108    audio_frame_input_ =
109        new LocalAudioFrameInput(cast_environment_, audio_sender_->AsWeakPtr());
110  }
111  cast_initialization_cb.Run(status);
112  if (video_sender_) {
113    DCHECK(audio_sender_->GetTargetPlayoutDelay() ==
114           video_sender_->GetTargetPlayoutDelay());
115  }
116}
117
118void CastSenderImpl::InitializeVideo(
119    const VideoSenderConfig& video_config,
120    const CastInitializationCallback& cast_initialization_cb,
121    const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
122    const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) {
123  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
124  CHECK(video_config.use_external_encoder ||
125        cast_environment_->HasVideoThread());
126
127  VLOG(1) << "CastSenderImpl@" << this << "::InitializeVideo()";
128
129  video_sender_.reset(new VideoSender(
130      cast_environment_,
131      video_config,
132      base::Bind(&CastSenderImpl::OnVideoInitialized,
133                 weak_factory_.GetWeakPtr(), cast_initialization_cb),
134      create_vea_cb,
135      create_video_encode_mem_cb,
136      transport_sender_,
137      base::Bind(&CastSenderImpl::SetTargetPlayoutDelay,
138                 weak_factory_.GetWeakPtr())));
139  if (audio_sender_) {
140    DCHECK(audio_sender_->GetTargetPlayoutDelay() ==
141           video_sender_->GetTargetPlayoutDelay());
142  }
143}
144
145CastSenderImpl::~CastSenderImpl() {
146  VLOG(1) << "CastSenderImpl@" << this << "::~CastSenderImpl()";
147}
148
149scoped_refptr<AudioFrameInput> CastSenderImpl::audio_frame_input() {
150  return audio_frame_input_;
151}
152
153scoped_refptr<VideoFrameInput> CastSenderImpl::video_frame_input() {
154  return video_frame_input_;
155}
156
157void CastSenderImpl::SetTargetPlayoutDelay(
158    base::TimeDelta new_target_playout_delay) {
159  VLOG(1) << "CastSenderImpl@" << this << "::SetTargetPlayoutDelay("
160          << new_target_playout_delay.InMilliseconds() << " ms)";
161  if (audio_sender_) {
162    audio_sender_->SetTargetPlayoutDelay(new_target_playout_delay);
163  }
164  if (video_sender_) {
165    video_sender_->SetTargetPlayoutDelay(new_target_playout_delay);
166  }
167}
168
169void CastSenderImpl::OnVideoInitialized(
170    const CastInitializationCallback& initialization_cb,
171    media::cast::CastInitializationStatus result) {
172  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
173  video_frame_input_ =
174      new LocalVideoFrameInput(cast_environment_, video_sender_->AsWeakPtr());
175  initialization_cb.Run(result);
176}
177
178}  // namespace cast
179}  // namespace media
180