Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / native_client_sdk / src / examples / api / audio / audio.cc
blob27daf5799a695fcc6b6aab6ec8ccfafc7511a51a
1 // Copyright (c) 2012 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.
5 #include <cassert>
6 #include <cmath>
7 #include <limits>
8 #include <sstream>
9 #include "ppapi/cpp/audio.h"
10 #include "ppapi/cpp/instance.h"
11 #include "ppapi/cpp/module.h"
12 #include "ppapi/cpp/var.h"
14 namespace {
15 const char* const kPlaySoundId = "playSound";
16 const char* const kStopSoundId = "stopSound";
17 const char* const kSetFrequencyId = "setFrequency";
18 static const char kMessageArgumentSeparator = ':';
20 const double kDefaultFrequency = 440.0;
21 const double kPi = 3.141592653589;
22 const double kTwoPi = 2.0 * kPi;
23 // The sample count we will request.
24 const uint32_t kSampleFrameCount = 4096u;
25 // Only supporting stereo audio for now.
26 const uint32_t kChannels = 2u;
27 } // namespace
29 class AudioInstance : public pp::Instance {
30 public:
31 explicit AudioInstance(PP_Instance instance)
32 : pp::Instance(instance),
33 frequency_(kDefaultFrequency),
34 theta_(0),
35 sample_frame_count_(kSampleFrameCount) {}
36 virtual ~AudioInstance() {}
38 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
40 // Called by the browser to handle the postMessage() call in Javascript.
41 // |var_message| is expected to be a string that contains the name of the
42 // method to call. Note that the setFrequency method takes a single
43 // parameter, the frequency. The frequency parameter is encoded as a string
44 // and appended to the 'setFrequency' method name after a ':'. Examples
45 // of possible message strings are:
46 // playSound
47 // stopSound
48 // setFrequency:880
49 // If |var_message| is not a recognized method name, this method does nothing.
50 virtual void HandleMessage(const pp::Var& var_message);
52 // Set the frequency of the sine wave to |frequency|. Posts a message back
53 // to the browser with the new frequency value.
54 void SetFrequency(double frequency);
56 // The frequency property accessor.
57 double frequency() const { return frequency_; }
59 private:
60 static void SineWaveCallback(void* samples,
61 uint32_t buffer_size,
62 void* data) {
63 AudioInstance* instance = reinterpret_cast<AudioInstance*>(data);
64 const double frequency = instance->frequency();
65 const double delta = kTwoPi * frequency / PP_AUDIOSAMPLERATE_44100;
66 const int16_t max_int16 = std::numeric_limits<int16_t>::max();
68 int16_t* buff = reinterpret_cast<int16_t*>(samples);
70 // Make sure we can't write outside the buffer.
71 assert(buffer_size >=
72 (sizeof(*buff) * kChannels * instance->sample_frame_count_));
74 for (size_t sample_i = 0; sample_i < instance->sample_frame_count_;
75 ++sample_i, instance->theta_ += delta) {
76 // Keep theta_ from going beyond 2*Pi.
77 if (instance->theta_ > kTwoPi) {
78 instance->theta_ -= kTwoPi;
80 double sin_value(std::sin(instance->theta_));
81 int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16);
82 for (size_t channel = 0; channel < kChannels; ++channel) {
83 *buff++ = scaled_value;
88 pp::Audio audio_;
89 double frequency_;
91 // The last parameter sent to the sin function. Used to prevent sine wave
92 // skips on buffer boundaries.
93 double theta_;
95 // The count of sample frames per channel in an audio buffer.
96 uint32_t sample_frame_count_;
99 bool AudioInstance::Init(uint32_t argc,
100 const char* argn[],
101 const char* argv[]) {
102 // Ask the device for an appropriate sample count size.
103 sample_frame_count_ = pp::AudioConfig::RecommendSampleFrameCount(
104 this, PP_AUDIOSAMPLERATE_44100, kSampleFrameCount);
105 audio_ = pp::Audio(
106 this,
107 pp::AudioConfig(this, PP_AUDIOSAMPLERATE_44100, sample_frame_count_),
108 SineWaveCallback,
109 this);
110 return true;
113 void AudioInstance::HandleMessage(const pp::Var& var_message) {
114 if (!var_message.is_string()) {
115 return;
117 std::string message = var_message.AsString();
118 if (message == kPlaySoundId) {
119 audio_.StartPlayback();
120 } else if (message == kStopSoundId) {
121 audio_.StopPlayback();
122 } else if (message.find(kSetFrequencyId) == 0) {
123 // The argument to setFrequency is everything after the first ':'.
124 size_t sep_pos = message.find_first_of(kMessageArgumentSeparator);
125 if (sep_pos != std::string::npos) {
126 std::string string_arg = message.substr(sep_pos + 1);
127 // Got the argument value as a string: try to convert it to a number.
128 std::istringstream stream(string_arg);
129 double double_value;
130 if (stream >> double_value) {
131 SetFrequency(double_value);
132 return;
138 void AudioInstance::SetFrequency(double frequency) {
139 frequency_ = frequency;
140 PostMessage(pp::Var(frequency_));
143 class AudioModule : public pp::Module {
144 public:
145 AudioModule() : pp::Module() {}
146 ~AudioModule() {}
148 virtual pp::Instance* CreateInstance(PP_Instance instance) {
149 return new AudioInstance(instance);
153 namespace pp {
154 Module* CreateModule() { return new AudioModule(); }
155 } // namespace pp