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