diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 23:40:00 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 23:40:00 +0000 |
commit | e9f141340f1fead15d353b430fd7883264b14b0d (patch) | |
tree | cf97a7499d570718f72b4c68ff0462f82abe5c25 /ppapi/examples | |
parent | 1bafb3c7bef6bced676f2aa1988c58c61a57819e (diff) | |
download | chromium_src-e9f141340f1fead15d353b430fd7883264b14b0d.zip chromium_src-e9f141340f1fead15d353b430fd7883264b14b0d.tar.gz chromium_src-e9f141340f1fead15d353b430fd7883264b14b0d.tar.bz2 |
Pepper: Add an example/test plugin for audio input (a.k.a. microphone).
Review URL: http://codereview.chromium.org/8662020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111444 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/examples')
-rw-r--r-- | ppapi/examples/audio_input/audio_input.cc | 194 | ||||
-rw-r--r-- | ppapi/examples/audio_input/audio_input.html | 18 |
2 files changed, 212 insertions, 0 deletions
diff --git a/ppapi/examples/audio_input/audio_input.cc b/ppapi/examples/audio_input/audio_input.cc new file mode 100644 index 0000000..13b1237 --- /dev/null +++ b/ppapi/examples/audio_input/audio_input.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2011 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 <string.h> + +#include <algorithm> +#include <limits> + +#include "ppapi/cpp/audio_config.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/dev/audio_input_dev.h" +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/logging.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/rect.h" +#include "ppapi/cpp/size.h" + +class MyInstance : public pp::Instance { + public: + explicit MyInstance(PP_Instance instance) + : pp::Instance(instance), + callback_factory_(this), + sample_count_(0), + channel_count_(0), + samples_(NULL), + timer_interval_(0), + pending_paint_(false), + waiting_for_flush_completion_(false) { + } + virtual ~MyInstance() { + audio_input_.StopCapture(); + delete[] samples_; + } + + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { + // This sample frequency is guaranteed to work. + const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100; + const uint32_t kSampleCount = 1024; + const uint32_t kChannelCount = 1; + + sample_count_ = pp::AudioConfig::RecommendSampleFrameCount(kSampleFrequency, + kSampleCount); + PP_DCHECK(sample_count_ > 0); + channel_count_ = kChannelCount; + pp::AudioConfig config = pp::AudioConfig(this, + kSampleFrequency, + sample_count_); + samples_ = new int16_t[sample_count_ * channel_count_]; + memset(samples_, 0, sample_count_ * channel_count_ * sizeof(int16_t)); + audio_input_ = pp::AudioInput_Dev(this, config, CaptureCallback, this); + if (!audio_input_.StartCapture()) + return false; + + // Try to ensure that we pick up a new set of samples between each + // timer-generated repaint. + timer_interval_ = (sample_count_ * 1000) / kSampleFrequency + 5; + ScheduleNextTimer(); + + return true; + } + + virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { + if (position.size() == size_) + return; + + size_ = position.size(); + device_context_ = pp::Graphics2D(this, size_, false); + if (!BindGraphics(device_context_)) + return; + + Paint(); + } + + private: + void ScheduleNextTimer() { + PP_DCHECK(timer_interval_ > 0); + pp::Module::Get()->core()->CallOnMainThread( + timer_interval_, + callback_factory_.NewRequiredCallback(&MyInstance::OnTimer), + 0); + } + + void OnTimer(int32_t) { + ScheduleNextTimer(); + Paint(); + } + + void DidFlush(int32_t result) { + waiting_for_flush_completion_ = false; + if (pending_paint_) + Paint(); + } + + void Paint() { + if (waiting_for_flush_completion_) { + pending_paint_ = true; + return; + } + + pending_paint_ = false; + + if (size_.IsEmpty()) + return; // Nothing to do. + + pp::ImageData image = PaintImage(size_); + if (!image.is_null()) { + device_context_.ReplaceContents(&image); + waiting_for_flush_completion_ = true; + device_context_.Flush( + callback_factory_.NewRequiredCallback(&MyInstance::DidFlush)); + } + } + + pp::ImageData PaintImage(const pp::Size& size) { + pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false); + if (image.is_null()) + return image; + + // Clear to dark grey. + for (int y = 0; y < size.height(); y++) { + for (int x = 0; x < size.width(); x++) + *image.GetAddr32(pp::Point(x, y)) = 0xff202020; + } + + int mid_height = size.height() / 2; + int max_amplitude = size.height() * 4 / 10; + + // Draw some lines. + for (int x = 0; x < size.width(); x++) { + *image.GetAddr32(pp::Point(x, mid_height)) = 0xff606060; + *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = 0xff404040; + *image.GetAddr32(pp::Point(x, mid_height - max_amplitude)) = 0xff404040; + } + + // Draw our samples. + for (int x = 0, i = 0; + x < std::min(size.width(), static_cast<int>(sample_count_)); + x++, i += channel_count_) { + int y = samples_[i] * max_amplitude / + (std::numeric_limits<int16_t>::max() + 1) + mid_height; + *image.GetAddr32(pp::Point(x, y)) = 0xffffffff; + } + + return image; + } + + // TODO(viettrungluu): Danger! We really should lock, but which thread + // primitives to use? In any case, the |StopCapture()| in the destructor + // shouldn't return until this callback is done, so at least we should be + // writing to a valid region of memory. + static void CaptureCallback(const void* samples, + uint32_t num_bytes, + void* ctx) { + MyInstance* thiz = static_cast<MyInstance*>(ctx); + PP_DCHECK(num_bytes == + thiz->sample_count_ * thiz->channel_count_ * sizeof(int16_t)); + memcpy(thiz->samples_, samples, num_bytes); + } + + pp::CompletionCallbackFactory<MyInstance> callback_factory_; + + uint32_t sample_count_; + uint32_t channel_count_; + int16_t* samples_; + + int32_t timer_interval_; + + // Painting stuff. + pp::Size size_; + pp::Graphics2D device_context_; + bool pending_paint_; + bool waiting_for_flush_completion_; + + pp::AudioInput_Dev audio_input_; +}; + +class MyModule : public pp::Module { + public: + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new MyInstance(instance); + } +}; + +namespace pp { + +// Factory function for your specialization of the Module object. +Module* CreateModule() { + return new MyModule(); +} + +} // namespace pp diff --git a/ppapi/examples/audio_input/audio_input.html b/ppapi/examples/audio_input/audio_input.html new file mode 100644 index 0000000..bfa91cd --- /dev/null +++ b/ppapi/examples/audio_input/audio_input.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright (c) 2011 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. + --> +<head> + <title>Audio Input Example</title> +</head> + +<body> + +<embed id="plugin" type="application/x-ppapi-example-audio-input" + width="800" height="400"/> + +</body> +</html> |