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

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: 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 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698