1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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
|