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

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

Issue 1151973003: ppapi: implement PPB_AudioEncoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months 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 <algorithm>
9 #include <limits>
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 //
40 virtual void HandleMessage(const pp::Var& var_message);
41
42 void AddAudioProfile(PP_AudioProfile profile, const std::string& profile_str);
43 void InitializeVideoProfiles();
44 PP_AudioProfile ProfileFromString(const std::string& string);
45 std::string ProfileToString(PP_AudioProfile profile);
46
47 void ProbeEncoder();
48 void OnEncoderProbed(int32_t result,
49 const std::vector<PP_AudioProfileDescription> profiles);
50
51 void StartAudioTrack(const pp::Resource& resource_track);
52 void StopAudioTrack();
53 void OnGetFirstBuffer(int32_t result, pp::AudioBuffer buffer);
54 void OnGetBuffer(int32_t result, pp::AudioBuffer buffer);
55
56 void InitializeEncoder(uint32_t channels,
57 uint32_t sample_rate,
58 uint32_t sample_size);
59 void OnEncoderInitialized(int32_t result);
60 void OnAudioTrackReconfigured(int32_t result);
61 void GetEncoderBuffer(const pp::AudioBuffer& track_buffer);
62 void OnGetEncoderBuffer(int32_t result,
63 pp::AudioBuffer buffer,
64 pp::AudioBuffer track_buffer);
65 void OnEncodeDone(int32_t result);
66 void OnBitstreamBuffer(int32_t result, const PP_AudioBitstreamBuffer& buffer);
67
68 pp::VarDictionary NewCommand(const std::string& type);
69
70 void Log(const std::string& message);
71 void LogError(int32_t error, const std::string& message);
72
73 void PostAudioFormat(const pp::AudioBuffer& buffer);
74 void PostDataMessage(const void* data, uint32_t size);
75
76 pp::CompletionCallbackFactory<AudioEncoderInstance> callback_factory_;
77
78 bool no_encoding_;
79 bool is_encoding_;
80 uint32_t sample_rate_;
81 PP_AudioProfile encoding_profile_;
82
83 pp::MediaStreamAudioTrack audio_track_;
84 pp::AudioEncoder audio_encoder_;
85
86 typedef std::map<std::string, PP_AudioProfile> AudioProfileFromStringMap;
87 AudioProfileFromStringMap profile_from_string_;
88
89 typedef std::map<PP_AudioProfile, std::string> AudioProfileToStringMap;
90 AudioProfileToStringMap profile_to_string_;
91 };
92
93 AudioEncoderInstance::AudioEncoderInstance(PP_Instance instance)
94 : pp::Instance(instance),
95 callback_factory_(this),
96 no_encoding_(true),
97 is_encoding_(false),
98 encoding_profile_(PP_AUDIOPROFILE_OPUS) {
99 InitializeVideoProfiles();
100 ProbeEncoder();
101 }
102
103 AudioEncoderInstance::~AudioEncoderInstance() {
104 }
105
106 void AudioEncoderInstance::HandleMessage(const pp::Var& var_message) {
107 if (!var_message.is_dictionary()) {
108 LogError(PP_ERROR_FAILED,
109 "Cannot handle incoming message, not a dictionary");
110 return;
111 }
112
113 pp::VarDictionary dict_message(var_message);
114 std::string command = dict_message.Get("command").AsString();
115
116 if (command == "start") {
117 pp::Var var_track = dict_message.Get("track");
118 if (!var_track.is_resource()) {
119 LogError(PP_ERROR_FAILED, "Given track is not a resource");
120 return;
121 }
122 std::string profile = dict_message.Get("profile").AsString();
123 if (profile == "wav")
124 no_encoding_ = true;
125 else {
126 no_encoding_ = false;
127 encoding_profile_ = ProfileFromString(profile);
128 }
129 StartAudioTrack(var_track.AsResource());
130 } else if (command == "stop") {
131 StopAudioTrack();
132 } else {
133 LogError(PP_ERROR_FAILED, "Invalid command");
134 }
135 }
136
137 void AudioEncoderInstance::AddAudioProfile(PP_AudioProfile profile,
138 const std::string& profile_str) {
139 profile_to_string_.insert(std::make_pair(profile, profile_str));
140 profile_from_string_.insert(std::make_pair(profile_str, profile));
141 }
142
143 void AudioEncoderInstance::InitializeVideoProfiles() {
144 AddAudioProfile(PP_AUDIOPROFILE_OPUS, "opus");
145 AddAudioProfile(PP_AUDIOPROFILE_SPEEX, "speex");
146 }
147
148 PP_AudioProfile AudioEncoderInstance::ProfileFromString(
149 const std::string& string) {
150 AudioProfileFromStringMap::iterator it = profile_from_string_.find(string);
151 if (it == profile_from_string_.end())
152 return PP_AUDIOPROFILE_OPUS;
153 return it->second;
154 }
155
156 std::string AudioEncoderInstance::ProfileToString(PP_AudioProfile profile) {
157 AudioProfileToStringMap::iterator it = profile_to_string_.find(profile);
158 if (it == profile_to_string_.end())
159 return "unknown";
160 return it->second;
161 }
162
163 void AudioEncoderInstance::ProbeEncoder() {
164 audio_encoder_ = pp::AudioEncoder(this);
165 audio_encoder_.GetSupportedProfiles(callback_factory_.NewCallbackWithOutput(
166 &AudioEncoderInstance::OnEncoderProbed));
167 }
168
169 void AudioEncoderInstance::OnEncoderProbed(
170 int32_t result,
171 const std::vector<PP_AudioProfileDescription> profiles) {
172 pp::VarDictionary dictionary = NewCommand("supportedProfiles");
173 pp::VarArray js_profiles;
174 dictionary.Set(pp::Var("profiles"), js_profiles);
175
176 if (result < 0) {
177 LogError(result, "Cannot get supported profiles");
178 PostMessage(dictionary);
179 }
180
181 int32_t idx = 0;
182 for (const PP_AudioProfileDescription& profile : profiles) {
183 pp::VarDictionary js_profile;
184 js_profile.Set(pp::Var("name"), pp::Var(ProfileToString(profile.profile)));
185 js_profile.Set(pp::Var("sample_size"),
186 pp::Var(static_cast<int32_t>(profile.sample_size)));
187 js_profile.Set(pp::Var("sample_rate"),
188 pp::Var(static_cast<int32_t>(profile.sample_rate)));
189 js_profiles.Set(idx++, js_profile);
190 }
191 PostMessage(dictionary);
192 }
193
194 void AudioEncoderInstance::StartAudioTrack(const pp::Resource& resource_track) {
195 audio_track_ = pp::MediaStreamAudioTrack(resource_track);
196 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
197 &AudioEncoderInstance::OnGetFirstBuffer));
198 }
199
200 void AudioEncoderInstance::StopAudioTrack() {
201 Log("StopAudioTrack!");
202 audio_encoder_.Close();
203 audio_encoder_ = pp::AudioEncoder();
204 audio_track_.Close();
205 audio_track_ = pp::MediaStreamAudioTrack();
206 }
207
208 void AudioEncoderInstance::OnGetFirstBuffer(int32_t result,
209 pp::AudioBuffer buffer) {
210 if (result == PP_ERROR_ABORTED)
211 return;
212 if (result != PP_OK) {
213 LogError(result, "Cannot get audio track buffer");
214 return;
215 }
216
217 PostAudioFormat(buffer);
218
219 if (no_encoding_) {
220 PostDataMessage(buffer.GetDataBuffer(), buffer.GetDataBufferSize());
221 audio_track_.RecycleBuffer(buffer);
222 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
223 &AudioEncoderInstance::OnGetBuffer));
224 } else {
225 uint32_t channels = buffer.GetNumberOfChannels(),
226 sample_rate = buffer.GetSampleRate(),
227 sample_size = buffer.GetSampleSize();
228 audio_track_.RecycleBuffer(buffer);
229 InitializeEncoder(channels, sample_rate, sample_size);
230 }
231 }
232
233 void AudioEncoderInstance::OnGetBuffer(int32_t result, pp::AudioBuffer buffer) {
234 if (result == PP_ERROR_ABORTED)
235 return;
236 if (result != PP_OK) {
237 LogError(result, "Cannot get audio track buffer");
238 return;
239 }
240
241 if (no_encoding_) {
242 PostDataMessage(buffer.GetDataBuffer(), buffer.GetDataBufferSize());
243 audio_track_.RecycleBuffer(buffer);
244 } else
245 GetEncoderBuffer(buffer);
246
247 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
248 &AudioEncoderInstance::OnGetBuffer));
249 }
250
251 void AudioEncoderInstance::InitializeEncoder(uint32_t channels,
252 uint32_t sample_rate,
253 uint32_t sample_size) {
254 sample_rate_ = sample_rate;
255 audio_encoder_ = pp::AudioEncoder(this);
256 audio_encoder_.Initialize(
257 channels, static_cast<PP_AudioBuffer_SampleRate>(sample_rate),
258 static_cast<PP_AudioBuffer_SampleSize>(sample_size), encoding_profile_,
259 100000, PP_HARDWAREACCELERATION_WITHFALLBACK,
260 callback_factory_.NewCallback(
261 &AudioEncoderInstance::OnEncoderInitialized));
262 }
263
264 void AudioEncoderInstance::OnEncoderInitialized(int32_t result) {
265 if (result == PP_ERROR_ABORTED)
266 return;
267 if (result != PP_OK) {
268 LogError(result, "Cannot initialize encoder");
269 return;
270 }
271
272 int32_t attribs[] = {
273 // Duration in milliseconds.
274 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_DURATION,
275 1000 / (sample_rate_ / audio_encoder_.GetNumberOfSamples()),
276 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE};
277 audio_track_.Configure(attribs,
278 callback_factory_.NewCallback(
279 &AudioEncoderInstance::OnAudioTrackReconfigured));
280 }
281
282 void AudioEncoderInstance::OnAudioTrackReconfigured(int32_t result) {
283 if (result == PP_ERROR_ABORTED)
284 return;
285 if (result != PP_OK) {
286 LogError(result, "Cannot reconfigure audio track buffer duration");
287 return;
288 }
289
290 is_encoding_ = true;
291 audio_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput(
292 &AudioEncoderInstance::OnBitstreamBuffer));
293 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
294 &AudioEncoderInstance::OnGetBuffer));
295 }
296
297 void AudioEncoderInstance::GetEncoderBuffer(
298 const pp::AudioBuffer& track_buffer) {
299 audio_encoder_.GetBuffer(callback_factory_.NewCallbackWithOutput(
300 &AudioEncoderInstance::OnGetEncoderBuffer, track_buffer));
301 }
302
303 void AudioEncoderInstance::OnGetEncoderBuffer(int32_t result,
304 pp::AudioBuffer buffer,
305 pp::AudioBuffer track_buffer) {
306 if (result == PP_ERROR_ABORTED) {
307 audio_track_.RecycleBuffer(track_buffer);
308 return;
309 }
310 if (result != PP_OK) {
311 audio_track_.RecycleBuffer(track_buffer);
312 LogError(result, "Cannot get encoder buffer");
313 return;
314 }
315
316 if (buffer.GetDataBufferSize() != track_buffer.GetDataBufferSize()) {
317 audio_track_.RecycleBuffer(track_buffer);
318 LogError(PP_ERROR_FAILED, "Invalid buffer size");
319 return;
320 }
321
322 memcpy(buffer.GetDataBuffer(), track_buffer.GetDataBuffer(),
323 buffer.GetDataBufferSize());
324 audio_track_.RecycleBuffer(track_buffer);
325
326 audio_encoder_.Encode(buffer, callback_factory_.NewCallback(
327 &AudioEncoderInstance::OnEncodeDone));
328 }
329
330 void AudioEncoderInstance::OnEncodeDone(int32_t result) {
331 }
332
333 void AudioEncoderInstance::OnBitstreamBuffer(
334 int32_t result,
335 const PP_AudioBitstreamBuffer& buffer) {
336 if (result == PP_ERROR_ABORTED)
337 return;
338 if (result != PP_OK) {
339 LogError(result, "Cannot get bitstream buffer");
340 return;
341 }
342
343 audio_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput(
344 &AudioEncoderInstance::OnBitstreamBuffer));
345
346 PostDataMessage(buffer.buffer, buffer.size);
347 audio_encoder_.RecycleBitstreamBuffer(buffer);
348 }
349
350 pp::VarDictionary AudioEncoderInstance::NewCommand(const std::string& type) {
351 pp::VarDictionary dictionary;
352 dictionary.Set(pp::Var("command"), pp::Var(type));
353 return dictionary;
354 }
355
356 void AudioEncoderInstance::Log(const std::string& message) {
357 pp::VarDictionary dictionary = NewCommand("log");
358 dictionary.Set(pp::Var("message"), pp::Var(message));
359 PostMessage(dictionary);
360 }
361
362 void AudioEncoderInstance::LogError(int32_t error, const std::string& message) {
363 pp::VarDictionary dictionary = NewCommand("error");
364 std::string msg("Error: ");
365 msg.append(message);
366 msg.append(" : ");
367 msg.append(pp::Var(error).DebugString());
368 dictionary.Set(pp::Var("message"), pp::Var(msg));
369 PostMessage(dictionary);
370 }
371
372 void AudioEncoderInstance::PostAudioFormat(const pp::AudioBuffer& buffer) {
373 pp::VarDictionary dictionary = NewCommand("format");
374 dictionary.Set(pp::Var("sample_rate"),
375 pp::Var(static_cast<int32_t>(buffer.GetSampleRate())));
376 dictionary.Set(pp::Var("sample_size"),
377 pp::Var(static_cast<int32_t>(buffer.GetSampleSize())));
378 dictionary.Set(pp::Var("sample_per_frame"),
379 pp::Var(static_cast<int32_t>(buffer.GetNumberOfSamples())));
380 dictionary.Set(pp::Var("channels"),
381 pp::Var(static_cast<int32_t>(buffer.GetNumberOfChannels())));
382 PostMessage(dictionary);
383 }
384
385 void AudioEncoderInstance::PostDataMessage(const void* data, uint32_t size) {
386 pp::VarDictionary dictionary = NewCommand("data");
387 uint8_t* buffer;
388
389 pp::VarArrayBuffer array_buffer = pp::VarArrayBuffer(size);
390 buffer = static_cast<uint8_t*>(array_buffer.Map());
391 memcpy(buffer, data, size);
392 array_buffer.Unmap();
393
394 dictionary.Set(pp::Var("buffer"), array_buffer);
395
396 PostMessage(dictionary);
397 }
398
399 class AudioEncoderModule : public pp::Module {
400 public:
401 virtual pp::Instance* CreateInstance(PP_Instance instance) {
402 return new AudioEncoderInstance(instance);
403 }
404 };
405
406 } // namespace
407
408 namespace pp {
409
410 // Factory function for your specialization of the Module object.
411 Module* CreateModule() {
412 return new AudioEncoderModule();
413 }
414
415 } // 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