Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ppapi / examples / media_stream_audio / media_stream_audio.cc
blob1d7bac1748db5f563ea92143ace75a2484fb1c05
1 // Copyright 2014 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.
5 #include <stdlib.h>
6 #include <string.h>
8 #include <algorithm>
9 #include <limits>
10 #include <vector>
12 #include "ppapi/cpp/audio_buffer.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/media_stream_audio_track.h"
18 #include "ppapi/cpp/module.h"
19 #include "ppapi/cpp/rect.h"
20 #include "ppapi/cpp/size.h"
21 #include "ppapi/cpp/var_dictionary.h"
22 #include "ppapi/utility/completion_callback_factory.h"
24 // When compiling natively on Windows, PostMessage can be #define-d to
25 // something else.
26 #ifdef PostMessage
27 #undef PostMessage
28 #endif
30 // This example demonstrates receiving audio samples from an AndioMediaTrack
31 // and visualizing them.
33 namespace {
35 const uint32_t kColorRed = 0xFFFF0000;
36 const uint32_t kColorGreen = 0xFF00FF00;
37 const uint32_t kColorGrey1 = 0xFF202020;
38 const uint32_t kColorGrey2 = 0xFF404040;
39 const uint32_t kColorGrey3 = 0xFF606060;
41 class MediaStreamAudioInstance : public pp::Instance {
42 public:
43 explicit MediaStreamAudioInstance(PP_Instance instance)
44 : pp::Instance(instance),
45 callback_factory_(this),
46 first_buffer_(true),
47 sample_count_(0),
48 channel_count_(0),
49 timer_interval_(0),
50 pending_paint_(false),
51 waiting_for_flush_completion_(false) {
54 virtual ~MediaStreamAudioInstance() {
57 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
58 if (position.size() == size_)
59 return;
61 size_ = position.size();
62 device_context_ = pp::Graphics2D(this, size_, false);
63 if (!BindGraphics(device_context_))
64 return;
66 Paint();
69 virtual void HandleMessage(const pp::Var& var_message) {
70 if (!var_message.is_dictionary())
71 return;
72 pp::VarDictionary var_dictionary_message(var_message);
73 pp::Var var_track = var_dictionary_message.Get("track");
74 if (!var_track.is_resource())
75 return;
77 pp::Resource resource_track = var_track.AsResource();
78 audio_track_ = pp::MediaStreamAudioTrack(resource_track);
79 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
80 &MediaStreamAudioInstance::OnGetBuffer));
83 private:
84 void ScheduleNextTimer() {
85 PP_DCHECK(timer_interval_ > 0);
86 pp::Module::Get()->core()->CallOnMainThread(
87 timer_interval_,
88 callback_factory_.NewCallback(&MediaStreamAudioInstance::OnTimer),
89 0);
92 void OnTimer(int32_t) {
93 ScheduleNextTimer();
94 Paint();
97 void DidFlush(int32_t result) {
98 waiting_for_flush_completion_ = false;
99 if (pending_paint_)
100 Paint();
103 void Paint() {
104 if (waiting_for_flush_completion_) {
105 pending_paint_ = true;
106 return;
109 pending_paint_ = false;
111 if (size_.IsEmpty())
112 return; // Nothing to do.
114 pp::ImageData image = PaintImage(size_);
115 if (!image.is_null()) {
116 device_context_.ReplaceContents(&image);
117 waiting_for_flush_completion_ = true;
118 device_context_.Flush(
119 callback_factory_.NewCallback(&MediaStreamAudioInstance::DidFlush));
123 pp::ImageData PaintImage(const pp::Size& size) {
124 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
125 if (image.is_null())
126 return image;
128 // Clear to dark grey.
129 for (int y = 0; y < size.height(); y++) {
130 for (int x = 0; x < size.width(); x++)
131 *image.GetAddr32(pp::Point(x, y)) = kColorGrey1;
134 int mid_height = size.height() / 2;
135 int max_amplitude = size.height() * 4 / 10;
137 // Draw some lines.
138 for (int x = 0; x < size.width(); x++) {
139 *image.GetAddr32(pp::Point(x, mid_height)) = kColorGrey3;
140 *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = kColorGrey2;
141 *image.GetAddr32(pp::Point(x, mid_height - max_amplitude)) = kColorGrey2;
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 for (uint32_t ch = 0; ch < std::min(channel_count_, 2U); ++ch) {
150 int y = samples_[i + ch] * max_amplitude /
151 (std::numeric_limits<int16_t>::max() + 1) + mid_height;
152 *image.GetAddr32(pp::Point(x, y)) = (ch == 0 ? kColorRed : kColorGreen);
156 return image;
159 // Callback that is invoked when new buffers are received.
160 void OnGetBuffer(int32_t result, pp::AudioBuffer buffer) {
161 if (result != PP_OK)
162 return;
164 PP_DCHECK(buffer.GetSampleSize() == PP_AUDIOBUFFER_SAMPLESIZE_16_BITS);
165 const char* data = static_cast<const char*>(buffer.GetDataBuffer());
166 uint32_t channels = buffer.GetNumberOfChannels();
167 uint32_t samples = buffer.GetNumberOfSamples() / channels;
169 if (channel_count_ != channels || sample_count_ != samples) {
170 channel_count_ = channels;
171 sample_count_ = samples;
173 samples_.resize(sample_count_ * channel_count_);
174 timer_interval_ = (sample_count_ * 1000) / buffer.GetSampleRate() + 5;
175 // Start the timer for the first buffer.
176 if (first_buffer_) {
177 first_buffer_ = false;
178 ScheduleNextTimer();
182 memcpy(samples_.data(), data,
183 sample_count_ * channel_count_ * sizeof(int16_t));
185 audio_track_.RecycleBuffer(buffer);
186 audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
187 &MediaStreamAudioInstance::OnGetBuffer));
191 pp::MediaStreamAudioTrack audio_track_;
192 pp::CompletionCallbackFactory<MediaStreamAudioInstance> callback_factory_;
194 bool first_buffer_;
195 uint32_t sample_count_;
196 uint32_t channel_count_;
197 std::vector<int16_t> samples_;
199 int32_t timer_interval_;
201 // Painting stuff.
202 pp::Size size_;
203 pp::Graphics2D device_context_;
204 bool pending_paint_;
205 bool waiting_for_flush_completion_;
208 class MediaStreamAudioModule : public pp::Module {
209 public:
210 virtual pp::Instance* CreateInstance(PP_Instance instance) {
211 return new MediaStreamAudioInstance(instance);
215 } // namespace
217 namespace pp {
219 // Factory function for your specialization of the Module object.
220 Module* CreateModule() {
221 return new MediaStreamAudioModule();
224 } // namespace pp