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 "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 | |
OLD | NEW |