OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "base/memory/shared_memory.h" |
| 6 #include "ppapi/c/pp_array_output.h" |
| 7 #include "ppapi/c/pp_codecs.h" |
| 8 #include "ppapi/proxy/audio_buffer_resource.h" |
5 #include "ppapi/proxy/audio_encoder_resource.h" | 9 #include "ppapi/proxy/audio_encoder_resource.h" |
| 10 #include "ppapi/proxy/ppapi_messages.h" |
| 11 #include "ppapi/shared_impl/array_writer.h" |
| 12 #include "ppapi/shared_impl/media_stream_buffer.h" |
| 13 #include "ppapi/thunk/enter.h" |
6 | 14 |
7 namespace ppapi { | 15 namespace ppapi { |
8 namespace proxy { | 16 namespace proxy { |
9 | 17 |
| 18 namespace { |
| 19 |
| 20 void RunCallback(scoped_refptr<TrackedCallback>* callback, int32_t error) { |
| 21 if (TrackedCallback::IsPending(*callback)) { |
| 22 scoped_refptr<TrackedCallback> temp; |
| 23 callback->swap(temp); |
| 24 temp->Run(error); |
| 25 } |
| 26 } |
| 27 |
| 28 } // namespace |
| 29 |
10 AudioEncoderResource::AudioEncoderResource(Connection connection, | 30 AudioEncoderResource::AudioEncoderResource(Connection connection, |
11 PP_Instance instance) | 31 PP_Instance instance) |
12 : PluginResource(connection, instance) { | 32 : PluginResource(connection, instance), |
| 33 encoder_last_error_(PP_ERROR_FAILED), |
| 34 initialized_(false), |
| 35 audio_buffer_manager_(this), |
| 36 bitstream_buffer_manager_(this) { |
| 37 SendCreate(RENDERER, PpapiHostMsg_AudioEncoder_Create()); |
13 } | 38 } |
14 | 39 |
15 AudioEncoderResource::~AudioEncoderResource() { | 40 AudioEncoderResource::~AudioEncoderResource() { |
16 } | 41 } |
17 | 42 |
18 thunk::PPB_AudioEncoder_API* AudioEncoderResource::AsPPB_AudioEncoder_API() { | 43 thunk::PPB_AudioEncoder_API* AudioEncoderResource::AsPPB_AudioEncoder_API() { |
19 return this; | 44 return this; |
20 } | 45 } |
21 | 46 |
22 int32_t AudioEncoderResource::GetSupportedProfiles( | 47 int32_t AudioEncoderResource::GetSupportedProfiles( |
23 const PP_ArrayOutput& output, | 48 const PP_ArrayOutput& output, |
24 const scoped_refptr<TrackedCallback>& callback) { | 49 const scoped_refptr<TrackedCallback>& callback) { |
25 return PP_ERROR_NOTSUPPORTED; | 50 if (TrackedCallback::IsPending(get_supported_profiles_callback_)) |
| 51 return PP_ERROR_INPROGRESS; |
| 52 |
| 53 get_supported_profiles_callback_ = callback; |
| 54 Call<PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply>( |
| 55 RENDERER, PpapiHostMsg_AudioEncoder_GetSupportedProfiles(), |
| 56 base::Bind(&AudioEncoderResource::OnPluginMsgGetSupportedProfilesReply, |
| 57 this, output)); |
| 58 return PP_OK_COMPLETIONPENDING; |
26 } | 59 } |
27 | 60 |
28 int32_t AudioEncoderResource::Initialize( | 61 int32_t AudioEncoderResource::Initialize( |
29 uint32_t channels, | 62 uint32_t channels, |
30 PP_AudioBuffer_SampleRate input_sample_rate, | 63 PP_AudioBuffer_SampleRate input_sample_rate, |
31 PP_AudioBuffer_SampleSize input_sample_size, | 64 PP_AudioBuffer_SampleSize input_sample_size, |
32 PP_AudioProfile output_profile, | 65 PP_AudioProfile output_profile, |
33 uint32_t initial_bitrate, | 66 uint32_t initial_bitrate, |
34 PP_HardwareAcceleration acceleration, | 67 PP_HardwareAcceleration acceleration, |
35 const scoped_refptr<TrackedCallback>& callback) { | 68 const scoped_refptr<TrackedCallback>& callback) { |
36 return PP_ERROR_NOTSUPPORTED; | 69 if (initialized_) |
| 70 return PP_ERROR_FAILED; |
| 71 if (TrackedCallback::IsPending(initialize_callback_)) |
| 72 return PP_ERROR_INPROGRESS; |
| 73 |
| 74 initialize_callback_ = callback; |
| 75 |
| 76 PPB_AudioEncodeParameters parameters; |
| 77 parameters.channels = channels; |
| 78 parameters.input_sample_rate = input_sample_rate; |
| 79 parameters.input_sample_size = input_sample_size; |
| 80 parameters.output_profile = output_profile; |
| 81 parameters.initial_bitrate = initial_bitrate; |
| 82 parameters.acceleration = acceleration; |
| 83 |
| 84 Call<PpapiPluginMsg_AudioEncoder_InitializeReply>( |
| 85 RENDERER, PpapiHostMsg_AudioEncoder_Initialize(parameters), |
| 86 base::Bind(&AudioEncoderResource::OnPluginMsgInitializeReply, this)); |
| 87 return PP_OK_COMPLETIONPENDING; |
37 } | 88 } |
38 | 89 |
39 int32_t AudioEncoderResource::GetNumberOfSamples() { | 90 int32_t AudioEncoderResource::GetNumberOfSamples() { |
40 return PP_ERROR_NOTSUPPORTED; | 91 if (encoder_last_error_) |
| 92 return encoder_last_error_; |
| 93 return number_of_samples_; |
41 } | 94 } |
42 | 95 |
43 int32_t AudioEncoderResource::GetBuffer( | 96 int32_t AudioEncoderResource::GetBuffer( |
44 PP_Resource* audio_buffer, | 97 PP_Resource* audio_buffer, |
45 const scoped_refptr<TrackedCallback>& callback) { | 98 const scoped_refptr<TrackedCallback>& callback) { |
46 return PP_ERROR_NOTSUPPORTED; | 99 if (encoder_last_error_) |
| 100 return encoder_last_error_; |
| 101 if (TrackedCallback::IsPending(get_buffer_callback_)) |
| 102 return PP_ERROR_INPROGRESS; |
| 103 |
| 104 get_buffer_data_ = audio_buffer; |
| 105 get_buffer_callback_ = callback; |
| 106 |
| 107 TryGetAudioBuffer(); |
| 108 |
| 109 return PP_OK_COMPLETIONPENDING; |
47 } | 110 } |
48 | 111 |
49 int32_t AudioEncoderResource::Encode( | 112 int32_t AudioEncoderResource::Encode( |
50 PP_Resource audio_buffer, | 113 PP_Resource audio_buffer, |
51 const scoped_refptr<TrackedCallback>& callback) { | 114 const scoped_refptr<TrackedCallback>& callback) { |
52 return PP_ERROR_NOTSUPPORTED; | 115 if (encoder_last_error_) |
| 116 return encoder_last_error_; |
| 117 |
| 118 AudioBufferMap::iterator it = audio_buffers_.find(audio_buffer); |
| 119 if (it == audio_buffers_.end()) |
| 120 // TODO(llandwerlin): accept MediaStreamAudioTrack's audio buffers. |
| 121 return PP_ERROR_BADRESOURCE; |
| 122 |
| 123 scoped_refptr<AudioBufferResource> buffer_resource = it->second; |
| 124 |
| 125 encode_callbacks_.insert( |
| 126 std::make_pair(buffer_resource->GetBufferIndex(), callback)); |
| 127 |
| 128 Post(RENDERER, |
| 129 PpapiHostMsg_AudioEncoder_Encode(buffer_resource->GetBufferIndex())); |
| 130 |
| 131 // Invalidate the buffer to prevent a CHECK failure when the |
| 132 // AudioBufferResource is destructed. |
| 133 buffer_resource->Invalidate(); |
| 134 audio_buffers_.erase(it); |
| 135 |
| 136 return PP_OK_COMPLETIONPENDING; |
53 } | 137 } |
54 | 138 |
55 int32_t AudioEncoderResource::GetBitstreamBuffer( | 139 int32_t AudioEncoderResource::GetBitstreamBuffer( |
56 PP_AudioBitstreamBuffer* bitstream_buffer, | 140 PP_AudioBitstreamBuffer* bitstream_buffer, |
57 const scoped_refptr<TrackedCallback>& callback) { | 141 const scoped_refptr<TrackedCallback>& callback) { |
58 return PP_ERROR_NOTSUPPORTED; | 142 if (encoder_last_error_) |
| 143 return encoder_last_error_; |
| 144 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_)) |
| 145 return PP_ERROR_INPROGRESS; |
| 146 |
| 147 get_bitstream_buffer_callback_ = callback; |
| 148 get_bitstream_buffer_data_ = bitstream_buffer; |
| 149 |
| 150 TryWriteBitstreamBuffer(); |
| 151 |
| 152 return PP_OK_COMPLETIONPENDING; |
59 } | 153 } |
60 | 154 |
61 void AudioEncoderResource::RecycleBitstreamBuffer( | 155 void AudioEncoderResource::RecycleBitstreamBuffer( |
62 const PP_AudioBitstreamBuffer* bitstream_buffer) { | 156 const PP_AudioBitstreamBuffer* bitstream_buffer) { |
| 157 if (encoder_last_error_) |
| 158 return; |
| 159 |
| 160 BufferMap::const_iterator it = |
| 161 bitstream_buffer_map_.find(bitstream_buffer->buffer); |
| 162 if (it != bitstream_buffer_map_.end()) |
| 163 Post(RENDERER, |
| 164 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer(it->second)); |
63 } | 165 } |
64 | 166 |
65 void AudioEncoderResource::RequestBitrateChange(uint32_t bitrate) { | 167 void AudioEncoderResource::RequestBitrateChange(uint32_t bitrate) { |
| 168 if (encoder_last_error_) |
| 169 return; |
| 170 Post(RENDERER, PpapiHostMsg_AudioEncoder_RequestBitrateChange(bitrate)); |
66 } | 171 } |
67 | 172 |
68 void AudioEncoderResource::Close() { | 173 void AudioEncoderResource::Close() { |
| 174 if (encoder_last_error_) |
| 175 return; |
| 176 Post(RENDERER, PpapiHostMsg_AudioEncoder_Close()); |
| 177 if (!encoder_last_error_ || !initialized_) |
| 178 NotifyError(PP_ERROR_ABORTED); |
| 179 ReleaseBuffers(); |
| 180 } |
| 181 |
| 182 void AudioEncoderResource::OnReplyReceived( |
| 183 const ResourceMessageReplyParams& params, |
| 184 const IPC::Message& msg) { |
| 185 PPAPI_BEGIN_MESSAGE_MAP(AudioEncoderResource, msg) |
| 186 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 187 PpapiPluginMsg_AudioEncoder_BitstreamBufferReady, |
| 188 OnPluginMsgBitstreamBufferReady) |
| 189 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_AudioEncoder_EncodeReply, |
| 190 OnPluginMsgEncodeReply) |
| 191 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_AudioEncoder_NotifyError, |
| 192 OnPluginMsgNotifyError) |
| 193 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( |
| 194 PluginResource::OnReplyReceived(params, msg)) |
| 195 PPAPI_END_MESSAGE_MAP() |
| 196 } |
| 197 |
| 198 void AudioEncoderResource::OnPluginMsgGetSupportedProfilesReply( |
| 199 const PP_ArrayOutput& output, |
| 200 const ResourceMessageReplyParams& params, |
| 201 const std::vector<PP_AudioProfileDescription>& profiles) { |
| 202 ArrayWriter writer(output); |
| 203 if (params.result() != PP_OK || !writer.is_valid() || |
| 204 !writer.StoreVector(profiles)) { |
| 205 RunCallback(&get_supported_profiles_callback_, PP_ERROR_FAILED); |
| 206 return; |
| 207 } |
| 208 |
| 209 RunCallback(&get_supported_profiles_callback_, |
| 210 base::checked_cast<int32_t>(profiles.size())); |
| 211 } |
| 212 |
| 213 void AudioEncoderResource::OnPluginMsgInitializeReply( |
| 214 const ResourceMessageReplyParams& params, |
| 215 int32_t number_of_samples, |
| 216 int32_t audio_buffer_count, |
| 217 int32_t audio_buffer_size, |
| 218 int32_t bitstream_buffer_count, |
| 219 int32_t bitstream_buffer_size) { |
| 220 DCHECK(!initialized_); |
| 221 |
| 222 int32_t error = params.result(); |
| 223 if (error) { |
| 224 RunCallback(&initialize_callback_, error); |
| 225 return; |
| 226 } |
| 227 |
| 228 // Get audio buffers shared memory buffer. |
| 229 base::SharedMemoryHandle buffer_handle; |
| 230 if (!params.TakeSharedMemoryHandleAtIndex(0, &buffer_handle) || |
| 231 !audio_buffer_manager_.SetBuffers( |
| 232 audio_buffer_count, audio_buffer_size, |
| 233 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)), |
| 234 true)) { |
| 235 RunCallback(&initialize_callback_, PP_ERROR_NOMEMORY); |
| 236 return; |
| 237 } |
| 238 |
| 239 // Get bitstream buffers shared memory buffer. |
| 240 if (!params.TakeSharedMemoryHandleAtIndex(1, &buffer_handle) || |
| 241 !bitstream_buffer_manager_.SetBuffers( |
| 242 bitstream_buffer_count, bitstream_buffer_size, |
| 243 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)), |
| 244 false)) { |
| 245 RunCallback(&initialize_callback_, PP_ERROR_NOMEMORY); |
| 246 return; |
| 247 } |
| 248 |
| 249 for (int32_t i = 0; i < bitstream_buffer_manager_.number_of_buffers(); i++) |
| 250 bitstream_buffer_map_.insert(std::make_pair( |
| 251 bitstream_buffer_manager_.GetBufferPointer(i)->bitstream.data, i)); |
| 252 |
| 253 encoder_last_error_ = PP_OK; |
| 254 number_of_samples_ = number_of_samples; |
| 255 initialized_ = true; |
| 256 |
| 257 RunCallback(&initialize_callback_, PP_OK); |
| 258 } |
| 259 |
| 260 void AudioEncoderResource::OnPluginMsgEncodeReply( |
| 261 const ResourceMessageReplyParams& params, |
| 262 int32_t buffer_id) { |
| 263 // We need to ensure there are still callbacks to be called before |
| 264 // processing this message. We might receive an EncodeReply message after |
| 265 // having sent a Close message to the renderer. In this case, we don't |
| 266 // have any callback left to call. |
| 267 if (encode_callbacks_.empty()) |
| 268 return; |
| 269 |
| 270 EncodeMap::iterator it = encode_callbacks_.find(buffer_id); |
| 271 DCHECK(encode_callbacks_.end() != it); |
| 272 |
| 273 scoped_refptr<TrackedCallback> callback = it->second; |
| 274 encode_callbacks_.erase(it); |
| 275 RunCallback(&callback, encoder_last_error_); |
| 276 |
| 277 audio_buffer_manager_.EnqueueBuffer(buffer_id); |
| 278 // If the plugin is waiting for an audio buffer, we can give the one |
| 279 // that just became available again. |
| 280 if (TrackedCallback::IsPending(get_buffer_callback_)) |
| 281 TryGetAudioBuffer(); |
| 282 } |
| 283 |
| 284 void AudioEncoderResource::OnPluginMsgBitstreamBufferReady( |
| 285 const ResourceMessageReplyParams& params, |
| 286 int32_t buffer_id) { |
| 287 bitstream_buffer_manager_.EnqueueBuffer(buffer_id); |
| 288 |
| 289 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_)) |
| 290 TryWriteBitstreamBuffer(); |
| 291 } |
| 292 |
| 293 void AudioEncoderResource::OnPluginMsgNotifyError( |
| 294 const ResourceMessageReplyParams& params, |
| 295 int32_t error) { |
| 296 NotifyError(error); |
| 297 } |
| 298 |
| 299 void AudioEncoderResource::NotifyError(int32_t error) { |
| 300 DCHECK(error); |
| 301 |
| 302 encoder_last_error_ = error; |
| 303 RunCallback(&get_supported_profiles_callback_, error); |
| 304 RunCallback(&initialize_callback_, error); |
| 305 RunCallback(&get_buffer_callback_, error); |
| 306 get_buffer_data_ = nullptr; |
| 307 RunCallback(&get_bitstream_buffer_callback_, error); |
| 308 get_bitstream_buffer_data_ = nullptr; |
| 309 for (EncodeMap::iterator it = encode_callbacks_.begin(); |
| 310 it != encode_callbacks_.end(); ++it) |
| 311 RunCallback(&it->second, error); |
| 312 encode_callbacks_.clear(); |
| 313 } |
| 314 |
| 315 void AudioEncoderResource::TryGetAudioBuffer() { |
| 316 DCHECK(TrackedCallback::IsPending(get_buffer_callback_)); |
| 317 |
| 318 if (!audio_buffer_manager_.HasAvailableBuffer()) |
| 319 return; |
| 320 |
| 321 int32_t buffer_id = audio_buffer_manager_.DequeueBuffer(); |
| 322 scoped_refptr<AudioBufferResource> resource = new AudioBufferResource( |
| 323 pp_instance(), buffer_id, |
| 324 audio_buffer_manager_.GetBufferPointer(buffer_id)); |
| 325 audio_buffers_.insert( |
| 326 AudioBufferMap::value_type(resource->pp_resource(), resource)); |
| 327 |
| 328 // Take a reference for the plugin. |
| 329 *get_buffer_data_ = resource->GetReference(); |
| 330 get_buffer_data_ = nullptr; |
| 331 RunCallback(&get_buffer_callback_, PP_OK); |
| 332 } |
| 333 |
| 334 void AudioEncoderResource::TryWriteBitstreamBuffer() { |
| 335 DCHECK(TrackedCallback::IsPending(get_bitstream_buffer_callback_)); |
| 336 |
| 337 if (!bitstream_buffer_manager_.HasAvailableBuffer()) |
| 338 return; |
| 339 |
| 340 int32_t buffer_id = bitstream_buffer_manager_.DequeueBuffer(); |
| 341 MediaStreamBuffer* buffer = |
| 342 bitstream_buffer_manager_.GetBufferPointer(buffer_id); |
| 343 |
| 344 get_bitstream_buffer_data_->buffer = buffer->bitstream.data; |
| 345 get_bitstream_buffer_data_->size = buffer->bitstream.data_size; |
| 346 get_bitstream_buffer_data_ = nullptr; |
| 347 RunCallback(&get_bitstream_buffer_callback_, PP_OK); |
| 348 } |
| 349 |
| 350 void AudioEncoderResource::ReleaseBuffers() { |
| 351 for (AudioBufferMap::iterator it = audio_buffers_.begin(); |
| 352 it != audio_buffers_.end(); ++it) |
| 353 it->second->Invalidate(); |
| 354 audio_buffers_.clear(); |
69 } | 355 } |
70 | 356 |
71 } // namespace proxy | 357 } // namespace proxy |
72 } // namespace ppapi | 358 } // namespace ppapi |
OLD | NEW |