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