OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include <stdlib.h> |
5 #include <string.h> | 6 #include <string.h> |
6 | 7 |
7 #include <algorithm> | 8 #include <algorithm> |
8 #include <limits> | 9 #include <limits> |
9 #include <vector> | 10 #include <vector> |
10 | 11 |
11 #include "ppapi/cpp/audio_config.h" | 12 #include "ppapi/cpp/audio_config.h" |
12 #include "ppapi/cpp/dev/audio_input_dev.h" | 13 #include "ppapi/cpp/dev/audio_input_dev.h" |
13 #include "ppapi/cpp/dev/device_ref_dev.h" | 14 #include "ppapi/cpp/dev/device_ref_dev.h" |
14 #include "ppapi/cpp/graphics_2d.h" | 15 #include "ppapi/cpp/graphics_2d.h" |
(...skipping 10 matching lines...) Expand all Loading... |
25 #ifdef PostMessage | 26 #ifdef PostMessage |
26 #undef PostMessage | 27 #undef PostMessage |
27 #endif | 28 #endif |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 // This sample frequency is guaranteed to work. | 32 // This sample frequency is guaranteed to work. |
32 const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100; | 33 const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100; |
33 const uint32_t kSampleCount = 1024; | 34 const uint32_t kSampleCount = 1024; |
34 const uint32_t kChannelCount = 1; | 35 const uint32_t kChannelCount = 1; |
| 36 const char* const kDelimiter = "#__#"; |
35 | 37 |
36 } // namespace | 38 } // namespace |
37 | 39 |
38 class MyInstance : public pp::Instance { | 40 class MyInstance : public pp::Instance { |
39 public: | 41 public: |
40 explicit MyInstance(PP_Instance instance) | 42 explicit MyInstance(PP_Instance instance) |
41 : pp::Instance(instance), | 43 : pp::Instance(instance), |
42 callback_factory_(this), | 44 callback_factory_(this), |
43 sample_count_(0), | 45 sample_count_(0), |
44 channel_count_(0), | 46 channel_count_(0), |
45 samples_(NULL), | 47 samples_(NULL), |
46 timer_interval_(0), | 48 timer_interval_(0), |
47 pending_paint_(false), | 49 pending_paint_(false), |
48 waiting_for_flush_completion_(false) { | 50 waiting_for_flush_completion_(false) { |
49 } | 51 } |
50 virtual ~MyInstance() { | 52 virtual ~MyInstance() { |
| 53 device_detector_.MonitorDeviceChange(NULL, NULL); |
51 audio_input_.Close(); | 54 audio_input_.Close(); |
52 | 55 |
53 delete[] samples_; | 56 delete[] samples_; |
54 } | 57 } |
55 | 58 |
56 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | 59 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { |
57 sample_count_ = pp::AudioConfig::RecommendSampleFrameCount(this, | 60 sample_count_ = pp::AudioConfig::RecommendSampleFrameCount(this, |
58 kSampleFrequency, | 61 kSampleFrequency, |
59 kSampleCount); | 62 kSampleCount); |
60 PP_DCHECK(sample_count_ > 0); | 63 PP_DCHECK(sample_count_ > 0); |
61 channel_count_ = kChannelCount; | 64 channel_count_ = kChannelCount; |
62 samples_ = new int16_t[sample_count_ * channel_count_]; | 65 samples_ = new int16_t[sample_count_ * channel_count_]; |
63 memset(samples_, 0, sample_count_ * channel_count_ * sizeof(int16_t)); | 66 memset(samples_, 0, sample_count_ * channel_count_ * sizeof(int16_t)); |
64 | 67 |
65 audio_input_ = pp::AudioInput_Dev(this); | 68 device_detector_ = pp::AudioInput_Dev(this); |
66 | 69 |
67 // Try to ensure that we pick up a new set of samples between each | 70 // Try to ensure that we pick up a new set of samples between each |
68 // timer-generated repaint. | 71 // timer-generated repaint. |
69 timer_interval_ = (sample_count_ * 1000) / kSampleFrequency + 5; | 72 timer_interval_ = (sample_count_ * 1000) / kSampleFrequency + 5; |
70 ScheduleNextTimer(); | 73 ScheduleNextTimer(); |
71 | 74 |
72 return true; | 75 return true; |
73 } | 76 } |
74 | 77 |
75 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { | 78 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { |
76 if (position.size() == size_) | 79 if (position.size() == size_) |
77 return; | 80 return; |
78 | 81 |
79 size_ = position.size(); | 82 size_ = position.size(); |
80 device_context_ = pp::Graphics2D(this, size_, false); | 83 device_context_ = pp::Graphics2D(this, size_, false); |
81 if (!BindGraphics(device_context_)) | 84 if (!BindGraphics(device_context_)) |
82 return; | 85 return; |
83 | 86 |
84 Paint(); | 87 Paint(); |
85 } | 88 } |
86 | 89 |
87 virtual void HandleMessage(const pp::Var& message_data) { | 90 virtual void HandleMessage(const pp::Var& message_data) { |
88 if (message_data.is_string()) { | 91 if (message_data.is_string()) { |
89 std::string event = message_data.AsString(); | 92 std::string event = message_data.AsString(); |
90 if (event == "PageInitialized") { | 93 if (event == "PageInitialized") { |
| 94 int32_t result = device_detector_.MonitorDeviceChange( |
| 95 &MyInstance::MonitorDeviceChangeCallback, this); |
| 96 if (result != PP_OK) |
| 97 PostMessage(pp::Var("MonitorDeviceChangeFailed")); |
| 98 |
91 pp::CompletionCallbackWithOutput<std::vector<pp::DeviceRef_Dev> > | 99 pp::CompletionCallbackWithOutput<std::vector<pp::DeviceRef_Dev> > |
92 callback = callback_factory_.NewCallbackWithOutput( | 100 callback = callback_factory_.NewCallbackWithOutput( |
93 &MyInstance::EnumerateDevicesFinished); | 101 &MyInstance::EnumerateDevicesFinished); |
94 int32_t result = audio_input_.EnumerateDevices(callback); | 102 result = device_detector_.EnumerateDevices(callback); |
95 if (result != PP_OK_COMPLETIONPENDING) | 103 if (result != PP_OK_COMPLETIONPENDING) |
96 PostMessage(pp::Var("EnumerationFailed")); | 104 PostMessage(pp::Var("EnumerationFailed")); |
97 } else if (event == "UseDefault") { | 105 } else if (event == "UseDefault") { |
98 Open(pp::DeviceRef_Dev()); | 106 Open(pp::DeviceRef_Dev()); |
99 } else if (event == "Stop") { | 107 } else if (event == "Stop") { |
100 Stop(); | 108 Stop(); |
101 } else if (event == "Start") { | 109 } else if (event == "Start") { |
102 Start(); | 110 Start(); |
103 } | 111 } else if (event.find("Monitor:") == 0) { |
104 } else if (message_data.is_number()) { | 112 std::string index_str = event.substr(strlen("Monitor:")); |
105 int index = message_data.AsInt(); | 113 int index = atoi(index_str.c_str()); |
106 if (index >= 0 && index < static_cast<int>(devices_.size())) { | 114 if (index >= 0 && index < static_cast<int>(monitor_devices_.size())) |
107 Open(devices_[index]); | 115 Open(monitor_devices_[index]); |
108 } else { | 116 else |
109 PP_NOTREACHED(); | 117 PP_NOTREACHED(); |
| 118 } else if (event.find("Enumerate:") == 0) { |
| 119 std::string index_str = event.substr(strlen("Enumerate:")); |
| 120 int index = atoi(index_str.c_str()); |
| 121 if (index >= 0 && index < static_cast<int>(enumerate_devices_.size())) |
| 122 Open(enumerate_devices_[index]); |
| 123 else |
| 124 PP_NOTREACHED(); |
110 } | 125 } |
111 } | 126 } |
112 } | 127 } |
113 | 128 |
114 private: | 129 private: |
115 void ScheduleNextTimer() { | 130 void ScheduleNextTimer() { |
116 PP_DCHECK(timer_interval_ > 0); | 131 PP_DCHECK(timer_interval_ > 0); |
117 pp::Module::Get()->core()->CallOnMainThread( | 132 pp::Module::Get()->core()->CallOnMainThread( |
118 timer_interval_, | 133 timer_interval_, |
119 callback_factory_.NewCallback(&MyInstance::OnTimer), | 134 callback_factory_.NewCallback(&MyInstance::OnTimer), |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 x < std::min(size.width(), static_cast<int>(sample_count_)); | 192 x < std::min(size.width(), static_cast<int>(sample_count_)); |
178 x++, i += channel_count_) { | 193 x++, i += channel_count_) { |
179 int y = samples_[i] * max_amplitude / | 194 int y = samples_[i] * max_amplitude / |
180 (std::numeric_limits<int16_t>::max() + 1) + mid_height; | 195 (std::numeric_limits<int16_t>::max() + 1) + mid_height; |
181 *image.GetAddr32(pp::Point(x, y)) = 0xffffffff; | 196 *image.GetAddr32(pp::Point(x, y)) = 0xffffffff; |
182 } | 197 } |
183 | 198 |
184 return image; | 199 return image; |
185 } | 200 } |
186 | 201 |
187 // TODO(viettrungluu): Danger! We really should lock, but which thread | 202 void Open(const pp::DeviceRef_Dev& device) { |
188 // primitives to use? In any case, the |StopCapture()| in the destructor | 203 audio_input_.Close(); |
189 // shouldn't return until this callback is done, so at least we should be | 204 audio_input_ = pp::AudioInput_Dev(this); |
190 // writing to a valid region of memory. | |
191 static void CaptureCallback(const void* samples, | |
192 uint32_t num_bytes, | |
193 void* ctx) { | |
194 MyInstance* thiz = static_cast<MyInstance*>(ctx); | |
195 uint32_t buffer_size = | |
196 thiz->sample_count_ * thiz->channel_count_ * sizeof(int16_t); | |
197 PP_DCHECK(num_bytes <= buffer_size); | |
198 PP_DCHECK(num_bytes % (thiz->channel_count_ * sizeof(int16_t)) == 0); | |
199 memcpy(thiz->samples_, samples, num_bytes); | |
200 memset(reinterpret_cast<char*>(thiz->samples_) + num_bytes, 0, | |
201 buffer_size - num_bytes); | |
202 } | |
203 | 205 |
204 void Open(const pp::DeviceRef_Dev& device) { | |
205 pp::AudioConfig config = pp::AudioConfig(this, | 206 pp::AudioConfig config = pp::AudioConfig(this, |
206 kSampleFrequency, | 207 kSampleFrequency, |
207 sample_count_); | 208 sample_count_); |
208 pp::CompletionCallback callback = callback_factory_.NewCallback( | 209 pp::CompletionCallback callback = callback_factory_.NewCallback( |
209 &MyInstance::OpenFinished); | 210 &MyInstance::OpenFinished); |
210 int32_t result = audio_input_.Open(device, config, CaptureCallback, this, | 211 int32_t result = audio_input_.Open(device, config, CaptureCallback, this, |
211 callback); | 212 callback); |
212 if (result != PP_OK_COMPLETIONPENDING) | 213 if (result != PP_OK_COMPLETIONPENDING) |
213 PostMessage(pp::Var("OpenFailed")); | 214 PostMessage(pp::Var("OpenFailed")); |
214 } | 215 } |
215 | 216 |
216 void Stop() { | 217 void Stop() { |
217 if (!audio_input_.StopCapture()) | 218 if (!audio_input_.StopCapture()) |
218 PostMessage(pp::Var("StopFailed")); | 219 PostMessage(pp::Var("StopFailed")); |
219 } | 220 } |
220 | 221 |
221 void Start() { | 222 void Start() { |
222 if (!audio_input_.StartCapture()) | 223 if (!audio_input_.StartCapture()) |
223 PostMessage(pp::Var("StartFailed")); | 224 PostMessage(pp::Var("StartFailed")); |
224 } | 225 } |
225 | 226 |
226 void EnumerateDevicesFinished(int32_t result, | 227 void EnumerateDevicesFinished(int32_t result, |
227 std::vector<pp::DeviceRef_Dev>& devices) { | 228 std::vector<pp::DeviceRef_Dev>& devices) { |
228 static const char* const kDelimiter = "#__#"; | |
229 | |
230 if (result == PP_OK) { | 229 if (result == PP_OK) { |
231 devices_.swap(devices); | 230 enumerate_devices_.swap(devices); |
232 std::string device_names; | 231 std::string device_names = "Enumerate:"; |
233 for (size_t index = 0; index < devices_.size(); ++index) { | 232 for (size_t index = 0; index < enumerate_devices_.size(); ++index) { |
234 pp::Var name = devices_[index].GetName(); | 233 pp::Var name = enumerate_devices_[index].GetName(); |
235 PP_DCHECK(name.is_string()); | 234 PP_DCHECK(name.is_string()); |
236 | 235 |
237 if (index != 0) | 236 if (index != 0) |
238 device_names += kDelimiter; | 237 device_names += kDelimiter; |
239 device_names += name.AsString(); | 238 device_names += name.AsString(); |
240 } | 239 } |
241 PostMessage(pp::Var(device_names)); | 240 PostMessage(pp::Var(device_names)); |
242 } else { | 241 } else { |
243 PostMessage(pp::Var("EnumerationFailed")); | 242 PostMessage(pp::Var("EnumerationFailed")); |
244 } | 243 } |
245 } | 244 } |
246 | 245 |
247 void OpenFinished(int32_t result) { | 246 void OpenFinished(int32_t result) { |
248 if (result == PP_OK) { | 247 if (result == PP_OK) { |
249 if (!audio_input_.StartCapture()) | 248 if (!audio_input_.StartCapture()) |
250 PostMessage(pp::Var("StartFailed")); | 249 PostMessage(pp::Var("StartFailed")); |
251 } else { | 250 } else { |
252 PostMessage(pp::Var("OpenFailed")); | 251 PostMessage(pp::Var("OpenFailed")); |
253 } | 252 } |
254 } | 253 } |
255 | 254 |
| 255 // TODO(viettrungluu): Danger! We really should lock, but which thread |
| 256 // primitives to use? In any case, the |StopCapture()| in the destructor |
| 257 // shouldn't return until this callback is done, so at least we should be |
| 258 // writing to a valid region of memory. |
| 259 static void CaptureCallback(const void* samples, |
| 260 uint32_t num_bytes, |
| 261 void* ctx) { |
| 262 MyInstance* thiz = static_cast<MyInstance*>(ctx); |
| 263 uint32_t buffer_size = |
| 264 thiz->sample_count_ * thiz->channel_count_ * sizeof(int16_t); |
| 265 PP_DCHECK(num_bytes <= buffer_size); |
| 266 PP_DCHECK(num_bytes % (thiz->channel_count_ * sizeof(int16_t)) == 0); |
| 267 memcpy(thiz->samples_, samples, num_bytes); |
| 268 memset(reinterpret_cast<char*>(thiz->samples_) + num_bytes, 0, |
| 269 buffer_size - num_bytes); |
| 270 } |
| 271 |
| 272 static void MonitorDeviceChangeCallback(void* user_data, |
| 273 uint32_t device_count, |
| 274 const PP_Resource devices[]) { |
| 275 MyInstance* thiz = static_cast<MyInstance*>(user_data); |
| 276 |
| 277 std::string device_names = "Monitor:"; |
| 278 thiz->monitor_devices_.clear(); |
| 279 thiz->monitor_devices_.reserve(device_count); |
| 280 for (size_t index = 0; index < device_count; ++index) { |
| 281 thiz->monitor_devices_.push_back(pp::DeviceRef_Dev(devices[index])); |
| 282 pp::Var name = thiz->monitor_devices_.back().GetName(); |
| 283 PP_DCHECK(name.is_string()); |
| 284 |
| 285 if (index != 0) |
| 286 device_names += kDelimiter; |
| 287 device_names += name.AsString(); |
| 288 } |
| 289 thiz->PostMessage(pp::Var(device_names)); |
| 290 } |
| 291 |
256 pp::CompletionCallbackFactory<MyInstance> callback_factory_; | 292 pp::CompletionCallbackFactory<MyInstance> callback_factory_; |
257 | 293 |
258 uint32_t sample_count_; | 294 uint32_t sample_count_; |
259 uint32_t channel_count_; | 295 uint32_t channel_count_; |
260 int16_t* samples_; | 296 int16_t* samples_; |
261 | 297 |
262 int32_t timer_interval_; | 298 int32_t timer_interval_; |
263 | 299 |
264 // Painting stuff. | 300 // Painting stuff. |
265 pp::Size size_; | 301 pp::Size size_; |
266 pp::Graphics2D device_context_; | 302 pp::Graphics2D device_context_; |
267 bool pending_paint_; | 303 bool pending_paint_; |
268 bool waiting_for_flush_completion_; | 304 bool waiting_for_flush_completion_; |
269 | 305 |
| 306 // There is no need to have two resources to do capturing and device detecting |
| 307 // separately. However, this makes the code of monitoring device change |
| 308 // easier. |
270 pp::AudioInput_Dev audio_input_; | 309 pp::AudioInput_Dev audio_input_; |
| 310 pp::AudioInput_Dev device_detector_; |
271 | 311 |
272 std::vector<pp::DeviceRef_Dev> devices_; | 312 std::vector<pp::DeviceRef_Dev> enumerate_devices_; |
| 313 std::vector<pp::DeviceRef_Dev> monitor_devices_; |
273 }; | 314 }; |
274 | 315 |
275 class MyModule : public pp::Module { | 316 class MyModule : public pp::Module { |
276 public: | 317 public: |
277 virtual pp::Instance* CreateInstance(PP_Instance instance) { | 318 virtual pp::Instance* CreateInstance(PP_Instance instance) { |
278 return new MyInstance(instance); | 319 return new MyInstance(instance); |
279 } | 320 } |
280 }; | 321 }; |
281 | 322 |
282 namespace pp { | 323 namespace pp { |
283 | 324 |
284 // Factory function for your specialization of the Module object. | 325 // Factory function for your specialization of the Module object. |
285 Module* CreateModule() { | 326 Module* CreateModule() { |
286 return new MyModule(); | 327 return new MyModule(); |
287 } | 328 } |
288 | 329 |
289 } // namespace pp | 330 } // namespace pp |
OLD | NEW |