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 bool PP_HardwareAccelerationCompatible(bool accelerated, |
| 30 PP_HardwareAcceleration requested) { |
| 31 switch (requested) { |
| 32 case PP_HARDWAREACCELERATION_ONLY: |
| 33 return accelerated; |
| 34 case PP_HARDWAREACCELERATION_NONE: |
| 35 return !accelerated; |
| 36 case PP_HARDWAREACCELERATION_WITHFALLBACK: |
| 37 return true; |
| 38 // No default case, to catch unhandled PP_HardwareAcceleration values. |
| 39 } |
| 40 return false; |
| 41 } |
| 42 |
| 43 } // namespace |
| 44 |
| 45 // This class should be constructed and initialized on the main renderer |
| 46 // thread, used and destructed on the media thread. |
| 47 class PepperAudioEncoderHost::AudioEncoderImpl { |
| 48 public: |
| 49 // Callback used to signal encoded data. If |size| is negative, an error |
| 50 // occurred. |
| 51 using BitstreamBufferReadyCB = base::Callback<void(int32_t size)>; |
| 52 |
| 53 AudioEncoderImpl(); |
| 54 ~AudioEncoderImpl(); |
| 55 |
| 56 // Used on the renderer thread. |
| 57 static std::vector<PP_AudioProfileDescription> GetSupportedProfiles(); |
| 58 bool Initialize(const ppapi::proxy::PPB_AudioEncodeParameters& parameters); |
| 59 int32_t GetNumberOfSamplesPerFrame(); |
| 60 |
| 61 // Used on the media thread. |
| 62 void Encode(uint8_t* input_data, |
| 63 size_t input_size, |
| 64 uint8_t* output_data, |
| 65 size_t output_size, |
| 66 BitstreamBufferReadyCB callback); |
| 67 void RequestBitrateChange(uint32_t bitrate); |
| 68 |
| 69 private: |
| 70 scoped_ptr<uint8[]> encoder_memory_; |
| 71 OpusEncoder* opus_encoder_; |
| 72 |
| 73 // Initialization parameters, only valid if |encoder_memory_| is not |
| 74 // nullptr. |
| 75 ppapi::proxy::PPB_AudioEncodeParameters parameters_; |
| 76 |
| 77 DISALLOW_COPY_AND_ASSIGN(AudioEncoderImpl); |
| 78 }; |
| 79 |
| 80 PepperAudioEncoderHost::AudioEncoderImpl::AudioEncoderImpl() |
| 81 : opus_encoder_(nullptr) {} |
| 82 |
| 83 PepperAudioEncoderHost::AudioEncoderImpl::~AudioEncoderImpl() {} |
| 84 |
| 85 // static |
| 86 std::vector<PP_AudioProfileDescription> |
| 87 PepperAudioEncoderHost::AudioEncoderImpl::GetSupportedProfiles() { |
| 88 std::vector<PP_AudioProfileDescription> profiles; |
| 89 static const uint32_t sampling_rates[] = {8000, 12000, 16000, 24000, 48000}; |
| 90 |
| 91 for (uint32_t i = 0; i < arraysize(sampling_rates); ++i) { |
| 92 PP_AudioProfileDescription profile; |
| 93 profile.profile = PP_AUDIOPROFILE_OPUS; |
| 94 profile.max_channels = 2; |
| 95 profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS; |
| 96 profile.sample_rate = sampling_rates[i]; |
| 97 profile.hardware_accelerated = PP_FALSE; |
| 98 profiles.push_back(profile); |
| 99 } |
| 100 return profiles; |
| 101 } |
| 102 |
| 103 bool PepperAudioEncoderHost::AudioEncoderImpl::Initialize( |
| 104 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { |
| 105 if (parameters.output_profile != PP_AUDIOPROFILE_OPUS) |
| 106 return false; |
| 107 |
| 108 DCHECK(!encoder_memory_); |
| 109 |
| 110 int32_t encoder_size = opus_encoder_get_size(parameters.channels); |
| 111 if (encoder_size < 1) |
| 112 return false; |
| 113 |
| 114 scoped_ptr<uint8[]> encoder_memory(new uint8[encoder_size]); |
| 115 opus_encoder_ = reinterpret_cast<OpusEncoder*>(encoder_memory.get()); |
| 116 |
| 117 if (opus_encoder_init(opus_encoder_, parameters.input_sample_rate, |
| 118 parameters.channels, OPUS_APPLICATION_AUDIO) != OPUS_OK) |
| 119 return false; |
| 120 |
| 121 if (opus_encoder_ctl(opus_encoder_, |
| 122 OPUS_SET_BITRATE(parameters.initial_bitrate <= 0 |
| 123 ? OPUS_AUTO |
| 124 : parameters.initial_bitrate)) != |
| 125 OPUS_OK) |
| 126 return false; |
| 127 |
| 128 encoder_memory_.swap(encoder_memory); |
| 129 parameters_ = parameters; |
| 130 |
| 131 return true; |
| 132 } |
| 133 |
| 134 int32_t PepperAudioEncoderHost::AudioEncoderImpl::GetNumberOfSamplesPerFrame() { |
| 135 DCHECK(encoder_memory_); |
| 136 // Opus supports 2.5, 5, 10, 20, 40 or 60ms audio frames. We take |
| 137 // 10ms by default. |
| 138 return parameters_.input_sample_rate / 100; |
| 139 } |
| 140 |
| 141 void PepperAudioEncoderHost::AudioEncoderImpl::Encode( |
| 142 uint8_t* input_data, |
| 143 size_t input_size, |
| 144 uint8_t* output_data, |
| 145 size_t output_size, |
| 146 BitstreamBufferReadyCB callback) { |
| 147 DCHECK(encoder_memory_); |
| 148 int32_t result = opus_encode( |
| 149 opus_encoder_, reinterpret_cast<opus_int16*>(input_data), |
| 150 (input_size / parameters_.channels) / parameters_.input_sample_size, |
| 151 output_data, output_size); |
| 152 callback.Run(result); |
| 153 } |
| 154 |
| 155 void PepperAudioEncoderHost::AudioEncoderImpl::RequestBitrateChange( |
| 156 uint32_t bitrate) { |
| 157 DCHECK(encoder_memory_); |
| 158 opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate)); |
| 159 } |
| 160 |
| 161 PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host, |
| 162 PP_Instance instance, |
| 163 PP_Resource resource) |
| 164 : ResourceHost(host->GetPpapiHost(), instance, resource), |
| 165 renderer_ppapi_host_(host), |
| 166 initialized_(false), |
| 167 encoder_last_error_(PP_ERROR_FAILED), |
| 168 media_task_runner_(RenderThreadImpl::current() |
| 169 ->GetMediaThreadTaskRunner()), |
| 170 weak_ptr_factory_(this) {} |
| 171 |
| 172 PepperAudioEncoderHost::~PepperAudioEncoderHost() { |
| 173 Close(); |
| 174 } |
| 175 |
| 176 int32_t PepperAudioEncoderHost::OnResourceMessageReceived( |
| 177 const IPC::Message& msg, |
| 178 ppapi::host::HostMessageContext* context) { |
| 179 PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg) |
| 180 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( |
| 181 PpapiHostMsg_AudioEncoder_GetSupportedProfiles, |
| 182 OnHostMsgGetSupportedProfiles) |
| 183 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize, |
| 184 OnHostMsgInitialize) |
| 185 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode, |
| 186 OnHostMsgEncode) |
| 187 PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| 188 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer, |
| 189 OnHostMsgRecycleBitstreamBuffer) |
| 190 PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| 191 PpapiHostMsg_AudioEncoder_RequestBitrateChange, |
| 192 OnHostMsgRequestBitrateChange) |
| 193 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close, |
| 194 OnHostMsgClose) |
| 195 PPAPI_END_MESSAGE_MAP() |
| 196 return PP_ERROR_FAILED; |
| 197 } |
| 198 |
| 199 int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles( |
| 200 ppapi::host::HostMessageContext* context) { |
| 201 std::vector<PP_AudioProfileDescription> profiles; |
| 202 GetSupportedProfiles(&profiles); |
| 203 |
| 204 host()->SendReply( |
| 205 context->MakeReplyMessageContext(), |
| 206 PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles)); |
| 207 |
| 208 return PP_OK_COMPLETIONPENDING; |
| 209 } |
| 210 |
| 211 int32_t PepperAudioEncoderHost::OnHostMsgInitialize( |
| 212 ppapi::host::HostMessageContext* context, |
| 213 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { |
| 214 if (initialized_) |
| 215 return PP_ERROR_FAILED; |
| 216 |
| 217 if (!IsInitializationValid(parameters)) |
| 218 return PP_ERROR_NOTSUPPORTED; |
| 219 |
| 220 scoped_ptr<AudioEncoderImpl> encoder(new AudioEncoderImpl); |
| 221 if (!encoder->Initialize(parameters)) |
| 222 return PP_ERROR_FAILED; |
| 223 if (!AllocateBuffers(parameters, encoder->GetNumberOfSamplesPerFrame())) |
| 224 return PP_ERROR_NOMEMORY; |
| 225 |
| 226 initialized_ = true; |
| 227 encoder_last_error_ = PP_OK; |
| 228 encoder_.swap(encoder); |
| 229 |
| 230 ppapi::host::ReplyMessageContext reply_context = |
| 231 context->MakeReplyMessageContext(); |
| 232 reply_context.params.AppendHandle( |
| 233 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote( |
| 234 audio_buffer_manager_->shm()->handle()), |
| 235 audio_buffer_manager_->shm()->mapped_size())); |
| 236 reply_context.params.AppendHandle( |
| 237 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote( |
| 238 bitstream_buffer_manager_->shm()->handle()), |
| 239 bitstream_buffer_manager_->shm()->mapped_size())); |
| 240 host()->SendReply(reply_context, |
| 241 PpapiPluginMsg_AudioEncoder_InitializeReply( |
| 242 encoder_->GetNumberOfSamplesPerFrame(), |
| 243 audio_buffer_manager_->number_of_buffers(), |
| 244 audio_buffer_manager_->buffer_size(), |
| 245 bitstream_buffer_manager_->number_of_buffers(), |
| 246 bitstream_buffer_manager_->buffer_size())); |
| 247 |
| 248 return PP_OK_COMPLETIONPENDING; |
| 249 } |
| 250 |
| 251 int32_t PepperAudioEncoderHost::OnHostMsgEncode( |
| 252 ppapi::host::HostMessageContext* context, |
| 253 int32_t buffer_id) { |
| 254 if (encoder_last_error_) |
| 255 return encoder_last_error_; |
| 256 |
| 257 if (buffer_id < 0 || buffer_id >= audio_buffer_manager_->number_of_buffers()) |
| 258 return PP_ERROR_FAILED; |
| 259 |
| 260 audio_buffer_manager_->EnqueueBuffer(buffer_id); |
| 261 |
| 262 DoEncode(); |
| 263 |
| 264 return PP_OK_COMPLETIONPENDING; |
| 265 } |
| 266 |
| 267 int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer( |
| 268 ppapi::host::HostMessageContext* context, |
| 269 int32_t buffer_id) { |
| 270 if (encoder_last_error_) |
| 271 return encoder_last_error_; |
| 272 |
| 273 if (buffer_id < 0 || |
| 274 buffer_id >= bitstream_buffer_manager_->number_of_buffers()) |
| 275 return PP_ERROR_FAILED; |
| 276 |
| 277 bitstream_buffer_manager_->EnqueueBuffer(buffer_id); |
| 278 |
| 279 DoEncode(); |
| 280 |
| 281 return PP_OK; |
| 282 } |
| 283 |
| 284 int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange( |
| 285 ppapi::host::HostMessageContext* context, |
| 286 uint32_t bitrate) { |
| 287 if (encoder_last_error_) |
| 288 return encoder_last_error_; |
| 289 |
| 290 media_task_runner_->PostTask( |
| 291 FROM_HERE, base::Bind(&AudioEncoderImpl::RequestBitrateChange, |
| 292 base::Unretained(encoder_.get()), bitrate)); |
| 293 |
| 294 return PP_OK; |
| 295 } |
| 296 |
| 297 int32_t PepperAudioEncoderHost::OnHostMsgClose( |
| 298 ppapi::host::HostMessageContext* context) { |
| 299 encoder_last_error_ = PP_ERROR_FAILED; |
| 300 Close(); |
| 301 |
| 302 return PP_OK; |
| 303 } |
| 304 |
| 305 void PepperAudioEncoderHost::GetSupportedProfiles( |
| 306 std::vector<PP_AudioProfileDescription>* profiles) { |
| 307 DCHECK(RenderThreadImpl::current()); |
| 308 |
| 309 *profiles = AudioEncoderImpl::GetSupportedProfiles(); |
| 310 } |
| 311 |
| 312 bool PepperAudioEncoderHost::IsInitializationValid( |
| 313 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { |
| 314 DCHECK(RenderThreadImpl::current()); |
| 315 |
| 316 std::vector<PP_AudioProfileDescription> profiles; |
| 317 GetSupportedProfiles(&profiles); |
| 318 |
| 319 for (const PP_AudioProfileDescription& profile : profiles) { |
| 320 if (parameters.output_profile == profile.profile && |
| 321 parameters.input_sample_size == profile.sample_size && |
| 322 parameters.input_sample_rate == profile.sample_rate && |
| 323 parameters.channels <= profile.max_channels && |
| 324 PP_HardwareAccelerationCompatible( |
| 325 profile.hardware_accelerated == PP_TRUE, parameters.acceleration)) |
| 326 return true; |
| 327 } |
| 328 |
| 329 return false; |
| 330 } |
| 331 |
| 332 bool PepperAudioEncoderHost::AllocateBuffers( |
| 333 const ppapi::proxy::PPB_AudioEncodeParameters& parameters, |
| 334 int32_t samples_per_frame) { |
| 335 DCHECK(RenderThreadImpl::current()); |
| 336 |
| 337 // Audio buffers size computation. |
| 338 base::CheckedNumeric<size_t> audio_buffer_size = samples_per_frame; |
| 339 audio_buffer_size *= parameters.channels; |
| 340 audio_buffer_size *= parameters.input_sample_size; |
| 341 |
| 342 base::CheckedNumeric<size_t> total_audio_buffer_size = audio_buffer_size; |
| 343 total_audio_buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio); |
| 344 base::CheckedNumeric<size_t> total_audio_memory_size = |
| 345 total_audio_buffer_size; |
| 346 total_audio_memory_size *= kDefaultNumberOfAudioBuffers; |
| 347 |
| 348 // Bitstream buffers size computation (individual bitstream buffers are |
| 349 // twice the size of the raw data, to handle the worst case where |
| 350 // compression doesn't work). |
| 351 base::CheckedNumeric<size_t> bitstream_buffer_size = audio_buffer_size; |
| 352 bitstream_buffer_size *= 2; |
| 353 bitstream_buffer_size += sizeof(ppapi::MediaStreamBuffer::Bitstream); |
| 354 base::CheckedNumeric<size_t> total_bitstream_memory_size = |
| 355 bitstream_buffer_size; |
| 356 total_bitstream_memory_size *= kDefaultNumberOfAudioBuffers; |
| 357 |
| 358 if (!total_audio_memory_size.IsValid() || |
| 359 !total_bitstream_memory_size.IsValid()) |
| 360 return false; |
| 361 |
| 362 scoped_ptr<base::SharedMemory> audio_memory( |
| 363 RenderThreadImpl::current()->HostAllocateSharedMemoryBuffer( |
| 364 total_audio_memory_size.ValueOrDie())); |
| 365 if (!audio_memory) |
| 366 return false; |
| 367 scoped_ptr<ppapi::MediaStreamBufferManager> audio_buffer_manager( |
| 368 new ppapi::MediaStreamBufferManager(this)); |
| 369 if (!audio_buffer_manager->SetBuffers(kDefaultNumberOfAudioBuffers, |
| 370 total_audio_buffer_size.ValueOrDie(), |
| 371 audio_memory.Pass(), false)) |
| 372 return false; |
| 373 |
| 374 for (int32_t i = 0; i < audio_buffer_manager->number_of_buffers(); ++i) { |
| 375 ppapi::MediaStreamBuffer::Audio* buffer = |
| 376 &(audio_buffer_manager->GetBufferPointer(i)->audio); |
| 377 buffer->header.size = total_audio_buffer_size.ValueOrDie(); |
| 378 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO; |
| 379 buffer->sample_rate = |
| 380 static_cast<PP_AudioBuffer_SampleRate>(parameters.input_sample_rate); |
| 381 buffer->number_of_channels = parameters.channels; |
| 382 buffer->number_of_samples = samples_per_frame; |
| 383 buffer->data_size = audio_buffer_size.ValueOrDie(); |
| 384 } |
| 385 |
| 386 scoped_ptr<base::SharedMemory> bitstream_memory( |
| 387 RenderThreadImpl::current()->HostAllocateSharedMemoryBuffer( |
| 388 total_bitstream_memory_size.ValueOrDie())); |
| 389 if (!bitstream_memory) |
| 390 return false; |
| 391 scoped_ptr<ppapi::MediaStreamBufferManager> bitstream_buffer_manager( |
| 392 new ppapi::MediaStreamBufferManager(this)); |
| 393 if (!bitstream_buffer_manager->SetBuffers(kDefaultNumberOfAudioBuffers, |
| 394 bitstream_buffer_size.ValueOrDie(), |
| 395 bitstream_memory.Pass(), true)) |
| 396 return false; |
| 397 |
| 398 for (int32_t i = 0; i < bitstream_buffer_manager->number_of_buffers(); ++i) { |
| 399 ppapi::MediaStreamBuffer::Bitstream* buffer = |
| 400 &(bitstream_buffer_manager->GetBufferPointer(i)->bitstream); |
| 401 buffer->header.size = bitstream_buffer_size.ValueOrDie(); |
| 402 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_BITSTREAM; |
| 403 } |
| 404 |
| 405 audio_buffer_manager_.swap(audio_buffer_manager); |
| 406 bitstream_buffer_manager_.swap(bitstream_buffer_manager); |
| 407 |
| 408 return true; |
| 409 } |
| 410 |
| 411 void PepperAudioEncoderHost::DoEncode() { |
| 412 DCHECK(RenderThreadImpl::current()); |
| 413 DCHECK(!encoder_last_error_); |
| 414 |
| 415 if (!audio_buffer_manager_->HasAvailableBuffer() || |
| 416 !bitstream_buffer_manager_->HasAvailableBuffer()) |
| 417 return; |
| 418 |
| 419 int32_t audio_buffer_id = audio_buffer_manager_->DequeueBuffer(); |
| 420 int32_t bitstream_buffer_id = bitstream_buffer_manager_->DequeueBuffer(); |
| 421 |
| 422 ppapi::MediaStreamBuffer* audio_buffer = |
| 423 audio_buffer_manager_->GetBufferPointer(audio_buffer_id); |
| 424 ppapi::MediaStreamBuffer* bitstream_buffer = |
| 425 bitstream_buffer_manager_->GetBufferPointer(bitstream_buffer_id); |
| 426 |
| 427 media_task_runner_->PostTask( |
| 428 FROM_HERE, |
| 429 base::Bind(&AudioEncoderImpl::Encode, base::Unretained(encoder_.get()), |
| 430 static_cast<uint8_t*>(audio_buffer->audio.data), |
| 431 audio_buffer_manager_->buffer_size() - |
| 432 sizeof(ppapi::MediaStreamBuffer::Audio), |
| 433 static_cast<uint8_t*>(bitstream_buffer->bitstream.data), |
| 434 bitstream_buffer_manager_->buffer_size() - |
| 435 sizeof(ppapi::MediaStreamBuffer::Bitstream), |
| 436 media::BindToCurrentLoop( |
| 437 base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady, |
| 438 weak_ptr_factory_.GetWeakPtr(), audio_buffer_id, |
| 439 bitstream_buffer_id)))); |
| 440 } |
| 441 |
| 442 void PepperAudioEncoderHost::BitstreamBufferReady(int32_t audio_buffer_id, |
| 443 int32_t bitstream_buffer_id, |
| 444 int32_t result) { |
| 445 DCHECK(RenderThreadImpl::current()); |
| 446 |
| 447 if (encoder_last_error_) |
| 448 return; |
| 449 |
| 450 if (result < 0) { |
| 451 NotifyPepperError(PP_ERROR_FAILED); |
| 452 return; |
| 453 } |
| 454 |
| 455 host()->SendUnsolicitedReply( |
| 456 pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(audio_buffer_id)); |
| 457 |
| 458 ppapi::MediaStreamBuffer::Bitstream* buffer = |
| 459 &(bitstream_buffer_manager_->GetBufferPointer(bitstream_buffer_id) |
| 460 ->bitstream); |
| 461 buffer->data_size = static_cast<uint32_t>(result); |
| 462 |
| 463 host()->SendUnsolicitedReply( |
| 464 pp_resource(), |
| 465 PpapiPluginMsg_AudioEncoder_BitstreamBufferReady(bitstream_buffer_id)); |
| 466 } |
| 467 |
| 468 void PepperAudioEncoderHost::NotifyPepperError(int32_t error) { |
| 469 DCHECK(RenderThreadImpl::current()); |
| 470 |
| 471 encoder_last_error_ = error; |
| 472 Close(); |
| 473 host()->SendUnsolicitedReply( |
| 474 pp_resource(), |
| 475 PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_)); |
| 476 } |
| 477 |
| 478 void PepperAudioEncoderHost::Close() { |
| 479 DCHECK(RenderThreadImpl::current()); |
| 480 |
| 481 // Destroy the encoder and the audio/bitstream buffers on the media thread |
| 482 // to avoid freeing memory the encoder might still be working on. |
| 483 media_task_runner_->PostTask( |
| 484 FROM_HERE, base::Bind(&StopAudioEncoder, base::Passed(encoder_.Pass()), |
| 485 base::Passed(audio_buffer_manager_.Pass()), |
| 486 base::Passed(bitstream_buffer_manager_.Pass()))); |
| 487 } |
| 488 |
| 489 // static |
| 490 void PepperAudioEncoderHost::StopAudioEncoder( |
| 491 scoped_ptr<AudioEncoderImpl> encoder, |
| 492 scoped_ptr<ppapi::MediaStreamBufferManager> audio_buffer_manager, |
| 493 scoped_ptr<ppapi::MediaStreamBufferManager> bitstream_buffer_manager) {} |
| 494 |
| 495 } // namespace content |
OLD | NEW |