OLD | NEW |
---|---|
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 |
OLD | NEW |