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

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

Powered by Google App Engine
This is Rietveld 408576698