OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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/remoting/remoting_controller.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/single_thread_task_runner.h" | |
10 | |
11 namespace media { | |
12 | |
13 RemotingController::RemotingController( | |
14 mojom::RemotingSourceRequest source_request, | |
15 mojom::RemoterPtr remoter) | |
16 : binding_(this, std::move(source_request)), | |
17 remoter_(std::move(remoter)), | |
18 task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
19 weak_factory_(this) {} | |
20 | |
21 RemotingController::~RemotingController() {} | |
22 | |
23 void RemotingController::OnSinkAvailable() { | |
24 DCHECK(task_runner_->BelongsToCurrentThread()); | |
25 | |
26 is_sink_available_ = true; | |
27 UpdateAndMaybeSwitch(); | |
28 } | |
29 | |
30 void RemotingController::OnSinkGone() { | |
31 DCHECK(task_runner_->BelongsToCurrentThread()); | |
32 | |
33 is_sink_available_ = false; | |
34 UpdateAndMaybeSwitch(); | |
35 } | |
36 | |
37 void RemotingController::OnStarted() { | |
38 DCHECK(task_runner_->BelongsToCurrentThread()); | |
39 | |
40 VLOG(1) << "Remoting started successively."; | |
41 if (is_remoting_) | |
42 switch_renderer_cb_.Run(); | |
43 else | |
44 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); | |
45 } | |
46 | |
47 void RemotingController::OnStartFailed(mojom::RemotingStartFailReason reason) { | |
48 DCHECK(task_runner_->BelongsToCurrentThread()); | |
49 | |
50 VLOG(1) << "Failed to start remoting:" << reason; | |
51 is_remoting_ = false; | |
52 } | |
53 | |
54 void RemotingController::OnMessageFromSink( | |
55 const std::vector<uint8_t>& message) { | |
56 DCHECK(task_runner_->BelongsToCurrentThread()); | |
57 | |
58 // TODO(xjz): Merge with Eric's CL to handle the RPC messages here. | |
59 NOTIMPLEMENTED(); | |
60 } | |
61 | |
62 void RemotingController::OnStopped(mojom::RemotingStopReason reason) { | |
63 DCHECK(task_runner_->BelongsToCurrentThread()); | |
64 | |
65 VLOG(1) << "Remoting stopped: " << reason; | |
66 is_remoting_ = false; | |
67 } | |
68 | |
69 void RemotingController::OnEnteredFullscreen() { | |
70 DCHECK(task_runner_->BelongsToCurrentThread()); | |
71 | |
72 is_fullscreen_ = true; | |
73 UpdateAndMaybeSwitch(); | |
74 } | |
75 | |
76 void RemotingController::OnExitedFullscreen() { | |
77 DCHECK(task_runner_->BelongsToCurrentThread()); | |
78 | |
79 is_fullscreen_ = false; | |
80 UpdateAndMaybeSwitch(); | |
81 } | |
82 | |
83 void RemotingController::OnSetCdm(CdmContext* cdm_context) { | |
84 DCHECK(task_runner_->BelongsToCurrentThread()); | |
85 | |
86 // TODO(xjz): Not implemented. Will add in up-coming change. | |
87 NOTIMPLEMENTED(); | |
88 } | |
89 | |
90 void RemotingController::SetSwitchRendererCallback( | |
91 const SwitchRendererCallback& cb) { | |
92 DCHECK(task_runner_->BelongsToCurrentThread()); | |
93 DCHECK(!cb.is_null()); | |
94 | |
95 switch_renderer_cb_ = cb; | |
96 } | |
97 | |
98 void RemotingController::OnMetadata(const PipelineMetadata& metadata) { | |
99 DCHECK(task_runner_->BelongsToCurrentThread()); | |
100 | |
101 has_video_ = metadata.has_video; | |
102 has_audio_ = metadata.has_audio; | |
103 if (!has_video_ && !has_audio_) | |
104 return; | |
105 | |
106 if (has_video_) { | |
107 DCHECK(metadata.video_decoder_config.IsValidConfig()); | |
108 video_decoder_config_ = metadata.video_decoder_config; | |
109 } | |
110 if (has_audio_) { | |
111 DCHECK(metadata.audio_decoder_config.IsValidConfig()); | |
112 audio_decoder_config_ = metadata.audio_decoder_config; | |
113 } | |
114 UpdateAndMaybeSwitch(); | |
115 } | |
116 | |
117 bool RemotingController::IsVideoConfigSupported() { | |
118 DCHECK(task_runner_->BelongsToCurrentThread()); | |
119 DCHECK(has_video_); | |
120 | |
121 switch (video_decoder_config_.codec()) { | |
122 case VideoCodec::kCodecH264: | |
123 case VideoCodec::kCodecVP8: | |
124 return true; | |
125 default: | |
126 VLOG(2) << "Remoting does not support video codec: " | |
127 << video_decoder_config_.codec(); | |
128 return false; | |
129 } | |
130 } | |
131 | |
132 bool RemotingController::IsAudioConfigSupported() { | |
133 DCHECK(task_runner_->BelongsToCurrentThread()); | |
134 DCHECK(has_audio_); | |
135 | |
136 switch (audio_decoder_config_.codec()) { | |
137 case AudioCodec::kCodecAAC: | |
138 case AudioCodec::kCodecMP3: | |
139 case AudioCodec::kCodecPCM: | |
140 case AudioCodec::kCodecVorbis: | |
141 case AudioCodec::kCodecFLAC: | |
142 case AudioCodec::kCodecAMR_NB: | |
143 case AudioCodec::kCodecAMR_WB: | |
144 case AudioCodec::kCodecPCM_MULAW: | |
145 case AudioCodec::kCodecGSM_MS: | |
146 case AudioCodec::kCodecPCM_S16BE: | |
147 case AudioCodec::kCodecPCM_S24BE: | |
148 case AudioCodec::kCodecOpus: | |
149 case AudioCodec::kCodecEAC3: | |
150 case AudioCodec::kCodecPCM_ALAW: | |
151 case AudioCodec::kCodecALAC: | |
152 case AudioCodec::kCodecAC3: | |
153 return true; | |
154 default: | |
155 VLOG(2) << "Remoting does not support audio codec: " | |
156 << audio_decoder_config_.codec(); | |
157 return false; | |
158 } | |
159 } | |
160 | |
161 bool RemotingController::ShouldBeRemoting() { | |
162 DCHECK(task_runner_->BelongsToCurrentThread()); | |
163 | |
164 // TODO(xjz): The control logic for EME will be added in a later CL. | |
165 if (video_decoder_config_.is_encrypted()) | |
xhwang
2016/10/05 05:27:53
How about make this check part of IsVideoConfigSup
xjz
2016/10/05 17:24:23
I would leave this check here for now. It will cha
xhwang
2016/10/05 17:36:41
Then please at least check |has_video_| before che
xjz
2016/10/05 23:39:01
Done.
| |
166 return false; | |
167 if (audio_decoder_config_.is_encrypted()) | |
168 return false; | |
169 if (!is_sink_available_) | |
170 return false; | |
171 if (!is_fullscreen_) | |
172 return false; | |
173 if (has_video_ && !IsVideoConfigSupported()) | |
174 return false; | |
175 if (has_audio_ && !IsAudioConfigSupported()) | |
176 return false; | |
177 return true; | |
178 } | |
179 | |
180 void RemotingController::UpdateAndMaybeSwitch() { | |
181 DCHECK(task_runner_->BelongsToCurrentThread()); | |
182 | |
183 // TODO(xjz): The switching logic for encrypted content will be added in a | |
184 // later CL. | |
185 | |
186 // Demuxer is not initialized yet. | |
187 if (!has_audio_ && !has_video_) | |
188 return; | |
189 | |
190 DCHECK(!switch_renderer_cb_.is_null()); | |
191 | |
192 bool should_be_remoting = ShouldBeRemoting(); | |
193 if (is_remoting_ == should_be_remoting) | |
194 return; | |
195 | |
196 // Switch between local and remoting. | |
197 is_remoting_ = should_be_remoting; | |
198 if (is_remoting_) { | |
199 // |swithc_renderer_cb_.Run()| will be called after remoting is started | |
200 // successfully. | |
201 remoter_->Start(); | |
202 } else { | |
203 switch_renderer_cb_.Run(); | |
204 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); | |
205 } | |
206 } | |
207 | |
208 } // namespace media | |
OLD | NEW |