summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/src/examples/api/audio/audio.cc
diff options
context:
space:
mode:
Diffstat (limited to 'native_client_sdk/src/examples/api/audio/audio.cc')
-rw-r--r--native_client_sdk/src/examples/api/audio/audio.cc155
1 files changed, 155 insertions, 0 deletions
diff --git a/native_client_sdk/src/examples/api/audio/audio.cc b/native_client_sdk/src/examples/api/audio/audio.cc
new file mode 100644
index 0000000..27daf57
--- /dev/null
+++ b/native_client_sdk/src/examples/api/audio/audio.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 The Chromium 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 <cassert>
+#include <cmath>
+#include <limits>
+#include <sstream>
+#include "ppapi/cpp/audio.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/var.h"
+
+namespace {
+const char* const kPlaySoundId = "playSound";
+const char* const kStopSoundId = "stopSound";
+const char* const kSetFrequencyId = "setFrequency";
+static const char kMessageArgumentSeparator = ':';
+
+const double kDefaultFrequency = 440.0;
+const double kPi = 3.141592653589;
+const double kTwoPi = 2.0 * kPi;
+// The sample count we will request.
+const uint32_t kSampleFrameCount = 4096u;
+// Only supporting stereo audio for now.
+const uint32_t kChannels = 2u;
+} // namespace
+
+class AudioInstance : public pp::Instance {
+ public:
+ explicit AudioInstance(PP_Instance instance)
+ : pp::Instance(instance),
+ frequency_(kDefaultFrequency),
+ theta_(0),
+ sample_frame_count_(kSampleFrameCount) {}
+ virtual ~AudioInstance() {}
+
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
+
+ // Called by the browser to handle the postMessage() call in Javascript.
+ // |var_message| is expected to be a string that contains the name of the
+ // method to call. Note that the setFrequency method takes a single
+ // parameter, the frequency. The frequency parameter is encoded as a string
+ // and appended to the 'setFrequency' method name after a ':'. Examples
+ // of possible message strings are:
+ // playSound
+ // stopSound
+ // setFrequency:880
+ // If |var_message| is not a recognized method name, this method does nothing.
+ virtual void HandleMessage(const pp::Var& var_message);
+
+ // Set the frequency of the sine wave to |frequency|. Posts a message back
+ // to the browser with the new frequency value.
+ void SetFrequency(double frequency);
+
+ // The frequency property accessor.
+ double frequency() const { return frequency_; }
+
+ private:
+ static void SineWaveCallback(void* samples,
+ uint32_t buffer_size,
+ void* data) {
+ AudioInstance* instance = reinterpret_cast<AudioInstance*>(data);
+ const double frequency = instance->frequency();
+ const double delta = kTwoPi * frequency / PP_AUDIOSAMPLERATE_44100;
+ const int16_t max_int16 = std::numeric_limits<int16_t>::max();
+
+ int16_t* buff = reinterpret_cast<int16_t*>(samples);
+
+ // Make sure we can't write outside the buffer.
+ assert(buffer_size >=
+ (sizeof(*buff) * kChannels * instance->sample_frame_count_));
+
+ for (size_t sample_i = 0; sample_i < instance->sample_frame_count_;
+ ++sample_i, instance->theta_ += delta) {
+ // Keep theta_ from going beyond 2*Pi.
+ if (instance->theta_ > kTwoPi) {
+ instance->theta_ -= kTwoPi;
+ }
+ double sin_value(std::sin(instance->theta_));
+ int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16);
+ for (size_t channel = 0; channel < kChannels; ++channel) {
+ *buff++ = scaled_value;
+ }
+ }
+ }
+
+ pp::Audio audio_;
+ double frequency_;
+
+ // The last parameter sent to the sin function. Used to prevent sine wave
+ // skips on buffer boundaries.
+ double theta_;
+
+ // The count of sample frames per channel in an audio buffer.
+ uint32_t sample_frame_count_;
+};
+
+bool AudioInstance::Init(uint32_t argc,
+ const char* argn[],
+ const char* argv[]) {
+ // Ask the device for an appropriate sample count size.
+ sample_frame_count_ = pp::AudioConfig::RecommendSampleFrameCount(
+ this, PP_AUDIOSAMPLERATE_44100, kSampleFrameCount);
+ audio_ = pp::Audio(
+ this,
+ pp::AudioConfig(this, PP_AUDIOSAMPLERATE_44100, sample_frame_count_),
+ SineWaveCallback,
+ this);
+ return true;
+}
+
+void AudioInstance::HandleMessage(const pp::Var& var_message) {
+ if (!var_message.is_string()) {
+ return;
+ }
+ std::string message = var_message.AsString();
+ if (message == kPlaySoundId) {
+ audio_.StartPlayback();
+ } else if (message == kStopSoundId) {
+ audio_.StopPlayback();
+ } else if (message.find(kSetFrequencyId) == 0) {
+ // The argument to setFrequency is everything after the first ':'.
+ size_t sep_pos = message.find_first_of(kMessageArgumentSeparator);
+ if (sep_pos != std::string::npos) {
+ std::string string_arg = message.substr(sep_pos + 1);
+ // Got the argument value as a string: try to convert it to a number.
+ std::istringstream stream(string_arg);
+ double double_value;
+ if (stream >> double_value) {
+ SetFrequency(double_value);
+ return;
+ }
+ }
+ }
+}
+
+void AudioInstance::SetFrequency(double frequency) {
+ frequency_ = frequency;
+ PostMessage(pp::Var(frequency_));
+}
+
+class AudioModule : public pp::Module {
+ public:
+ AudioModule() : pp::Module() {}
+ ~AudioModule() {}
+
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new AudioInstance(instance);
+ }
+};
+
+namespace pp {
+Module* CreateModule() { return new AudioModule(); }
+} // namespace pp