Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: media/remoting/remoting_controller.cc

Issue 2457563002: Media Remoting: Add remoting control logic for encrypted contents. (Closed)
Patch Set: Addressed comments from PS#12. Fixed ASAN. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/remoting/remoting_controller.h ('k') | media/remoting/remoting_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/bind_helpers.h"
9 #include "base/callback_helpers.h"
10 #include "base/logging.h"
11 #include "base/single_thread_task_runner.h"
12 #include "media/remoting/rpc/proto_utils.h"
13 #include "media/remoting/rpc/rpc_broker.h"
14
15 namespace media {
16
17 RemotingController::RemotingController(
18 mojom::RemotingSourceRequest source_request,
19 mojom::RemoterPtr remoter)
20 : binding_(this, std::move(source_request)),
21 remoter_(std::move(remoter)),
22 task_runner_(base::ThreadTaskRunnerHandle::Get()),
23 weak_factory_(this) {
24 DCHECK(remoter_);
25 rpc_broker_.reset(new remoting::RpcBroker(base::Bind(
26 &RemotingController::OnSendMessageToSink, weak_factory_.GetWeakPtr())));
27 }
28
29 RemotingController::~RemotingController() {}
30
31 void RemotingController::StartDataPipe(
32 std::unique_ptr<mojo::DataPipe> audio_data_pipe,
33 std::unique_ptr<mojo::DataPipe> video_data_pipe,
34 const DataPipeStartCallback& done_callback) {
35 VLOG(2) << __FUNCTION__;
36 DCHECK(task_runner_->BelongsToCurrentThread());
37 DCHECK(!done_callback.is_null());
38 bool audio = audio_data_pipe != nullptr;
39 bool video = video_data_pipe != nullptr;
40
41 if (!audio && !video) {
42 LOG(ERROR) << "No audio and video to establish data pipe";
43 done_callback.Run(mojom::RemotingDataStreamSenderPtrInfo(),
44 mojom::RemotingDataStreamSenderPtrInfo(),
45 mojo::ScopedDataPipeProducerHandle(),
46 mojo::ScopedDataPipeProducerHandle());
47 return;
48 }
49
50 mojom::RemotingDataStreamSenderPtr audio_stream_sender;
51 mojom::RemotingDataStreamSenderPtr video_stream_sender;
52 remoter_->StartDataStreams(
53 audio ? std::move(audio_data_pipe->consumer_handle)
54 : mojo::ScopedDataPipeConsumerHandle(),
55 video ? std::move(video_data_pipe->consumer_handle)
56 : mojo::ScopedDataPipeConsumerHandle(),
57 audio ? mojo::GetProxy(&audio_stream_sender)
58 : media::mojom::RemotingDataStreamSenderRequest(),
59 video ? mojo::GetProxy(&video_stream_sender)
60 : media::mojom::RemotingDataStreamSenderRequest());
61
62 done_callback.Run(audio_stream_sender.PassInterface(),
63 video_stream_sender.PassInterface(),
64 audio ? std::move(audio_data_pipe->producer_handle)
65 : mojo::ScopedDataPipeProducerHandle(),
66 video ? std::move(video_data_pipe->producer_handle)
67 : mojo::ScopedDataPipeProducerHandle());
68 }
69
70 base::WeakPtr<remoting::RpcBroker> RemotingController::GetRpcBroker() const {
71 DCHECK(task_runner_->BelongsToCurrentThread());
72 return rpc_broker_->GetWeakPtr();
73 }
74
75 void RemotingController::OnSendMessageToSink(
76 std::unique_ptr<std::vector<uint8_t>> message) {
77 DCHECK(task_runner_->BelongsToCurrentThread());
78 remoter_->SendMessageToSink(*message);
79 }
80
81 void RemotingController::OnSinkAvailable() {
82 DCHECK(task_runner_->BelongsToCurrentThread());
83
84 is_sink_available_ = true;
85 UpdateAndMaybeSwitch();
86 }
87
88 void RemotingController::OnSinkGone() {
89 DCHECK(task_runner_->BelongsToCurrentThread());
90
91 is_sink_available_ = false;
92 UpdateAndMaybeSwitch();
93 }
94
95 void RemotingController::OnStarted() {
96 DCHECK(task_runner_->BelongsToCurrentThread());
97
98 VLOG(1) << "Remoting started successively.";
99 if (is_remoting_)
100 switch_renderer_cb_.Run();
101 else
102 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK);
103 }
104
105 void RemotingController::OnStartFailed(mojom::RemotingStartFailReason reason) {
106 DCHECK(task_runner_->BelongsToCurrentThread());
107
108 VLOG(1) << "Failed to start remoting:" << reason;
109 is_remoting_ = false;
110 }
111
112 void RemotingController::OnMessageFromSink(
113 const std::vector<uint8_t>& message) {
114 DCHECK(task_runner_->BelongsToCurrentThread());
115 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
116 if (!rpc->ParseFromArray(message.data(), message.size())) {
117 LOG(ERROR) << "corrupted Rpc message";
118 return;
119 }
120
121 rpc_broker_->ProcessMessageFromRemote(std::move(rpc));
122 }
123
124 void RemotingController::OnStopped(mojom::RemotingStopReason reason) {
125 DCHECK(task_runner_->BelongsToCurrentThread());
126
127 VLOG(1) << "Remoting stopped: " << reason;
128 is_remoting_ = false;
129 }
130
131 void RemotingController::OnEnteredFullscreen() {
132 DCHECK(task_runner_->BelongsToCurrentThread());
133
134 is_fullscreen_ = true;
135 UpdateAndMaybeSwitch();
136 }
137
138 void RemotingController::OnExitedFullscreen() {
139 DCHECK(task_runner_->BelongsToCurrentThread());
140
141 is_fullscreen_ = false;
142 UpdateAndMaybeSwitch();
143 }
144
145 void RemotingController::OnSetCdm(CdmContext* cdm_context) {
146 DCHECK(task_runner_->BelongsToCurrentThread());
147
148 // TODO(xjz): Not implemented. Will add in up-coming change.
149 NOTIMPLEMENTED();
150 }
151
152 void RemotingController::SetSwitchRendererCallback(
153 const SwitchRendererCallback& cb) {
154 DCHECK(task_runner_->BelongsToCurrentThread());
155 DCHECK(!cb.is_null());
156
157 switch_renderer_cb_ = cb;
158 }
159
160 void RemotingController::OnMetadataChanged(const PipelineMetadata& metadata) {
161 DCHECK(task_runner_->BelongsToCurrentThread());
162
163 has_video_ = metadata.has_video;
164 has_audio_ = metadata.has_audio;
165 if (!has_video_ && !has_audio_)
166 return;
167
168 // On Android, when using the MediaPlayerRenderer, |has_video_| and
169 // |has_audio_| will be true, but the respective configs will be empty.
170 // We cannot make any assumptions on the validity of configs.
171 if (has_video_) {
172 video_decoder_config_ = metadata.video_decoder_config;
173 is_encrypted_ |= video_decoder_config_.is_encrypted();
174 }
175 if (has_audio_) {
176 audio_decoder_config_ = metadata.audio_decoder_config;
177 is_encrypted_ |= audio_decoder_config_.is_encrypted();
178 }
179 UpdateAndMaybeSwitch();
180 }
181
182 bool RemotingController::IsVideoCodecSupported() {
183 DCHECK(task_runner_->BelongsToCurrentThread());
184 DCHECK(has_video_);
185
186 switch (video_decoder_config_.codec()) {
187 case VideoCodec::kCodecH264:
188 case VideoCodec::kCodecVP8:
189 return true;
190 default:
191 VLOG(2) << "Remoting does not support video codec: "
192 << video_decoder_config_.codec();
193 return false;
194 }
195 }
196
197 bool RemotingController::IsAudioCodecSupported() {
198 DCHECK(task_runner_->BelongsToCurrentThread());
199 DCHECK(has_audio_);
200
201 switch (audio_decoder_config_.codec()) {
202 case AudioCodec::kCodecAAC:
203 case AudioCodec::kCodecMP3:
204 case AudioCodec::kCodecPCM:
205 case AudioCodec::kCodecVorbis:
206 case AudioCodec::kCodecFLAC:
207 case AudioCodec::kCodecAMR_NB:
208 case AudioCodec::kCodecAMR_WB:
209 case AudioCodec::kCodecPCM_MULAW:
210 case AudioCodec::kCodecGSM_MS:
211 case AudioCodec::kCodecPCM_S16BE:
212 case AudioCodec::kCodecPCM_S24BE:
213 case AudioCodec::kCodecOpus:
214 case AudioCodec::kCodecEAC3:
215 case AudioCodec::kCodecPCM_ALAW:
216 case AudioCodec::kCodecALAC:
217 case AudioCodec::kCodecAC3:
218 return true;
219 default:
220 VLOG(2) << "Remoting does not support audio codec: "
221 << audio_decoder_config_.codec();
222 return false;
223 }
224 }
225
226 bool RemotingController::ShouldBeRemoting() {
227 DCHECK(task_runner_->BelongsToCurrentThread());
228
229 // TODO(xjz): The control logic for EME will be added in a later CL.
230 if (is_encrypted_)
231 return false;
232
233 if (!is_sink_available_)
234 return false;
235 if (!is_fullscreen_)
236 return false;
237 if (has_video_ && !IsVideoCodecSupported())
238 return false;
239 if (has_audio_ && !IsAudioCodecSupported())
240 return false;
241 return true;
242 }
243
244 void RemotingController::UpdateAndMaybeSwitch() {
245 DCHECK(task_runner_->BelongsToCurrentThread());
246
247 // TODO(xjz): The switching logic for encrypted content will be added in a
248 // later CL.
249
250 // Demuxer is not initialized yet.
251 if (!has_audio_ && !has_video_)
252 return;
253
254 DCHECK(!switch_renderer_cb_.is_null());
255
256 bool should_be_remoting = ShouldBeRemoting();
257 if (is_remoting_ == should_be_remoting)
258 return;
259
260 // Switch between local and remoting.
261 is_remoting_ = should_be_remoting;
262 if (is_remoting_) {
263 // |swithc_renderer_cb_.Run()| will be called after remoting is started
264 // successfully.
265 remoter_->Start();
266 } else {
267 switch_renderer_cb_.Run();
268 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK);
269 }
270 }
271
272 } // namespace media
OLDNEW
« no previous file with comments | « media/remoting/remoting_controller.h ('k') | media/remoting/remoting_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698