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

Side by Side Diff: media/remoting/remoting_source_impl.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_source_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/remoting/remoting_controller.h" 5 #include "media/remoting/remoting_source_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_helpers.h"
10 #include "base/logging.h" 8 #include "base/logging.h"
11 #include "base/single_thread_task_runner.h"
12 #include "media/remoting/rpc/proto_utils.h" 9 #include "media/remoting/rpc/proto_utils.h"
13 #include "media/remoting/rpc/rpc_broker.h"
14 10
15 namespace media { 11 namespace media {
16 12
17 RemotingController::RemotingController( 13 RemotingSourceImpl::RemotingSourceImpl(
18 mojom::RemotingSourceRequest source_request, 14 mojom::RemotingSourceRequest source_request,
19 mojom::RemoterPtr remoter) 15 mojom::RemoterPtr remoter)
20 : binding_(this, std::move(source_request)), 16 : rpc_broker_(base::Bind(&RemotingSourceImpl::SendMessageToSink,
21 remoter_(std::move(remoter)), 17 base::Unretained(this))),
22 task_runner_(base::ThreadTaskRunnerHandle::Get()), 18 binding_(this, std::move(source_request)),
23 weak_factory_(this) { 19 remoter_(std::move(remoter)) {
24 DCHECK(remoter_); 20 DCHECK(remoter_);
25 rpc_broker_.reset(new remoting::RpcBroker(base::Bind( 21 }
26 &RemotingController::OnSendMessageToSink, weak_factory_.GetWeakPtr()))); 22
27 } 23 RemotingSourceImpl::~RemotingSourceImpl() {
28 24 DCHECK(thread_checker_.CalledOnValidThread());
29 RemotingController::~RemotingController() {} 25
30 26 if (!clients_.empty()) {
31 void RemotingController::StartDataPipe( 27 Shutdown();
28 clients_.clear();
29 }
30 }
31
32 void RemotingSourceImpl::OnSinkAvailable() {
33 DCHECK(thread_checker_.CalledOnValidThread());
34
35 if (state_ == RemotingSessionState::SESSION_UNAVAILABLE)
36 UpdateAndNotifyState(RemotingSessionState::SESSION_CAN_START);
37 }
38
39 void RemotingSourceImpl::OnSinkGone() {
40 DCHECK(thread_checker_.CalledOnValidThread());
41
42 if (state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED)
43 return;
44 if (state_ == RemotingSessionState::SESSION_CAN_START) {
45 UpdateAndNotifyState(RemotingSessionState::SESSION_UNAVAILABLE);
46 return;
47 }
48 if (state_ == RemotingSessionState::SESSION_STARTED ||
49 state_ == RemotingSessionState::SESSION_STARTING) {
50 VLOG(1) << "Sink is gone in a remoting session.";
51 // Remoting is being stopped by Remoter.
52 UpdateAndNotifyState(RemotingSessionState::SESSION_STOPPING);
53 }
54 }
55
56 void RemotingSourceImpl::OnStarted() {
57 DCHECK(thread_checker_.CalledOnValidThread());
58
59 VLOG(1) << "Remoting started successively.";
60 if (clients_.empty() ||
61 state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED ||
62 state_ == RemotingSessionState::SESSION_STOPPING) {
63 for (Client* client : clients_)
64 client->OnStarted(false);
65 return;
66 }
67 for (Client* client : clients_)
68 client->OnStarted(true);
69 state_ = RemotingSessionState::SESSION_STARTED;
70 }
71
72 void RemotingSourceImpl::OnStartFailed(mojom::RemotingStartFailReason reason) {
73 DCHECK(thread_checker_.CalledOnValidThread());
74
75 VLOG(1) << "Failed to start remoting:" << reason;
76 for (Client* client : clients_)
77 client->OnStarted(false);
78 if (state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED)
79 return;
80 state_ = RemotingSessionState::SESSION_UNAVAILABLE;
81 }
82
83 void RemotingSourceImpl::OnStopped(mojom::RemotingStopReason reason) {
84 DCHECK(thread_checker_.CalledOnValidThread());
85
86 VLOG(1) << "Remoting stopped: " << reason;
87 if (state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED)
88 return;
89 RemotingSessionState state = RemotingSessionState::SESSION_UNAVAILABLE;
90 UpdateAndNotifyState(state);
91 }
92
93 void RemotingSourceImpl::OnMessageFromSink(
94 const std::vector<uint8_t>& message) {
95 DCHECK(thread_checker_.CalledOnValidThread());
96
97 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
98 if (!rpc->ParseFromArray(message.data(), message.size())) {
99 LOG(ERROR) << "corrupted Rpc message";
100 Shutdown();
101 return;
102 }
103 rpc_broker_.ProcessMessageFromRemote(std::move(rpc));
104 }
105
106 void RemotingSourceImpl::UpdateAndNotifyState(RemotingSessionState state) {
107 DCHECK(thread_checker_.CalledOnValidThread());
108
109 if (state_ == state)
110 return;
111 state_ = state;
112 for (Client* client : clients_)
113 client->OnSessionStateChanged();
114 }
115
116 void RemotingSourceImpl::StartRemoting(Client* client) {
117 DCHECK(std::find(clients_.begin(), clients_.end(), client) != clients_.end());
118
119 switch (state_) {
120 case SESSION_CAN_START:
121 remoter_->Start();
122 UpdateAndNotifyState(RemotingSessionState::SESSION_STARTING);
123 break;
124 case SESSION_STARTING:
125 break;
126 case SESSION_STARTED:
127 client->OnStarted(true);
128 break;
129 case SESSION_STOPPING:
130 case SESSION_UNAVAILABLE:
131 case SESSION_PERMANENTLY_STOPPED:
132 client->OnStarted(false);
133 break;
134 }
135 }
136
137 void RemotingSourceImpl::StopRemoting(Client* client) {
138 DCHECK(std::find(clients_.begin(), clients_.end(), client) != clients_.end());
139
140 VLOG(1) << "RemotingSourceImpl::StopRemoting: " << state_;
141
142 if (state_ != RemotingSessionState::SESSION_STARTING &&
143 state_ != RemotingSessionState::SESSION_STARTED)
144 return;
145
146 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK);
147 UpdateAndNotifyState(RemotingSessionState::SESSION_STOPPING);
148 }
149
150 void RemotingSourceImpl::AddClient(Client* client) {
151 DCHECK(thread_checker_.CalledOnValidThread());
152 DCHECK(std::find(clients_.begin(), clients_.end(), client) == clients_.end());
153
154 clients_.push_back(client);
155 client->OnSessionStateChanged();
156 }
157
158 void RemotingSourceImpl::RemoveClient(Client* client) {
159 DCHECK(thread_checker_.CalledOnValidThread());
160
161 auto it = std::find(clients_.begin(), clients_.end(), client);
162 DCHECK(it != clients_.end());
163
164 clients_.erase(it);
165 if (clients_.empty() && (state_ == RemotingSessionState::SESSION_STARTED ||
166 state_ == RemotingSessionState::SESSION_STARTING)) {
167 remoter_->Stop(mojom::RemotingStopReason::SOURCE_GONE);
168 state_ = RemotingSessionState::SESSION_STOPPING;
169 }
170 }
171
172 void RemotingSourceImpl::Shutdown() {
173 DCHECK(thread_checker_.CalledOnValidThread());
174
175 if (state_ == RemotingSessionState::SESSION_STARTED ||
176 state_ == RemotingSessionState::SESSION_STARTING)
177 remoter_->Stop(mojom::RemotingStopReason::UNEXPECTED_FAILURE);
178 UpdateAndNotifyState(RemotingSessionState::SESSION_PERMANENTLY_STOPPED);
179 }
180
181 void RemotingSourceImpl::StartDataPipe(
32 std::unique_ptr<mojo::DataPipe> audio_data_pipe, 182 std::unique_ptr<mojo::DataPipe> audio_data_pipe,
33 std::unique_ptr<mojo::DataPipe> video_data_pipe, 183 std::unique_ptr<mojo::DataPipe> video_data_pipe,
34 const DataPipeStartCallback& done_callback) { 184 const DataPipeStartCallback& done_callback) {
35 VLOG(2) << __FUNCTION__; 185 DCHECK(thread_checker_.CalledOnValidThread());
36 DCHECK(task_runner_->BelongsToCurrentThread());
37 DCHECK(!done_callback.is_null()); 186 DCHECK(!done_callback.is_null());
187
38 bool audio = audio_data_pipe != nullptr; 188 bool audio = audio_data_pipe != nullptr;
39 bool video = video_data_pipe != nullptr; 189 bool video = video_data_pipe != nullptr;
40
41 if (!audio && !video) { 190 if (!audio && !video) {
42 LOG(ERROR) << "No audio and video to establish data pipe"; 191 LOG(ERROR) << "No audio and video to establish data pipe";
43 done_callback.Run(mojom::RemotingDataStreamSenderPtrInfo(), 192 done_callback.Run(mojom::RemotingDataStreamSenderPtrInfo(),
44 mojom::RemotingDataStreamSenderPtrInfo(), 193 mojom::RemotingDataStreamSenderPtrInfo(),
45 mojo::ScopedDataPipeProducerHandle(), 194 mojo::ScopedDataPipeProducerHandle(),
46 mojo::ScopedDataPipeProducerHandle()); 195 mojo::ScopedDataPipeProducerHandle());
47 return; 196 return;
48 } 197 }
49
50 mojom::RemotingDataStreamSenderPtr audio_stream_sender; 198 mojom::RemotingDataStreamSenderPtr audio_stream_sender;
51 mojom::RemotingDataStreamSenderPtr video_stream_sender; 199 mojom::RemotingDataStreamSenderPtr video_stream_sender;
52 remoter_->StartDataStreams( 200 remoter_->StartDataStreams(
53 audio ? std::move(audio_data_pipe->consumer_handle) 201 audio ? std::move(audio_data_pipe->consumer_handle)
54 : mojo::ScopedDataPipeConsumerHandle(), 202 : mojo::ScopedDataPipeConsumerHandle(),
55 video ? std::move(video_data_pipe->consumer_handle) 203 video ? std::move(video_data_pipe->consumer_handle)
56 : mojo::ScopedDataPipeConsumerHandle(), 204 : mojo::ScopedDataPipeConsumerHandle(),
57 audio ? mojo::GetProxy(&audio_stream_sender) 205 audio ? mojo::GetProxy(&audio_stream_sender)
58 : media::mojom::RemotingDataStreamSenderRequest(), 206 : media::mojom::RemotingDataStreamSenderRequest(),
59 video ? mojo::GetProxy(&video_stream_sender) 207 video ? mojo::GetProxy(&video_stream_sender)
60 : media::mojom::RemotingDataStreamSenderRequest()); 208 : media::mojom::RemotingDataStreamSenderRequest());
61
62 done_callback.Run(audio_stream_sender.PassInterface(), 209 done_callback.Run(audio_stream_sender.PassInterface(),
63 video_stream_sender.PassInterface(), 210 video_stream_sender.PassInterface(),
64 audio ? std::move(audio_data_pipe->producer_handle) 211 audio ? std::move(audio_data_pipe->producer_handle)
65 : mojo::ScopedDataPipeProducerHandle(), 212 : mojo::ScopedDataPipeProducerHandle(),
66 video ? std::move(video_data_pipe->producer_handle) 213 video ? std::move(video_data_pipe->producer_handle)
67 : mojo::ScopedDataPipeProducerHandle()); 214 : mojo::ScopedDataPipeProducerHandle());
68 } 215 }
69 216
70 base::WeakPtr<remoting::RpcBroker> RemotingController::GetRpcBroker() const { 217 remoting::RpcBroker* RemotingSourceImpl::GetRpcBroker() const {
71 DCHECK(task_runner_->BelongsToCurrentThread()); 218 DCHECK(thread_checker_.CalledOnValidThread());
72 return rpc_broker_->GetWeakPtr(); 219 // TODO(xjz): Fix the const-correctness.
73 } 220 return const_cast<remoting::RpcBroker*>(&rpc_broker_);
74 221 }
75 void RemotingController::OnSendMessageToSink( 222
223 void RemotingSourceImpl::SendMessageToSink(
76 std::unique_ptr<std::vector<uint8_t>> message) { 224 std::unique_ptr<std::vector<uint8_t>> message) {
77 DCHECK(task_runner_->BelongsToCurrentThread()); 225 DCHECK(thread_checker_.CalledOnValidThread());
78 remoter_->SendMessageToSink(*message); 226 remoter_->SendMessageToSink(*message);
79 } 227 }
80 228
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 229 } // namespace media
OLDNEW
« no previous file with comments | « media/remoting/remoting_source_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698