OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "base/bind.h" | |
6 #include "base/memory/shared_memory.h" | |
7 #include "base/numerics/safe_math.h" | |
8 #include "content/public/renderer/renderer_ppapi_host.h" | |
9 #include "content/renderer/pepper/audio_encoder_shim.h" | |
10 #include "content/renderer/pepper/host_globals.h" | |
11 #include "content/renderer/pepper/pepper_audio_encoder_host.h" | |
12 #include "content/renderer/render_thread_impl.h" | |
13 #include "media/base/bind_to_current_loop.h" | |
14 #include "ppapi/c/pp_codecs.h" | |
15 #include "ppapi/c/pp_errors.h" | |
16 #include "ppapi/host/dispatch_host_message.h" | |
17 #include "ppapi/host/ppapi_host.h" | |
18 #include "ppapi/proxy/ppapi_messages.h" | |
19 #include "ppapi/shared_impl/media_stream_buffer.h" | |
20 | |
21 using ppapi::proxy::SerializedHandle; | |
22 | |
23 namespace content { | |
24 | |
25 namespace { | |
26 | |
27 // Number of input audio buffers (150ms at 10ms per frame). | |
28 const uint32_t kDefaultNumberOfAudioFrames = 15; | |
29 | |
30 // Number of bitstream buffers. | |
31 const uint32_t kDefaultNumberOfBitstreamBuffers = 8; | |
32 | |
33 // Default bitstream buffers size. | |
34 // TODO(llandwerlin): Would having this a multiple of the audio frame | |
35 // size would make more sense? | |
36 const size_t kDefaultBitstreamBufferSize = 100000; | |
37 | |
38 bool PP_HardwareAccelerationCompatible(bool accelerated, | |
39 PP_HardwareAcceleration requested) { | |
40 switch (requested) { | |
41 case PP_HARDWAREACCELERATION_ONLY: | |
42 return accelerated; | |
43 case PP_HARDWAREACCELERATION_NONE: | |
44 return !accelerated; | |
45 case PP_HARDWAREACCELERATION_WITHFALLBACK: | |
46 return true; | |
47 // No default case, to catch unhandled PP_HardwareAcceleration values. | |
48 } | |
49 return false; | |
50 } | |
51 | |
52 } // namespace | |
53 | |
54 class PepperAudioEncoderHost::BufferManager | |
55 : public base::RefCountedThreadSafe<BufferManager> { | |
56 public: | |
57 uint32_t number_of_buffers() const { return number_of_buffers_; } | |
58 size_t buffer_size() const { return buffer_size_; } | |
59 | |
60 virtual bool Initialize(uint32_t number_of_buffers, size_t buffer_size) { | |
61 number_of_buffers_ = number_of_buffers; | |
62 buffer_size_ = buffer_size; | |
63 return true; | |
64 } | |
65 | |
66 virtual uint8_t* GetBuffer(uint32_t id) = 0; | |
67 virtual base::SharedMemory* GetSharedMemory() = 0; | |
68 | |
69 uint32_t DequeueBuffer() { | |
70 DCHECK(!enqueued_buffers_.empty()); | |
71 uint32_t id = enqueued_buffers_.front(); | |
72 enqueued_buffers_.pop_front(); | |
73 buffers_.erase(id); | |
74 return id; | |
75 } | |
76 void EnqueueBuffer(uint32_t id) { | |
77 DCHECK(!IsBufferQueued(id)); | |
78 enqueued_buffers_.push_back(id); | |
79 buffers_.insert(id); | |
80 } | |
81 bool HasAvailableBuffer() { return !enqueued_buffers_.empty(); } | |
82 bool IsBufferQueued(uint32_t id) { | |
83 return buffers_.find(id) != buffers_.end(); | |
84 } | |
85 | |
86 protected: | |
87 friend class base::RefCountedThreadSafe<BufferManager>; | |
88 BufferManager() : number_of_buffers_(0), buffer_size_(0) {} | |
89 virtual ~BufferManager() {} | |
90 | |
91 private: | |
92 uint32_t number_of_buffers_; | |
93 size_t buffer_size_; | |
94 std::deque<uint32_t> enqueued_buffers_; | |
95 std::set<uint32_t> buffers_; | |
96 | |
97 DISALLOW_COPY_AND_ASSIGN(BufferManager); | |
98 }; | |
99 | |
100 class PepperAudioEncoderHost::PcmBufferManager : public BufferManager { | |
101 public: | |
102 PcmBufferManager(const ppapi::proxy::PPB_AudioEncodeParameters& parameters, | |
103 uint32_t number_of_samples) | |
104 : encode_parameters_(parameters), | |
105 number_of_samples_(number_of_samples), | |
106 total_buffer_size_(0) {} | |
107 | |
108 private: | |
109 ~PcmBufferManager() override {} | |
110 | |
111 // PepperAudioEncoderHost::BufferManager: | |
112 bool Initialize(uint32_t number_of_buffers, size_t buffer_size) override { | |
113 base::CheckedNumeric<size_t> total_buffer_size = | |
114 buffer_size + sizeof(ppapi::MediaStreamBuffer::Audio); | |
115 total_buffer_size_ = total_buffer_size.ValueOrDie(); | |
116 base::CheckedNumeric<size_t> total_memory_size = total_buffer_size_; | |
117 total_memory_size *= number_of_buffers; | |
118 shm_ = RenderThreadImpl::current() | |
Tom Sepez
2015/10/05 16:54:16
you might want to call IsValid() and return false
llandwerlin-old
2015/10/05 17:16:31
Done.
| |
119 ->HostAllocateSharedMemoryBuffer(total_memory_size.ValueOrDie()) | |
120 .Pass(); | |
121 if (!shm_ || !shm_->Map(total_memory_size.ValueOrDie())) | |
122 return false; | |
123 | |
124 for (uint32_t i = 0; i < number_of_buffers; ++i) { | |
125 uint8_t* mem = | |
126 static_cast<uint8_t*>(shm_->memory()) + total_buffer_size_ * i; | |
127 ppapi::MediaStreamBuffer::Audio* buffer = | |
128 reinterpret_cast<ppapi::MediaStreamBuffer::Audio*>(mem); | |
129 buffer->header.size = total_buffer_size_; | |
130 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO; | |
131 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>( | |
132 encode_parameters_.input_sample_rate); | |
133 buffer->number_of_channels = encode_parameters_.channels; | |
134 buffer->number_of_samples = number_of_samples_; | |
135 buffer->data_size = buffer_size; | |
136 } | |
137 | |
138 return BufferManager::Initialize(number_of_buffers, buffer_size); | |
139 } | |
140 uint8_t* GetBuffer(uint32_t id) override { | |
141 if (id >= number_of_buffers()) | |
142 return nullptr; | |
143 uint8_t* mem = | |
144 static_cast<uint8_t*>(shm_->memory()) + total_buffer_size_ * id; | |
145 return static_cast<uint8_t*>( | |
146 reinterpret_cast<ppapi::MediaStreamBuffer::Audio*>(mem)->data); | |
147 } | |
148 base::SharedMemory* GetSharedMemory() override { return shm_.get(); } | |
149 | |
150 scoped_ptr<base::SharedMemory> shm_; | |
151 ppapi::proxy::PPB_AudioEncodeParameters encode_parameters_; | |
152 uint32_t number_of_samples_; | |
153 size_t total_buffer_size_; | |
154 }; | |
155 | |
156 class PepperAudioEncoderHost::BitstreamBufferManager : public BufferManager { | |
157 public: | |
158 BitstreamBufferManager() {} | |
159 | |
160 private: | |
161 ~BitstreamBufferManager() override {} | |
162 | |
163 // PepperAudioEncoderHost::BufferManager: | |
164 bool Initialize(uint32_t number_of_buffers, size_t buffer_size) override { | |
165 base::CheckedNumeric<size_t> total_size = number_of_buffers * buffer_size; | |
Tom Sepez
2015/10/05 16:54:16
need to assign first, then multiply as you did abo
llandwerlin-old
2015/10/05 17:16:31
Sorry, missed this one.
| |
166 shm_ = RenderThreadImpl::current() | |
167 ->HostAllocateSharedMemoryBuffer(total_size.ValueOrDie()) | |
168 .Pass(); | |
169 if (!shm_ || !shm_->Map(total_size.ValueOrDie())) | |
170 return false; | |
171 | |
172 for (uint32_t i = 0; i < number_of_buffers; ++i) | |
173 EnqueueBuffer(i); | |
174 | |
175 return BufferManager::Initialize(number_of_buffers, buffer_size); | |
176 } | |
177 uint8_t* GetBuffer(uint32_t id) override { | |
178 if (id >= number_of_buffers()) | |
179 return nullptr; | |
180 return static_cast<uint8_t*>(shm_->memory()) + (id * buffer_size()); | |
181 } | |
182 base::SharedMemory* GetSharedMemory() override { return shm_.get(); } | |
183 | |
184 scoped_ptr<base::SharedMemory> shm_; | |
185 }; | |
186 | |
187 class PepperAudioEncoderHost::AudioData : public AudioEncoderShim::AudioData { | |
188 public: | |
189 AudioData(int32_t id, const scoped_refptr<BufferManager>& buffer_manager) | |
190 : id_(id), buffer_manager_(buffer_manager) {} | |
191 | |
192 int32_t id() const { return id_; } | |
193 | |
194 private: | |
195 ~AudioData() override {} | |
196 | |
197 // AudioEncoderShim::AudioData: | |
198 uint8_t* GetData() override { return buffer_manager_->GetBuffer(id_); } | |
199 size_t GetSize() override { return buffer_manager_->buffer_size(); } | |
200 | |
201 int32_t id_; | |
202 scoped_refptr<BufferManager> buffer_manager_; | |
203 | |
204 DISALLOW_COPY_AND_ASSIGN(AudioData); | |
205 }; | |
206 | |
207 PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host, | |
208 PP_Instance instance, | |
209 PP_Resource resource) | |
210 : ResourceHost(host->GetPpapiHost(), instance, resource), | |
211 renderer_ppapi_host_(host), | |
212 initialized_(false), | |
213 encoder_last_error_(PP_ERROR_FAILED), | |
214 weak_ptr_factory_(this) {} | |
215 | |
216 PepperAudioEncoderHost::~PepperAudioEncoderHost() { | |
217 Close(); | |
218 } | |
219 | |
220 int32_t PepperAudioEncoderHost::OnResourceMessageReceived( | |
221 const IPC::Message& msg, | |
222 ppapi::host::HostMessageContext* context) { | |
223 PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg) | |
224 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( | |
225 PpapiHostMsg_AudioEncoder_GetSupportedProfiles, | |
226 OnHostMsgGetSupportedProfiles) | |
227 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize, | |
228 OnHostMsgInitialize) | |
229 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( | |
230 PpapiHostMsg_AudioEncoder_GetAudioFrames, OnHostMsgGetAudioFrames) | |
231 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode, | |
232 OnHostMsgEncode) | |
233 PPAPI_DISPATCH_HOST_RESOURCE_CALL( | |
234 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer, | |
235 OnHostMsgRecycleBitstreamBuffer) | |
236 PPAPI_DISPATCH_HOST_RESOURCE_CALL( | |
237 PpapiHostMsg_AudioEncoder_RequestBitrateChange, | |
238 OnHostMsgRequestBitrateChange) | |
239 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close, | |
240 OnHostMsgClose) | |
241 PPAPI_END_MESSAGE_MAP() | |
242 return PP_ERROR_FAILED; | |
243 } | |
244 | |
245 int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles( | |
246 ppapi::host::HostMessageContext* context) { | |
247 std::vector<PP_AudioProfileDescription> profiles; | |
248 GetSupportedProfiles(&profiles); | |
249 | |
250 host()->SendReply( | |
251 context->MakeReplyMessageContext(), | |
252 PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles)); | |
253 | |
254 return PP_OK_COMPLETIONPENDING; | |
255 } | |
256 | |
257 int32_t PepperAudioEncoderHost::OnHostMsgInitialize( | |
258 ppapi::host::HostMessageContext* context, | |
259 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { | |
260 if (initialized_) | |
261 return PP_ERROR_FAILED; | |
262 | |
263 if (!IsInitializationValid(parameters)) | |
264 return PP_ERROR_NOTSUPPORTED; | |
265 | |
266 encode_parameters_ = parameters; | |
267 initialize_reply_context_ = context->MakeReplyMessageContext(); | |
268 | |
269 int32_t error = PP_ERROR_FAILED; | |
270 if (parameters.acceleration == PP_HARDWAREACCELERATION_NONE || | |
271 parameters.acceleration == PP_HARDWAREACCELERATION_WITHFALLBACK) { | |
272 encoder_.reset(new AudioEncoderShim); | |
273 if (encoder_->Initialize(parameters)) { | |
274 if (AllocateBitstreamBuffers(kDefaultBitstreamBufferSize)) { | |
275 encoder_last_error_ = PP_OK; | |
276 return PP_OK_COMPLETIONPENDING; | |
277 } | |
278 error = PP_ERROR_NOMEMORY; | |
279 } else | |
280 error = PP_ERROR_FAILED; | |
281 } | |
282 | |
283 initialize_reply_context_ = ppapi::host::ReplyMessageContext(); | |
284 encoder_ = nullptr; | |
285 | |
286 return error; | |
287 } | |
288 | |
289 int32_t PepperAudioEncoderHost::OnHostMsgGetAudioFrames( | |
290 ppapi::host::HostMessageContext* context) { | |
291 if (encoder_last_error_) | |
292 return encoder_last_error_; | |
293 | |
294 get_audio_frames_reply_context_ = context->MakeReplyMessageContext(); | |
295 if (!AllocateAudioFrames(encoder_->GetNumberOfSamplesPerFrame())) | |
296 return PP_ERROR_NOMEMORY; | |
297 | |
298 return PP_OK_COMPLETIONPENDING; | |
299 } | |
300 | |
301 int32_t PepperAudioEncoderHost::OnHostMsgEncode( | |
302 ppapi::host::HostMessageContext* context, | |
303 uint32_t buffer_id) { | |
304 if (encoder_last_error_) | |
305 return encoder_last_error_; | |
306 | |
307 if (buffer_id >= audio_buffer_manager_->number_of_buffers() || | |
308 audio_buffer_manager_->IsBufferQueued(buffer_id)) | |
309 return PP_ERROR_BADARGUMENT; | |
310 | |
311 audio_buffer_manager_->EnqueueBuffer(buffer_id); | |
312 | |
313 DoEncode(); | |
314 | |
315 return PP_OK_COMPLETIONPENDING; | |
316 } | |
317 | |
318 int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer( | |
319 ppapi::host::HostMessageContext* context, | |
320 uint32_t buffer_id) { | |
321 if (encoder_last_error_) | |
322 return encoder_last_error_; | |
323 | |
324 if (buffer_id >= bitstream_buffer_manager_->number_of_buffers() || | |
325 bitstream_buffer_manager_->IsBufferQueued(buffer_id)) | |
326 return PP_ERROR_BADARGUMENT; | |
327 | |
328 bitstream_buffer_manager_->EnqueueBuffer(buffer_id); | |
329 | |
330 DoEncode(); | |
331 | |
332 return PP_OK; | |
333 } | |
334 | |
335 int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange( | |
336 ppapi::host::HostMessageContext* context, | |
337 uint32_t bitrate) { | |
338 if (encoder_last_error_) | |
339 return encoder_last_error_; | |
340 | |
341 encoder_->RequestBitrateChange(bitrate); | |
342 | |
343 return PP_OK; | |
344 } | |
345 | |
346 int32_t PepperAudioEncoderHost::OnHostMsgClose( | |
347 ppapi::host::HostMessageContext* context) { | |
348 encoder_last_error_ = PP_ERROR_FAILED; | |
349 Close(); | |
350 | |
351 return PP_OK; | |
352 } | |
353 | |
354 void PepperAudioEncoderHost::GetSupportedProfiles( | |
355 std::vector<PP_AudioProfileDescription>* profiles) { | |
356 DCHECK(RenderThreadImpl::current()); | |
357 | |
358 AudioEncoderShim software_encoder; | |
359 *profiles = software_encoder.GetSupportedProfiles(); | |
360 } | |
361 | |
362 bool PepperAudioEncoderHost::IsInitializationValid( | |
363 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { | |
364 DCHECK(RenderThreadImpl::current()); | |
365 | |
366 std::vector<PP_AudioProfileDescription> profiles; | |
367 GetSupportedProfiles(&profiles); | |
368 | |
369 for (const PP_AudioProfileDescription& profile : profiles) { | |
370 if (parameters.output_profile == profile.profile && | |
371 parameters.input_sample_size == profile.sample_size && | |
372 parameters.input_sample_rate == profile.sample_rate && | |
373 parameters.channels <= profile.max_channels && | |
374 PP_HardwareAccelerationCompatible( | |
375 profile.hardware_accelerated == PP_TRUE ? true : false, | |
376 parameters.acceleration)) | |
377 return true; | |
378 } | |
379 | |
380 return false; | |
381 } | |
382 | |
383 bool PepperAudioEncoderHost::AllocateAudioFrames(uint32_t number_of_samples) { | |
384 DCHECK(RenderThreadImpl::current()); | |
385 DCHECK(initialized_); | |
386 DCHECK(get_audio_frames_reply_context_.is_valid()); | |
387 | |
388 // Frames have already been allocated. | |
389 if (audio_buffer_manager_) | |
390 return false; | |
391 | |
392 scoped_refptr<BufferManager> buffer_manager( | |
393 new PcmBufferManager(encode_parameters_, number_of_samples)); | |
394 base::CheckedNumeric<size_t> buffer_size = number_of_samples; | |
395 buffer_size *= | |
396 encode_parameters_.channels * encode_parameters_.input_sample_size; | |
Tom Sepez
2015/10/05 16:54:16
again, you need to do the multplications one at a
llandwerlin-old
2015/10/05 17:16:31
Ok, left this one because the encode_parameters_ a
| |
397 if (!buffer_manager->Initialize(kDefaultNumberOfAudioFrames, | |
398 buffer_size.ValueOrDie())) { | |
399 get_audio_frames_reply_context_ = ppapi::host::ReplyMessageContext(); | |
400 return false; | |
401 } | |
402 | |
403 get_audio_frames_reply_context_.params.AppendHandle( | |
404 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote( | |
405 buffer_manager->GetSharedMemory()->handle()), | |
406 buffer_manager->GetSharedMemory()->mapped_size())); | |
407 | |
408 host()->SendReply( | |
409 get_audio_frames_reply_context_, | |
410 PpapiPluginMsg_AudioEncoder_GetAudioFramesReply( | |
411 buffer_manager->number_of_buffers(), buffer_manager->buffer_size())); | |
412 | |
413 audio_buffer_manager_ = buffer_manager; | |
414 get_audio_frames_reply_context_ = ppapi::host::ReplyMessageContext(); | |
415 | |
416 return true; | |
417 } | |
418 | |
419 bool PepperAudioEncoderHost::AllocateBitstreamBuffers(size_t buffer_size) { | |
420 DCHECK(RenderThreadImpl::current()); | |
421 // We assume RequireBitstreamBuffers is only called once. | |
422 DCHECK(!initialized_); | |
423 DCHECK(initialize_reply_context_.is_valid()); | |
424 | |
425 scoped_refptr<BufferManager> buffer_manager(new BitstreamBufferManager); | |
426 if (!buffer_manager->Initialize(kDefaultNumberOfBitstreamBuffers, | |
427 buffer_size)) { | |
428 initialize_reply_context_ = ppapi::host::ReplyMessageContext(); | |
429 return false; | |
430 } | |
431 | |
432 initialize_reply_context_.params.AppendHandle( | |
433 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote( | |
434 buffer_manager->GetSharedMemory()->handle()), | |
435 buffer_manager->GetSharedMemory()->mapped_size())); | |
436 | |
437 host()->SendReply( | |
438 initialize_reply_context_, | |
439 PpapiPluginMsg_AudioEncoder_InitializeReply( | |
440 encoder_->GetNumberOfSamplesPerFrame(), | |
441 buffer_manager->number_of_buffers(), buffer_manager->buffer_size())); | |
442 | |
443 bitstream_buffer_manager_ = buffer_manager; | |
444 initialize_reply_context_ = ppapi::host::ReplyMessageContext(); | |
445 | |
446 return true; | |
447 } | |
448 | |
449 scoped_refptr<PepperAudioEncoderHost::AudioData> | |
450 PepperAudioEncoderHost::GetAudioData( | |
451 const scoped_refptr<BufferManager>& buffer_manager) { | |
452 if (!buffer_manager->HasAvailableBuffer()) | |
453 return scoped_refptr<AudioData>(); | |
454 return make_scoped_refptr( | |
455 new AudioData(buffer_manager->DequeueBuffer(), buffer_manager)); | |
456 } | |
457 | |
458 void PepperAudioEncoderHost::DoEncode() { | |
459 if (!audio_buffer_manager_->HasAvailableBuffer() || | |
460 !bitstream_buffer_manager_->HasAvailableBuffer()) | |
461 return; | |
462 | |
463 scoped_refptr<AudioData> input(GetAudioData(audio_buffer_manager_)); | |
464 encoder_->Encode(input, GetAudioData(bitstream_buffer_manager_), | |
465 base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady, | |
466 weak_ptr_factory_.GetWeakPtr(), input->id())); | |
467 } | |
468 | |
469 void PepperAudioEncoderHost::BitstreamBufferReady( | |
470 uint32_t audio_buffer_id, | |
471 const scoped_refptr<AudioEncoderShim::AudioData>& output, | |
472 size_t size) { | |
473 DCHECK(RenderThreadImpl::current()); | |
474 | |
475 if (encoder_last_error_) | |
476 return; | |
477 | |
478 host()->SendUnsolicitedReply( | |
479 pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(audio_buffer_id)); | |
480 | |
481 if (size < 0) { | |
482 NotifyPepperError(PP_ERROR_FAILED); | |
483 return; | |
484 } | |
485 | |
486 host()->SendUnsolicitedReply( | |
487 pp_resource(), PpapiPluginMsg_AudioEncoder_BitstreamBufferReady( | |
488 static_cast<AudioData*>(output.get())->id(), size)); | |
489 } | |
490 | |
491 void PepperAudioEncoderHost::NotifyPepperError(int32_t error) { | |
492 DCHECK(RenderThreadImpl::current()); | |
493 | |
494 encoder_last_error_ = error; | |
495 Close(); | |
496 host()->SendUnsolicitedReply( | |
497 pp_resource(), | |
498 PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_)); | |
499 } | |
500 | |
501 void PepperAudioEncoderHost::Close() { | |
502 DCHECK(RenderThreadImpl::current()); | |
503 | |
504 encoder_ = nullptr; | |
505 audio_buffer_manager_ = nullptr; | |
506 bitstream_buffer_manager_ = nullptr; | |
507 } | |
508 | |
509 } // namespace content | |
OLD | NEW |