#include <stdint.h>
#include <cmath>
#include <limits>
#include <string>
#include "native_client/src/shared/platform/nacl_check.h"
#include "native_client/src/shared/platform/nacl_log.h"
#include "ppapi/c/pp_bool.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppb_audio.h"
#include "ppapi/c/ppb_audio_config.h"
#include "ppapi/cpp/audio.h"
#include "ppapi/cpp/audio_config.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100;
const uint32_t kSampleFrameCount = 4096;
const uint32_t kDefaultFrequency = 400;
const uint32_t kDefaultDuration = 10000;
const int kNumChannelsForStereo = 2;
const size_t kSizeSingleSample = kNumChannelsForStereo * sizeof(int16_t);
const double kPi = 3.141592653589;
const double kTwoPi = 2.0 * kPi;
class MyInstance : public pp::Instance {
private:
pp::Audio audio_;
uint32_t obtained_sample_frame_count_;
double audio_wave_time_;
uint32_t duration_;
uint32_t frequency_;
static void SoundCallback(void* samples, uint32_t num_bytes, void* thiz) {
MyInstance* instance = reinterpret_cast<MyInstance*>(thiz);
CHECK(instance->obtained_sample_frame_count_ * kSizeSingleSample ==
num_bytes);
const double delta = kTwoPi * instance->frequency_ / kSampleFrequency;
const int16_t max_int16 = std::numeric_limits<int16_t>::max();
int16_t* buf = reinterpret_cast<int16_t*>(samples);
for (size_t i = 0; i < instance->obtained_sample_frame_count_; ++i) {
const double v = sin(instance->audio_wave_time_) * max_int16;
*buf++ = static_cast<int16_t>(v);
*buf++ = static_cast<int16_t>(v);
instance->audio_wave_time_ += delta;
if (instance->audio_wave_time_ > kTwoPi)
instance->audio_wave_time_ -= kTwoPi * 2.0;
}
}
static void StopOutput(void* thiz, int32_t err) {
if (PP_OK == err) {
MyInstance* instance = static_cast<MyInstance*>(thiz);
instance->audio_.StopPlayback();
}
}
void ExtraChecks(pp::AudioConfig* config) {
CHECK(obtained_sample_frame_count_ >= PP_AUDIOMINSAMPLEFRAMECOUNT);
CHECK(obtained_sample_frame_count_ <= PP_AUDIOMAXSAMPLEFRAMECOUNT);
PPB_GetInterface get_browser_if =
pp::Module::Get()->get_browser_interface();
const PPB_AudioConfig* audio_config_if =
static_cast<const PPB_AudioConfig*>(
get_browser_if(PPB_AUDIO_CONFIG_INTERFACE));
const PPB_Audio* audio_if =
static_cast<const PPB_Audio*>(
get_browser_if(PPB_AUDIO_INTERFACE));
CHECK(NULL != audio_config_if);
CHECK(NULL != audio_if);
const PP_Resource audio_config_res = config->pp_resource();
const PP_Resource audio_res = audio_.pp_resource();
CHECK(PP_TRUE == audio_config_if->IsAudioConfig(audio_config_res));
CHECK(PP_TRUE == audio_if->IsAudio(audio_res));
CHECK(PP_FALSE == audio_config_if->IsAudioConfig(audio_res));
CHECK(PP_FALSE == audio_if->IsAudio(audio_config_res));
CHECK(audio_if->GetCurrentConfig(audio_res) == audio_config_res);
CHECK(0 == audio_if->GetCurrentConfig(audio_config_res));
CHECK(audio_config_if->GetSampleRate(audio_config_res) ==
config->sample_rate());
CHECK(audio_config_if->GetSampleFrameCount(audio_config_res) ==
config->sample_frame_count());
CHECK(audio_.config().pp_resource() == audio_config_res);
}
void ParseArgs(uint32_t argc, const char* argn[], const char* argv[]) {
for (uint32_t i = 0; i < argc; ++i) {
const std::string tag = argn[i];
if (tag == "duration") duration_ = strtol(argv[i], 0, 0);
if (tag == "frequency") frequency_ = strtol(argv[i], 0, 0);
}
}
public:
explicit MyInstance(PP_Instance instance)
: pp::Instance(instance),
duration_(kDefaultDuration), frequency_(kDefaultFrequency) {}
virtual ~MyInstance() {}
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
ParseArgs(argc, argn, argv);
obtained_sample_frame_count_ = pp::AudioConfig::RecommendSampleFrameCount(
kSampleFrequency, kSampleFrameCount);
pp::AudioConfig config =
pp::AudioConfig(this, kSampleFrequency, obtained_sample_frame_count_);
audio_ = pp::Audio(this, config, SoundCallback, this);
ExtraChecks(&config);
CHECK(audio_.StartPlayback());
pp::CompletionCallback cc(StopOutput, this);
pp::Module::Get()->core()->CallOnMainThread(duration_, cc, PP_OK);
return true;
}
};
class MyModule : public pp::Module {
public:
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new MyInstance(instance);
}
};
namespace pp {
Module* CreateModule() {
return new MyModule();
}
}