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

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

Issue 2457563002: Media Remoting: Add remoting control logic for encrypted contents. (Closed)
Patch Set: Bug fix. 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
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" 10 #include "media/remoting/rpc/rpc_broker.h"
14 11
15 namespace media { 12 namespace media {
16 13
17 RemotingController::RemotingController( 14 RemotingSourceImpl::RemotingSourceImpl(
18 mojom::RemotingSourceRequest source_request, 15 mojom::RemotingSourceRequest source_request,
19 mojom::RemoterPtr remoter) 16 mojom::RemoterPtr remoter)
20 : binding_(this, std::move(source_request)), 17 : binding_(this, std::move(source_request)), remoter_(std::move(remoter)) {
21 remoter_(std::move(remoter)),
22 task_runner_(base::ThreadTaskRunnerHandle::Get()),
23 weak_factory_(this) {
24 DCHECK(remoter_); 18 DCHECK(remoter_);
25 rpc_broker_.reset(new remoting::RpcBroker(base::Bind( 19 rpc_broker_.reset(new remoting::RpcBroker(
miu 2016/11/05 04:05:16 Please move this to the initializer list.
xjz 2016/11/07 19:03:55 Done.
26 &RemotingController::OnSendMessageToSink, weak_factory_.GetWeakPtr()))); 20 base::Bind(&RemotingSourceImpl::OnSendMessageToSink, this)));
27 } 21 }
28 22
29 RemotingController::~RemotingController() {} 23 RemotingSourceImpl::~RemotingSourceImpl() {
30 24 DCHECK(thread_checker_.CalledOnValidThread());
31 void RemotingController::StartDataPipe( 25
26 if (!clients_.empty()) {
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";
miu 2016/11/05 04:05:16 We should shut down remoting if a message is corru
xjz 2016/11/07 19:03:55 Done.
100 return;
101 }
102 rpc_broker_->ProcessMessageFromRemote(std::move(rpc));
103 }
104
105 void RemotingSourceImpl::UpdateAndNotifyState(RemotingSessionState state) {
106 DCHECK(thread_checker_.CalledOnValidThread());
107
108 if (state_ == state)
109 return;
110 state_ = state;
111 for (Client* client : clients_)
112 client->OnSessionStateChanged();
113 }
114
115 void RemotingSourceImpl::StartRemoting(Client* client) {
116 DCHECK(std::find(clients_.begin(), clients_.end(), client) != clients_.end());
117
118 switch (state_) {
119 case SESSION_CAN_START:
120 remoter_->Start();
121 UpdateAndNotifyState(RemotingSessionState::SESSION_STARTING);
122 break;
123 case SESSION_STARTING:
124 break;
125 case SESSION_STARTED:
126 client->OnStarted(true);
127 break;
128 case SESSION_STOPPING:
129 case SESSION_UNAVAILABLE:
130 case SESSION_PERMANENTLY_STOPPED:
131 client->OnStarted(false);
132 break;
133 }
134 }
135
136 void RemotingSourceImpl::StopRemoting(Client* client) {
137 DCHECK(std::find(clients_.begin(), clients_.end(), client) != clients_.end());
138
139 VLOG(1) << "RemotingSourceImpl::StopRemoting: " << state_;
140
141 if (state_ != RemotingSessionState::SESSION_STARTING &&
142 state_ != RemotingSessionState::SESSION_STARTED)
143 return;
144
145 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK);
146 UpdateAndNotifyState(RemotingSessionState::SESSION_STOPPING);
147 }
148
149 void RemotingSourceImpl::AddClient(Client* client) {
150 DCHECK(thread_checker_.CalledOnValidThread());
151 DCHECK(std::find(clients_.begin(), clients_.end(), client) == clients_.end());
152
153 clients_.push_back(client);
154 client->OnSessionStateChanged();
155 }
156
157 void RemotingSourceImpl::RemoveClient(Client* client) {
158 DCHECK(thread_checker_.CalledOnValidThread());
159
160 auto it = std::find(clients_.begin(), clients_.end(), client);
161 DCHECK(it != clients_.end());
162
163 clients_.erase(it);
164 if (clients_.empty() && (state_ == RemotingSessionState::SESSION_STARTED ||
165 state_ == RemotingSessionState::SESSION_STARTING)) {
166 remoter_->Stop(mojom::RemotingStopReason::SOURCE_GONE);
167 state_ = RemotingSessionState::SESSION_STOPPING;
168 }
169 }
170
171 void RemotingSourceImpl::Shutdown() {
172 DCHECK(thread_checker_.CalledOnValidThread());
173
174 if (state_ == RemotingSessionState::SESSION_STARTED ||
175 state_ == RemotingSessionState::SESSION_STARTING)
176 remoter_->Stop(mojom::RemotingStopReason::UNEXPECTED_FAILURE);
177 UpdateAndNotifyState(RemotingSessionState::SESSION_PERMANENTLY_STOPPED);
178 }
179
180 void RemotingSourceImpl::StartDataPipe(
32 std::unique_ptr<mojo::DataPipe> audio_data_pipe, 181 std::unique_ptr<mojo::DataPipe> audio_data_pipe,
33 std::unique_ptr<mojo::DataPipe> video_data_pipe, 182 std::unique_ptr<mojo::DataPipe> video_data_pipe,
34 const DataPipeStartCallback& done_callback) { 183 const DataPipeStartCallback& done_callback) {
35 VLOG(2) << __FUNCTION__; 184 DCHECK(thread_checker_.CalledOnValidThread());
36 DCHECK(task_runner_->BelongsToCurrentThread());
37 DCHECK(!done_callback.is_null()); 185 DCHECK(!done_callback.is_null());
186
38 bool audio = audio_data_pipe != nullptr; 187 bool audio = audio_data_pipe != nullptr;
39 bool video = video_data_pipe != nullptr; 188 bool video = video_data_pipe != nullptr;
40
41 if (!audio && !video) { 189 if (!audio && !video) {
42 LOG(ERROR) << "No audio and video to establish data pipe"; 190 LOG(ERROR) << "No audio and video to establish data pipe";
43 done_callback.Run(mojom::RemotingDataStreamSenderPtrInfo(), 191 done_callback.Run(mojom::RemotingDataStreamSenderPtrInfo(),
44 mojom::RemotingDataStreamSenderPtrInfo(), 192 mojom::RemotingDataStreamSenderPtrInfo(),
45 mojo::ScopedDataPipeProducerHandle(), 193 mojo::ScopedDataPipeProducerHandle(),
46 mojo::ScopedDataPipeProducerHandle()); 194 mojo::ScopedDataPipeProducerHandle());
47 return; 195 return;
48 } 196 }
49
50 mojom::RemotingDataStreamSenderPtr audio_stream_sender; 197 mojom::RemotingDataStreamSenderPtr audio_stream_sender;
51 mojom::RemotingDataStreamSenderPtr video_stream_sender; 198 mojom::RemotingDataStreamSenderPtr video_stream_sender;
52 remoter_->StartDataStreams( 199 remoter_->StartDataStreams(
53 audio ? std::move(audio_data_pipe->consumer_handle) 200 audio ? std::move(audio_data_pipe->consumer_handle)
54 : mojo::ScopedDataPipeConsumerHandle(), 201 : mojo::ScopedDataPipeConsumerHandle(),
55 video ? std::move(video_data_pipe->consumer_handle) 202 video ? std::move(video_data_pipe->consumer_handle)
56 : mojo::ScopedDataPipeConsumerHandle(), 203 : mojo::ScopedDataPipeConsumerHandle(),
57 audio ? mojo::GetProxy(&audio_stream_sender) 204 audio ? mojo::GetProxy(&audio_stream_sender)
58 : media::mojom::RemotingDataStreamSenderRequest(), 205 : media::mojom::RemotingDataStreamSenderRequest(),
59 video ? mojo::GetProxy(&video_stream_sender) 206 video ? mojo::GetProxy(&video_stream_sender)
60 : media::mojom::RemotingDataStreamSenderRequest()); 207 : media::mojom::RemotingDataStreamSenderRequest());
61
62 done_callback.Run(audio_stream_sender.PassInterface(), 208 done_callback.Run(audio_stream_sender.PassInterface(),
63 video_stream_sender.PassInterface(), 209 video_stream_sender.PassInterface(),
64 audio ? std::move(audio_data_pipe->producer_handle) 210 audio ? std::move(audio_data_pipe->producer_handle)
65 : mojo::ScopedDataPipeProducerHandle(), 211 : mojo::ScopedDataPipeProducerHandle(),
66 video ? std::move(video_data_pipe->producer_handle) 212 video ? std::move(video_data_pipe->producer_handle)
67 : mojo::ScopedDataPipeProducerHandle()); 213 : mojo::ScopedDataPipeProducerHandle());
68 } 214 }
69 215
70 base::WeakPtr<remoting::RpcBroker> RemotingController::GetRpcBroker() const { 216 base::WeakPtr<remoting::RpcBroker> RemotingSourceImpl::GetRpcBroker() const {
71 DCHECK(task_runner_->BelongsToCurrentThread()); 217 DCHECK(thread_checker_.CalledOnValidThread());
72 return rpc_broker_->GetWeakPtr(); 218 return rpc_broker_->GetWeakPtr();
73 } 219 }
74 220 void RemotingSourceImpl::OnSendMessageToSink(
miu 2016/11/05 04:05:16 naming nit: Just "SendMessageToSink()" since this
xjz 2016/11/07 19:03:55 Done.
75 void RemotingController::OnSendMessageToSink(
76 std::unique_ptr<std::vector<uint8_t>> message) { 221 std::unique_ptr<std::vector<uint8_t>> message) {
77 DCHECK(task_runner_->BelongsToCurrentThread()); 222 DCHECK(thread_checker_.CalledOnValidThread());
78 remoter_->SendMessageToSink(*message); 223 remoter_->SendMessageToSink(*message);
79 } 224 }
80 225
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 226 } // namespace media
OLDNEW
« media/remoting/remoting_source_impl.h ('K') | « media/remoting/remoting_source_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698