Home | History | Annotate | Download | only in audio
      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.
      4 
      5 // Needed on Windows to get |M_PI| from math.h.
      6 #ifdef _WIN32
      7 #define _USE_MATH_DEFINES
      8 #endif
      9 
     10 #include <math.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 
     14 #include <limits>
     15 
     16 #include "ppapi/c/pp_errors.h"
     17 #include "ppapi/cpp/audio.h"
     18 #include "ppapi/cpp/audio_config.h"
     19 #include "ppapi/cpp/completion_callback.h"
     20 #include "ppapi/cpp/instance.h"
     21 #include "ppapi/cpp/module.h"
     22 #include "ppapi/cpp/view.h"
     23 
     24 // Separate left and right frequency to make sure we didn't swap L & R.
     25 // Sounds pretty horrible, though...
     26 const double kLeftFrequency = 400;
     27 const double kRightFrequency = 1000;
     28 
     29 // This sample frequency is guaranteed to work.
     30 const PP_AudioSampleRate kDefaultSampleRate = PP_AUDIOSAMPLERATE_44100;
     31 const uint32_t kDefaultSampleCount = 4096;
     32 
     33 const char kSampleRateAttributeName[] = "samplerate";
     34 
     35 class MyInstance : public pp::Instance {
     36  public:
     37   explicit MyInstance(PP_Instance instance)
     38       : pp::Instance(instance),
     39         visible_(false),
     40         sample_rate_(kDefaultSampleRate),
     41         sample_count_(0),
     42         audio_wave_l_(0.0),
     43         audio_wave_r_(0.0) {
     44   }
     45 
     46   virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
     47     for (uint32_t i = 0; i < argc; i++) {
     48       if (strcmp(kSampleRateAttributeName, argn[i]) == 0) {
     49         int value = atoi(argv[i]);
     50         if (value > 0 && value <= 1000000)
     51           sample_rate_ = static_cast<PP_AudioSampleRate>(value);
     52         else
     53           return false;
     54       }
     55     }
     56 
     57     pp::AudioConfig config;
     58     sample_count_ = pp::AudioConfig::RecommendSampleFrameCount(
     59         this, sample_rate_, kDefaultSampleCount);
     60     config = pp::AudioConfig(this, sample_rate_, sample_count_);
     61     audio_ = pp::Audio(this, config, SineWaveCallbackTrampoline, this);
     62     return audio_.StartPlayback();
     63   }
     64 
     65   virtual void DidChangeView(const pp::View& view) {
     66     // The frequency will change depending on whether the page is in the
     67     // foreground or background.
     68     visible_ = view.IsPageVisible();
     69   }
     70 
     71  private:
     72   static void SineWaveCallbackTrampoline(void* samples,
     73                                          uint32_t num_bytes,
     74                                          void* thiz) {
     75     static_cast<MyInstance*>(thiz)->SineWaveCallback(samples, num_bytes);
     76   }
     77 
     78   void SineWaveCallback(void* samples, uint32_t num_bytes) {
     79     double delta_l = 2.0 * M_PI * kLeftFrequency / sample_rate_ /
     80         (visible_ ? 1 : 2);
     81     double delta_r = 2.0 * M_PI * kRightFrequency / sample_rate_ /
     82         (visible_ ? 1 : 2);
     83 
     84     // Use per channel audio wave value to avoid clicks on buffer boundries.
     85     double wave_l = audio_wave_l_;
     86     double wave_r = audio_wave_r_;
     87     const int16_t max_int16 = std::numeric_limits<int16_t>::max();
     88     int16_t* buf = reinterpret_cast<int16_t*>(samples);
     89     for (size_t sample = 0; sample < sample_count_; ++sample) {
     90       *buf++ = static_cast<int16_t>(sin(wave_l) * max_int16);
     91       *buf++ = static_cast<int16_t>(sin(wave_r) * max_int16);
     92       // Add delta, keep within -2 * M_PI .. 2 * M_PI to preserve precision.
     93       wave_l += delta_l;
     94       if (wave_l > 2.0 * M_PI)
     95         wave_l -= 2.0 * M_PI;
     96       wave_r += delta_r;
     97       if (wave_r > 2.0 * M_PI)
     98         wave_r -= 2.0 * M_PI;
     99     }
    100     // Store current value to use as starting point for next callback.
    101     audio_wave_l_ = wave_l;
    102     audio_wave_r_ = wave_r;
    103   }
    104 
    105   bool visible_;
    106 
    107   PP_AudioSampleRate sample_rate_;
    108   uint32_t sample_count_;
    109 
    110   pp::Audio audio_;
    111 
    112   // Current audio wave position, used to prevent sine wave skips
    113   // on buffer boundaries.
    114   double audio_wave_l_;
    115   double audio_wave_r_;
    116 };
    117 
    118 class MyModule : public pp::Module {
    119  public:
    120   // Override CreateInstance to create your customized Instance object.
    121   virtual pp::Instance* CreateInstance(PP_Instance instance) {
    122     return new MyInstance(instance);
    123   }
    124 };
    125 
    126 namespace pp {
    127 
    128 // Factory function for your specialization of the Module object.
    129 Module* CreateModule() {
    130   return new MyModule();
    131 }
    132 
    133 }  // namespace pp
    134