diff options
Diffstat (limited to 'native_client_sdk/src/examples/api/audio/audio.cc')
-rw-r--r-- | native_client_sdk/src/examples/api/audio/audio.cc | 155 |
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 |