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

Side by Side Diff: content/renderer/pepper/pepper_audio_encoder_host.cc

Issue 1348563003: ppapi: implement PPB_AudioEncoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address tsepez's review Created 5 years, 2 months 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
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698