Chromium Code Reviews| Index: ppapi/examples/audio_input/audio_input.cc |
| diff --git a/ppapi/examples/audio_input/audio_input.cc b/ppapi/examples/audio_input/audio_input.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..48e343abf05714f943899b834a225f3aee354089 |
| --- /dev/null |
| +++ b/ppapi/examples/audio_input/audio_input.cc |
| @@ -0,0 +1,202 @@ |
| +// 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 "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_ = 44100 / sample_count_ + 5; |
|
dmichael (off chromium)
2011/11/23 20:15:52
This doesn't make sense to me. timer_interval_ is
viettrungluu
2011/11/23 21:06:25
Right, good catch. Fixed.
|
| + 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_) { |
| + pending_paint_ = false; |
| + Paint(); |
| + } |
| + } |
| + |
| + void Paint() { |
| + if (size_.IsEmpty()) { |
| + pending_paint_ = false; |
| + return; |
| + } |
| + |
| + if (waiting_for_flush_completion_) { |
| + pending_paint_ = true; |
| + return; |
| + } |
| + |
| + pp::ImageData image = PaintImage(size_, |
| + samples_, |
| + sample_count_, |
| + channel_count_); |
| + 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, |
| + const int16_t* samples, |
| + uint32_t sample_count, |
| + uint32_t channel_count) { |
|
dmichael (off chromium)
2011/11/23 20:15:52
nit: Is there a reason to use parameters for these
viettrungluu
2011/11/23 21:06:25
No good reason; I got rid of the last three parame
|
| + 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 / 32768 + mid_height; |
|
dmichael (off chromium)
2011/11/23 20:15:52
nit: std::numeric_limits<int16_t>::max()+1 might l
viettrungluu
2011/11/23 21:06:25
Done.
|
| + *image.GetAddr32(pp::Point(x, y)) = 0xffffffff; |
| + } |
| + |
| + return image; |
| + } |
| + |
| + // TODO(viettrungluu): Danger! We really should lock, but which thread |
|
dmichael (off chromium)
2011/11/23 20:15:52
I have some threading primitive wrappers sitting s
|
| + // 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. |
|
dmichael (off chromium)
2011/11/23 20:15:52
But I agree... in this case, the worst that will h
viettrungluu
2011/11/23 21:06:25
Yeah, we should fix it, but let's hold off on it f
|
| + static void CaptureCallback(const void* samples, |
| + uint32_t num_bytes, |
| + void* ctx) { |
| + MyInstance* thiz = reinterpret_cast<MyInstance*>(ctx); |
|
dmichael (off chromium)
2011/11/23 20:15:52
static_cast
viettrungluu
2011/11/23 21:06:25
Done.
|
| + PP_DCHECK(num_bytes == |
| + thiz->sample_count_ * 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_; |
| + |
| + |
|
yzshen1
2011/11/23 21:21:17
One redundant empty line could be removed.
viettrungluu
2011/11/23 21:31:30
Done.
|
| + // Allocated in |Init()|, freed on destruction. |
| + pp::AudioInput_Dev audio_input_; |
|
yzshen1
2011/11/23 21:21:17
nit: Allocated / freed may not be accurate. It sou
viettrungluu
2011/11/23 21:31:30
I removed this misleading comment (which I forgot
|
| +}; |
| + |
| +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 |