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

Side by Side Diff: ppapi/examples/audio_encode/audio_encode.cc

Issue 1343273005: ppapi: add AudioEncode example (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@nacl-audio-encoder
Patch Set: Created 5 years 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
« no previous file with comments | « ppapi/examples/audio_encode/BUILD.gn ('k') | ppapi/examples/audio_encode/audio_encode.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 <stdlib.h>
6 #include <string.h>
7
8 #include <map>
9 #include <string>
10 #include <vector>
11
12 #include "ppapi/cpp/audio_buffer.h"
13 #include "ppapi/cpp/audio_encoder.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/logging.h"
16 #include "ppapi/cpp/media_stream_audio_track.h"
17 #include "ppapi/cpp/module.h"
18 #include "ppapi/cpp/var_array_buffer.h"
19 #include "ppapi/cpp/var_dictionary.h"
20 #include "ppapi/utility/completion_callback_factory.h"
21
22 // When compiling natively on Windows, PostMessage can be #define-d to
23 // something else.
24 #ifdef PostMessage
25 #undef PostMessage
26 #endif
27
28 // This example demonstrates receiving audio samples from an audio
29 // track and encoding them.
30
31 namespace {
32
33 class AudioEncoderInstance : public pp::Instance {
34 public:
35 explicit AudioEncoderInstance(PP_Instance instance);
36 virtual ~AudioEncoderInstance();
37
38 private:
39 // pp::Instance implementation.
40 virtual void HandleMessage(const pp::Var& var_message);
41
42 std::string ProfileToString(PP_AudioProfile profile);
43
44 void GetSupportedProfiles();
45 void OnGetSupportedProfiles(
46 int32_t result,
47 const std::vector<PP_AudioProfileDescription> profiles);
48
49 void StartAudioTrack(const pp::Resource& resource_track);
50 void StopAudioTrack();
51 void OnGetBuffer(int32_t result, pp::AudioBuffer buffer);
52
53 void InitializeEncoder();
54 void OnEncoderInitialized(int32_t result);
55 void OnAudioTrackConfigured(int32_t result);
56 void GetEncoderBuffer(const pp::AudioBuffer& track_buffer);
57 void OnGetEncoderBuffer(int32_t result,
58 pp::AudioBuffer buffer,
59 pp::AudioBuffer track_buffer);
60 void OnEncodeDone(int32_t result);
61 void OnGetBitstreamBuffer(int32_t result,
62 const PP_AudioBitstreamBuffer& buffer);
63
64 pp::VarDictionary NewCommand(const std::string& type);
65
66 void Log(const std::string& message);
67 void LogError(int32_t error, const std::string& message);
68
69 void PostAudioFormat();
70 void PostDataMessage(const void* data, uint32_t size);
71
72 pp::CompletionCallbackFactory<AudioEncoderInstance> callback_factory_;
73
74 // Set when the plugin is not performing any encoding and just passing the
75 // uncompressed data directly to web page.
76 bool no_encoding_;
77
78 uint32_t channels_;
79 uint32_t sample_rate_;
80 uint32_t sample_size_;
81 uint32_t samples_per_frame_;
82
83 pp::MediaStreamAudioTrack audio_track_;
84 pp::AudioEncoder audio_encoder_;
85 };
86
87 AudioEncoderInstance::AudioEncoderInstance(PP_Instance instance)
88 : pp::Instance(instance),
89 callback_factory_(this),
90 no_encoding_(true),
91 channels_(0),
92 sample_rate_(0),
93 sample_size_(0),
94 samples_per_frame_(0) {
bbudge 2015/12/10 20:28:35 GetSupportedProfiles needs the audio_encoder_ to b
llandwerlin-old 2015/12/14 11:49:18 Done.
95 GetSupportedProfiles();
96 }
97
98 AudioEncoderInstance::~AudioEncoderInstance() {}
99
100 void AudioEncoderInstance::HandleMessage(const pp::Var& var_message) {
101 if (!var_message.is_dictionary()) {
102 LogError(PP_ERROR_FAILED,
103 "Cannot handle incoming message, not a dictionary");
104 return;
105 }
106
107 pp::VarDictionary dict_message(var_message);
108 std::string command = dict_message.Get("command").AsString();
109
110 if (command == "start") {
111 pp::Var var_track = dict_message.Get("track");
112 if (!var_track.is_resource()) {
113 LogError(PP_ERROR_FAILED, "Given track is not a resource");
114 return;
115 }
116 std::string profile = dict_message.Get("profile").AsString();
117 if (profile == "wav") {
118 no_encoding_ = true;
119 } else {
120 no_encoding_ = false;
121 }
122 StartAudioTrack(var_track.AsResource());
123 } else if (command == "stop") {
124 StopAudioTrack();
125 } else {
126 LogError(PP_ERROR_FAILED, "Invalid command");
127 }
128 }
129
130 std::string AudioEncoderInstance::ProfileToString(PP_AudioProfile profile) {
131 if (profile == PP_AUDIOPROFILE_OPUS)
132 return "opus";
133 return "unknown";
134 }
135
136 void AudioEncoderInstance::GetSupportedProfiles() {
137 audio_encoder_.GetSupportedProfiles(callback_factory_.NewCallbackWithOutput(
138 &AudioEncoderInstance::OnGetSupportedProfiles));
139 }
140
141 void AudioEncoderInstance::OnGetSupportedProfiles(
142 int32_t result,
143 const std::vector<PP_AudioProfileDescription> profiles) {
144 pp::VarDictionary dictionary = NewCommand("supportedProfiles");
145 pp::VarArray js_profiles;
146 dictionary.Set(pp::Var("profiles"), js_profiles);
147
148 if (result < 0) {
149 LogError(result, "Cannot get supported profiles");
150 PostMessage(dictionary);
151 }
152
153 int32_t idx = 0;
154 for (std::vector<PP_AudioProfileDescription>::const_iterator it =
155 profiles.begin();
156 it != profiles.end(); ++it) {
157 pp::VarDictionary js_profile;
158 js_profile.Set(pp::Var("name"), pp::Var(ProfileToString(it->profile)));
159 js_profile.Set(pp::Var("sample_size"),
160 pp::Var(static_cast<int32_t>(it->sample_size)));
161 js_profile.Set(pp::Var("sample_rate"),
162 pp::Var(static_cast<int32_t>(it->sample_rate)));
163 js_profiles.Set(idx++, js_profile);
164 }
165 PostMessage(dictionary);
166 }
167
168 void AudioEncoderInstance::StartAudioTrack(const pp::Resource& resource_track) {
169 audio_track_ = pp::MediaStreamAudioTrack(resource_track);
170 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
171 &AudioEncoderInstance::OnGetBuffer));
172 }
173
174 void AudioEncoderInstance::StopAudioTrack() {
175 channels_ = 0;
176 audio_track_.Close();
177 audio_track_ = pp::MediaStreamAudioTrack();
178 audio_encoder_.Close();
179 audio_encoder_ = pp::AudioEncoder();
180 }
181
182 void AudioEncoderInstance::OnGetBuffer(int32_t result, pp::AudioBuffer buffer) {
183 if (result == PP_ERROR_ABORTED)
184 return;
185 if (result != PP_OK) {
186 LogError(result, "Cannot get audio track buffer");
187 return;
188 }
189
190 // If this is the first buffer, then we need to initialize the encoder.
191 if (channels_ == 0) {
192 channels_ = buffer.GetNumberOfChannels();
193 sample_rate_ = buffer.GetSampleRate();
194 sample_size_ = buffer.GetSampleSize();
195 samples_per_frame_ = buffer.GetNumberOfSamples();
196
197 if (no_encoding_) {
198 PostAudioFormat();
199 PostDataMessage(buffer.GetDataBuffer(), buffer.GetDataBufferSize());
200 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
201 &AudioEncoderInstance::OnGetBuffer));
202 } else {
203 InitializeEncoder();
204 }
205
206 audio_track_.RecycleBuffer(buffer);
bbudge 2015/12/10 20:28:35 Maybe a comment stating that we discard the first
llandwerlin-old 2015/12/14 11:49:18 Done.
207 } else {
208 if (no_encoding_) {
209 PostDataMessage(buffer.GetDataBuffer(), buffer.GetDataBufferSize());
210 audio_track_.RecycleBuffer(buffer);
211 } else {
212 GetEncoderBuffer(buffer);
213 }
214
215 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
216 &AudioEncoderInstance::OnGetBuffer));
217 }
218 }
219
220 void AudioEncoderInstance::InitializeEncoder() {
221 audio_encoder_ = pp::AudioEncoder(this);
bbudge 2015/12/10 20:28:35 I guess you have to initialize this earlier, befor
llandwerlin-old 2015/12/14 11:49:18 Done.
222 audio_encoder_.Initialize(
223 channels_, static_cast<PP_AudioBuffer_SampleRate>(sample_rate_),
224 static_cast<PP_AudioBuffer_SampleSize>(sample_size_),
225 PP_AUDIOPROFILE_OPUS, 100000, PP_HARDWAREACCELERATION_WITHFALLBACK,
226 callback_factory_.NewCallback(
227 &AudioEncoderInstance::OnEncoderInitialized));
228 }
229
230 void AudioEncoderInstance::OnEncoderInitialized(int32_t result) {
231 if (result == PP_ERROR_ABORTED)
232 return;
233 if (result != PP_OK) {
234 LogError(result, "Cannot initialize encoder");
235 return;
236 }
237
238 int32_t attribs[] = {
239 // Duration in milliseconds.
240 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_DURATION,
241 1000 / (sample_rate_ / audio_encoder_.GetNumberOfSamples()),
242 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE};
243 audio_track_.Configure(attribs,
244 callback_factory_.NewCallback(
245 &AudioEncoderInstance::OnAudioTrackConfigured));
246
247 samples_per_frame_ = audio_encoder_.GetNumberOfSamples();
248 PostAudioFormat();
249 }
250
251 void AudioEncoderInstance::OnAudioTrackConfigured(int32_t result) {
252 if (result == PP_ERROR_ABORTED)
253 return;
254 if (result != PP_OK) {
255 LogError(result, "Cannot configure audio track buffer duration");
256 return;
257 }
258
259 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
260 &AudioEncoderInstance::OnGetBuffer));
261 audio_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput(
262 &AudioEncoderInstance::OnGetBitstreamBuffer));
263 }
264
265 void AudioEncoderInstance::GetEncoderBuffer(
266 const pp::AudioBuffer& track_buffer) {
267 audio_encoder_.GetBuffer(callback_factory_.NewCallbackWithOutput(
268 &AudioEncoderInstance::OnGetEncoderBuffer, track_buffer));
269 }
270
271 void AudioEncoderInstance::OnGetEncoderBuffer(int32_t result,
272 pp::AudioBuffer buffer,
273 pp::AudioBuffer track_buffer) {
274 const char* error(nullptr);
275
276 if (result != PP_OK)
277 error = "Cannot get encoder buffer";
278 if (buffer.GetDataBufferSize() != track_buffer.GetDataBufferSize()) {
279 result = PP_ERROR_FAILED;
280 error = "Invalid buffer size";
281 }
282
283 if (result == PP_OK) {
284 memcpy(buffer.GetDataBuffer(), track_buffer.GetDataBuffer(),
285 buffer.GetDataBufferSize());
286 audio_encoder_.Encode(buffer, callback_factory_.NewCallback(
287 &AudioEncoderInstance::OnEncodeDone));
288 } else {
289 LogError(result, error);
290 StopAudioTrack();
291 }
292 audio_track_.RecycleBuffer(track_buffer);
293 }
294
295 void AudioEncoderInstance::OnEncodeDone(int32_t result) {}
296
297 void AudioEncoderInstance::OnGetBitstreamBuffer(
298 int32_t result,
299 const PP_AudioBitstreamBuffer& buffer) {
300 if (result == PP_ERROR_ABORTED)
301 return;
302 if (result != PP_OK) {
303 LogError(result, "Cannot get bitstream buffer");
304 return;
305 }
306
307 audio_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput(
308 &AudioEncoderInstance::OnGetBitstreamBuffer));
309
310 PostDataMessage(buffer.buffer, buffer.size);
311 audio_encoder_.RecycleBitstreamBuffer(buffer);
312 }
313
314 pp::VarDictionary AudioEncoderInstance::NewCommand(const std::string& type) {
315 pp::VarDictionary dictionary;
316 dictionary.Set(pp::Var("command"), pp::Var(type));
317 return dictionary;
318 }
319
320 void AudioEncoderInstance::Log(const std::string& message) {
321 pp::VarDictionary dictionary = NewCommand("log");
322 dictionary.Set(pp::Var("message"), pp::Var(message));
323 PostMessage(dictionary);
324 }
325
326 void AudioEncoderInstance::LogError(int32_t error, const std::string& message) {
327 pp::VarDictionary dictionary = NewCommand("error");
328 std::string msg("Error: ");
329 msg.append(message);
330 msg.append(" : ");
331 msg.append(pp::Var(error).DebugString());
332 dictionary.Set(pp::Var("message"), pp::Var(msg));
333 PostMessage(dictionary);
334 }
335
336 void AudioEncoderInstance::PostAudioFormat() {
337 pp::VarDictionary dictionary = NewCommand("format");
338 dictionary.Set(pp::Var("channels"), pp::Var(static_cast<int32_t>(channels_)));
339 dictionary.Set(pp::Var("sample_rate"),
340 pp::Var(static_cast<int32_t>(sample_rate_)));
341 dictionary.Set(pp::Var("sample_size"),
342 pp::Var(static_cast<int32_t>(sample_size_)));
343 dictionary.Set(pp::Var("sample_per_frame"),
344 pp::Var(static_cast<int32_t>(samples_per_frame_)));
345 PostMessage(dictionary);
346 }
347
348 void AudioEncoderInstance::PostDataMessage(const void* data, uint32_t size) {
349 pp::VarDictionary dictionary = NewCommand("data");
350 uint8_t* buffer;
351
352 pp::VarArrayBuffer array_buffer = pp::VarArrayBuffer(size);
353 buffer = static_cast<uint8_t*>(array_buffer.Map());
354 memcpy(buffer, data, size);
355 array_buffer.Unmap();
356
357 dictionary.Set(pp::Var("buffer"), array_buffer);
358
359 PostMessage(dictionary);
360 }
361
362 class AudioEncoderModule : public pp::Module {
363 public:
364 virtual pp::Instance* CreateInstance(PP_Instance instance) {
365 return new AudioEncoderInstance(instance);
366 }
367 };
368
369 } // namespace
370
371 namespace pp {
372
373 // Factory function for your specialization of the Module object.
374 Module* CreateModule() {
375 return new AudioEncoderModule();
376 }
377
378 } // namespace pp
OLDNEW
« no previous file with comments | « ppapi/examples/audio_encode/BUILD.gn ('k') | ppapi/examples/audio_encode/audio_encode.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698