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

Unified Diff: ppapi/native_client/tests/ppapi_example_audio/audio.cc

Issue 7740013: Cloning a bunch of stuff from the native_client repository at r6528 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: ppapi/native_client/tests/ppapi_example_audio/audio.cc
===================================================================
--- ppapi/native_client/tests/ppapi_example_audio/audio.cc (revision 0)
+++ ppapi/native_client/tests/ppapi_example_audio/audio.cc (revision 0)
@@ -0,0 +1,302 @@
+// Copyright (c) 2011 The Native Client Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include <nacl/nacl_log.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cmath>
+#include <limits>
+#include <string>
+#include <nacl/nacl_inttypes.h>
+
+#include "native_client/src/shared/ppapi_proxy/utility.h"
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/ppb_audio.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/cpp/audio.h"
+#include "ppapi/cpp/audio_config.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/var.h"
+
+
+// Most of this example is borrowed from ppapi/examples/audio/audio.cc
+
+// Separate left and right frequency to make sure we didn't swap L & R.
+// Sounds pretty horrible, though...
+const double kDefaultFrequencyLeft = 400.0;
+const double kDefaultFrequencyRight = 1000.0;
+const uint32_t kDefaultDuration = 10000;
+
+// This sample frequency is guaranteed to work.
+const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100;
+// Buffer size in units of sample frames.
+// 4096 is a conservative size that should avoid underruns on most systems.
+const uint32_t kSampleFrameCount = 4096;
+
+const double kPi = 3.141592653589;
+const double kTwoPi = 2.0 * kPi;
+
+void LogFailure(const char* msg) {
+ NaClLog(LOG_ERROR, "\n*** FAILURE **** example: %s", msg);
+}
+
+class MyInstance : public pp::Instance {
+ private:
+ void ParseArgs(uint32_t argc, const char* argn[], const char* argv[]) {
+ NaClLog(1, "example: parsing %d args\n", static_cast<int>(argc));
+ for (uint32_t i = 0; i < argc; ++i) {
+ NaClLog(1, "example: arg %d: [%s] [%s]\n",
+ static_cast<int>(i), argn[i], argv[i]);
+ const std::string tag = argn[i];
+ if (tag == "frequency_l") frequency_l_ = strtod(argv[i], 0);
+ if (tag == "frequency_r") frequency_r_ = strtod(argv[i], 0);
+ if (tag == "amplitude_l") amplitude_l_ = strtod(argv[i], 0);
+ if (tag == "amplitude_r") amplitude_r_ = strtod(argv[i], 0);
+ if (tag == "duration_msec") duration_msec_ = strtod(argv[i], 0);
+ if (tag == "basic_tests") basic_tests_ = (0 != atoi(argv[i]));
+ if (tag == "stress_tests") stress_tests_ = (0 != atoi(argv[i]));
+ if (tag == "headless") headless_ = (0 != atoi(argv[i]));
+ // ignore other tags
+ }
+ }
+
+ public:
+ explicit MyInstance(PP_Instance instance)
+ : pp::Instance(instance),
+ config_(NULL),
+ audio_(NULL),
+ audio_wave_l_(0.0),
+ audio_wave_r_(0.0),
+ frequency_l_(kDefaultFrequencyLeft),
+ frequency_r_(kDefaultFrequencyRight),
+ amplitude_l_(1.0),
+ amplitude_r_(1.0),
+ headless_(false),
+ basic_tests_(false),
+ stress_tests_(false),
+ duration_msec_(kDefaultDuration),
+ obtained_sample_frame_count_(0),
+ callback_count_(0) {}
+
+ virtual void HandleMessage(const pp::Var& message) {
+ NaClLog(1, "example: received HandleMessage\n");
+ if (message.is_string()) {
+ if (message.AsString() == "StartPlayback") {
+ StartOutput();
+ }
+ }
+ }
+
+ void StartOutput() {
+ bool audio_start_playback = audio_->StartPlayback();
+ CHECK(true == audio_start_playback);
+ NaClLog(1, "example: frequencies are %f %f\n", frequency_l_, frequency_r_);
+ NaClLog(1, "example: amplitudes are %f %f\n", amplitude_l_, amplitude_r_);
+ NaClLog(1, "example: Scheduling StopOutput on main thread in %"
+ NACL_PRIu32"msec\n", duration_msec_);
+ // Schedule a callback in duration_msec_ to stop audio output
+ pp::CompletionCallback cc(StopOutput, this);
+ pp::Module::Get()->core()->CallOnMainThread(duration_msec_, cc, PP_OK);
+ }
+
+ static void StopOutput(void* user_data, int32_t err) {
+ MyInstance* instance = static_cast<MyInstance*>(user_data);
+
+ const int kMaxResult = 256;
+ char result[kMaxResult];
+ NaClLog(1, "example: StopOutput() invoked on main thread\n");
+ if (PP_OK == err) {
+ if (instance->audio_->StopPlayback()) {
+ // In headless mode, the build bots may not have an audio driver, in
+ // which case the callback won't be invoked.
+ // TODO(nfullagar): Other ways to determine if machine has audio
+ // capabilities. Currently PPAPI returns a valid resource regardless.
+ if ((instance->callback_count_ >= 2) || instance->headless_) {
+ snprintf(result, kMaxResult, "StopOutput:PASSED");
+ } else {
+ snprintf(result, kMaxResult, "StopOutput:FAILED - too "
+ "few callbacks (only %d callbacks detected)",
+ static_cast<int>(instance->callback_count_));
+ }
+ }
+ } else {
+ snprintf(result, kMaxResult,
+ "StopOutput: FAILED - returned err is %d", static_cast<int>(err));
+ }
+ // Release audio & config instance.
+ delete instance->audio_;
+ delete instance->config_;
+ instance->audio_ = NULL;
+ instance->config_ = NULL;
+ // At this point the test has finished, report result.
+ pp::Var message(result);
+ instance->PostMessage(message);
+ }
+
+ // To enable basic tests, use basic_tests="1" in the embed tag.
+ void BasicTests() {
+ // Verify obtained_sample_frame_count isn't out of range.
+ CHECK(obtained_sample_frame_count_ >= PP_AUDIOMINSAMPLEFRAMECOUNT);
+ CHECK(obtained_sample_frame_count_ <= PP_AUDIOMAXSAMPLEFRAMECOUNT);
+ // Do some sanity checks below; verify c & cpp interfaces agree.
+ // Note: This is test code and is not normally needed for an application.
+ PPB_GetInterface get_browser_interface =
+ pp::Module::Get()->get_browser_interface();
+ const struct PPB_AudioConfig* audio_config_interface =
+ static_cast<const struct PPB_AudioConfig*>(
+ get_browser_interface(PPB_AUDIO_CONFIG_INTERFACE));
+ const struct PPB_Audio* audio_interface =
+ static_cast<const struct PPB_Audio*>(
+ get_browser_interface(PPB_AUDIO_INTERFACE));
+ PP_Resource audio_config_resource = config_->pp_resource();
+ PP_Resource audio_resource = audio_->pp_resource();
+ NaClLog(1, "example: audio config resource: %"NACL_PRId32"\n",
+ audio_config_resource);
+ NaClLog(1, "example: audio resource: %"NACL_PRId32"\n", audio_resource);
+ CHECK(PP_TRUE == audio_config_interface->
+ IsAudioConfig(audio_config_resource));
+ CHECK(PP_TRUE == audio_interface->IsAudio(audio_resource));
+ CHECK(PP_FALSE == audio_config_interface->IsAudioConfig(audio_resource));
+ CHECK(PP_FALSE == audio_interface->IsAudio(audio_config_resource));
+ CHECK(audio_interface->GetCurrentConfig(audio_resource) ==
+ audio_config_resource);
+ CHECK(0 == audio_interface->GetCurrentConfig(audio_config_resource));
+ CHECK(audio_config_interface->GetSampleRate(audio_config_resource) ==
+ config_->sample_rate());
+ CHECK(audio_config_interface->GetSampleFrameCount(audio_config_resource) ==
+ config_->sample_frame_count());
+ CHECK(audio_->config().pp_resource() == audio_config_resource);
+ }
+
+ // To enable stress tests, use stress_tests="1" in the embed tag.
+ void StressTests() {
+ // Attempt to create many audio devices, then immediately shut them down.
+ // Chrome may generate some warnings on the console, but should not crash.
+ const int kNumManyAudio = 1000;
+ pp::Audio* many_audio[kNumManyAudio];
+ for (int i = 0; i < kNumManyAudio; ++i)
+ many_audio[i] = new pp::Audio(this, *config_, SilenceCallback, this);
+ for (int i = 0; i < kNumManyAudio; ++i)
+ CHECK(true == many_audio[i]->StartPlayback());
+ for (int i = 0; i < kNumManyAudio; ++i)
+ delete many_audio[i];
+ }
+
+ void TestSuite() {
+ if (basic_tests_)
+ BasicTests();
+ if (stress_tests_)
+ StressTests();
+ }
+
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
+ ParseArgs(argc, argn, argv);
+ obtained_sample_frame_count_ = pp::AudioConfig::RecommendSampleFrameCount(
+ kSampleFrequency, kSampleFrameCount);
+ config_ = new
+ pp::AudioConfig(this, kSampleFrequency, obtained_sample_frame_count_);
+ CHECK(NULL != config_);
+ audio_ = new pp::Audio(this, *config_, SineWaveCallback, this);
+ CHECK(NULL != audio_);
+ // Run through test suite before attempting real playback.
+ TestSuite();
+ return true;
+ }
+
+ private:
+ static void SineWaveCallback(void* samples, uint32_t num_bytes, void* thiz) {
+ MyInstance* instance = reinterpret_cast<MyInstance*>(thiz);
+ const double delta_l = kTwoPi * instance->frequency_l_ / kSampleFrequency;
+ const double delta_r = kTwoPi * instance->frequency_r_ / kSampleFrequency;
+
+ // Verify num_bytes and obtained_sample_frame_count match up.
+ const int kNumChannelsForStereo = 2;
+ const int kSizeOfSample = sizeof(int16_t);
+ const size_t single_sample = kNumChannelsForStereo * kSizeOfSample;
+
+ // CHECK inside callback is only for testing purposes.
+ CHECK(instance->obtained_sample_frame_count_ * single_sample == num_bytes);
+
+ // Use per channel audio wave value to avoid clicks on buffer boundries.
+ double wave_l = instance->audio_wave_l_;
+ double wave_r = instance->audio_wave_r_;
+ const int16_t max_int16 = std::numeric_limits<int16_t>::max();
+ int16_t* buf = reinterpret_cast<int16_t*>(samples);
+ for (size_t i = 0; i < instance->obtained_sample_frame_count_; ++i) {
+ const double l = sin(wave_l) * instance->amplitude_l_ * max_int16;
+ const double r = sin(wave_r) * instance->amplitude_r_ * max_int16;
+ *buf++ = static_cast<int16_t>(l);
+ *buf++ = static_cast<int16_t>(r);
+ // Add delta, keep within -kTwoPi..kTwoPi to preserve precision.
+ wave_l += delta_l;
+ if (wave_l > kTwoPi)
+ wave_l -= kTwoPi * 2.0;
+ wave_r += delta_r;
+ if (wave_r > kTwoPi)
+ wave_r -= kTwoPi * 2.0;
+ }
+ // Store current value to use as starting point for next callback.
+ instance->audio_wave_l_ = wave_l;
+ instance->audio_wave_r_ = wave_r;
+
+ ++instance->callback_count_;
+ }
+
+ static void SilenceCallback(void* samples, uint32_t num_bytes, void* thiz) {
+ memset(samples, 0, num_bytes);
+ }
+
+ // Audio config resource. Allocated in Init().
+ pp::AudioConfig* config_;
+
+ // Audio resource. Allocated in Init().
+ pp::Audio* audio_;
+
+ // Current audio wave position, used to prevent sine wave skips
+ // on buffer boundaries.
+ double audio_wave_l_;
+ double audio_wave_r_;
+
+ double frequency_l_;
+ double frequency_r_;
+
+ double amplitude_l_;
+ double amplitude_r_;
+
+ bool headless_;
+
+ bool basic_tests_;
+ bool stress_tests_;
+
+ uint32_t duration_msec_;
+ uint32_t obtained_sample_frame_count_;
+
+ int callback_count_;
+};
+
+class MyModule : public pp::Module {
+ public:
+ // Override CreateInstance to create your customized Instance object.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new MyInstance(instance);
+ }
+};
+
+namespace pp {
+
+// Factory function for your specialization of the Module object.
+Module* CreateModule() {
+ NaClLogModuleInit();
+ return new MyModule();
+}
+
+} // namespace pp

Powered by Google App Engine
This is Rietveld 408576698