Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ppapi / examples / media_stream_audio / media_stream_audio.cc
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.
4
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <algorithm>
9 #include <limits>
10 #include <vector>
11
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/utility/completion_callback_factory.h"
22
23 // When compiling natively on Windows, PostMessage can be #define-d to
24 // something else.
25 #ifdef PostMessage
26 #undef PostMessage
27 #endif
28
29 // This example demonstrates receiving audio samples from an AndioMediaTrack
30 // and visualizing them.
31
32 namespace {
33
34 const uint32_t kColorRed = 0xFFFF0000;
35 const uint32_t kColorGreen = 0xFF00FF00;
36 const uint32_t kColorGrey1 = 0xFF202020;
37 const uint32_t kColorGrey2 = 0xFF404040;
38 const uint32_t kColorGrey3 = 0xFF606060;
39
40 class MediaStreamAudioInstance : public pp::Instance {
41  public:
42   explicit MediaStreamAudioInstance(PP_Instance instance)
43       : pp::Instance(instance),
44         callback_factory_(this),
45         first_buffer_(true),
46         sample_count_(0),
47         channel_count_(0),
48         timer_interval_(0),
49         pending_paint_(false),
50         waiting_for_flush_completion_(false) {
51   }
52
53   virtual ~MediaStreamAudioInstance() {
54   }
55
56   virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
57     if (position.size() == size_)
58       return;
59
60     size_ = position.size();
61     device_context_ = pp::Graphics2D(this, size_, false);
62     if (!BindGraphics(device_context_))
63       return;
64
65     Paint();
66   }
67
68   virtual void HandleMessage(const pp::Var& var_message) {
69     if (!var_message.is_dictionary())
70       return;
71     pp::VarDictionary var_dictionary_message(var_message);
72     pp::Var var_track = var_dictionary_message.Get("track");
73     if (!var_track.is_resource())
74       return;
75
76     pp::Resource resource_track = var_track.AsResource();
77     audio_track_ = pp::MediaStreamAudioTrack(resource_track);
78     audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
79           &MediaStreamAudioInstance::OnGetBuffer));
80   }
81
82  private:
83   void ScheduleNextTimer() {
84     PP_DCHECK(timer_interval_ > 0);
85     pp::Module::Get()->core()->CallOnMainThread(
86         timer_interval_,
87         callback_factory_.NewCallback(&MediaStreamAudioInstance::OnTimer),
88         0);
89   }
90
91   void OnTimer(int32_t) {
92     ScheduleNextTimer();
93     Paint();
94   }
95
96   void DidFlush(int32_t result) {
97     waiting_for_flush_completion_ = false;
98     if (pending_paint_)
99       Paint();
100   }
101
102   void Paint() {
103     if (waiting_for_flush_completion_) {
104       pending_paint_ = true;
105       return;
106     }
107
108     pending_paint_ = false;
109
110     if (size_.IsEmpty())
111       return;  // Nothing to do.
112
113     pp::ImageData image = PaintImage(size_);
114     if (!image.is_null()) {
115       device_context_.ReplaceContents(&image);
116       waiting_for_flush_completion_ = true;
117       device_context_.Flush(
118           callback_factory_.NewCallback(&MediaStreamAudioInstance::DidFlush));
119     }
120   }
121
122   pp::ImageData PaintImage(const pp::Size& size) {
123     pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
124     if (image.is_null())
125       return image;
126
127     // Clear to dark grey.
128     for (int y = 0; y < size.height(); y++) {
129       for (int x = 0; x < size.width(); x++)
130         *image.GetAddr32(pp::Point(x, y)) = kColorGrey1;
131     }
132
133     int mid_height = size.height() / 2;
134     int max_amplitude = size.height() * 4 / 10;
135
136     // Draw some lines.
137     for (int x = 0; x < size.width(); x++) {
138       *image.GetAddr32(pp::Point(x, mid_height)) = kColorGrey3;
139       *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = kColorGrey2;
140       *image.GetAddr32(pp::Point(x, mid_height - max_amplitude)) = kColorGrey2;
141     }
142
143
144     // Draw our samples.
145     for (int x = 0, i = 0;
146          x < std::min(size.width(), static_cast<int>(sample_count_));
147          x++, i += channel_count_) {
148       for (uint32_t ch = 0; ch < std::min(channel_count_, 2U); ++ch) {
149         int y = samples_[i + ch] * max_amplitude /
150                 (std::numeric_limits<int16_t>::max() + 1) + mid_height;
151         *image.GetAddr32(pp::Point(x, y)) = (ch == 0 ? kColorRed : kColorGreen);
152       }
153     }
154
155     return image;
156   }
157
158   // Callback that is invoked when new buffers are received.
159   void OnGetBuffer(int32_t result, pp::AudioBuffer buffer) {
160     if (result != PP_OK)
161       return;
162
163     PP_DCHECK(buffer.GetSampleSize() == PP_AUDIOBUFFER_SAMPLESIZE_16_BITS);
164     const char* data = static_cast<const char*>(buffer.GetDataBuffer());
165     uint32_t channels = buffer.GetNumberOfChannels();
166     uint32_t samples = buffer.GetNumberOfSamples() / channels;
167
168     if (channel_count_ != channels || sample_count_ != samples) {
169       channel_count_ = channels;
170       sample_count_ = samples;
171
172       samples_.resize(sample_count_ * channel_count_);
173       timer_interval_ = (sample_count_ * 1000) / buffer.GetSampleRate() + 5;
174       // Start the timer for the first buffer.
175       if (first_buffer_) {
176         first_buffer_ = false;
177         ScheduleNextTimer();
178       }
179     }
180
181     memcpy(samples_.data(), data,
182         sample_count_ * channel_count_ * sizeof(int16_t));
183
184     audio_track_.RecycleBuffer(buffer);
185     audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput(
186         &MediaStreamAudioInstance::OnGetBuffer));
187
188   }
189
190   pp::MediaStreamAudioTrack audio_track_;
191   pp::CompletionCallbackFactory<MediaStreamAudioInstance> callback_factory_;
192
193   bool first_buffer_;
194   uint32_t sample_count_;
195   uint32_t channel_count_;
196   std::vector<int16_t> samples_;
197
198   int32_t timer_interval_;
199
200   // Painting stuff.
201   pp::Size size_;
202   pp::Graphics2D device_context_;
203   bool pending_paint_;
204   bool waiting_for_flush_completion_;
205 };
206
207 class MediaStreamAudioModule : public pp::Module {
208  public:
209   virtual pp::Instance* CreateInstance(PP_Instance instance) {
210     return new MediaStreamAudioInstance(instance);
211   }
212 };
213
214 }  // namespace
215
216 namespace pp {
217
218 // Factory function for your specialization of the Module object.
219 Module* CreateModule() {
220   return new MediaStreamAudioModule();
221 }
222
223 }  // namespace pp