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 |