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

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

Issue 1151973003: ppapi: implement PPB_AudioEncoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More Windows fixes in proxy code Created 5 years, 6 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 uint32_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 virtual uint8_t* GetBuffer(int32_t id) = 0;
66 virtual int32_t DequeueBuffer() = 0;
67 virtual void EnqueueBuffer(int32_t id) = 0;
68 virtual base::SharedMemory* GetSharedMemory() = 0;
69
70 protected:
71 friend class base::RefCountedThreadSafe<BufferManager>;
72 BufferManager() : number_of_buffers_(0), buffer_size_(0) {}
73 virtual ~BufferManager() {}
74
75 private:
76 uint32_t number_of_buffers_;
77 size_t buffer_size_;
78
79 DISALLOW_COPY_AND_ASSIGN(BufferManager);
80 };
81
82 class PepperAudioEncoderHost::PcmBufferManager
83 : public BufferManager,
84 public ppapi::MediaStreamBufferManager::Delegate {
85 public:
86 PcmBufferManager(const ppapi::proxy::PPB_AudioEncodeParameters& parameters,
87 uint32_t number_of_samples)
88 : buffer_manager_(this),
89 encode_parameters_(parameters),
90 number_of_samples_(number_of_samples) {}
91
92 private:
93 ~PcmBufferManager() override {}
94
95 // PepperAudioEncoderHost::BufferManager:
96 bool Initialize(uint32_t number_of_buffers, size_t buffer_size) override {
97 size_t total_buffer_size =
98 buffer_size + sizeof(ppapi::MediaStreamBuffer::Audio);
99 scoped_ptr<base::SharedMemory> shm(
100 RenderThreadImpl::current()
101 ->HostAllocateSharedMemoryBuffer(number_of_buffers *
102 total_buffer_size)
103 .Pass());
104 if (!shm ||
105 !buffer_manager_.SetBuffers(number_of_buffers, total_buffer_size,
106 shm.Pass(), false))
107 return false;
108
109 for (int32_t i = 0; i < base::checked_cast<int32_t>(number_of_buffers);
110 i++) {
111 ppapi::MediaStreamBuffer::Audio* buffer =
112 &(buffer_manager_.GetBufferPointer(i)->audio);
113 buffer->header.size = total_buffer_size;
114 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
115 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(
116 encode_parameters_.input_sample_rate);
117 buffer->number_of_channels = encode_parameters_.channels;
118 buffer->number_of_samples = number_of_samples_;
119 buffer->data_size = buffer_size;
120 }
121
122 return BufferManager::Initialize(number_of_buffers, buffer_size);
123 }
124 uint8_t* GetBuffer(int32_t id) override {
125 return static_cast<uint8_t*>(
126 buffer_manager_.GetBufferPointer(id)->audio.data);
127 }
128 int32_t DequeueBuffer() override { return buffer_manager_.DequeueBuffer(); }
129 void EnqueueBuffer(int32_t id) override { buffer_manager_.EnqueueBuffer(id); }
130 base::SharedMemory* GetSharedMemory() override {
131 return buffer_manager_.shm();
132 }
133
134 // ppapi::MediaStreamBufferManager::Delegate:
135 void OnNewBufferEnqueued() override {}
136
137 ppapi::MediaStreamBufferManager buffer_manager_;
138 ppapi::proxy::PPB_AudioEncodeParameters encode_parameters_;
139 uint32_t number_of_samples_;
140 };
141
142 class PepperAudioEncoderHost::BitstreamBufferManager : public BufferManager {
143 public:
144 BitstreamBufferManager() {}
145
146 private:
147 ~BitstreamBufferManager() override {}
148
149 // PepperAudioEncoderHost::BufferManager:
150 bool Initialize(uint32_t number_of_buffers, size_t buffer_size) override {
151 size_t total_size = number_of_buffers * buffer_size;
152 shm_ = RenderThreadImpl::current()
153 ->HostAllocateSharedMemoryBuffer(total_size)
154 .Pass();
155 if (!shm_ || !shm_->Map(total_size))
156 return false;
157
158 for (uint32_t i = 0; i < number_of_buffers; i++)
159 enqueued_buffers_.push_back(base::checked_cast<int32_t>(i));
160
161 return BufferManager::Initialize(number_of_buffers, buffer_size);
162 }
163 uint8_t* GetBuffer(int32_t id) override {
164 return static_cast<uint8_t*>(shm_->memory()) + (id * buffer_size());
165 }
166 int32_t DequeueBuffer() override {
167 if (enqueued_buffers_.empty())
168 return -1;
169 int32_t id = enqueued_buffers_.front();
170 enqueued_buffers_.pop_front();
171 return id;
172 }
173 void EnqueueBuffer(int32_t id) override { enqueued_buffers_.push_back(id); }
174 base::SharedMemory* GetSharedMemory() override { return shm_.get(); }
175
176 scoped_ptr<base::SharedMemory> shm_;
177 std::deque<int32_t> enqueued_buffers_;
178 };
179
180 class PepperAudioEncoderHost::AudioData : public AudioEncoderShim::AudioData {
181 public:
182 AudioData(int32_t id, const scoped_refptr<BufferManager>& buffer_manager)
183 : id_(id), buffer_manager_(buffer_manager) {}
184
185 int32_t id() const { return id_; }
186
187 private:
188 ~AudioData() override {}
189
190 // AudioEncoderShim::AudioData:
191 uint8_t* GetData() override { return buffer_manager_->GetBuffer(id_); }
192 size_t GetSize() override { return buffer_manager_->buffer_size(); }
193
194 int32_t id_;
195 scoped_refptr<BufferManager> buffer_manager_;
196
197 DISALLOW_COPY_AND_ASSIGN(AudioData);
198 };
199
200 PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host,
201 PP_Instance instance,
202 PP_Resource resource)
203 : ResourceHost(host->GetPpapiHost(), instance, resource),
204 renderer_ppapi_host_(host),
205 initialized_(false),
206 encoder_last_error_(PP_ERROR_FAILED),
207 weak_ptr_factory_(this) {
208 }
209
210 PepperAudioEncoderHost::~PepperAudioEncoderHost() {
211 Close();
212 }
213
214 int32_t PepperAudioEncoderHost::OnResourceMessageReceived(
215 const IPC::Message& msg,
216 ppapi::host::HostMessageContext* context) {
217 PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg)
218 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
219 PpapiHostMsg_AudioEncoder_GetSupportedProfiles,
220 OnHostMsgGetSupportedProfiles)
221 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize,
222 OnHostMsgInitialize)
223 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_GetAudioFrames,
224 OnHostMsgGetAudioFrames)
225 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode,
226 OnHostMsgEncode)
227 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
228 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer,
229 OnHostMsgRecycleBitstreamBuffer)
230 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
231 PpapiHostMsg_AudioEncoder_RequestBitrateChange,
232 OnHostMsgRequestBitrateChange)
233 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close,
234 OnHostMsgClose)
235 PPAPI_END_MESSAGE_MAP()
236 return PP_ERROR_FAILED;
237 }
238
239 int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles(
240 ppapi::host::HostMessageContext* context) {
241 std::vector<PP_AudioProfileDescription> profiles;
242 GetSupportedProfiles(&profiles);
243
244 host()->SendReply(
245 context->MakeReplyMessageContext(),
246 PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles));
247
248 return PP_OK_COMPLETIONPENDING;
249 }
250
251 int32_t PepperAudioEncoderHost::OnHostMsgInitialize(
252 ppapi::host::HostMessageContext* context,
253 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
254 if (initialized_)
255 return PP_ERROR_FAILED;
256
257 if (!IsInitializationValid(parameters))
258 return PP_ERROR_NOTSUPPORTED;
259
260 encode_parameters_ = parameters;
261 initialize_reply_context_ = context->MakeReplyMessageContext();
262
263 int32_t error = PP_ERROR_FAILED;
264 if (parameters.acceleration == PP_HARDWAREACCELERATION_NONE ||
265 parameters.acceleration == PP_HARDWAREACCELERATION_WITHFALLBACK) {
266 encoder_.reset(new AudioEncoderShim);
267 if (encoder_->Initialize(parameters)) {
268 if (AllocateBitstreamBuffers(kDefaultBitstreamBufferSize)) {
269 encoder_last_error_ = PP_OK;
270 return PP_OK_COMPLETIONPENDING;
271 }
272 error = PP_ERROR_NOMEMORY;
273 } else
274 error = PP_ERROR_FAILED;
275 }
276
277 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
278 encoder_ = nullptr;
279
280 return error;
281 }
282
283 int32_t PepperAudioEncoderHost::OnHostMsgGetAudioFrames(
284 ppapi::host::HostMessageContext* context) {
285 if (encoder_last_error_)
286 return encoder_last_error_;
287
288 get_audio_frames_reply_context_ = context->MakeReplyMessageContext();
289 if (!AllocateAudioFrames(encoder_->GetNumberOfSamplesPerFrame()))
290 return PP_ERROR_NOMEMORY;
291
292 return PP_OK_COMPLETIONPENDING;
293 }
294
295 int32_t PepperAudioEncoderHost::OnHostMsgEncode(
296 ppapi::host::HostMessageContext* context,
297 uint32_t buffer_id) {
298 if (encoder_last_error_)
299 return encoder_last_error_;
300
301 if (buffer_id >= audio_buffer_manager_->number_of_buffers())
302 return PP_ERROR_BADARGUMENT;
303
304 // audio_buffer_manager_->EnqueueBuffer(buffer_id);
305 pending_encode_buffers_.push_back(buffer_id);
306
307 DoEncode();
308
309 return PP_OK_COMPLETIONPENDING;
310 }
311
312 int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer(
313 ppapi::host::HostMessageContext* context,
314 uint32_t buffer_id) {
315 if (encoder_last_error_)
316 return encoder_last_error_;
317
318 if (buffer_id >= bitstream_buffer_manager_->number_of_buffers())
319 return PP_ERROR_BADARGUMENT;
320
321 bitstream_buffer_manager_->EnqueueBuffer(buffer_id);
322
323 DoEncode();
324
325 return PP_OK;
326 }
327
328 int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange(
329 ppapi::host::HostMessageContext* context,
330 uint32_t bitrate) {
331 if (encoder_last_error_)
332 return encoder_last_error_;
333
334 encoder_->RequestBitrateChange(bitrate);
335
336 return PP_OK;
337 }
338
339 int32_t PepperAudioEncoderHost::OnHostMsgClose(
340 ppapi::host::HostMessageContext* context) {
341 encoder_last_error_ = PP_ERROR_FAILED;
342 Close();
343
344 return PP_OK;
345 }
346
347 void PepperAudioEncoderHost::GetSupportedProfiles(
348 std::vector<PP_AudioProfileDescription>* profiles) {
349 DCHECK(RenderThreadImpl::current());
350
351 AudioEncoderShim software_encoder;
352 *profiles = software_encoder.GetSupportedProfiles();
353 }
354
355 bool PepperAudioEncoderHost::IsInitializationValid(
356 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
357 DCHECK(RenderThreadImpl::current());
358
359 std::vector<PP_AudioProfileDescription> profiles;
360 GetSupportedProfiles(&profiles);
361
362 for (const PP_AudioProfileDescription& profile : profiles) {
363 if (parameters.output_profile == profile.profile &&
364 parameters.input_sample_size == profile.sample_size &&
365 parameters.input_sample_rate == profile.sample_rate &&
366 parameters.channels <= profile.max_channels &&
367 PP_HardwareAccelerationCompatible(
368 profile.hardware_accelerated == PP_TRUE ? true : false,
369 parameters.acceleration))
370 return true;
371 }
372
373 return false;
374 }
375
376 bool PepperAudioEncoderHost::AllocateAudioFrames(uint32_t number_of_samples) {
377 DCHECK(RenderThreadImpl::current());
378 DCHECK(initialized_);
379 DCHECK(get_audio_frames_reply_context_.is_valid());
380
381 // Frames have already been allocated.
382 if (audio_buffer_manager_)
383 return false;
384
385 scoped_refptr<BufferManager> buffer_manager(
386 new PcmBufferManager(encode_parameters_, number_of_samples));
387 uint32_t buffer_size = number_of_samples * encode_parameters_.channels *
388 encode_parameters_.input_sample_size;
389 if (!buffer_manager->Initialize(kDefaultNumberOfAudioFrames, buffer_size)) {
390 get_audio_frames_reply_context_ = ppapi::host::ReplyMessageContext();
391 return false;
392 }
393
394 get_audio_frames_reply_context_.params.AppendHandle(
395 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
396 buffer_manager->GetSharedMemory()->handle()),
397 buffer_manager->GetSharedMemory()->mapped_size()));
398
399 host()->SendReply(
400 get_audio_frames_reply_context_,
401 PpapiPluginMsg_AudioEncoder_GetAudioFramesReply(
402 buffer_manager->number_of_buffers(), buffer_manager->buffer_size()));
403
404 audio_buffer_manager_ = buffer_manager;
405 get_audio_frames_reply_context_ = ppapi::host::ReplyMessageContext();
406
407 return true;
408 }
409
410 bool PepperAudioEncoderHost::AllocateBitstreamBuffers(size_t buffer_size) {
411 DCHECK(RenderThreadImpl::current());
412 // We assume RequireBitstreamBuffers is only called once.
413 DCHECK(!initialized_);
414 DCHECK(initialize_reply_context_.is_valid());
415
416 scoped_refptr<BufferManager> buffer_manager(new BitstreamBufferManager);
417 if (!buffer_manager->Initialize(kDefaultNumberOfBitstreamBuffers,
418 buffer_size)) {
419 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
420 return false;
421 }
422
423 initialize_reply_context_.params.AppendHandle(
424 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
425 buffer_manager->GetSharedMemory()->handle()),
426 buffer_manager->GetSharedMemory()->mapped_size()));
427
428 host()->SendReply(
429 initialize_reply_context_,
430 PpapiPluginMsg_AudioEncoder_InitializeReply(
431 encoder_->GetNumberOfSamplesPerFrame(),
432 buffer_manager->number_of_buffers(), buffer_manager->buffer_size()));
433
434 bitstream_buffer_manager_ = buffer_manager;
435 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
436
437 return true;
438 }
439
440 scoped_refptr<AudioEncoderShim::AudioData> PepperAudioEncoderHost::GetAudioData(
441 const scoped_refptr<BufferManager>& buffer_manager) {
442 int32_t buffer_id = buffer_manager->DequeueBuffer();
443 if (buffer_id < 0)
444 return scoped_refptr<AudioData>();
445 return make_scoped_refptr(new AudioData(buffer_id, buffer_manager));
446 }
447
448 void PepperAudioEncoderHost::DoEncode() {
449 if (pending_encode_buffers_.empty())
450 return;
451
452 scoped_refptr<AudioEncoderShim::AudioData> output =
453 GetAudioData(bitstream_buffer_manager_);
454 if (!output)
455 return;
456
457 int32_t audio_buffer_id = pending_encode_buffers_.front();
458 pending_encode_buffers_.pop_front();
459 scoped_refptr<AudioEncoderShim::AudioData> input =
460 new AudioData(audio_buffer_id, audio_buffer_manager_);
461 DCHECK(input);
462
463 encoder_->Encode(input, output,
464 base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady,
465 weak_ptr_factory_.GetWeakPtr(), audio_buffer_id));
466 }
467
468 void PepperAudioEncoderHost::BitstreamBufferReady(
469 int32_t audio_buffer_id,
470 const scoped_refptr<AudioEncoderShim::AudioData>& output,
471 int32_t size) {
472 DCHECK(RenderThreadImpl::current());
473
474 if (encoder_last_error_)
475 return;
476
477 host()->SendUnsolicitedReply(
478 pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(
479 base::checked_cast<uint32_t>(audio_buffer_id)));
480
481 if (size < 0) {
482 NotifyPepperError(PP_ERROR_FAILED);
483 return;
484 }
485
486 host()->SendUnsolicitedReply(pp_resource(),
487 PpapiPluginMsg_AudioEncoder_BitstreamBufferReady(
488 static_cast<AudioData*>(output.get())->id(),
489 base::checked_cast<uint32_t>(size)));
490 }
491
492 void PepperAudioEncoderHost::NotifyPepperError(int32_t error) {
493 DCHECK(RenderThreadImpl::current());
494
495 encoder_last_error_ = error;
496 Close();
497 host()->SendUnsolicitedReply(
498 pp_resource(),
499 PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_));
500 }
501
502 void PepperAudioEncoderHost::Close() {
503 DCHECK(RenderThreadImpl::current());
504
505 encoder_ = nullptr;
506 audio_buffer_manager_ = nullptr;
507 bitstream_buffer_manager_ = nullptr;
508 }
509
510 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_audio_encoder_host.h ('k') | content/renderer/pepper/plugin_module.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698