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

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: Drop checks on buffers already queued 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
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 kDefaultNumberOfAudioBuffers = 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 PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host,
55 PP_Instance instance,
56 PP_Resource resource)
57 : ResourceHost(host->GetPpapiHost(), instance, resource),
58 renderer_ppapi_host_(host),
59 initialized_(false),
60 encoder_last_error_(PP_ERROR_FAILED),
61 audio_buffer_manager_(this),
62 bitstream_buffer_manager_(this),
63 weak_ptr_factory_(this) {}
64
65 PepperAudioEncoderHost::~PepperAudioEncoderHost() {
66 Close();
67 }
68
69 int32_t PepperAudioEncoderHost::OnResourceMessageReceived(
70 const IPC::Message& msg,
71 ppapi::host::HostMessageContext* context) {
72 PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg)
73 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
74 PpapiHostMsg_AudioEncoder_GetSupportedProfiles,
75 OnHostMsgGetSupportedProfiles)
76 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize,
77 OnHostMsgInitialize)
78 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
79 PpapiHostMsg_AudioEncoder_GetAudioBuffers, OnHostMsgGetAudioBuffers)
80 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode,
81 OnHostMsgEncode)
82 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
83 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer,
84 OnHostMsgRecycleBitstreamBuffer)
85 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
86 PpapiHostMsg_AudioEncoder_RequestBitrateChange,
87 OnHostMsgRequestBitrateChange)
88 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close,
89 OnHostMsgClose)
90 PPAPI_END_MESSAGE_MAP()
91 return PP_ERROR_FAILED;
92 }
93
94 int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles(
95 ppapi::host::HostMessageContext* context) {
96 std::vector<PP_AudioProfileDescription> profiles;
97 GetSupportedProfiles(&profiles);
98
99 host()->SendReply(
100 context->MakeReplyMessageContext(),
101 PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles));
102
103 return PP_OK_COMPLETIONPENDING;
104 }
105
106 int32_t PepperAudioEncoderHost::OnHostMsgInitialize(
107 ppapi::host::HostMessageContext* context,
108 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
109 if (initialized_)
110 return PP_ERROR_FAILED;
111
112 if (!IsInitializationValid(parameters))
113 return PP_ERROR_NOTSUPPORTED;
114
115 encode_parameters_ = parameters;
116
117 int32_t error = PP_ERROR_FAILED;
118 if (parameters.acceleration == PP_HARDWAREACCELERATION_NONE ||
119 parameters.acceleration == PP_HARDWAREACCELERATION_WITHFALLBACK) {
120 encoder_.reset(new AudioEncoderShim);
121 if (encoder_->Initialize(parameters)) {
122 if (AllocateBitstreamBuffers(kDefaultBitstreamBufferSize)) {
123 initialized_ = true;
124 encoder_last_error_ = PP_OK;
125
126 ppapi::host::ReplyMessageContext reply_context =
127 context->MakeReplyMessageContext();
128 reply_context.params.AppendHandle(SerializedHandle(
129 renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
130 bitstream_buffer_manager_.shm()->handle()),
131 bitstream_buffer_manager_.shm()->mapped_size()));
132 host()->SendReply(reply_context,
133 PpapiPluginMsg_AudioEncoder_InitializeReply(
134 encoder_->GetNumberOfSamplesPerFrame(),
135 bitstream_buffer_manager_.number_of_buffers(),
136 bitstream_buffer_manager_.buffer_size()));
137
138 return PP_OK_COMPLETIONPENDING;
139 }
140 error = PP_ERROR_NOMEMORY;
141 } else
142 error = PP_ERROR_FAILED;
143 }
144
145 encoder_ = nullptr;
146
147 return error;
148 }
149
150 int32_t PepperAudioEncoderHost::OnHostMsgGetAudioBuffers(
151 ppapi::host::HostMessageContext* context) {
152 if (encoder_last_error_)
153 return encoder_last_error_;
154
155 if (!AllocateAudioBuffers(encoder_->GetNumberOfSamplesPerFrame()))
156 return PP_ERROR_NOMEMORY;
157
158 ppapi::host::ReplyMessageContext reply_context =
159 context->MakeReplyMessageContext();
160 reply_context.params.AppendHandle(
161 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
162 audio_buffer_manager_.shm()->handle()),
163 audio_buffer_manager_.shm()->mapped_size()));
164
165 host()->SendReply(reply_context,
166 PpapiPluginMsg_AudioEncoder_GetAudioBuffersReply(
167 audio_buffer_manager_.number_of_buffers(),
168 audio_buffer_manager_.buffer_size()));
169
170 return PP_OK_COMPLETIONPENDING;
171 }
172
173 int32_t PepperAudioEncoderHost::OnHostMsgEncode(
174 ppapi::host::HostMessageContext* context,
175 uint32_t buffer_id) {
176 if (encoder_last_error_)
177 return encoder_last_error_;
178
179 if (buffer_id >=
180 static_cast<uint32_t>(audio_buffer_manager_.number_of_buffers()))
181 return PP_ERROR_BADARGUMENT;
182
183 audio_buffer_manager_.EnqueueBuffer(buffer_id);
184
185 DoEncode();
186
187 return PP_OK_COMPLETIONPENDING;
188 }
189
190 int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer(
191 ppapi::host::HostMessageContext* context,
192 uint32_t buffer_id) {
193 if (encoder_last_error_)
194 return encoder_last_error_;
195
196 if (buffer_id >=
197 static_cast<uint32_t>(bitstream_buffer_manager_.number_of_buffers()))
198 return PP_ERROR_BADARGUMENT;
199
200 bitstream_buffer_manager_.EnqueueBuffer(buffer_id);
201
202 DoEncode();
203
204 return PP_OK;
205 }
206
207 int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange(
208 ppapi::host::HostMessageContext* context,
209 uint32_t bitrate) {
210 if (encoder_last_error_)
211 return encoder_last_error_;
212
213 encoder_->RequestBitrateChange(bitrate);
214
215 return PP_OK;
216 }
217
218 int32_t PepperAudioEncoderHost::OnHostMsgClose(
219 ppapi::host::HostMessageContext* context) {
220 encoder_last_error_ = PP_ERROR_FAILED;
221 Close();
222
223 return PP_OK;
224 }
225
226 void PepperAudioEncoderHost::GetSupportedProfiles(
227 std::vector<PP_AudioProfileDescription>* profiles) {
228 DCHECK(RenderThreadImpl::current());
229
230 AudioEncoderShim software_encoder;
231 *profiles = software_encoder.GetSupportedProfiles();
232 }
233
234 bool PepperAudioEncoderHost::IsInitializationValid(
235 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
236 DCHECK(RenderThreadImpl::current());
237
238 std::vector<PP_AudioProfileDescription> profiles;
239 GetSupportedProfiles(&profiles);
240
241 for (const PP_AudioProfileDescription& profile : profiles) {
242 if (parameters.output_profile == profile.profile &&
243 parameters.input_sample_size == profile.sample_size &&
244 parameters.input_sample_rate == profile.sample_rate &&
245 parameters.channels <= profile.max_channels &&
246 PP_HardwareAccelerationCompatible(
247 profile.hardware_accelerated == PP_TRUE ? true : false,
248 parameters.acceleration))
249 return true;
250 }
251
252 return false;
253 }
254
255 bool PepperAudioEncoderHost::AllocateAudioBuffers(uint32_t number_of_samples) {
256 DCHECK(RenderThreadImpl::current());
257 DCHECK(initialized_);
258
259 // Buffers have already been allocated.
260 if (audio_buffer_manager_.number_of_buffers() > 0)
261 return false;
262
263 base::CheckedNumeric<size_t> buffer_size = number_of_samples;
264 buffer_size *= encode_parameters_.channels;
265 buffer_size *= encode_parameters_.input_sample_size;
266 if (!buffer_size.IsValid())
267 return false;
268
269 base::CheckedNumeric<size_t> total_buffer_size = buffer_size.ValueOrDie();
270 total_buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio);
271 if (!total_buffer_size.IsValid())
272 return false;
273
274 base::CheckedNumeric<size_t> total_memory_size =
275 total_buffer_size.ValueOrDie();
276 total_memory_size *= kDefaultNumberOfAudioBuffers;
277 if (!total_memory_size.IsValid())
278 return false;
279
280 if (!audio_buffer_manager_.SetBuffers(
281 kDefaultNumberOfAudioBuffers, total_buffer_size.ValueOrDie(),
282 RenderThreadImpl::current()
283 ->HostAllocateSharedMemoryBuffer(total_memory_size.ValueOrDie())
284 .Pass(),
285 false))
286 return false;
287
288 for (int32_t i = 0; i < audio_buffer_manager_.number_of_buffers(); ++i) {
289 ppapi::MediaStreamBuffer::Audio* buffer =
290 &(audio_buffer_manager_.GetBufferPointer(i)->audio);
291 buffer->header.size = total_buffer_size.ValueOrDie();
292 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
293 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(
294 encode_parameters_.input_sample_rate);
295 buffer->number_of_channels = encode_parameters_.channels;
296 buffer->number_of_samples = number_of_samples;
297 buffer->data_size = buffer_size.ValueOrDie();
298 }
299
300 return true;
301 }
302
303 bool PepperAudioEncoderHost::AllocateBitstreamBuffers(size_t buffer_size) {
304 DCHECK(RenderThreadImpl::current());
305 // We assume RequireBitstreamBuffers is only called once.
306 DCHECK(!initialized_);
307
308 // Buffers have already been allocated.
309 if (bitstream_buffer_manager_.number_of_buffers() > 0)
310 return false;
311
312 base::CheckedNumeric<size_t> total_size = buffer_size;
313 total_size *= kDefaultNumberOfBitstreamBuffers;
314 if (!total_size.IsValid())
315 return false;
316
317 if (!bitstream_buffer_manager_.SetBuffers(
318 kDefaultNumberOfBitstreamBuffers, buffer_size,
319 RenderThreadImpl::current()
320 ->HostAllocateSharedMemoryBuffer(total_size.ValueOrDie())
321 .Pass(),
322 true))
323 return false;
324
325 return true;
326 }
327
328 AudioEncoderShim::AudioData PepperAudioEncoderHost::GetAudioData(
329 uint32_t* buffer_id) {
330 DCHECK(audio_buffer_manager_.HasAvailableBuffer());
331 int32_t id = audio_buffer_manager_.DequeueBuffer();
332 ppapi::MediaStreamBuffer* buffer = audio_buffer_manager_.GetBufferPointer(id);
333 *buffer_id = id;
334 return AudioEncoderShim::AudioData(static_cast<uint8_t*>(buffer->audio.data),
335 buffer->audio.data_size);
336 }
337
338 AudioEncoderShim::AudioData PepperAudioEncoderHost::GetBitstreamData(
339 uint32_t* buffer_id) {
340 DCHECK(bitstream_buffer_manager_.HasAvailableBuffer());
341 int32_t id = bitstream_buffer_manager_.DequeueBuffer();
342 uint8_t* buffer = reinterpret_cast<uint8_t*>(
343 bitstream_buffer_manager_.GetBufferPointer(id));
344 *buffer_id = id;
345 return AudioEncoderShim::AudioData(buffer,
346 bitstream_buffer_manager_.buffer_size());
347 }
348
349 void PepperAudioEncoderHost::DoEncode() {
350 if (!audio_buffer_manager_.HasAvailableBuffer() ||
351 !bitstream_buffer_manager_.HasAvailableBuffer())
352 return;
353
354 uint32_t audio_buffer_id, bitstream_buffer_id;
355 AudioEncoderShim::AudioData input(GetAudioData(&audio_buffer_id));
356 AudioEncoderShim::AudioData output(GetBitstreamData(&bitstream_buffer_id));
357 encoder_->Encode(input, output,
358 base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady,
359 weak_ptr_factory_.GetWeakPtr(), audio_buffer_id,
360 bitstream_buffer_id));
361 }
362
363 void PepperAudioEncoderHost::BitstreamBufferReady(
364 uint32_t audio_buffer_id,
365 uint32_t bitstream_buffer_id,
366 const AudioEncoderShim::AudioData& output,
367 int64_t size) {
368 DCHECK(RenderThreadImpl::current());
369
370 if (encoder_last_error_)
371 return;
372
373 host()->SendUnsolicitedReply(
374 pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(audio_buffer_id));
375
376 if (size < 0) {
377 NotifyPepperError(PP_ERROR_FAILED);
378 return;
379 }
380
381 host()->SendUnsolicitedReply(
382 pp_resource(), PpapiPluginMsg_AudioEncoder_BitstreamBufferReady(
383 bitstream_buffer_id, static_cast<uint32_t>(size)));
384 }
385
386 void PepperAudioEncoderHost::NotifyPepperError(int32_t error) {
387 DCHECK(RenderThreadImpl::current());
388
389 encoder_last_error_ = error;
390 Close();
391 host()->SendUnsolicitedReply(
392 pp_resource(),
393 PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_));
394 }
395
396 void PepperAudioEncoderHost::Close() {
397 DCHECK(RenderThreadImpl::current());
398
399 encoder_ = nullptr;
400 }
401
402 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698