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

Side by Side Diff: ppapi/proxy/audio_encoder_resource.cc

Issue 1348563003: ppapi: implement PPB_AudioEncoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address tsepez's review Created 5 years, 2 months 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
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 return;
23
24 scoped_refptr<TrackedCallback> temp;
25 callback->swap(temp);
26 temp->Run(error);
27 }
28
29 } // namespace
30
31 class AudioEncoderResource::BitstreamBufferManager {
32 public:
33 BitstreamBufferManager() : number_of_buffers_(0), buffer_size_(0) {}
34 ~BitstreamBufferManager() {}
35
36 bool Initialize(scoped_ptr<base::SharedMemory> shm,
37 uint32_t number_of_buffers,
38 size_t buffer_size) {
39 uint32_t total_size = number_of_buffers * buffer_size;
40 shm_ = shm.Pass();
41 if (!shm_ || !shm_->Map(base::checked_cast<size_t>(total_size)))
42 return false;
43
44 for (uint32_t i = 0; i < number_of_buffers; i++)
45 buffer_map_.insert(std::make_pair(
46 static_cast<uint8_t*>(shm_->memory()) + (i * buffer_size),
47 static_cast<int32_t>(i)));
48
49 number_of_buffers_ = number_of_buffers;
50 buffer_size_ = buffer_size;
51 return true;
52 }
53 int32_t GetBufferId(void* address) {
54 BufferMap::const_iterator it = buffer_map_.find(address);
55 if (it == buffer_map_.end())
56 return -1;
57 return it->second;
58 }
59 uint8_t* GetBuffer(int32_t id) {
60 if (id < 0 || static_cast<uint32_t>(id) >= number_of_buffers_)
61 return nullptr;
62 return static_cast<uint8_t*>(shm_->memory()) + (id * buffer_size_);
63 }
64 std::pair<int32_t, uint32_t> DequeueBuffer() {
65 if (enqueued_buffers_.empty())
66 return std::make_pair(-1, 0U);
67 std::pair<int32_t, uint32_t> tuple = enqueued_buffers_.front();
68 enqueued_buffers_.pop_front();
69 return tuple;
70 }
71 void EnqueueBuffer(int32_t id, uint32_t size) {
72 enqueued_buffers_.push_back(std::make_pair(id, size));
73 }
74 bool AvailableBuffers() { return !enqueued_buffers_.empty(); }
75
76 private:
77 uint32_t number_of_buffers_;
78
79 // Size of individual buffers in bytes.
80 size_t buffer_size_;
81
82 // Shared memory containing |number_of_buffers_| bitstream buffers.
83 scoped_ptr<base::SharedMemory> shm_;
84
85 // Queue of bitstream buffers received from the host, waiting to be
86 // handed to the plugin.
87 std::deque<std::pair<int32_t, uint32_t>> enqueued_buffers_;
88
89 // Memory pointer map using buffer id.
90 typedef std::map<void*, int32_t> BufferMap;
91 BufferMap buffer_map_;
92
93 DISALLOW_COPY_AND_ASSIGN(BitstreamBufferManager);
94 };
95
10 AudioEncoderResource::AudioEncoderResource(Connection connection, 96 AudioEncoderResource::AudioEncoderResource(Connection connection,
11 PP_Instance instance) 97 PP_Instance instance)
12 : PluginResource(connection, instance) { 98 : PluginResource(connection, instance),
99 encoder_last_error_(PP_ERROR_FAILED),
100 initialized_(false),
101 closed_(false),
102 buffer_manager_(this) {
103 SendCreate(RENDERER, PpapiHostMsg_AudioEncoder_Create());
13 } 104 }
14 105
15 AudioEncoderResource::~AudioEncoderResource() { 106 AudioEncoderResource::~AudioEncoderResource() {
16 } 107 }
17 108
18 thunk::PPB_AudioEncoder_API* AudioEncoderResource::AsPPB_AudioEncoder_API() { 109 thunk::PPB_AudioEncoder_API* AudioEncoderResource::AsPPB_AudioEncoder_API() {
19 return this; 110 return this;
20 } 111 }
21 112
22 int32_t AudioEncoderResource::GetSupportedProfiles( 113 int32_t AudioEncoderResource::GetSupportedProfiles(
23 const PP_ArrayOutput& output, 114 const PP_ArrayOutput& output,
24 const scoped_refptr<TrackedCallback>& callback) { 115 const scoped_refptr<TrackedCallback>& callback) {
25 return PP_ERROR_NOTSUPPORTED; 116 if (TrackedCallback::IsPending(get_supported_profiles_callback_))
117 return PP_ERROR_INPROGRESS;
118
119 get_supported_profiles_callback_ = callback;
120 Call<PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply>(
121 RENDERER, PpapiHostMsg_AudioEncoder_GetSupportedProfiles(),
122 base::Bind(&AudioEncoderResource::OnPluginMsgGetSupportedProfilesReply,
123 this, output));
124 return PP_OK_COMPLETIONPENDING;
26 } 125 }
27 126
28 int32_t AudioEncoderResource::Initialize( 127 int32_t AudioEncoderResource::Initialize(
29 uint32_t channels, 128 uint32_t channels,
30 PP_AudioBuffer_SampleRate input_sample_rate, 129 PP_AudioBuffer_SampleRate input_sample_rate,
31 PP_AudioBuffer_SampleSize input_sample_size, 130 PP_AudioBuffer_SampleSize input_sample_size,
32 PP_AudioProfile output_profile, 131 PP_AudioProfile output_profile,
33 uint32_t initial_bitrate, 132 uint32_t initial_bitrate,
34 PP_HardwareAcceleration acceleration, 133 PP_HardwareAcceleration acceleration,
35 const scoped_refptr<TrackedCallback>& callback) { 134 const scoped_refptr<TrackedCallback>& callback) {
36 return PP_ERROR_NOTSUPPORTED; 135 if (initialized_)
136 return PP_ERROR_FAILED;
137 if (TrackedCallback::IsPending(initialize_callback_))
138 return PP_ERROR_INPROGRESS;
139
140 initialize_callback_ = callback;
141
142 PPB_AudioEncodeParameters parameters;
143 parameters.channels = channels;
144 parameters.input_sample_rate = input_sample_rate;
145 parameters.input_sample_size = input_sample_size;
146 parameters.output_profile = output_profile;
147 parameters.initial_bitrate = initial_bitrate;
148 parameters.acceleration = acceleration;
149
150 Call<PpapiPluginMsg_AudioEncoder_InitializeReply>(
151 RENDERER, PpapiHostMsg_AudioEncoder_Initialize(parameters),
152 base::Bind(&AudioEncoderResource::OnPluginMsgInitializeReply, this));
153 return PP_OK_COMPLETIONPENDING;
37 } 154 }
38 155
39 int32_t AudioEncoderResource::GetNumberOfSamples() { 156 int32_t AudioEncoderResource::GetNumberOfSamples() {
40 return PP_ERROR_NOTSUPPORTED; 157 if (encoder_last_error_)
158 return encoder_last_error_;
159 return number_of_samples_;
41 } 160 }
42 161
43 int32_t AudioEncoderResource::GetBuffer( 162 int32_t AudioEncoderResource::GetBuffer(
44 PP_Resource* audio_buffer, 163 PP_Resource* audio_buffer,
45 const scoped_refptr<TrackedCallback>& callback) { 164 const scoped_refptr<TrackedCallback>& callback) {
46 return PP_ERROR_NOTSUPPORTED; 165 if (encoder_last_error_)
166 return encoder_last_error_;
167
168 if (TrackedCallback::IsPending(get_buffer_callback_))
169 return PP_ERROR_INPROGRESS;
170
171 get_buffer_data_ = audio_buffer;
172 get_buffer_callback_ = callback;
173
174 // Lazily ask for a shared memory buffer in which audio frames are allocated.
175 if (buffer_manager_.number_of_buffers() == 0) {
176 Call<PpapiPluginMsg_AudioEncoder_GetAudioFramesReply>(
177 RENDERER, PpapiHostMsg_AudioEncoder_GetAudioFrames(),
178 base::Bind(&AudioEncoderResource::OnPluginMsgGetAudioFramesReply,
179 this));
180 } else {
181 TryWriteAudioBuffer();
182 }
183
184 return PP_OK_COMPLETIONPENDING;
47 } 185 }
48 186
49 int32_t AudioEncoderResource::Encode( 187 int32_t AudioEncoderResource::Encode(
50 PP_Resource audio_buffer, 188 PP_Resource audio_buffer,
51 const scoped_refptr<TrackedCallback>& callback) { 189 const scoped_refptr<TrackedCallback>& callback) {
52 return PP_ERROR_NOTSUPPORTED; 190 if (encoder_last_error_)
191 return encoder_last_error_;
192
193 AudioBufferMap::iterator it = audio_buffers_.find(audio_buffer);
194 if (it == audio_buffers_.end())
195 // TODO(llandwerlin): accept MediaStreamAudioTrack's audio buffers.
196 return PP_ERROR_BADRESOURCE;
197
198 scoped_refptr<AudioBufferResource> buffer_resource = it->second;
199
200 encode_callbacks_.insert(
201 std::make_pair(buffer_resource->GetBufferIndex(), callback));
202
203 Post(RENDERER,
204 PpapiHostMsg_AudioEncoder_Encode(buffer_resource->GetBufferIndex()));
205
206 // Invalidate the frame to prevent the plugin from modifying it.
207 buffer_resource->Invalidate();
208 audio_buffers_.erase(it);
209
210 return PP_OK_COMPLETIONPENDING;
53 } 211 }
54 212
55 int32_t AudioEncoderResource::GetBitstreamBuffer( 213 int32_t AudioEncoderResource::GetBitstreamBuffer(
56 PP_AudioBitstreamBuffer* bitstream_buffer, 214 PP_AudioBitstreamBuffer* bitstream_buffer,
57 const scoped_refptr<TrackedCallback>& callback) { 215 const scoped_refptr<TrackedCallback>& callback) {
58 return PP_ERROR_NOTSUPPORTED; 216 if (encoder_last_error_)
217 return encoder_last_error_;
218 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_))
219 return PP_ERROR_INPROGRESS;
220
221 get_bitstream_buffer_callback_ = callback;
222 get_bitstream_buffer_data_ = bitstream_buffer;
223
224 TryWriteBitstreamBuffer();
225
226 return PP_OK_COMPLETIONPENDING;
59 } 227 }
60 228
61 void AudioEncoderResource::RecycleBitstreamBuffer( 229 void AudioEncoderResource::RecycleBitstreamBuffer(
62 const PP_AudioBitstreamBuffer* bitstream_buffer) { 230 const PP_AudioBitstreamBuffer* bitstream_buffer) {
231 if (encoder_last_error_)
232 return;
233 int32_t buffer_id =
234 bitstream_buffer_manager_->GetBufferId(bitstream_buffer->buffer);
235
236 if (buffer_id >= 0)
237 Post(RENDERER, PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer(buffer_id));
63 } 238 }
64 239
65 void AudioEncoderResource::RequestBitrateChange(uint32_t bitrate) { 240 void AudioEncoderResource::RequestBitrateChange(uint32_t bitrate) {
241 if (encoder_last_error_)
242 return;
243 Post(RENDERER, PpapiHostMsg_AudioEncoder_RequestBitrateChange(bitrate));
66 } 244 }
67 245
68 void AudioEncoderResource::Close() { 246 void AudioEncoderResource::Close() {
247 if (encoder_last_error_)
248 return;
249 Post(RENDERER, PpapiHostMsg_AudioEncoder_Close());
250 closed_ = true;
251 if (!encoder_last_error_ || !initialized_)
252 NotifyError(PP_ERROR_ABORTED);
253 ReleaseBuffers();
254 }
255
256 void AudioEncoderResource::OnReplyReceived(
257 const ResourceMessageReplyParams& params,
258 const IPC::Message& msg) {
259 PPAPI_BEGIN_MESSAGE_MAP(AudioEncoderResource, msg)
260 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
261 PpapiPluginMsg_AudioEncoder_BitstreamBufferReady,
262 OnPluginMsgBitstreamBufferReady)
263 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_AudioEncoder_EncodeReply,
264 OnPluginMsgEncodeReply)
265 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_AudioEncoder_NotifyError,
266 OnPluginMsgNotifyError)
267 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
268 PluginResource::OnReplyReceived(params, msg))
269 PPAPI_END_MESSAGE_MAP()
270 }
271
272 void AudioEncoderResource::OnPluginMsgGetSupportedProfilesReply(
273 const PP_ArrayOutput& output,
274 const ResourceMessageReplyParams& params,
275 const std::vector<PP_AudioProfileDescription>& profiles) {
276 int32_t error = params.result();
277 if (error) {
278 NotifyError(error);
279 return;
280 }
281
282 ArrayWriter writer(output);
283 if (!writer.is_valid()) {
284 RunCallback(&get_supported_profiles_callback_, PP_ERROR_BADARGUMENT);
285 return;
286 }
287
288 bool write_result = writer.StoreVector(profiles);
289
290 if (!write_result) {
291 RunCallback(&get_supported_profiles_callback_, PP_ERROR_FAILED);
292 return;
293 }
294
295 RunCallback(&get_supported_profiles_callback_,
296 base::checked_cast<int32_t>(profiles.size()));
297 }
298
299 void AudioEncoderResource::OnPluginMsgInitializeReply(
300 const ResourceMessageReplyParams& params,
301 uint32_t number_of_samples,
302 uint32_t buffer_count,
303 uint32_t buffer_size) {
304 DCHECK(!initialized_);
305
306 int32_t error = params.result();
307 if (error) {
308 NotifyError(error);
309 return;
310 }
311
312 base::SharedMemoryHandle buffer_handle;
313 if (!params.TakeSharedMemoryHandleAtIndex(0, &buffer_handle)) {
314 NotifyError(PP_ERROR_FAILED);
315 return;
316 }
317
318 bitstream_buffer_manager_.reset(new BitstreamBufferManager());
319 if (!bitstream_buffer_manager_->Initialize(
320 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)),
321 buffer_count, buffer_size)) {
322 NotifyError(PP_ERROR_FAILED);
323 return;
324 }
325
326 encoder_last_error_ = PP_OK;
327 number_of_samples_ = number_of_samples;
328 initialized_ = true;
329
330 RunCallback(&initialize_callback_, encoder_last_error_);
331 }
332
333 void AudioEncoderResource::OnPluginMsgGetAudioFramesReply(
334 const ResourceMessageReplyParams& params,
335 uint32_t frame_count,
336 uint32_t frame_length) {
337 int32_t error = params.result();
338 if (error) {
339 NotifyError(error);
340 return;
341 }
342
343 base::SharedMemoryHandle buffer_handle;
344 if (!params.TakeSharedMemoryHandleAtIndex(0, &buffer_handle)) {
345 NotifyError(PP_ERROR_FAILED);
346 return;
347 }
348
349 if (!buffer_manager_.SetBuffers(
350 frame_count, frame_length + sizeof(ppapi::MediaStreamBuffer::Audio),
351 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)),
352 true)) {
353 NotifyError(PP_ERROR_FAILED);
354 return;
355 }
356
357 if (TrackedCallback::IsPending(get_buffer_callback_))
358 TryWriteAudioBuffer();
359 }
360
361 void AudioEncoderResource::OnPluginMsgEncodeReply(
362 const ResourceMessageReplyParams& params,
363 uint32_t buffer_id) {
364 // We need to ensure there are still callbacks to be called before
365 // processing this message. We might receive a EncodeReply message
366 // after having sent a Close message to the renderer. In this case,
367 // we don't have any callback left to call.
368 if (encode_callbacks_.empty())
369 return;
370 encoder_last_error_ = params.result();
371
372 EncodeMap::iterator it = encode_callbacks_.find(buffer_id);
373 DCHECK(encode_callbacks_.end() != it);
374
375 scoped_refptr<TrackedCallback> callback = it->second;
376 encode_callbacks_.erase(it);
377 RunCallback(&callback, encoder_last_error_);
378
379 buffer_manager_.EnqueueBuffer(buffer_id);
380 // If the plugin is waiting for an audio buffer, we can give the one
381 // that just became available again.
382 if (TrackedCallback::IsPending(get_buffer_callback_))
383 TryWriteAudioBuffer();
384 }
385
386 void AudioEncoderResource::OnPluginMsgBitstreamBufferReady(
387 const ResourceMessageReplyParams& params,
388 uint32_t buffer_id,
389 uint32_t buffer_size) {
390 bitstream_buffer_manager_->EnqueueBuffer(
391 base::checked_cast<int32_t>(buffer_id), buffer_size);
392
393 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_))
394 TryWriteBitstreamBuffer();
395 }
396
397 void AudioEncoderResource::OnPluginMsgNotifyError(
398 const ResourceMessageReplyParams& params,
399 int32_t error) {
400 NotifyError(error);
401 }
402
403 void AudioEncoderResource::NotifyError(int32_t error) {
404 encoder_last_error_ = error;
405 RunCallback(&get_supported_profiles_callback_, error);
406 RunCallback(&initialize_callback_, error);
407 RunCallback(&get_buffer_callback_, error);
408 get_buffer_data_ = nullptr;
409 RunCallback(&get_bitstream_buffer_callback_, error);
410 get_bitstream_buffer_data_ = nullptr;
411 for (EncodeMap::iterator it = encode_callbacks_.begin();
412 it != encode_callbacks_.end(); ++it) {
413 scoped_refptr<TrackedCallback> callback = it->second;
414 RunCallback(&callback, error);
415 }
416 encode_callbacks_.clear();
417 }
418
419 void AudioEncoderResource::TryWriteAudioBuffer() {
420 DCHECK(TrackedCallback::IsPending(get_buffer_callback_));
421
422 int32_t buffer_id = buffer_manager_.DequeueBuffer();
423 if (buffer_id < 0)
424 return;
425
426 scoped_refptr<AudioBufferResource> resource = new AudioBufferResource(
427 pp_instance(), buffer_id, buffer_manager_.GetBufferPointer(buffer_id));
428 audio_buffers_.insert(
429 AudioBufferMap::value_type(resource->pp_resource(), resource));
430
431 *get_buffer_data_ = resource->GetReference();
432 get_buffer_data_ = nullptr;
433 RunCallback(&get_buffer_callback_, PP_OK);
434 }
435
436 void AudioEncoderResource::TryWriteBitstreamBuffer() {
437 DCHECK(TrackedCallback::IsPending(get_bitstream_buffer_callback_));
438
439 if (!bitstream_buffer_manager_->AvailableBuffers())
440 return;
441
442 std::pair<int32_t, uint32_t> data =
443 bitstream_buffer_manager_->DequeueBuffer();
444
445 get_bitstream_buffer_data_->buffer =
446 bitstream_buffer_manager_->GetBuffer(data.first);
447 get_bitstream_buffer_data_->size = data.second;
448 get_bitstream_buffer_data_ = nullptr;
449 RunCallback(&get_bitstream_buffer_callback_, PP_OK);
450 }
451
452 void AudioEncoderResource::ReleaseBuffers() {
453 for (AudioBufferMap::iterator it = audio_buffers_.begin();
454 it != audio_buffers_.end(); ++it) {
455 it->second->Invalidate();
456 it->second = nullptr;
457 }
458 audio_buffers_.clear();
69 } 459 }
70 460
71 } // namespace proxy 461 } // namespace proxy
72 } // namespace ppapi 462 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698