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.
9 #include "ppapi/cpp/audio.h"
10 #include "ppapi/cpp/instance.h"
11 #include "ppapi/cpp/module.h"
12 #include "ppapi/cpp/var.h"
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;
29 class AudioInstance
: public pp::Instance
{
31 explicit AudioInstance(PP_Instance instance
)
32 : pp::Instance(instance
),
33 frequency_(kDefaultFrequency
),
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:
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_
; }
60 static void SineWaveCallback(void* samples
,
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.
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
;
91 // The last parameter sent to the sin function. Used to prevent sine wave
92 // skips on buffer boundaries.
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
,
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
);
107 pp::AudioConfig(this, PP_AUDIOSAMPLERATE_44100
, sample_frame_count_
),
113 void AudioInstance::HandleMessage(const pp::Var
& var_message
) {
114 if (!var_message
.is_string()) {
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
);
130 if (stream
>> double_value
) {
131 SetFrequency(double_value
);
138 void AudioInstance::SetFrequency(double frequency
) {
139 frequency_
= frequency
;
140 PostMessage(pp::Var(frequency_
));
143 class AudioModule
: public pp::Module
{
145 AudioModule() : pp::Module() {}
148 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
149 return new AudioInstance(instance
);
154 Module
* CreateModule() { return new AudioModule(); }