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::OnMetadataChanged(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 // On Android, when using the MediaPlayerRenderer, |has_video_| and | |
107 // |has_audio_| will be true, but the respective configs will be empty. | |
108 // We cannot make any assumptions on the validity of configs. | |
109 if (has_video_) { | |
110 video_decoder_config_ = metadata.video_decoder_config; | |
111 is_encrypted_ |= video_decoder_config_.is_encrypted(); | |
112 } | |
113 if (has_audio_) { | |
114 audio_decoder_config_ = metadata.audio_decoder_config; | |
115 is_encrypted_ |= audio_decoder_config_.is_encrypted(); | |
116 } | |
117 UpdateAndMaybeSwitch(); | |
118 } | |
119 | |
120 bool RemotingController::IsVideoCodecSupported() { | |
121 DCHECK(task_runner_->BelongsToCurrentThread()); | |
122 DCHECK(has_video_); | |
123 | |
124 switch (video_decoder_config_.codec()) { | |
125 case VideoCodec::kCodecH264: | |
126 case VideoCodec::kCodecVP8: | |
127 return true; | |
128 default: | |
129 VLOG(2) << "Remoting does not support video codec: " | |
130 << video_decoder_config_.codec(); | |
131 return false; | |
132 } | |
133 } | |
134 | |
135 bool RemotingController::IsAudioCodecSupported() { | |
136 DCHECK(task_runner_->BelongsToCurrentThread()); | |
137 DCHECK(has_audio_); | |
138 | |
139 switch (audio_decoder_config_.codec()) { | |
140 case AudioCodec::kCodecAAC: | |
141 case AudioCodec::kCodecMP3: | |
142 case AudioCodec::kCodecPCM: | |
143 case AudioCodec::kCodecVorbis: | |
144 case AudioCodec::kCodecFLAC: | |
145 case AudioCodec::kCodecAMR_NB: | |
146 case AudioCodec::kCodecAMR_WB: | |
147 case AudioCodec::kCodecPCM_MULAW: | |
148 case AudioCodec::kCodecGSM_MS: | |
149 case AudioCodec::kCodecPCM_S16BE: | |
150 case AudioCodec::kCodecPCM_S24BE: | |
151 case AudioCodec::kCodecOpus: | |
152 case AudioCodec::kCodecEAC3: | |
153 case AudioCodec::kCodecPCM_ALAW: | |
154 case AudioCodec::kCodecALAC: | |
155 case AudioCodec::kCodecAC3: | |
156 return true; | |
157 default: | |
158 VLOG(2) << "Remoting does not support audio codec: " | |
159 << audio_decoder_config_.codec(); | |
160 return false; | |
161 } | |
162 } | |
163 | |
164 bool RemotingController::ShouldBeRemoting() { | |
165 DCHECK(task_runner_->BelongsToCurrentThread()); | |
166 | |
167 // TODO(xjz): The control logic for EME will be added in a later CL. | |
168 if (is_encrypted_) | |
169 return false; | |
170 | |
171 if (!is_sink_available_) | |
172 return false; | |
173 if (!is_fullscreen_) | |
174 return false; | |
175 if (has_video_ && !IsVideoCodecSupported()) | |
176 return false; | |
177 if (has_audio_ && !IsAudioCodecSupported()) | |
178 return false; | |
179 return true; | |
180 } | |
181 | |
182 void RemotingController::UpdateAndMaybeSwitch() { | |
183 DCHECK(task_runner_->BelongsToCurrentThread()); | |
184 | |
185 // TODO(xjz): The switching logic for encrypted content will be added in a | |
186 // later CL. | |
187 | |
188 // Demuxer is not initialized yet. | |
189 if (!has_audio_ && !has_video_) | |
190 return; | |
191 | |
192 DCHECK(!switch_renderer_cb_.is_null()); | |
193 | |
194 bool should_be_remoting = ShouldBeRemoting(); | |
195 if (is_remoting_ == should_be_remoting) | |
196 return; | |
197 | |
198 // Switch between local and remoting. | |
199 is_remoting_ = should_be_remoting; | |
200 if (is_remoting_) { | |
201 // |swithc_renderer_cb_.Run()| will be called after remoting is started | |
202 // successfully. | |
203 remoter_->Start(); | |
204 } else { | |
205 switch_renderer_cb_.Run(); | |
206 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); | |
207 } | |
208 } | |
209 | |
210 } // namespace media | |
OLD | NEW |