OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 #include <string.h> | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
9 | |
10 #include "ppapi/cpp/audio_config.h" | |
11 #include "ppapi/cpp/completion_callback.h" | |
12 #include "ppapi/cpp/dev/audio_input_dev.h" | |
13 #include "ppapi/cpp/graphics_2d.h" | |
14 #include "ppapi/cpp/image_data.h" | |
15 #include "ppapi/cpp/instance.h" | |
16 #include "ppapi/cpp/logging.h" | |
17 #include "ppapi/cpp/module.h" | |
18 #include "ppapi/cpp/rect.h" | |
19 #include "ppapi/cpp/size.h" | |
20 | |
21 class MyInstance : public pp::Instance { | |
22 public: | |
23 explicit MyInstance(PP_Instance instance) | |
24 : pp::Instance(instance), | |
25 callback_factory_(this), | |
26 sample_count_(0), | |
27 channel_count_(0), | |
28 samples_(NULL), | |
29 timer_interval_(0), | |
30 pending_paint_(false), | |
31 waiting_for_flush_completion_(false) { | |
32 } | |
33 virtual ~MyInstance() { | |
34 audio_input_.StopCapture(); | |
35 delete[] samples_; | |
36 } | |
37 | |
38 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | |
39 // This sample frequency is guaranteed to work. | |
40 const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100; | |
41 const uint32_t kSampleCount = 1024; | |
42 const uint32_t kChannelCount = 1; | |
43 | |
44 sample_count_ = pp::AudioConfig::RecommendSampleFrameCount(kSampleFrequency, | |
45 kSampleCount); | |
46 PP_DCHECK(sample_count_ > 0); | |
47 channel_count_ = kChannelCount; | |
48 pp::AudioConfig config = pp::AudioConfig(this, | |
49 kSampleFrequency, | |
50 sample_count_); | |
51 samples_ = new int16_t[sample_count_ * channel_count_]; | |
52 memset(samples_, 0, sample_count_ * channel_count_ * sizeof(int16_t)); | |
53 audio_input_ = pp::AudioInput_Dev(this, config, CaptureCallback, this); | |
54 if (!audio_input_.StartCapture()) | |
55 return false; | |
56 | |
57 // Try to ensure that we pick up a new set of samples between each | |
58 // timer-generated repaint. | |
59 timer_interval_ = (sample_count_ * 1000) / kSampleFrequency + 5; | |
60 ScheduleNextTimer(); | |
61 | |
62 return true; | |
63 } | |
64 | |
65 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { | |
66 if (position.size() == size_) | |
67 return; | |
68 | |
69 size_ = position.size(); | |
70 device_context_ = pp::Graphics2D(this, size_, false); | |
71 if (!BindGraphics(device_context_)) | |
72 return; | |
73 | |
74 Paint(); | |
75 } | |
76 | |
77 private: | |
78 void ScheduleNextTimer() { | |
79 PP_DCHECK(timer_interval_ > 0); | |
80 pp::Module::Get()->core()->CallOnMainThread( | |
81 timer_interval_, | |
82 callback_factory_.NewRequiredCallback(&MyInstance::OnTimer), | |
83 0); | |
84 } | |
85 | |
86 void OnTimer(int32_t) { | |
87 ScheduleNextTimer(); | |
88 Paint(); | |
89 } | |
90 | |
91 void DidFlush(int32_t result) { | |
92 waiting_for_flush_completion_ = false; | |
93 if (pending_paint_) { | |
94 pending_paint_ = false; | |
yzshen1
2011/11/23 21:21:17
nit: it might be better to make Paint() the only o
viettrungluu
2011/11/23 21:31:30
Done.
| |
95 Paint(); | |
96 } | |
97 } | |
98 | |
99 void Paint() { | |
100 if (size_.IsEmpty()) { | |
101 pending_paint_ = false; | |
102 return; | |
103 } | |
104 | |
105 if (waiting_for_flush_completion_) { | |
106 pending_paint_ = true; | |
107 return; | |
108 } | |
109 | |
110 pp::ImageData image = PaintImage(size_); | |
111 if (!image.is_null()) { | |
112 device_context_.ReplaceContents(&image); | |
113 waiting_for_flush_completion_ = true; | |
114 device_context_.Flush( | |
115 callback_factory_.NewRequiredCallback(&MyInstance::DidFlush)); | |
116 } | |
117 } | |
118 | |
119 pp::ImageData PaintImage(const pp::Size& size) { | |
120 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false); | |
121 if (image.is_null()) | |
122 return image; | |
123 | |
124 // Clear to dark grey. | |
125 for (int y = 0; y < size.height(); y++) { | |
126 for (int x = 0; x < size.width(); x++) | |
127 *image.GetAddr32(pp::Point(x, y)) = 0xff202020; | |
128 } | |
129 | |
130 int mid_height = size.height() / 2; | |
131 int max_amplitude = size.height() * 4 / 10; | |
132 | |
133 // Draw some lines. | |
134 for (int x = 0; x < size.width(); x++) { | |
135 *image.GetAddr32(pp::Point(x, mid_height)) = 0xff606060; | |
136 *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = 0xff404040; | |
137 *image.GetAddr32(pp::Point(x, mid_height - max_amplitude)) = 0xff404040; | |
138 } | |
139 | |
140 // Draw our samples. | |
141 for (int x = 0, i = 0; | |
142 x < std::min(size.width(), static_cast<int>(sample_count_)); | |
143 x++, i += channel_count_) { | |
144 int y = samples_[i] * max_amplitude / | |
145 (std::numeric_limits<int16_t>::max() + 1) + mid_height; | |
146 *image.GetAddr32(pp::Point(x, y)) = 0xffffffff; | |
147 } | |
148 | |
149 return image; | |
150 } | |
151 | |
152 // TODO(viettrungluu): Danger! We really should lock, but which thread | |
153 // primitives to use? In any case, the |StopCapture()| in the destructor | |
154 // shouldn't return until this callback is done, so at least we should be | |
155 // writing to a valid region of memory. | |
156 static void CaptureCallback(const void* samples, | |
157 uint32_t num_bytes, | |
158 void* ctx) { | |
159 MyInstance* thiz = static_cast<MyInstance*>(ctx); | |
160 PP_DCHECK(num_bytes == | |
161 thiz->sample_count_ * channel_count_ * sizeof(int16_t)); | |
yzshen1
2011/11/23 21:21:17
channel_count_ should be thiz->channel_count_, rig
viettrungluu
2011/11/23 21:31:30
Yes. I don't know how it managed to compile for me
| |
162 memcpy(thiz->samples_, samples, num_bytes); | |
163 } | |
164 | |
165 pp::CompletionCallbackFactory<MyInstance> callback_factory_; | |
166 | |
167 uint32_t sample_count_; | |
168 uint32_t channel_count_; | |
169 int16_t* samples_; | |
170 | |
171 int32_t timer_interval_; | |
172 | |
173 // Painting stuff. | |
174 pp::Size size_; | |
175 pp::Graphics2D device_context_; | |
176 bool pending_paint_; | |
177 bool waiting_for_flush_completion_; | |
178 | |
179 | |
180 // Allocated in |Init()|, freed on destruction. | |
181 pp::AudioInput_Dev audio_input_; | |
182 }; | |
183 | |
184 class MyModule : public pp::Module { | |
185 public: | |
186 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
187 return new MyInstance(instance); | |
188 } | |
189 }; | |
190 | |
191 namespace pp { | |
192 | |
193 // Factory function for your specialization of the Module object. | |
194 Module* CreateModule() { | |
195 return new MyModule(); | |
196 } | |
197 | |
198 } // namespace pp | |
OLD | NEW |