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

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: Drop bitstream buffer manager from proxy 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)) {
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 closed_(false),
bbudge 2015/11/17 00:53:40 initialize number_of_samples_ and get_buffer_data_
bbudge 2015/11/17 00:53:40 closed_ is written but never read, so you can remo
36 audio_buffer_manager_(this),
37 bitstream_buffer_manager_(this) {
38 SendCreate(RENDERER, PpapiHostMsg_AudioEncoder_Create());
13 } 39 }
14 40
15 AudioEncoderResource::~AudioEncoderResource() { 41 AudioEncoderResource::~AudioEncoderResource() {
16 } 42 }
17 43
18 thunk::PPB_AudioEncoder_API* AudioEncoderResource::AsPPB_AudioEncoder_API() { 44 thunk::PPB_AudioEncoder_API* AudioEncoderResource::AsPPB_AudioEncoder_API() {
19 return this; 45 return this;
20 } 46 }
21 47
22 int32_t AudioEncoderResource::GetSupportedProfiles( 48 int32_t AudioEncoderResource::GetSupportedProfiles(
23 const PP_ArrayOutput& output, 49 const PP_ArrayOutput& output,
24 const scoped_refptr<TrackedCallback>& callback) { 50 const scoped_refptr<TrackedCallback>& callback) {
25 return PP_ERROR_NOTSUPPORTED; 51 if (TrackedCallback::IsPending(get_supported_profiles_callback_))
52 return PP_ERROR_INPROGRESS;
53
54 get_supported_profiles_callback_ = callback;
55 Call<PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply>(
56 RENDERER, PpapiHostMsg_AudioEncoder_GetSupportedProfiles(),
57 base::Bind(&AudioEncoderResource::OnPluginMsgGetSupportedProfilesReply,
58 this, output));
59 return PP_OK_COMPLETIONPENDING;
26 } 60 }
27 61
28 int32_t AudioEncoderResource::Initialize( 62 int32_t AudioEncoderResource::Initialize(
29 uint32_t channels, 63 uint32_t channels,
30 PP_AudioBuffer_SampleRate input_sample_rate, 64 PP_AudioBuffer_SampleRate input_sample_rate,
31 PP_AudioBuffer_SampleSize input_sample_size, 65 PP_AudioBuffer_SampleSize input_sample_size,
32 PP_AudioProfile output_profile, 66 PP_AudioProfile output_profile,
33 uint32_t initial_bitrate, 67 uint32_t initial_bitrate,
34 PP_HardwareAcceleration acceleration, 68 PP_HardwareAcceleration acceleration,
35 const scoped_refptr<TrackedCallback>& callback) { 69 const scoped_refptr<TrackedCallback>& callback) {
36 return PP_ERROR_NOTSUPPORTED; 70 if (initialized_)
71 return PP_ERROR_FAILED;
72 if (TrackedCallback::IsPending(initialize_callback_))
73 return PP_ERROR_INPROGRESS;
74
75 initialize_callback_ = callback;
76
77 PPB_AudioEncodeParameters parameters;
78 parameters.channels = channels;
79 parameters.input_sample_rate = input_sample_rate;
80 parameters.input_sample_size = input_sample_size;
81 parameters.output_profile = output_profile;
82 parameters.initial_bitrate = initial_bitrate;
83 parameters.acceleration = acceleration;
84
85 Call<PpapiPluginMsg_AudioEncoder_InitializeReply>(
86 RENDERER, PpapiHostMsg_AudioEncoder_Initialize(parameters),
87 base::Bind(&AudioEncoderResource::OnPluginMsgInitializeReply, this));
88 return PP_OK_COMPLETIONPENDING;
37 } 89 }
38 90
39 int32_t AudioEncoderResource::GetNumberOfSamples() { 91 int32_t AudioEncoderResource::GetNumberOfSamples() {
40 return PP_ERROR_NOTSUPPORTED; 92 if (encoder_last_error_)
93 return encoder_last_error_;
94 return number_of_samples_;
41 } 95 }
42 96
43 int32_t AudioEncoderResource::GetBuffer( 97 int32_t AudioEncoderResource::GetBuffer(
44 PP_Resource* audio_buffer, 98 PP_Resource* audio_buffer,
45 const scoped_refptr<TrackedCallback>& callback) { 99 const scoped_refptr<TrackedCallback>& callback) {
46 return PP_ERROR_NOTSUPPORTED; 100 if (encoder_last_error_)
101 return encoder_last_error_;
102 if (TrackedCallback::IsPending(get_buffer_callback_))
103 return PP_ERROR_INPROGRESS;
104
105 get_buffer_data_ = audio_buffer;
106 get_buffer_callback_ = callback;
107
108 TryWriteAudioBuffer();
109
110 return PP_OK_COMPLETIONPENDING;
47 } 111 }
48 112
49 int32_t AudioEncoderResource::Encode( 113 int32_t AudioEncoderResource::Encode(
50 PP_Resource audio_buffer, 114 PP_Resource audio_buffer,
51 const scoped_refptr<TrackedCallback>& callback) { 115 const scoped_refptr<TrackedCallback>& callback) {
52 return PP_ERROR_NOTSUPPORTED; 116 if (encoder_last_error_)
117 return encoder_last_error_;
118
119 AudioBufferMap::iterator it = audio_buffers_.find(audio_buffer);
120 if (it == audio_buffers_.end())
121 // TODO(llandwerlin): accept MediaStreamAudioTrack's audio buffers.
122 return PP_ERROR_BADRESOURCE;
123
124 scoped_refptr<AudioBufferResource> buffer_resource = it->second;
125
126 encode_callbacks_.insert(
127 std::make_pair(buffer_resource->GetBufferIndex(), callback));
128
129 Post(RENDERER,
130 PpapiHostMsg_AudioEncoder_Encode(buffer_resource->GetBufferIndex()));
131
132 // Invalidate the buffer to prevent the plugin from modifying it.
133 buffer_resource->Invalidate();
bbudge 2015/11/17 00:53:40 The real reason to call Invalidate() is so the res
llandwerlin-old 2015/11/17 15:22:30 Done.
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 closed_ = true;
178 if (!encoder_last_error_ || !initialized_)
179 NotifyError(PP_ERROR_ABORTED);
180 ReleaseBuffers();
181 }
182
183 void AudioEncoderResource::OnReplyReceived(
184 const ResourceMessageReplyParams& params,
185 const IPC::Message& msg) {
186 PPAPI_BEGIN_MESSAGE_MAP(AudioEncoderResource, msg)
187 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
188 PpapiPluginMsg_AudioEncoder_BitstreamBufferReady,
189 OnPluginMsgBitstreamBufferReady)
190 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_AudioEncoder_EncodeReply,
191 OnPluginMsgEncodeReply)
192 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_AudioEncoder_NotifyError,
193 OnPluginMsgNotifyError)
194 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
195 PluginResource::OnReplyReceived(params, msg))
196 PPAPI_END_MESSAGE_MAP()
197 }
198
199 void AudioEncoderResource::OnPluginMsgGetSupportedProfilesReply(
200 const PP_ArrayOutput& output,
201 const ResourceMessageReplyParams& params,
202 const std::vector<PP_AudioProfileDescription>& profiles) {
203 int32_t error = params.result();
204 if (error) {
205 NotifyError(error);
bbudge 2015/11/17 00:53:40 It seems wrong to NotifyError in this case.
llandwerlin-old 2015/11/17 15:22:31 It seems that if the host is not able to answer th
206 return;
207 }
208
209 ArrayWriter writer(output);
210 if (!writer.is_valid()) {
211 RunCallback(&get_supported_profiles_callback_, PP_ERROR_BADARGUMENT);
bbudge 2015/11/17 00:53:40 In this case, we usually return PP_ERROR_FAILED si
llandwerlin-old 2015/11/17 15:22:30 Done.
212 return;
213 }
214
215 bool write_result = writer.StoreVector(profiles);
216
217 if (!write_result) {
218 RunCallback(&get_supported_profiles_callback_, PP_ERROR_FAILED);
219 return;
220 }
bbudge 2015/11/17 00:53:40 You could eliminate some duplication like this:
llandwerlin-old 2015/11/17 15:22:31 Done.
221
222 RunCallback(&get_supported_profiles_callback_,
223 base::checked_cast<int32_t>(profiles.size()));
224 }
225
226 void AudioEncoderResource::OnPluginMsgInitializeReply(
227 const ResourceMessageReplyParams& params,
228 int32_t number_of_samples,
229 int32_t audio_buffer_count,
230 int32_t audio_buffer_size,
231 int32_t bitstream_buffer_count,
232 int32_t bitstream_buffer_size) {
233 DCHECK(!initialized_);
234
235 int32_t error = params.result();
236 if (error) {
237 NotifyError(error);
bbudge 2015/11/17 00:53:41 I guess this works but you could also just call: R
llandwerlin-old 2015/11/17 15:22:31 Done.
238 return;
239 }
240
241 // Get audio buffers shared memory buffer.
242 base::SharedMemoryHandle buffer_handle;
243 if (!params.TakeSharedMemoryHandleAtIndex(0, &buffer_handle)) {
244 NotifyError(PP_ERROR_FAILED);
bbudge 2015/11/17 00:53:40 PP_ERROR_NOMEMORY here and below
llandwerlin-old 2015/11/17 15:22:31 Done.
245 return;
246 }
247
248 if (!audio_buffer_manager_.SetBuffers(
249 audio_buffer_count, audio_buffer_size,
250 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)),
251 true)) {
252 NotifyError(PP_ERROR_FAILED);
253 return;
254 }
255
256 // Get bitstreamer buffers shared memory buffer.
bbudge 2015/11/17 00:53:40 s/bitstreamer/bitstream
llandwerlin-old 2015/11/17 15:22:31 Done.
257 if (!params.TakeSharedMemoryHandleAtIndex(1, &buffer_handle)) {
258 NotifyError(PP_ERROR_FAILED);
259 return;
260 }
261
262 if (!bitstream_buffer_manager_.SetBuffers(
263 bitstream_buffer_count, bitstream_buffer_size,
264 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)),
265 false)) {
266 NotifyError(PP_ERROR_FAILED);
267 return;
268 }
269
270 for (int32_t i = 0; i < bitstream_buffer_manager_.number_of_buffers(); i++)
271 bitstream_buffer_map_.insert(
272 std::make_pair(bitstream_buffer_manager_.GetBufferPointer(i), i));
273
274 encoder_last_error_ = PP_OK;
275 number_of_samples_ = number_of_samples;
276 initialized_ = true;
277
278 RunCallback(&initialize_callback_, encoder_last_error_);
bbudge 2015/11/17 00:53:40 RunCallback(&initialize_callback_, PP_OK);
llandwerlin-old 2015/11/17 15:22:31 Done.
279
280 if (TrackedCallback::IsPending(get_buffer_callback_))
bbudge 2015/11/17 00:53:40 This should never be true so you could remove it.
llandwerlin-old 2015/11/17 15:22:31 Thanks, done.
281 TryWriteAudioBuffer();
282 }
283
284 void AudioEncoderResource::OnPluginMsgEncodeReply(
285 const ResourceMessageReplyParams& params,
286 int32_t buffer_id) {
287 // We need to ensure there are still callbacks to be called before
288 // processing this message. We might receive a EncodeReply message
289 // after having sent a Close message to the renderer. In this case,
290 // we don't have any callback left to call.
291 if (encode_callbacks_.empty())
292 return;
293 encoder_last_error_ = params.result();
bbudge 2015/11/17 00:53:40 Looking at the host, this is an unsolicited reply
llandwerlin-old 2015/11/17 15:22:31 Thanks, done.
294
295 EncodeMap::iterator it = encode_callbacks_.find(buffer_id);
296 DCHECK(encode_callbacks_.end() != it);
297
298 scoped_refptr<TrackedCallback> callback = it->second;
299 encode_callbacks_.erase(it);
300 RunCallback(&callback, encoder_last_error_);
301
302 audio_buffer_manager_.EnqueueBuffer(buffer_id);
303 // If the plugin is waiting for an audio buffer, we can give the one
304 // that just became available again.
305 if (TrackedCallback::IsPending(get_buffer_callback_))
306 TryWriteAudioBuffer();
307 }
308
309 void AudioEncoderResource::OnPluginMsgBitstreamBufferReady(
310 const ResourceMessageReplyParams& params,
311 int32_t buffer_id,
312 int32_t buffer_size) {
313 bitstream_buffer_manager_.EnqueueBuffer(buffer_id);
314 bitstream_queued_buffer_sizes_.push_back(buffer_size);
315
316 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_))
317 TryWriteBitstreamBuffer();
318 }
319
320 void AudioEncoderResource::OnPluginMsgNotifyError(
321 const ResourceMessageReplyParams& params,
322 int32_t error) {
323 NotifyError(error);
324 }
325
326 void AudioEncoderResource::NotifyError(int32_t error) {
bbudge 2015/11/17 00:53:40 DCHECK(error) might be a good idea here.
llandwerlin-old 2015/11/17 15:22:31 Done.
327 encoder_last_error_ = error;
328 RunCallback(&get_supported_profiles_callback_, error);
329 RunCallback(&initialize_callback_, error);
330 RunCallback(&get_buffer_callback_, error);
331 get_buffer_data_ = nullptr;
332 RunCallback(&get_bitstream_buffer_callback_, error);
333 get_bitstream_buffer_data_ = nullptr;
334 for (EncodeMap::iterator it = encode_callbacks_.begin();
335 it != encode_callbacks_.end(); ++it) {
336 scoped_refptr<TrackedCallback> callback = it->second;
337 RunCallback(&callback, error);
bbudge 2015/11/17 00:53:41 RunCallback(&it->second, error); // doesn't seem
llandwerlin-old 2015/11/17 15:22:31 Done.
338 }
339 encode_callbacks_.clear();
340 }
341
342 void AudioEncoderResource::TryWriteAudioBuffer() {
bbudge 2015/11/17 00:53:40 I'm finding this method name confusing. How about
llandwerlin-old 2015/11/17 15:22:31 Done.
343 DCHECK(TrackedCallback::IsPending(get_buffer_callback_));
344
345 if (!audio_buffer_manager_.HasAvailableBuffer())
346 return;
347
348 int32_t buffer_id = audio_buffer_manager_.DequeueBuffer();
349 scoped_refptr<AudioBufferResource> resource = new AudioBufferResource(
350 pp_instance(), buffer_id,
351 audio_buffer_manager_.GetBufferPointer(buffer_id));
352 audio_buffers_.insert(
353 AudioBufferMap::value_type(resource->pp_resource(), resource));
354
355 *get_buffer_data_ = resource->GetReference();
bbudge 2015/11/17 00:53:40 This line deserves a comment: // Take a reference
llandwerlin-old 2015/11/17 15:22:31 Done.
356 get_buffer_data_ = nullptr;
357 RunCallback(&get_buffer_callback_, PP_OK);
358 }
359
360 void AudioEncoderResource::TryWriteBitstreamBuffer() {
361 DCHECK(TrackedCallback::IsPending(get_bitstream_buffer_callback_));
362
363 if (!bitstream_buffer_manager_.HasAvailableBuffer())
364 return;
365
366 int32_t buffer_id = bitstream_buffer_manager_.DequeueBuffer();
367 int32_t buffer_size = bitstream_queued_buffer_sizes_.front();
368 bitstream_queued_buffer_sizes_.pop_front();
369
370 get_bitstream_buffer_data_->buffer =
371 static_cast<void*>(bitstream_buffer_manager_.GetBufferPointer(buffer_id));
bbudge 2015/11/17 00:53:40 Is this cast needed?
372 get_bitstream_buffer_data_->size = static_cast<uint32_t>(buffer_size);
373 get_bitstream_buffer_data_ = nullptr;
374 RunCallback(&get_bitstream_buffer_callback_, PP_OK);
375 }
376
377 void AudioEncoderResource::ReleaseBuffers() {
378 for (AudioBufferMap::iterator it = audio_buffers_.begin();
379 it != audio_buffers_.end(); ++it) {
380 it->second->Invalidate();
381 it->second = nullptr;
bbudge 2015/11/17 00:53:40 This line isn't strictly needed. clear() will caus
llandwerlin-old 2015/11/17 15:22:31 Done.
382 }
383 audio_buffers_.clear();
69 } 384 }
70 385
71 } // namespace proxy 386 } // namespace proxy
72 } // namespace ppapi 387 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698