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

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: Switch to int32_t buffer ids Created 5 years, 1 month 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
« no previous file with comments | « content/renderer/pepper/pepper_audio_encoder_host.h ('k') | ppapi/ppapi_sources.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "content/public/renderer/renderer_ppapi_host.h"
8 #include "content/renderer/pepper/host_globals.h"
9 #include "content/renderer/pepper/pepper_audio_encoder_host.h"
10 #include "content/renderer/render_thread_impl.h"
11 #include "media/base/bind_to_current_loop.h"
12 #include "ppapi/c/pp_codecs.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/host/dispatch_host_message.h"
15 #include "ppapi/host/ppapi_host.h"
16 #include "ppapi/proxy/ppapi_messages.h"
17 #include "ppapi/shared_impl/media_stream_buffer.h"
18 #include "third_party/opus/src/include/opus.h"
19
20 using ppapi::proxy::SerializedHandle;
21
22 namespace content {
23
24 namespace {
25
26 // Buffer up to 150ms (15 x 10ms per frame).
27 const uint32_t kDefaultNumberOfAudioBuffers = 15;
28
29 // Class used to pass audio data between threads.
30 class AudioData {
31 public:
32 AudioData(const AudioData& other) : data(other.data), size(other.size) {}
33 AudioData(uint8_t* data, size_t size) : data(data), size(size) {}
34 ~AudioData() {}
35
36 uint8_t* data;
37 size_t size;
38 };
39
40 bool PP_HardwareAccelerationCompatible(bool accelerated,
41 PP_HardwareAcceleration requested) {
42 switch (requested) {
43 case PP_HARDWAREACCELERATION_ONLY:
44 return accelerated;
45 case PP_HARDWAREACCELERATION_NONE:
46 return !accelerated;
47 case PP_HARDWAREACCELERATION_WITHFALLBACK:
48 return true;
49 // No default case, to catch unhandled PP_HardwareAcceleration values.
50 }
51 return false;
52 }
53
54 AudioData GetAudioDataFromBufferManager(
55 ppapi::MediaStreamBufferManager* buffer_manager,
56 int32_t* buffer_id) {
57 DCHECK(buffer_manager->HasAvailableBuffer());
58 int32_t id = buffer_manager->DequeueBuffer();
59 ppapi::MediaStreamBuffer* buffer = buffer_manager->GetBufferPointer(id);
60 *buffer_id = id;
61 return AudioData(static_cast<uint8_t*>(buffer->audio.data),
62 buffer->audio.data_size);
63 }
64
65 AudioData GetBitstreamDataFromBufferManager(
66 ppapi::MediaStreamBufferManager* buffer_manager,
67 int32_t* buffer_id) {
68 DCHECK(buffer_manager->HasAvailableBuffer());
69 int32_t id = buffer_manager->DequeueBuffer();
70 uint8_t* buffer =
71 reinterpret_cast<uint8_t*>(buffer_manager->GetBufferPointer(id));
72 *buffer_id = id;
73 return AudioData(buffer, buffer_manager->buffer_size());
74 }
75
76 void SignalEvent(base::WaitableEvent* event) {
77 event->Signal();
78 }
79
80 } // namespace
81
82 // This class should be constructed, used, and destructed on the main
83 // (renderer) thread.
84 class PepperAudioEncoderHost::AudioEncoderImpl {
85 public:
86 // Callback used to signal encoded data. If |size| is negative, an error
87 // occured.
88 using BitstreamBufferReadyCB = base::Callback<void(int32_t size)>;
89
90 AudioEncoderImpl();
91 ~AudioEncoderImpl();
92
93 std::vector<PP_AudioProfileDescription> GetSupportedProfiles();
94 bool Initialize(const ppapi::proxy::PPB_AudioEncodeParameters& parameters);
95 int32_t GetNumberOfSamplesPerFrame();
96 void Encode(const AudioData& input,
97 const AudioData& output,
98 BitstreamBufferReadyCB callback);
99 void RequestBitrateChange(uint32_t bitrate);
100
101 private:
102 void DoEncode(const AudioData& input,
103 const AudioData& output,
104 BitstreamBufferReadyCB callback);
105 void DoRequestBitrateChange(uint32_t bitrate);
106 void OnEncodeDone(BitstreamBufferReadyCB callback, int32_t output_size);
107
108 // Task calling from/into PepperAudioEncoderHost.
109 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
110
111 // Task doing the encoding.
112 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
113
114 // Initialization parameters.
115 ppapi::proxy::PPB_AudioEncodeParameters parameters_;
116
117 scoped_ptr<uint8[]> encoder_memory_;
118 OpusEncoder* opus_encoder_;
119
120 base::WeakPtrFactory<AudioEncoderImpl> weak_ptr_factory_;
121
122 DISALLOW_COPY_AND_ASSIGN(AudioEncoderImpl);
123 };
124
125 PepperAudioEncoderHost::AudioEncoderImpl::AudioEncoderImpl()
126 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
127 media_task_runner_(RenderThreadImpl::current()
128 ->GetMediaThreadTaskRunner()),
129 weak_ptr_factory_(this) {}
130
131 PepperAudioEncoderHost::AudioEncoderImpl::~AudioEncoderImpl() {
132 if (encoder_memory_) {
133 base::WaitableEvent event(false, false);
134 media_task_runner_->PostTask(FROM_HERE, base::Bind(&SignalEvent, &event));
135 event.Wait();
136 }
137 }
138
139 std::vector<PP_AudioProfileDescription>
140 PepperAudioEncoderHost::AudioEncoderImpl::GetSupportedProfiles() {
141 std::vector<PP_AudioProfileDescription> profiles;
142 static const uint32_t sampling_rates[] = {8000, 12000, 16000, 24000, 48000};
143
144 for (uint32_t i = 0; i < arraysize(sampling_rates); ++i) {
145 PP_AudioProfileDescription profile;
146 profile.profile = PP_AUDIOPROFILE_OPUS;
147 profile.max_channels = 2;
148 profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS;
149 profile.sample_rate = sampling_rates[i];
150 profile.hardware_accelerated = PP_FALSE;
151 profiles.push_back(profile);
152 }
153 return profiles;
154 }
155
156 bool PepperAudioEncoderHost::AudioEncoderImpl::Initialize(
157 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
158 if (parameters.output_profile != PP_AUDIOPROFILE_OPUS)
159 return false;
160
161 DCHECK(!encoder_memory_);
162
163 int32_t encoder_size = opus_encoder_get_size(parameters.channels);
164 if (encoder_size < 1)
165 return false;
166
167 encoder_memory_.reset(new uint8[encoder_size]);
168 opus_encoder_ = reinterpret_cast<OpusEncoder*>(encoder_memory_.get());
169
170 if (opus_encoder_init(opus_encoder_, parameters.input_sample_rate,
171 parameters.channels, OPUS_APPLICATION_AUDIO) != OPUS_OK)
172 return false;
173
174 if (opus_encoder_ctl(opus_encoder_,
175 OPUS_SET_BITRATE(parameters.initial_bitrate <= 0
176 ? OPUS_AUTO
177 : parameters.initial_bitrate)) !=
178 OPUS_OK)
179 return false;
180
181 parameters_ = parameters;
182
183 return true;
184 }
185
186 int32_t PepperAudioEncoderHost::AudioEncoderImpl::GetNumberOfSamplesPerFrame() {
187 // Opus supports 2.5, 5, 10, 20, 40 or 60ms audio frames. We take
188 // 10ms by default.
189 return parameters_.input_sample_rate / 100;
190 }
191
192 void PepperAudioEncoderHost::AudioEncoderImpl::Encode(
193 const AudioData& input,
194 const AudioData& output,
195 BitstreamBufferReadyCB callback) {
196 media_task_runner_->PostTask(
197 FROM_HERE,
198 base::Bind(&AudioEncoderImpl::DoEncode, weak_ptr_factory_.GetWeakPtr(),
199 input, output, callback));
200 }
201
202 void PepperAudioEncoderHost::AudioEncoderImpl::DoEncode(
203 const AudioData& input,
204 const AudioData& output,
205 BitstreamBufferReadyCB callback) {
206 int32_t result = opus_encode(
207 opus_encoder_, reinterpret_cast<opus_int16*>(input.data),
208 (input.size / parameters_.channels) / parameters_.input_sample_size,
209 output.data, output.size);
210 main_task_runner_->PostTask(
211 FROM_HERE, base::Bind(&AudioEncoderImpl::OnEncodeDone,
212 weak_ptr_factory_.GetWeakPtr(), callback, result));
213 }
214
215 void PepperAudioEncoderHost::AudioEncoderImpl::RequestBitrateChange(
216 uint32_t bitrate) {
217 media_task_runner_->PostTask(
218 FROM_HERE, base::Bind(&AudioEncoderImpl::RequestBitrateChange,
bbudge 2015/11/11 22:43:18 Should be DoRequestBitrateChange.
llandwerlin-old 2015/11/12 10:53:55 Ooops, done.
219 weak_ptr_factory_.GetWeakPtr(), bitrate));
220 }
221
222 void PepperAudioEncoderHost::AudioEncoderImpl::DoRequestBitrateChange(
223 uint32_t bitrate) {
224 opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate));
225 }
226
227 void PepperAudioEncoderHost::AudioEncoderImpl::OnEncodeDone(
228 BitstreamBufferReadyCB callback,
229 int32_t size) {
230 callback.Run(size);
231 }
232
233 PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host,
234 PP_Instance instance,
235 PP_Resource resource)
236 : ResourceHost(host->GetPpapiHost(), instance, resource),
237 renderer_ppapi_host_(host),
238 initialized_(false),
239 encoder_last_error_(PP_ERROR_FAILED),
240 audio_buffer_manager_(this),
241 bitstream_buffer_manager_(this) {}
242
243 PepperAudioEncoderHost::~PepperAudioEncoderHost() {
244 Close();
245 }
246
247 int32_t PepperAudioEncoderHost::OnResourceMessageReceived(
248 const IPC::Message& msg,
249 ppapi::host::HostMessageContext* context) {
250 PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg)
251 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
252 PpapiHostMsg_AudioEncoder_GetSupportedProfiles,
253 OnHostMsgGetSupportedProfiles)
254 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize,
255 OnHostMsgInitialize)
256 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode,
257 OnHostMsgEncode)
258 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
259 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer,
260 OnHostMsgRecycleBitstreamBuffer)
261 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
262 PpapiHostMsg_AudioEncoder_RequestBitrateChange,
263 OnHostMsgRequestBitrateChange)
264 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close,
265 OnHostMsgClose)
266 PPAPI_END_MESSAGE_MAP()
267 return PP_ERROR_FAILED;
268 }
269
270 int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles(
271 ppapi::host::HostMessageContext* context) {
272 std::vector<PP_AudioProfileDescription> profiles;
273 GetSupportedProfiles(&profiles);
274
275 host()->SendReply(
276 context->MakeReplyMessageContext(),
277 PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles));
278
279 return PP_OK_COMPLETIONPENDING;
280 }
281
282 int32_t PepperAudioEncoderHost::OnHostMsgInitialize(
283 ppapi::host::HostMessageContext* context,
284 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
285 if (initialized_)
286 return PP_ERROR_FAILED;
287
288 if (!IsInitializationValid(parameters))
289 return PP_ERROR_NOTSUPPORTED;
290
291 encode_parameters_ = parameters;
292
293 int32_t error = PP_ERROR_FAILED;
294 if (parameters.acceleration == PP_HARDWAREACCELERATION_NONE ||
295 parameters.acceleration == PP_HARDWAREACCELERATION_WITHFALLBACK) {
296 encoder_.reset(new AudioEncoderImpl);
297 if (encoder_->Initialize(parameters)) {
298 if (AllocateBuffers()) {
299 initialized_ = true;
300 encoder_last_error_ = PP_OK;
301
302 ppapi::host::ReplyMessageContext reply_context =
303 context->MakeReplyMessageContext();
304 reply_context.params.AppendHandle(SerializedHandle(
305 renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
306 audio_buffer_manager_.shm()->handle()),
307 audio_buffer_manager_.shm()->mapped_size()));
308 reply_context.params.AppendHandle(SerializedHandle(
309 renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
310 bitstream_buffer_manager_.shm()->handle()),
311 bitstream_buffer_manager_.shm()->mapped_size()));
312
313 host()->SendReply(reply_context,
314 PpapiPluginMsg_AudioEncoder_InitializeReply(
315 encoder_->GetNumberOfSamplesPerFrame(),
316 audio_buffer_manager_.number_of_buffers(),
317 audio_buffer_manager_.buffer_size(),
318 bitstream_buffer_manager_.number_of_buffers(),
319 bitstream_buffer_manager_.buffer_size()));
320
321 return PP_OK_COMPLETIONPENDING;
322 }
323 error = PP_ERROR_NOMEMORY;
324 } else
325 error = PP_ERROR_FAILED;
326 }
327
328 encoder_ = nullptr;
329
330 return error;
331 }
332
333 int32_t PepperAudioEncoderHost::OnHostMsgEncode(
334 ppapi::host::HostMessageContext* context,
335 int32_t buffer_id) {
336 if (encoder_last_error_)
337 return encoder_last_error_;
338
339 if (buffer_id < 0 || buffer_id >= audio_buffer_manager_.number_of_buffers())
340 return PP_ERROR_BADARGUMENT;
341
342 audio_buffer_manager_.EnqueueBuffer(buffer_id);
343
344 DoEncode();
345
346 return PP_OK_COMPLETIONPENDING;
347 }
348
349 int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer(
350 ppapi::host::HostMessageContext* context,
351 int32_t buffer_id) {
352 if (encoder_last_error_)
353 return encoder_last_error_;
354
355 if (buffer_id < 0 ||
356 buffer_id >= bitstream_buffer_manager_.number_of_buffers())
357 return PP_ERROR_BADARGUMENT;
358
359 bitstream_buffer_manager_.EnqueueBuffer(buffer_id);
360
361 DoEncode();
362
363 return PP_OK;
364 }
365
366 int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange(
367 ppapi::host::HostMessageContext* context,
368 uint32_t bitrate) {
369 if (encoder_last_error_)
370 return encoder_last_error_;
371
372 encoder_->RequestBitrateChange(bitrate);
373
374 return PP_OK;
375 }
376
377 int32_t PepperAudioEncoderHost::OnHostMsgClose(
378 ppapi::host::HostMessageContext* context) {
379 encoder_last_error_ = PP_ERROR_FAILED;
380 Close();
381
382 return PP_OK;
383 }
384
385 void PepperAudioEncoderHost::GetSupportedProfiles(
386 std::vector<PP_AudioProfileDescription>* profiles) {
387 DCHECK(RenderThreadImpl::current());
388
389 AudioEncoderImpl software_encoder;
390 *profiles = software_encoder.GetSupportedProfiles();
391 }
392
393 bool PepperAudioEncoderHost::IsInitializationValid(
394 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
395 DCHECK(RenderThreadImpl::current());
396
397 std::vector<PP_AudioProfileDescription> profiles;
398 GetSupportedProfiles(&profiles);
399
400 for (const PP_AudioProfileDescription& profile : profiles) {
401 if (parameters.output_profile == profile.profile &&
402 parameters.input_sample_size == profile.sample_size &&
403 parameters.input_sample_rate == profile.sample_rate &&
404 parameters.channels <= profile.max_channels &&
405 PP_HardwareAccelerationCompatible(
406 profile.hardware_accelerated == PP_TRUE ? true : false,
407 parameters.acceleration))
408 return true;
409 }
410
411 return false;
412 }
413
414 bool PepperAudioEncoderHost::AllocateBuffers() {
415 DCHECK(RenderThreadImpl::current());
416 DCHECK(encoder_);
417
418 base::CheckedNumeric<size_t> buffer_size =
419 encoder_->GetNumberOfSamplesPerFrame();
420 buffer_size *= encode_parameters_.channels;
421 buffer_size *= encode_parameters_.input_sample_size;
422
423 return AllocateAudioBuffers(buffer_size) &&
424 AllocateBitstreamBuffers(buffer_size);
425 }
426
427 bool PepperAudioEncoderHost::AllocateAudioBuffers(
428 const base::CheckedNumeric<size_t>& buffer_size) {
429 base::CheckedNumeric<size_t> total_buffer_size = buffer_size;
430 total_buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio);
431 if (!total_buffer_size.IsValid())
432 return false;
433
434 base::CheckedNumeric<size_t> total_memory_size =
435 total_buffer_size.ValueOrDie();
436 total_memory_size *= kDefaultNumberOfAudioBuffers;
437 if (!total_memory_size.IsValid())
438 return false;
439
440 if (!audio_buffer_manager_.SetBuffers(
441 kDefaultNumberOfAudioBuffers, total_buffer_size.ValueOrDie(),
442 RenderThreadImpl::current()
443 ->HostAllocateSharedMemoryBuffer(total_memory_size.ValueOrDie())
444 .Pass(),
445 false))
446 return false;
447
448 for (int32_t i = 0; i < audio_buffer_manager_.number_of_buffers(); ++i) {
449 ppapi::MediaStreamBuffer::Audio* buffer =
450 &(audio_buffer_manager_.GetBufferPointer(i)->audio);
451 buffer->header.size = total_buffer_size.ValueOrDie();
452 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
453 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(
454 encode_parameters_.input_sample_rate);
455 buffer->number_of_channels = encode_parameters_.channels;
456 buffer->number_of_samples = encoder_->GetNumberOfSamplesPerFrame();
457 buffer->data_size = buffer_size.ValueOrDie();
458 }
459
460 return true;
461 }
462
463 bool PepperAudioEncoderHost::AllocateBitstreamBuffers(
464 const base::CheckedNumeric<size_t>& buffer_size) {
465 // Individual buffers are twice the size of the raw data.
466 base::CheckedNumeric<size_t> bitstream_buffer_size = buffer_size;
467 bitstream_buffer_size *= 2;
468 if (!bitstream_buffer_size.IsValid())
469 return false;
470
471 base::CheckedNumeric<size_t> total_size = bitstream_buffer_size;
472 total_size *= kDefaultNumberOfAudioBuffers;
473 if (!total_size.IsValid())
474 return false;
475
476 if (!bitstream_buffer_manager_.SetBuffers(
477 kDefaultNumberOfAudioBuffers, bitstream_buffer_size.ValueOrDie(),
478 RenderThreadImpl::current()
479 ->HostAllocateSharedMemoryBuffer(total_size.ValueOrDie())
480 .Pass(),
481 true))
482 return false;
483
484 return true;
485 }
486
487 void PepperAudioEncoderHost::DoEncode() {
488 if (!audio_buffer_manager_.HasAvailableBuffer() ||
489 !bitstream_buffer_manager_.HasAvailableBuffer())
490 return;
491
492 int32_t audio_buffer_id, bitstream_buffer_id;
493 AudioData input(
494 GetAudioDataFromBufferManager(&audio_buffer_manager_, &audio_buffer_id));
495 AudioData output(GetBitstreamDataFromBufferManager(&bitstream_buffer_manager_,
496 &bitstream_buffer_id));
497 encoder_->Encode(
498 input, output,
499 base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady,
500 base::Unretained(this), audio_buffer_id, bitstream_buffer_id));
501 }
502
503 void PepperAudioEncoderHost::BitstreamBufferReady(int32_t audio_buffer_id,
504 int32_t bitstream_buffer_id,
505 int32_t size) {
506 DCHECK(RenderThreadImpl::current());
507
508 if (encoder_last_error_)
509 return;
510
511 host()->SendUnsolicitedReply(
512 pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(audio_buffer_id));
513
514 if (size < 0) {
515 NotifyPepperError(PP_ERROR_FAILED);
516 return;
517 }
518
519 host()->SendUnsolicitedReply(
520 pp_resource(), PpapiPluginMsg_AudioEncoder_BitstreamBufferReady(
521 bitstream_buffer_id, static_cast<uint32_t>(size)));
522 }
523
524 void PepperAudioEncoderHost::NotifyPepperError(int32_t error) {
525 DCHECK(RenderThreadImpl::current());
526
527 encoder_last_error_ = error;
528 Close();
529 host()->SendUnsolicitedReply(
530 pp_resource(),
531 PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_));
532 }
533
534 void PepperAudioEncoderHost::Close() {
535 DCHECK(RenderThreadImpl::current());
536
537 encoder_ = nullptr;
538 }
539
540 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_audio_encoder_host.h ('k') | ppapi/ppapi_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698